-
Notifications
You must be signed in to change notification settings - Fork 100
Backend/moderation: UMS coverage for thread comments and replies #8510
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
e398051
Backend/moderation: UMS coverage for thread comments and replies
aapeliv 00be2cb
Generate migrations
couchersbot[bot] b633a07
Migration 0149: extend moderationobjecttype enum and backfill states
aapeliv f6a89e4
Address review: use moderation helper in threads, backfill ID range i…
aapeliv 7998edc
Renumber UMS migration 0149 -> 0151 after rebase onto develop
aapeliv 9d2de66
Test that total_num_responses includes author's own shadowed content
aapeliv d766ae5
Address review: take viewing user id, use unpack_thread_id
aapeliv f799b94
Revert thread_to_pb / total_num_responses to take CouchersContext
aapeliv cf11811
Renumber UMS migration 0151 -> 0152 after rebase onto develop
aapeliv 4180a6f
Restore original comments on pack/unpack_thread_id
aapeliv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
145 changes: 145 additions & 0 deletions
145
app/backend/src/couchers/migrations/versions/0152_backend_moderation_ums_coverage_for_.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| """Backend/moderation: UMS coverage for thread comments and replies | ||
|
|
||
| Revision ID: 0152 | ||
| Revises: 0151 | ||
| Create Date: 2026-05-10 00:57:29.125757 | ||
|
|
||
| """ | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = "0152" | ||
| down_revision = "0151" | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| # Add 'comment' and 'reply' to the ModerationObjectType enum. | ||
| # Must use rename/recreate pattern instead of ADD VALUE, because ADD VALUE | ||
| # cannot be used in the same transaction as DML that references the new value. | ||
| op.execute("ALTER TYPE moderationobjecttype RENAME TO moderationobjecttype_old") | ||
| op.execute( | ||
| "CREATE TYPE moderationobjecttype AS ENUM " | ||
| "('host_request', 'group_chat', 'friend_request', 'event_occurrence', 'comment', 'reply')" | ||
| ) | ||
| op.execute(""" | ||
| ALTER TABLE moderation_states | ||
| ALTER COLUMN object_type TYPE moderationobjecttype | ||
| USING object_type::text::moderationobjecttype | ||
| """) | ||
| op.execute("DROP TYPE moderationobjecttype_old") | ||
|
|
||
| # Add moderation_state_id columns as nullable so we can backfill before enforcing NOT NULL. | ||
| op.add_column("comments", sa.Column("moderation_state_id", sa.BigInteger(), nullable=True)) | ||
| op.add_column("replies", sa.Column("moderation_state_id", sa.BigInteger(), nullable=True)) | ||
|
|
||
| # Backfill moderation states for existing comments (using the < 2000000 ID range reserved for backfills) | ||
| op.execute(""" | ||
| INSERT INTO moderation_states (id, object_type, object_id, visibility) | ||
| SELECT | ||
| (SELECT COALESCE(MAX(id), 0) FROM moderation_states WHERE id < 2000000) + ROW_NUMBER() OVER (ORDER BY id), | ||
| 'comment', | ||
| id, | ||
| 'visible' | ||
| FROM comments | ||
| """) | ||
| op.execute(""" | ||
| INSERT INTO moderation_log (id, moderation_state_id, action, moderator_user_id, new_visibility, reason) | ||
| SELECT | ||
| (SELECT GREATEST( | ||
| COALESCE((SELECT MAX(id) FROM moderation_states WHERE id < 2000000), 0), | ||
| COALESCE((SELECT MAX(id) FROM moderation_log WHERE id < 2000000), 0) | ||
| )) + ROW_NUMBER() OVER (ORDER BY c.id), | ||
| ms.id, | ||
| 'create', | ||
| c.author_user_id, | ||
| 'visible', | ||
| 'Migration: existing comment' | ||
| FROM moderation_states ms | ||
| JOIN comments c ON ms.object_id = c.id AND ms.object_type = 'comment' | ||
| """) | ||
| op.execute(""" | ||
| UPDATE comments | ||
| SET moderation_state_id = moderation_states.id | ||
| FROM moderation_states | ||
| WHERE moderation_states.object_type = 'comment' | ||
| AND moderation_states.object_id = comments.id | ||
| """) | ||
|
|
||
| # Backfill moderation states for existing replies (using the < 2000000 ID range reserved for backfills) | ||
| op.execute(""" | ||
| INSERT INTO moderation_states (id, object_type, object_id, visibility) | ||
| SELECT | ||
| (SELECT COALESCE(MAX(id), 0) FROM moderation_states WHERE id < 2000000) + ROW_NUMBER() OVER (ORDER BY id), | ||
| 'reply', | ||
| id, | ||
| 'visible' | ||
| FROM replies | ||
| """) | ||
| op.execute(""" | ||
| INSERT INTO moderation_log (id, moderation_state_id, action, moderator_user_id, new_visibility, reason) | ||
| SELECT | ||
| (SELECT GREATEST( | ||
| COALESCE((SELECT MAX(id) FROM moderation_states WHERE id < 2000000), 0), | ||
| COALESCE((SELECT MAX(id) FROM moderation_log WHERE id < 2000000), 0) | ||
| )) + ROW_NUMBER() OVER (ORDER BY r.id), | ||
| ms.id, | ||
| 'create', | ||
| r.author_user_id, | ||
| 'visible', | ||
| 'Migration: existing reply' | ||
| FROM moderation_states ms | ||
| JOIN replies r ON ms.object_id = r.id AND ms.object_type = 'reply' | ||
| """) | ||
| op.execute(""" | ||
| UPDATE replies | ||
| SET moderation_state_id = moderation_states.id | ||
| FROM moderation_states | ||
| WHERE moderation_states.object_type = 'reply' | ||
| AND moderation_states.object_id = replies.id | ||
| """) | ||
|
|
||
| # Now enforce NOT NULL and add the index + FK constraints. | ||
| op.alter_column("comments", "moderation_state_id", nullable=False) | ||
| op.create_index(op.f("ix_comments_moderation_state_id"), "comments", ["moderation_state_id"], unique=False) | ||
| op.create_foreign_key( | ||
| op.f("fk_comments_moderation_state_id_moderation_states"), | ||
| "comments", | ||
| "moderation_states", | ||
| ["moderation_state_id"], | ||
| ["id"], | ||
| ) | ||
|
|
||
| op.alter_column("replies", "moderation_state_id", nullable=False) | ||
| op.create_index(op.f("ix_replies_moderation_state_id"), "replies", ["moderation_state_id"], unique=False) | ||
| op.create_foreign_key( | ||
| op.f("fk_replies_moderation_state_id_moderation_states"), | ||
| "replies", | ||
| "moderation_states", | ||
| ["moderation_state_id"], | ||
| ["id"], | ||
| ) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| op.drop_constraint(op.f("fk_replies_moderation_state_id_moderation_states"), "replies", type_="foreignkey") | ||
| op.drop_index(op.f("ix_replies_moderation_state_id"), table_name="replies") | ||
| op.drop_column("replies", "moderation_state_id") | ||
| op.drop_constraint(op.f("fk_comments_moderation_state_id_moderation_states"), "comments", type_="foreignkey") | ||
| op.drop_index(op.f("ix_comments_moderation_state_id"), table_name="comments") | ||
| op.drop_column("comments", "moderation_state_id") | ||
|
|
||
| # Clean up moderation data for comments and replies. | ||
| op.execute(""" | ||
| DELETE FROM moderation_log | ||
| WHERE moderation_state_id IN ( | ||
| SELECT id FROM moderation_states WHERE object_type IN ('comment', 'reply') | ||
| ) | ||
| """) | ||
| op.execute("DELETE FROM moderation_states WHERE object_type IN ('comment', 'reply')") | ||
|
|
||
| # Note: we cannot remove enum values in PostgreSQL easily, so we leave 'comment'/'reply' | ||
| # in the moderationobjecttype enum. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.