"""ORM 模型""" from datetime import datetime, timezone from sqlalchemy import ( Column, Integer, String, Boolean, Text, DateTime, ForeignKey, JSON, ) from sqlalchemy.orm import relationship from .database import Base from .crypto_storage import EncryptedText def _utcnow(): """返回时区感知的 UTC 当前时间,替代 _utcnow()。""" return datetime.now(timezone.utc) class User(Base): """系统用户""" __tablename__ = "users" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(64), unique=True, nullable=False, index=True) password_hash = Column(String(256), nullable=False) role = Column(String(32), nullable=False, default="support") # super_admin / operation / support is_active = Column(Boolean, default=True) remark = Column(String(256), default="") custom_permissions = Column(JSON, nullable=True, comment="自定义权限列表,null表示使用角色默认权限") created_at = Column(DateTime, default=_utcnow) updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow) # 客服被分配的账号 assigned_accounts = relationship("Account", back_populates="assigned_user", foreign_keys="Account.assigned_to") class Account(Base): """斗鱼账号""" __tablename__ = "accounts" id = Column(Integer, primary_key=True, autoincrement=True) username = Column(String(128), nullable=False) password = Column(EncryptedText(), nullable=False) email = Column(EncryptedText(), nullable=False) email_password = Column(EncryptedText(), nullable=False) email_imap_server = Column(String(128), default="") email_imap_port = Column(Integer, default=993) email_imap_ssl = Column(Boolean, default=True) assigned_to = Column(Integer, ForeignKey("users.id"), nullable=True, index=True) tag = Column(String(64), default="") remark = Column(String(256), default="") created_at = Column(DateTime, default=_utcnow) assigned_user = relationship("User", back_populates="assigned_accounts", foreign_keys=[assigned_to]) login_tasks = relationship("LoginTask", back_populates="account") class LoginTask(Base): """单次登录任务""" __tablename__ = "login_tasks" id = Column(Integer, primary_key=True, autoincrement=True) batch_id = Column(String(64), nullable=False, index=True) # 批次ID account_id = Column(Integer, ForeignKey("accounts.id"), nullable=False) status = Column(String(32), default="pending") # pending / running / success / failed / error cookie = Column(EncryptedText(), default="") message = Column(String(512), default="") created_by = Column(Integer, ForeignKey("users.id"), nullable=False) created_at = Column(DateTime, default=_utcnow) finished_at = Column(DateTime, nullable=True) account = relationship("Account", back_populates="login_tasks") class ProxyConfig(Base): """代理配置(全局单条记录)""" __tablename__ = "proxy_config" id = Column(Integer, primary_key=True, autoincrement=True) enabled = Column(Boolean, default=False) api_url = Column(EncryptedText(), default="") http = Column(EncryptedText(), default="") https = Column(EncryptedText(), default="") # 白名单 whitelist_enabled = Column(Boolean, default=False) whitelist_platform = Column(String(32), default="xiequ") whitelist_credentials = Column(JSON, nullable=True) # 旧字段保留(向后兼容双写) whitelist_uid = Column(EncryptedText(), default="") whitelist_ukey = Column(EncryptedText(), default="") class AuditLog(Base): """操作审计日志""" __tablename__ = "audit_logs" id = Column(Integer, primary_key=True, autoincrement=True) user_id = Column(Integer, nullable=True) username = Column(String(64), default="") action = Column(String(128), nullable=False) target = Column(String(256), default="") detail = Column(Text, default="") created_at = Column(DateTime, default=_utcnow)