from __future__ import annotations import enum import uuid from datetime import datetime from typing import Optional from sqlalchemy import DateTime, Enum, ForeignKey, Integer, String, Text, UniqueConstraint, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from app.db.base_class import Base class SmtpSecurity(str, enum.Enum): NONE = "NONE" SSL = "SSL" STARTTLS = "STARTTLS" class EmailVerificationPurpose(str, enum.Enum): REGISTER = "REGISTER" PASSWORD_RESET = "PASSWORD_RESET" PASSWORD_RESET_LINK = "PASSWORD_RESET_LINK" class SystemEmailSettings(Base): __tablename__ = "system_email_settings" __table_args__ = (UniqueConstraint("register_domain", name="uq_system_email_settings_register_domain"),) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) register_domain: Mapped[str] = mapped_column(String(255), nullable=False, default="huapont.cn") smtp_host: Mapped[str] = mapped_column(String(255), nullable=False, default="") smtp_port: Mapped[int] = mapped_column(Integer, nullable=False) smtp_security: Mapped[SmtpSecurity] = mapped_column( Enum(SmtpSecurity, name="smtp_security"), nullable=False, default=SmtpSecurity.SSL, server_default=SmtpSecurity.SSL.value, ) smtp_username: Mapped[str] = mapped_column(String(255), nullable=False, default="") smtp_password_encrypted: Mapped[Optional[str]] = mapped_column(Text, nullable=True) sender_email: Mapped[str] = mapped_column(String(255), nullable=False, default="") sender_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) allowed_register_domain: Mapped[str] = mapped_column(String(255), nullable=False, default="huapont.cn") verification_code_ttl_minutes: Mapped[int] = mapped_column(Integer, nullable=False, default=10) send_cooldown_seconds: Mapped[int] = mapped_column(Integer, nullable=False, default=60) max_verify_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=5) updated_by: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now() ) class EmailVerificationCode(Base): __tablename__ = "email_verification_codes" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email: Mapped[str] = mapped_column(String(255), nullable=False, index=True) purpose: Mapped[EmailVerificationPurpose] = mapped_column( Enum(EmailVerificationPurpose, name="email_verification_purpose"), nullable=False, default=EmailVerificationPurpose.REGISTER, server_default=EmailVerificationPurpose.REGISTER.value, ) code_hash: Mapped[str] = mapped_column(String(255), nullable=False) expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) verified_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())