Build and Push / build (release) Successful in 1m16s
- Add PostgreSQL database with async SQLAlchemy - Add Alembic migrations for schema management - Add User, Role, UserPreferences, ApiKey models - Add auth endpoints: /auth/me, /auth/users, /auth/users/sync-from-authentik - Add token validation via Authentik userinfo endpoint - Add bulk user sync from Authentik admin API - Add database health check to diagnostics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
95 lines
2.3 KiB
Python
95 lines
2.3 KiB
Python
"""
|
|
User Model
|
|
|
|
Represents users synced from Authentik SSO.
|
|
"""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import TYPE_CHECKING, List
|
|
|
|
from sqlalchemy import String, Boolean, DateTime, func
|
|
from sqlalchemy.dialects.postgresql import UUID
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from src.db.database import Base
|
|
|
|
if TYPE_CHECKING:
|
|
from src.db.models.role import Role
|
|
from src.db.models.user_preferences import UserPreferences
|
|
from src.db.models.api_key import ApiKey
|
|
|
|
|
|
class User(Base):
|
|
"""
|
|
User model synced from Authentik
|
|
|
|
Users are created/updated when they authenticate via OIDC.
|
|
The authentik_id links to the Authentik user record.
|
|
"""
|
|
|
|
__tablename__ = "users"
|
|
|
|
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,
|
|
)
|
|
email: Mapped[str] = mapped_column(
|
|
String(255),
|
|
unique=True,
|
|
nullable=False,
|
|
index=True,
|
|
)
|
|
name: Mapped[str] = mapped_column(
|
|
String(255),
|
|
nullable=False,
|
|
)
|
|
avatar_url: Mapped[str | None] = mapped_column(
|
|
String(500),
|
|
nullable=True,
|
|
)
|
|
api_keys_enabled: Mapped[bool] = mapped_column(
|
|
Boolean,
|
|
default=True,
|
|
nullable=False,
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
server_default=func.now(),
|
|
nullable=False,
|
|
)
|
|
last_login: Mapped[datetime | None] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=True,
|
|
)
|
|
|
|
# Relationships
|
|
roles: Mapped[List["Role"]] = relationship(
|
|
"Role",
|
|
secondary="user_roles",
|
|
back_populates="users",
|
|
lazy="selectin",
|
|
)
|
|
preferences: Mapped["UserPreferences"] = relationship(
|
|
"UserPreferences",
|
|
back_populates="user",
|
|
uselist=False,
|
|
lazy="selectin",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
api_keys: Mapped[List["ApiKey"]] = relationship(
|
|
"ApiKey",
|
|
back_populates="user",
|
|
lazy="selectin",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
|
|
def __repr__(self) -> str:
|
|
return f"<User {self.email}>"
|