"""SQLAlchemy-modeller för user management.""" import uuid from datetime import datetime from enum import Enum as PyEnum from sqlalchemy import Column, String, DateTime, Boolean, ForeignKey, Enum, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from app.database import Base class UserRole(str, PyEnum): ADMIN = "admin" MANAGER = "manager" ANALYST = "analyst" VIEWER = "viewer" class UserStatus(str, PyEnum): ACTIVE = "active" INACTIVE = "inactive" PENDING = "pending" # Invited, not yet set password class User(Base): __tablename__ = "users" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = Column(String(255), unique=True, nullable=False, index=True) hashed_password = Column(String(255), nullable=True) # NULL until invitation accepted first_name = Column(String(100), nullable=False) last_name = Column(String(100), nullable=False) role = Column(Enum(UserRole), nullable=False, default=UserRole.VIEWER) status = Column(Enum(UserStatus), nullable=False, default=UserStatus.PENDING) is_superuser = Column(Boolean, default=False) last_login_at = Column(DateTime(timezone=True), nullable=True) created_at = Column(DateTime(timezone=True), default=datetime.utcnow) updated_at = Column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow) tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True) tenant = relationship("Tenant", back_populates="users") invitations_sent = relationship("Invitation", foreign_keys="Invitation.invited_by_id", back_populates="inviter") invitations_received = relationship("Invitation", foreign_keys="Invitation.email", primaryjoin="User.email == Invitation.email", viewonly=True) def __repr__(self): return f"" class Tenant(Base): __tablename__ = "tenants" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column(String(255), nullable=False) slug = Column(String(100), unique=True, nullable=False, index=True) description = Column(Text, nullable=True) created_at = Column(DateTime(timezone=True), default=datetime.utcnow) updated_at = Column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow) users = relationship("User", back_populates="tenant") def __repr__(self): return f"" class Invitation(Base): __tablename__ = "invitations" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = Column(String(255), nullable=False, index=True) token = Column(String(255), unique=True, nullable=False, index=True) role = Column(Enum(UserRole), nullable=False, default=UserRole.VIEWER) tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True) invited_by_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) expires_at = Column(DateTime(timezone=True), nullable=False) accepted_at = Column(DateTime(timezone=True), nullable=True) created_at = Column(DateTime(timezone=True), default=datetime.utcnow) inviter = relationship("User", foreign_keys=[invited_by_id], back_populates="invitations_sent") tenant = relationship("Tenant") def __repr__(self): return f""