70 lines
3.4 KiB
Python
70 lines
3.4 KiB
Python
"""用户模型"""
|
|
from __future__ import annotations
|
|
|
|
from .base import Base
|
|
from .enums import UserRole, UserStatus
|
|
from .types import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from sqlalchemy import BigInteger, VARCHAR, TEXT, Integer, Boolean, TIMESTAMP
|
|
from typing import List, Optional, TYPE_CHECKING, Any
|
|
|
|
if TYPE_CHECKING:
|
|
from .user_skill_binding import UserSkillBinding
|
|
from .user_project import UserProject
|
|
from .user_workload import UserWorkload
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(VARCHAR(100), nullable=False, unique=True)
|
|
email: Mapped[str] = mapped_column(VARCHAR(255), nullable=False, unique=True)
|
|
phone_country_code: Mapped[Optional[str]] = mapped_column(VARCHAR(8), nullable=True)
|
|
phone_number: Mapped[Optional[str]] = mapped_column(VARCHAR(32), nullable=True)
|
|
phone_e164: Mapped[Optional[str]] = mapped_column(VARCHAR(32), nullable=True, unique=True, index=True)
|
|
phone_verified_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True)
|
|
last_login_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True)
|
|
login_method: Mapped[Optional[str]] = mapped_column(VARCHAR(32), nullable=True)
|
|
password_hash: Mapped[str] = mapped_column(VARCHAR(255), nullable=False)
|
|
name: Mapped[str] = mapped_column(VARCHAR(100), nullable=False)
|
|
role: Mapped[str] = mapped_column(VARCHAR(50), nullable=False)
|
|
assigned_domains: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
|
|
workload: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
status: Mapped[str] = mapped_column(VARCHAR(50), nullable=False, default="active")
|
|
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
avatar_url: Mapped[Optional[str]] = mapped_column(VARCHAR(500), nullable=True)
|
|
bio: Mapped[Optional[str]] = mapped_column(TEXT, nullable=True)
|
|
|
|
skill_bindings: Mapped[List["UserSkillBinding"]] = relationship(
|
|
"UserSkillBinding", back_populates="user", cascade="all, delete-orphan"
|
|
)
|
|
workload_rel: Mapped[Optional["UserWorkload"]] = relationship(
|
|
"UserWorkload", back_populates="user", uselist=False, cascade="all, delete-orphan"
|
|
)
|
|
project_links: Mapped[List["UserProject"]] = relationship(
|
|
"UserProject", back_populates="user", cascade="all, delete-orphan"
|
|
)
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"id": str(self.id),
|
|
"tenant_id": str(self.tenant_id),
|
|
"username": self.username,
|
|
"name": self.name,
|
|
"email": self.email,
|
|
"phone_country_code": self.phone_country_code,
|
|
"phone_number": self.phone_number,
|
|
"phone_e164": self.phone_e164,
|
|
"phone_verified_at": self.phone_verified_at.isoformat() if self.phone_verified_at else None,
|
|
"last_login_at": self.last_login_at.isoformat() if self.last_login_at else None,
|
|
"login_method": self.login_method,
|
|
"role": self.role,
|
|
"assigned_domains": self.assigned_domains or [],
|
|
"workload": self.workload,
|
|
"status": self.status,
|
|
"is_active": self.is_active,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
}
|