""" Authentication Schemas Pydantic models for auth request/response payloads. """ import uuid from datetime import datetime from typing import Optional from pydantic import Field from src.base_schema import BaseSchema class AuthSyncRequest(BaseSchema): """ Request payload for POST /auth/sync The client sends this after obtaining an OIDC token from Authentik. The access_token is validated against Authentik's userinfo endpoint. """ access_token: str = Field( ..., description="OIDC access token from Authentik", ) class RoleSchema(BaseSchema): """Role information in domain:action format""" name: str = Field(..., description="Role name (e.g., 'control-room:admin')") domain: str = Field(..., description="Permission domain (e.g., 'control-room')") action: str = Field(..., description="Permission action (e.g., 'admin')") class UserPreferencesSchema(BaseSchema): """User preferences""" theme: str = Field(default="system", description="Theme preference: system, light, dark") default_room: str = Field(default="front-hall", description="Default room for housekeeping") preferences_json: dict = Field(default_factory=dict, description="Extended preferences") class UserSchema(BaseSchema): """User information returned from sync""" id: uuid.UUID = Field(..., description="Internal user ID") authentik_id: uuid.UUID = Field(..., description="Authentik user ID") email: str = Field(..., description="User email") name: str = Field(..., description="Display name") avatar_url: Optional[str] = Field(None, description="Profile picture URL") created_at: datetime = Field(..., description="Account creation timestamp") last_login: Optional[datetime] = Field(None, description="Last login timestamp") class AuthSyncResponse(BaseSchema): """ Response from POST /auth/sync Contains the synced user profile, roles, and preferences. """ user: UserSchema = Field(..., description="User profile") roles: list[RoleSchema] = Field(..., description="User's permission roles") preferences: UserPreferencesSchema = Field(..., description="User preferences") is_new_user: bool = Field(..., description="True if user was just created") class TokenInfoSchema(BaseSchema): """ Token information from Authentik userinfo endpoint This is what Authentik returns when validating an access token. """ sub: str = Field(..., description="Subject (Authentik user ID)") email: str = Field(..., description="User email") name: Optional[str] = Field(None, description="Display name") preferred_username: Optional[str] = Field(None, description="Username") groups: list[str] = Field(default_factory=list, description="Group memberships") picture: Optional[str] = Field(None, description="Profile picture URL") class UserListItemSchema(BaseSchema): """User item for list display""" id: uuid.UUID = Field(..., description="Internal user ID") email: str = Field(..., description="User email") name: str = Field(..., description="Display name") avatar_url: Optional[str] = Field(None, description="Profile picture URL") created_at: datetime = Field(..., description="Account creation timestamp") last_login: Optional[datetime] = Field(None, description="Last login timestamp") roles: list[str] = Field(default_factory=list, description="Role names") class UsersListResponse(BaseSchema): """Response from GET /auth/users""" items: list[UserListItemSchema] = Field(..., description="List of users") total: int = Field(..., description="Total count of users") class BulkSyncResultSchema(BaseSchema): """Result from bulk sync operation""" created: int = Field(..., description="Number of users created") updated: int = Field(..., description="Number of users updated") failed: int = Field(..., description="Number of users that failed to sync") total_in_authentik: int = Field(..., description="Total users in Authentik") errors: list[str] = Field(default_factory=list, description="Error messages for failed syncs") class GroupListItemSchema(BaseSchema): """Group item for list display""" id: uuid.UUID = Field(..., description="Internal group ID") authentik_id: uuid.UUID = Field(..., description="Authentik group ID") name: str = Field(..., description="Group name") is_superuser: bool = Field(default=False, description="Whether group has superuser privileges") parent_name: Optional[str] = Field(None, description="Parent group name") member_count: int = Field(default=0, description="Number of users in this group") synced_at: datetime = Field(..., description="Last sync timestamp") class GroupsListResponse(BaseSchema): """Response from GET /auth/groups""" items: list[GroupListItemSchema] = Field(..., description="List of groups") total: int = Field(..., description="Total count of groups")