"""数据库模型定义""" from tortoise import fields from tortoise.models import Model class TimestampMixin: """通用时间戳字段。所有业务表统一包含 created_at / updated_at。""" created_at = fields.DatetimeField(auto_now_add=True, description="创建时间") updated_at = fields.DatetimeField(auto_now=True, description="更新时间") class Message(TimestampMixin, Model): """消息记录""" id = fields.BigIntField(pk=True, generated=True) msg_id = fields.BigIntField(null=True) chat_id = fields.BigIntField() user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) first_name = fields.CharField(max_length=255, null=True) text = fields.TextField(null=True) is_spam = fields.BooleanField(default=False) spam_reason = fields.CharField(max_length=255, null=True) manually_deleted = fields.BooleanField(default=False) deleted_at = fields.DatetimeField(null=True) delete_reason = fields.CharField(max_length=255, null=True) class Meta: table = "messages" indexes = (("chat_id", "msg_id"), ("user_id", "created_at"), ("is_spam", "created_at")) class Ban(TimestampMixin, Model): """封禁记录""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) first_name = fields.CharField(max_length=255, null=True) reason = fields.CharField(max_length=500, null=True) method = fields.CharField(max_length=50, default="auto") # auto/command/verify_fail duration_minutes = fields.IntField(default=2) auto_unban = fields.BooleanField(default=True) unban_at = fields.DatetimeField(null=True) class Meta: table = "bans" indexes = (("user_id", "created_at"), ("auto_unban", "unban_at")) class Action(TimestampMixin, Model): """操作日志(入群/退群/删除/解封/警告等)""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) action = fields.CharField(max_length=50) user_id = fields.BigIntField(null=True) username = fields.CharField(max_length=255, null=True) operator_id = fields.BigIntField(null=True) details = fields.JSONField(null=True) class Meta: table = "actions" indexes = (("action", "created_at"), ("user_id", "created_at"), ("operator_id", "created_at")) class VerifyQueue(TimestampMixin, Model): """入群验证队列""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) question = fields.CharField(max_length=500, null=True) answer = fields.CharField(max_length=500, null=True) attempts = fields.IntField(default=0) status = fields.CharField(max_length=20, default="pending") verified_at = fields.DatetimeField(null=True) class Meta: table = "verify_queue" indexes = (("user_id", "status"), ("status", "created_at")) class UserBinding(TimestampMixin, Model): """TG ↔ Harvest 账号绑定""" id = fields.BigIntField(pk=True, generated=True) tg_user_id = fields.BigIntField(unique=True) tg_username = fields.CharField(max_length=255, null=True) harvest_uid = fields.CharField(max_length=255, null=True) harvest_token = fields.CharField(max_length=500, null=True) auth_email = fields.CharField(max_length=255, null=True) time_expire = fields.CharField(max_length=100, null=True) # 兼容旧代码/展示语义:绑定时间;created_at 仍作为统一审计字段 bound_at = fields.DatetimeField(auto_now_add=True) class Meta: table = "user_bindings" indexes = (("tg_user_id",), ("harvest_uid",)) class Warning(TimestampMixin, Model): """警告记录""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) reason = fields.CharField(max_length=500, null=True) operator_id = fields.BigIntField(null=True) active = fields.BooleanField(default=True) class Meta: table = "warnings" indexes = (("user_id", "active"), ("operator_id", "created_at")) class GameScore(TimestampMixin, Model): """游戏积分""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) game_type = fields.CharField(max_length=50) score = fields.IntField(default=0) wins = fields.IntField(default=0) total = fields.IntField(default=0) streak = fields.IntField(default=0) last_played = fields.DatetimeField(null=True) class Meta: table = "game_scores" unique_together = (("chat_id", "user_id", "game_type"),) indexes = (("chat_id", "game_type", "score"), ("chat_id", "user_id", "game_type")) class GroupConfig(TimestampMixin, Model): """群组配置""" key = fields.CharField(max_length=100, pk=True) value = fields.JSONField(null=True) class Meta: table = "group_config" class ShopItem(TimestampMixin, Model): """群组积分商城商品""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) item_key = fields.CharField(max_length=50) name = fields.CharField(max_length=255) cost = fields.IntField(default=0) desc = fields.CharField(max_length=500, null=True) enabled = fields.BooleanField(default=True) class Meta: table = "shop_items" unique_together = (("chat_id", "item_key"),) indexes = (("chat_id", "enabled"),) class ShopTransaction(TimestampMixin, Model): """积分商城交易记录""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField(default=0) user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) item_key = fields.CharField(max_length=50) item_name = fields.CharField(max_length=255) cost = fields.IntField(default=0) status = fields.CharField(max_length=30, default="success") note = fields.CharField(max_length=500, null=True) class Meta: table = "shop_transactions" indexes = (("chat_id", "created_at"), ("chat_id", "user_id"), ("item_key", "created_at"),) class LotteryEvent(TimestampMixin, Model): """群内抽奖活动""" id = fields.BigIntField(pk=True, generated=True) chat_id = fields.BigIntField() message_id = fields.BigIntField(null=True) creator_id = fields.BigIntField() creator_name = fields.CharField(max_length=255, null=True) title = fields.CharField(max_length=255, null=True) description = fields.TextField(null=True) draw_type = fields.CharField(max_length=50, default="people") # instant/people/time/manual draw_at = fields.DatetimeField(null=True) max_participants = fields.IntField(default=0) prize = fields.CharField(max_length=500) condition_type = fields.CharField(max_length=50, default="all") # all/checkin/min_points condition_value = fields.IntField(default=0) end_type = fields.CharField(max_length=50, default="people") # people/minutes/manual end_value = fields.IntField(default=0) status = fields.CharField(max_length=20, default="active") winner_id = fields.BigIntField(null=True) winner_name = fields.CharField(max_length=255, null=True) ended_at = fields.DatetimeField(null=True) class Meta: table = "lottery_events" indexes = (("chat_id", "status"), ("creator_id", "created_at")) class LotteryParticipant(TimestampMixin, Model): """抽奖参与者""" id = fields.BigIntField(pk=True, generated=True) event_id = fields.BigIntField() user_id = fields.BigIntField() username = fields.CharField(max_length=255, null=True) first_name = fields.CharField(max_length=255, null=True) class Meta: table = "lottery_participants" indexes = (("event_id", "user_id"),)