"""Phase 14: API Key Pydantic schemas.""" from __future__ import annotations from datetime import datetime from typing import List, Optional from uuid import UUID from pydantic import BaseModel, Field, field_validator from app.models.api_key import VALID_SCOPES class ApiKeyCreate(BaseModel): name: str = Field(..., min_length=1, max_length=200) description: Optional[str] = None scopes: List[str] = Field(default=["read"]) expires_at: Optional[datetime] = None @field_validator("scopes") @classmethod def validate_scopes(cls, v: list) -> list: invalid = set(v) - VALID_SCOPES if invalid: raise ValueError(f"Invalid scopes: {invalid}. Valid: {VALID_SCOPES}") if not v: raise ValueError("At least one scope is required") return v class ApiKeyOut(BaseModel): """Safe representation — never exposes key_hash.""" id: UUID name: str description: Optional[str] = None key_prefix: str user_id: UUID scopes: List[str] last_used_at: Optional[datetime] = None expires_at: Optional[datetime] = None is_active: bool created_at: Optional[datetime] = None class Config: from_attributes = True class ApiKeyCreated(ApiKeyOut): """Returned only once at creation — includes the raw key.""" raw_key: str = Field(..., description="The full API key — shown only this once.") class ApiKeyUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = None scopes: Optional[List[str]] = None expires_at: Optional[datetime] = None is_active: Optional[bool] = None @field_validator("scopes") @classmethod def validate_scopes(cls, v: Optional[list]) -> Optional[list]: if v is None: return v invalid = set(v) - VALID_SCOPES if invalid: raise ValueError(f"Invalid scopes: {invalid}") return v