from __future__ import annotations from datetime import datetime from sqlalchemy import String, Boolean, Integer, ForeignKey, UniqueConstraint, DateTime, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.db.common import CommonBase class User(CommonBase): __tablename__ = "users" __table_args__ = (UniqueConstraint("email", name="uq_user_email"),) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) email: Mapped[str] = mapped_column(String(255), index=True) full_name: Mapped[str] = mapped_column(String(255), default="") password_hash: Mapped[str] = mapped_column(String(255)) tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id"), index=True) branch_id: Mapped[int] = mapped_column(ForeignKey("branches.id"), index=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True) allow_login: Mapped[bool] = mapped_column(Boolean, default=True) is_locked: Mapped[bool] = mapped_column(Boolean, default=False) locked_at_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) must_change_password: Mapped[bool] = mapped_column(Boolean, default=False) password_changed_at_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) # Phase 7Q.3 - common user profile/personalisation fields. # Employee/consultant/client master records remain the source for official data; # these fields are used for display, dashboards, client-facing contact cards and branding. profile_photo_path: Mapped[str | None] = mapped_column(String(500), nullable=True) qualification: Mapped[str | None] = mapped_column(String(200), nullable=True) designation: Mapped[str | None] = mapped_column(String(200), nullable=True) mobile: Mapped[str | None] = mapped_column(String(30), nullable=True) bio: Mapped[str | None] = mapped_column(Text, nullable=True) signature_image_path: Mapped[str | None] = mapped_column(String(500), nullable=True) class LoginAttempt(CommonBase): __tablename__ = "login_attempts" __table_args__ = (UniqueConstraint("key", name="uq_login_attempt_key"),) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) key: Mapped[str] = mapped_column(String(255), index=True) # email|ip attempts: Mapped[int] = mapped_column(Integer, default=0) locked_until_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) updated_at_utc: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)