""" Group Model Represents groups synced from Authentik. Groups are used for access control and user organization. """ import uuid from datetime import datetime from typing import TYPE_CHECKING, List from sqlalchemy import String, Boolean, DateTime, func, Table, Column, ForeignKey from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from src.db.database import Base # Association table for User-Group many-to-many relationship user_groups = Table( "user_groups", Base.metadata, Column("user_id", UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), primary_key=True), Column("group_id", UUID(as_uuid=True), ForeignKey("groups.id", ondelete="CASCADE"), primary_key=True), ) class Group(Base): """ Group model synced from Authentik Groups are fetched from Authentik admin API and cached locally. They represent organizational units for access control. """ __tablename__ = "groups" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, ) authentik_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), unique=True, nullable=False, index=True, comment="Authentik group UUID", ) name: Mapped[str] = mapped_column( String(255), unique=True, nullable=False, index=True, ) is_superuser: Mapped[bool] = mapped_column( Boolean, default=False, nullable=False, comment="Whether members of this group have superuser privileges", ) parent_name: Mapped[str | None] = mapped_column( String(255), nullable=True, comment="Parent group name for hierarchy", ) member_count: Mapped[int] = mapped_column( default=0, nullable=False, comment="Number of users in this group", ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) synced_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, comment="Last sync from Authentik", ) def __repr__(self) -> str: return f""