import enum import uuid from datetime import datetime from sqlalchemy import DateTime, Enum, ForeignKey, String, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from app.db.base_class import Base class UserRole(str, enum.Enum): ADMIN = "ADMIN" PM = "PM" CRA = "CRA" PV = "PV" IMP = "IMP" QA = "QA" class UserStatus(str, enum.Enum): PENDING = "PENDING" ACTIVE = "ACTIVE" REJECTED = "REJECTED" DISABLED = "DISABLED" class User(Base): __tablename__ = "users" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False) password_hash: Mapped[str] = mapped_column(String(255), nullable=False) full_name: Mapped[str] = mapped_column(String(255), nullable=False) role: Mapped[UserRole] = mapped_column(Enum(UserRole, name="user_role"), nullable=False) clinical_department: Mapped[str] = mapped_column(String(255), nullable=False) status: Mapped[UserStatus] = mapped_column( Enum(UserStatus, name="user_status"), nullable=False, server_default=UserStatus.PENDING.value, default=UserStatus.PENDING, ) 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(), ) approved_by: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id"), nullable=True, ) approved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) avatar_url: Mapped[str | None] = mapped_column(String(500), nullable=True) @property def is_active(self) -> bool: # compatibility helper for existing checks return self.status == UserStatus.ACTIVE @property def username(self) -> str: # backward compatibility for existing UI copy return self.email