from __future__ import annotations from typing import Optional import enum import uuid from datetime import datetime from sqlalchemy import Boolean, 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 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) clinical_department: Mapped[str] = mapped_column(String(255), nullable=False) is_admin: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default="false", default=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[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id"), nullable=True, ) approved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) avatar_url: Mapped[Optional[str]] = 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