Build and Push / build (release) Successful in 50s
- GET /auth/groups - list groups with search/pagination - POST /auth/groups/sync-from-authentik - bulk sync from Authentik - Group model and database migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
86 lines
2.3 KiB
Python
86 lines
2.3 KiB
Python
"""
|
|
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"<Group {self.name}>"
|