Skip to content

Discover moderated content models dynamically#8652

Merged
aapeliv merged 4 commits into
developfrom
backend/refactor/ums-moderation-registry
May 18, 2026
Merged

Discover moderated content models dynamically#8652
aapeliv merged 4 commits into
developfrom
backend/refactor/ums-moderation-registry

Conversation

@aapeliv

@aapeliv aapeliv commented May 17, 2026

Copy link
Copy Markdown
Member

Pure refactor of the Unified Moderation System plumbing, no behavior change.

Previously the set of UMS-governed models was encoded in several hand-maintained places: the seven per-object-type branches inside moderation_state_column_visible, the moderationobjecttype2model dict in servicers/moderation.py, and the _ModeratedContent union in sql.py. Adding a moderated type meant updating each.

This replaces them with a single source of truth on the models themselves:

  • Each moderated model declares __moderation_object_type__ alongside the existing __moderation_author_column__.
  • get_moderated_models() discovers them by scanning the SQLAlchemy mapper registry and returns {ModerationObjectType: ModeratedModel}, where ModeratedModel resolves the model, object type, and author column.
  • moderation_state_column_visible and servicers/moderation.py now iterate that registry instead of hardcoded lists.
  • The duplicated mutual-block exists(...) clause is factored into a _users_block_each_other helper.

Testing

  • make format and make mypy pass (the two remaining mypy errors — test_calendar_events.py missing ics stubs and fixtures/misc.py return type — are pre-existing on develop).
  • 142 tests pass across test_moderation, test_threads, test_notifications, test_discussions.
  • To replicate: cd app/backend && make format && make mypy && uv run pytest.

Backend checklist

  • Added tests for any new code or added a regression test if fixing a bug
  • Run the backend locally and it works
  • Added migrations if there are any database changes, rebased onto develop if necessary for linear migration history (no DB changes)

For maintainers

  • Maintainers can push commits to my branch
  • Maintainers can merge this PR for me

This PR was created with the Couchers PR skill.

Replace the hand-maintained moderated-model lists (the per-type branches in
moderation_state_column_visible and the moderationobjecttype2model dict) with a
registry built from __moderation_object_type__ declared on each model, and
factor the duplicated mutual-block clause into a shared helper.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
couchers Ready Ready Preview May 18, 2026 3:00am

Request Review

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aapeliv
aapeliv marked this pull request as ready for review May 17, 2026 13:53
@aapeliv
aapeliv requested a review from tristanlabelle May 17, 2026 13:53
tristanlabelle
tristanlabelle previously approved these changes May 17, 2026

@tristanlabelle tristanlabelle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, much better. I think we can still go one step further with typing.Protocol.

Comment on lines +27 to +29
type ModeratedContentModel = type[
HostRequest | GroupChat | FriendRelationship | EventOccurrence | Comment | Reply | Discussion
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried using typing.Protocol? My proof-of-concept works great and avoids the union and getattr(cls, cls.__moderation_author_column__),.

from enum import Enum, auto
from typing import ClassVar, Protocol

class ModerationObjectType(Enum):
    event_occurrence = auto()

class ModeratedContent(Protocol):
    __moderation_author_column__: ClassVar[str]
    __moderation_object_type__: ClassVar[ModerationObjectType]
    # id: Mapped[int]

class EventOccurrence:
    __moderation_author_column__ = "creator_user_id"
    __moderation_object_type__ = ModerationObjectType.event_occurrence


moderated_content_type: type[ModeratedContent] = EventOccurrence
print(moderated_content_type.__moderation_author_column__)
print(moderated_content_type.__moderation_object_type__)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, implemented, thanks! typing was a bit inflexible, otherwise worked

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aapeliv
aapeliv merged commit d64a3d5 into develop May 18, 2026
7 checks passed
@aapeliv
aapeliv deleted the backend/refactor/ums-moderation-registry branch May 18, 2026 03:11
@github-actions

Copy link
Copy Markdown
Contributor

📝 Release Notes

This PR does not need to be included in release notes.

Reason: This PR is explicitly described as a pure refactor of moderation system plumbing with no behavior change. It improves internal maintainability and reduces hand-maintained duplication, but does not add a user-facing feature, noticeable UX improvement, or clearly significant end-user-impacting reliability change on its own.

🤖 Bot Debug Information

Model: couchers.openai.gpt-5.4
Decision: exclude
Reasoning: This PR is explicitly described as a pure refactor of moderation system plumbing with no behavior change. It improves internal maintainability and reduces hand-maintained duplication, but does not add a user-facing feature, noticeable UX improvement, or clearly significant end-user-impacting reliability change on its own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants