diff --git a/app/filters.py b/app/filters.py index 9386e8f..875315c 100644 --- a/app/filters.py +++ b/app/filters.py @@ -27,6 +27,7 @@ REASON_TRANSLATIONS = { 'reselling': '倒卖邀请', 'harassment': '骚扰他人', 'scamming': '诈骗行为', + 'no_data': '注册后无数据', 'other': '其他 (请在描述中详述)' } diff --git a/migrations/versions/db2662009e3d_merge_multiple_reports_for_same_user.py b/migrations/versions/db2662009e3d_merge_multiple_reports_for_same_user.py new file mode 100644 index 0000000..9f4f950 --- /dev/null +++ b/migrations/versions/db2662009e3d_merge_multiple_reports_for_same_user.py @@ -0,0 +1,198 @@ +"""merge multiple reports for same user + +Revision ID: db2662009e3d +Revises: +Create Date: 2025-11-24 22:33:03.614231 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'db2662009e3d' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('blacklist', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('username', sa.String(length=64), nullable=True), + sa.Column('email', sa.String(length=120), nullable=True), + sa.Column('normalized_email', sa.String(length=120), nullable=True), + sa.Column('pt_site', sa.String(length=100), nullable=True), + sa.Column('uid', sa.String(length=50), nullable=True), + sa.Column('report_ids', sa.JSON(), nullable=False), + sa.Column('reason_categories', sa.JSON(), nullable=False), + sa.Column('status', sa.String(length=16), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('blacklist', schema=None) as batch_op: + batch_op.create_index('idx_blacklist_email_status', ['normalized_email', 'status'], unique=False) + batch_op.create_index('idx_blacklist_username_status', ['username', 'status'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_created_at'), ['created_at'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_email'), ['email'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_normalized_email'), ['normalized_email'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_pt_site'), ['pt_site'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_status'), ['status'], unique=False) + batch_op.create_index(batch_op.f('ix_blacklist_username'), ['username'], unique=False) + + op.create_table('partner_sites', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=100), nullable=False), + sa.Column('url', sa.String(length=255), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('partner_sites', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_partner_sites_is_active'), ['is_active'], unique=False) + batch_op.create_index(batch_op.f('ix_partner_sites_name'), ['name'], unique=True) + + op.create_table('users', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('username', sa.String(length=64), nullable=False), + sa.Column('email', sa.String(length=120), nullable=False), + sa.Column('password_hash', sa.String(length=256), nullable=True), + sa.Column('role', sa.String(length=16), nullable=True), + sa.Column('status', sa.String(length=16), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('pt_site', sa.String(length=100), nullable=True), + sa.Column('uid', sa.String(length=50), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_users_email'), ['email'], unique=True) + batch_op.create_index(batch_op.f('ix_users_role'), ['role'], unique=False) + batch_op.create_index(batch_op.f('ix_users_status'), ['status'], unique=False) + batch_op.create_index(batch_op.f('ix_users_username'), ['username'], unique=True) + + op.create_table('appeals', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('reason', sa.Text(), nullable=False), + sa.Column('status', sa.String(length=32), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.Column('appealer_id', sa.Integer(), nullable=True), + sa.Column('blacklist_entry_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['appealer_id'], ['users.id'], ondelete='CASCADE'), + sa.ForeignKeyConstraint(['blacklist_entry_id'], ['blacklist.id'], ondelete='SET NULL'), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('appeals', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_appeals_created_at'), ['created_at'], unique=False) + batch_op.create_index(batch_op.f('ix_appeals_status'), ['status'], unique=False) + + op.create_table('reports', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('reporter_id', sa.Integer(), nullable=False), + sa.Column('reported_pt_site', sa.String(length=100), nullable=False), + sa.Column('reported_username', sa.String(length=50), nullable=True), + sa.Column('reported_email', sa.String(length=120), nullable=False), + sa.Column('reason_category', sa.String(length=16), nullable=False), + sa.Column('description', sa.Text(), nullable=False), + sa.Column('status', sa.String(length=16), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['reporter_id'], ['users.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('reports', schema=None) as batch_op: + batch_op.create_index('idx_report_status_created', ['status', 'created_at'], unique=False) + batch_op.create_index(batch_op.f('ix_reports_created_at'), ['created_at'], unique=False) + batch_op.create_index(batch_op.f('ix_reports_reported_email'), ['reported_email'], unique=False) + batch_op.create_index(batch_op.f('ix_reports_status'), ['status'], unique=False) + + op.create_table('appeal_messages', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('body', sa.Text(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('author_id', sa.Integer(), nullable=True), + sa.Column('appeal_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['appeal_id'], ['appeals.id'], ondelete='CASCADE'), + sa.ForeignKeyConstraint(['author_id'], ['users.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('appeal_messages', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_appeal_messages_created_at'), ['created_at'], unique=False) + + op.create_table('comments', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('body', sa.Text(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('author_id', sa.Integer(), nullable=True), + sa.Column('report_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['author_id'], ['users.id'], ondelete='CASCADE'), + sa.ForeignKeyConstraint(['report_id'], ['reports.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('comments', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_comments_created_at'), ['created_at'], unique=False) + + op.create_table('evidences', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('report_id', sa.Integer(), nullable=False), + sa.Column('file_url', sa.String(length=1024), nullable=False), + sa.Column('file_type', sa.String(length=16), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['report_id'], ['reports.id'], ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('evidences') + with op.batch_alter_table('comments', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_comments_created_at')) + + op.drop_table('comments') + with op.batch_alter_table('appeal_messages', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_appeal_messages_created_at')) + + op.drop_table('appeal_messages') + with op.batch_alter_table('reports', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_reports_status')) + batch_op.drop_index(batch_op.f('ix_reports_reported_email')) + batch_op.drop_index(batch_op.f('ix_reports_created_at')) + batch_op.drop_index('idx_report_status_created') + + op.drop_table('reports') + with op.batch_alter_table('appeals', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_appeals_status')) + batch_op.drop_index(batch_op.f('ix_appeals_created_at')) + + op.drop_table('appeals') + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_users_username')) + batch_op.drop_index(batch_op.f('ix_users_status')) + batch_op.drop_index(batch_op.f('ix_users_role')) + batch_op.drop_index(batch_op.f('ix_users_email')) + + op.drop_table('users') + with op.batch_alter_table('partner_sites', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_partner_sites_name')) + batch_op.drop_index(batch_op.f('ix_partner_sites_is_active')) + + op.drop_table('partner_sites') + with op.batch_alter_table('blacklist', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_blacklist_username')) + batch_op.drop_index(batch_op.f('ix_blacklist_status')) + batch_op.drop_index(batch_op.f('ix_blacklist_pt_site')) + batch_op.drop_index(batch_op.f('ix_blacklist_normalized_email')) + batch_op.drop_index(batch_op.f('ix_blacklist_email')) + batch_op.drop_index(batch_op.f('ix_blacklist_created_at')) + batch_op.drop_index('idx_blacklist_username_status') + batch_op.drop_index('idx_blacklist_email_status') + + op.drop_table('blacklist') + # ### end Alembic commands ###