用户认证: - User 模型(支持邮箱/手机号登录) - 双 Token JWT 认证(accessToken + refreshToken) - 注册/登录/刷新 Token API 组织模型: - Brand(品牌方)、Agency(代理商)、Creator(达人) - 多对多关系:品牌方↔代理商、代理商↔达人 项目与任务: - Project 模型(品牌方发布) - Task 模型(完整审核流程追踪) - Brief 模型(解析后的结构化内容) 文件上传: - 阿里云 OSS 直传签名服务 - 支持分片上传,最大 500MB 数据库迁移: - 003_user_org_project_task.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
"""
|
||
用户模型
|
||
"""
|
||
from typing import TYPE_CHECKING, Optional
|
||
from datetime import datetime
|
||
from sqlalchemy import String, Boolean, DateTime, Enum as SQLEnum
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||
import enum
|
||
|
||
from app.models.base import Base, TimestampMixin
|
||
|
||
if TYPE_CHECKING:
|
||
from app.models.organization import Brand, Agency, Creator
|
||
|
||
|
||
class UserRole(str, enum.Enum):
|
||
"""用户角色"""
|
||
BRAND = "brand" # 品牌方
|
||
AGENCY = "agency" # 代理商
|
||
CREATOR = "creator" # 达人
|
||
|
||
|
||
class User(Base, TimestampMixin):
|
||
"""用户表"""
|
||
__tablename__ = "users"
|
||
|
||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||
|
||
# 登录凭证(邮箱和手机号都可以登录)
|
||
email: Mapped[Optional[str]] = mapped_column(String(255), unique=True, nullable=True, index=True)
|
||
phone: Mapped[Optional[str]] = mapped_column(String(20), unique=True, nullable=True, index=True)
|
||
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
||
|
||
# 用户信息
|
||
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
||
avatar: Mapped[Optional[str]] = mapped_column(String(2048), nullable=True)
|
||
|
||
# 角色
|
||
role: Mapped[UserRole] = mapped_column(
|
||
SQLEnum(UserRole, name="user_role_enum"),
|
||
nullable=False,
|
||
index=True,
|
||
)
|
||
|
||
# 状态
|
||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||
is_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||
|
||
# 最后登录
|
||
last_login_at: Mapped[Optional[datetime]] = mapped_column(
|
||
DateTime(timezone=True),
|
||
nullable=True,
|
||
)
|
||
|
||
# Refresh Token(用于 JWT 刷新)
|
||
refresh_token: Mapped[Optional[str]] = mapped_column(String(512), nullable=True)
|
||
refresh_token_expires_at: Mapped[Optional[datetime]] = mapped_column(
|
||
DateTime(timezone=True),
|
||
nullable=True,
|
||
)
|
||
|
||
# 关联的组织(根据角色不同,关联到不同的组织)
|
||
brand: Mapped[Optional["Brand"]] = relationship(
|
||
"Brand",
|
||
back_populates="user",
|
||
uselist=False,
|
||
)
|
||
agency: Mapped[Optional["Agency"]] = relationship(
|
||
"Agency",
|
||
back_populates="user",
|
||
uselist=False,
|
||
)
|
||
creator: Mapped[Optional["Creator"]] = relationship(
|
||
"Creator",
|
||
back_populates="user",
|
||
uselist=False,
|
||
)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<User(id={self.id}, email={self.email}, role={self.role})>"
|