Bot become a Community Guard & Post send manager

added: dictionary support for censore
message/user management with dict triggers
This commit is contained in:
2025-08-22 21:44:14 +09:00
parent efdafb0efa
commit c16ec54891
27 changed files with 1746 additions and 184 deletions

View File

@@ -0,0 +1,185 @@
"""wip
Revision ID: 492141c83560
Revises: 0001_init
Create Date: 2025-08-22 09:31:45.682385
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '492141c83560'
down_revision = '0001_init'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('message_events',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.Column('tg_user_id', sa.BigInteger(), nullable=False),
sa.Column('message_id', sa.BigInteger(), nullable=True),
sa.Column('content_hash', sa.String(length=128), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_message_events_chat_id'), 'message_events', ['chat_id'], unique=False)
op.create_index(op.f('ix_message_events_content_hash'), 'message_events', ['content_hash'], unique=False)
op.create_index(op.f('ix_message_events_tg_user_id'), 'message_events', ['tg_user_id'], unique=False)
op.create_table('moderation_logs',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.Column('tg_user_id', sa.BigInteger(), nullable=False),
sa.Column('message_id', sa.BigInteger(), nullable=True),
sa.Column('reason', sa.Text(), nullable=False),
sa.Column('action', sa.String(length=16), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_moderation_logs_chat_id'), 'moderation_logs', ['chat_id'], unique=False)
op.create_index(op.f('ix_moderation_logs_tg_user_id'), 'moderation_logs', ['tg_user_id'], unique=False)
op.create_table('user_strikes',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.Column('tg_user_id', sa.BigInteger(), nullable=False),
sa.Column('strikes', sa.Integer(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('chat_id', 'tg_user_id', name='uq_strikes_chat_user')
)
op.create_index(op.f('ix_user_strikes_chat_id'), 'user_strikes', ['chat_id'], unique=False)
op.create_index(op.f('ix_user_strikes_tg_user_id'), 'user_strikes', ['tg_user_id'], unique=False)
op.create_table('chat_members',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('tg_user_id', sa.BigInteger(), nullable=False),
sa.Column('username', sa.String(length=255), nullable=True),
sa.Column('first_name', sa.String(length=255), nullable=True),
sa.Column('last_name', sa.String(length=255), nullable=True),
sa.Column('status', sa.String(length=32), nullable=True),
sa.Column('is_admin', sa.Boolean(), nullable=False),
sa.Column('first_seen_at', sa.DateTime(), nullable=False),
sa.Column('last_seen_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('chat_id', 'tg_user_id', name='uq_chat_members_chat_user')
)
op.create_index(op.f('ix_chat_members_chat_id'), 'chat_members', ['chat_id'], unique=False)
op.create_index(op.f('ix_chat_members_status'), 'chat_members', ['status'], unique=False)
op.create_index(op.f('ix_chat_members_tg_user_id'), 'chat_members', ['tg_user_id'], unique=False)
op.create_index(op.f('ix_chat_members_user_id'), 'chat_members', ['user_id'], unique=False)
op.create_table('security_policies',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('owner_user_id', sa.Integer(), nullable=True),
sa.Column('name', sa.String(length=100), nullable=False),
sa.Column('block_adult', sa.Boolean(), nullable=False),
sa.Column('block_spam', sa.Boolean(), nullable=False),
sa.Column('block_scam', sa.Boolean(), nullable=False),
sa.Column('block_profanity', sa.Boolean(), nullable=False),
sa.Column('cooldown_seconds', sa.Integer(), nullable=False),
sa.Column('duplicate_window_seconds', sa.Integer(), nullable=False),
sa.Column('max_links', sa.Integer(), nullable=False),
sa.Column('max_mentions', sa.Integer(), nullable=False),
sa.Column('use_whitelist', sa.Boolean(), nullable=False),
sa.Column('enforce_action_default', sa.String(length=16), nullable=False),
sa.Column('timeout_minutes', sa.Integer(), nullable=False),
sa.Column('strikes_to_warn', sa.Integer(), nullable=False),
sa.Column('strikes_to_timeout', sa.Integer(), nullable=False),
sa.Column('strikes_to_ban', sa.Integer(), nullable=False),
sa.Column('user_msg_per_minute', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['owner_user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_security_policies_owner_user_id'), 'security_policies', ['owner_user_id'], unique=False)
op.create_table('spam_dictionaries',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('owner_user_id', sa.Integer(), nullable=True),
sa.Column('name', sa.String(length=120), nullable=False),
sa.Column('category', sa.String(length=32), nullable=False),
sa.Column('kind', sa.String(length=16), nullable=False),
sa.Column('lang', sa.String(length=8), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['owner_user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_spam_dictionaries_owner_user_id'), 'spam_dictionaries', ['owner_user_id'], unique=False)
op.create_table('chat_security',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.Column('policy_id', sa.Integer(), nullable=False),
sa.Column('enabled', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['policy_id'], ['security_policies.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_chat_security_chat_id'), 'chat_security', ['chat_id'], unique=True)
op.create_index(op.f('ix_chat_security_policy_id'), 'chat_security', ['policy_id'], unique=False)
op.create_table('dictionary_entries',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('dictionary_id', sa.Integer(), nullable=False),
sa.Column('pattern', sa.Text(), nullable=False),
sa.Column('is_regex', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(['dictionary_id'], ['spam_dictionaries.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_dictionary_entries_dictionary_id'), 'dictionary_entries', ['dictionary_id'], unique=False)
op.create_table('domain_rules',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('policy_id', sa.Integer(), nullable=False),
sa.Column('domain', sa.String(length=255), nullable=False),
sa.Column('kind', sa.String(length=16), nullable=False),
sa.ForeignKeyConstraint(['policy_id'], ['security_policies.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('policy_id', 'domain', 'kind', name='uq_domain_rule')
)
op.create_index(op.f('ix_domain_rules_policy_id'), 'domain_rules', ['policy_id'], unique=False)
op.create_table('policy_dict_links',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('policy_id', sa.Integer(), nullable=False),
sa.Column('dictionary_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['dictionary_id'], ['spam_dictionaries.id'], ),
sa.ForeignKeyConstraint(['policy_id'], ['security_policies.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('policy_id', 'dictionary_id', name='uq_policy_dict')
)
op.create_index(op.f('ix_policy_dict_links_dictionary_id'), 'policy_dict_links', ['dictionary_id'], unique=False)
op.create_index(op.f('ix_policy_dict_links_policy_id'), 'policy_dict_links', ['policy_id'], unique=False)
op.add_column('deliveries', sa.Column('content_hash', sa.String(length=128), nullable=True))
op.create_index(op.f('ix_deliveries_content_hash'), 'deliveries', ['content_hash'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_deliveries_content_hash'), table_name='deliveries')
op.drop_column('deliveries', 'content_hash')
op.drop_index(op.f('ix_policy_dict_links_policy_id'), table_name='policy_dict_links')
op.drop_index(op.f('ix_policy_dict_links_dictionary_id'), table_name='policy_dict_links')
op.drop_table('policy_dict_links')
op.drop_index(op.f('ix_domain_rules_policy_id'), table_name='domain_rules')
op.drop_table('domain_rules')
op.drop_index(op.f('ix_dictionary_entries_dictionary_id'), table_name='dictionary_entries')
op.drop_table('dictionary_entries')
op.drop_index(op.f('ix_chat_security_policy_id'), table_name='chat_security')
op.drop_index(op.f('ix_chat_security_chat_id'), table_name='chat_security')
op.drop_table('chat_security')
op.drop_index(op.f('ix_spam_dictionaries_owner_user_id'), table_name='spam_dictionaries')
op.drop_table('spam_dictionaries')
op.drop_index(op.f('ix_security_policies_owner_user_id'), table_name='security_policies')
op.drop_table('security_policies')
op.drop_index(op.f('ix_chat_members_user_id'), table_name='chat_members')
op.drop_index(op.f('ix_chat_members_tg_user_id'), table_name='chat_members')
op.drop_index(op.f('ix_chat_members_status'), table_name='chat_members')
op.drop_index(op.f('ix_chat_members_chat_id'), table_name='chat_members')
op.drop_table('chat_members')
op.drop_index(op.f('ix_user_strikes_tg_user_id'), table_name='user_strikes')
op.drop_index(op.f('ix_user_strikes_chat_id'), table_name='user_strikes')
op.drop_table('user_strikes')
op.drop_index(op.f('ix_moderation_logs_tg_user_id'), table_name='moderation_logs')
op.drop_index(op.f('ix_moderation_logs_chat_id'), table_name='moderation_logs')
op.drop_table('moderation_logs')
op.drop_index(op.f('ix_message_events_tg_user_id'), table_name='message_events')
op.drop_index(op.f('ix_message_events_content_hash'), table_name='message_events')
op.drop_index(op.f('ix_message_events_chat_id'), table_name='message_events')
op.drop_table('message_events')
# ### end Alembic commands ###