81 lines
2.1 KiB
Python
81 lines
2.1 KiB
Python
|
|
"""Pydantic schemas for user-related request and response bodies."""
|
||
|
|
|
||
|
|
import uuid
|
||
|
|
from datetime import datetime
|
||
|
|
from typing import Literal, Optional
|
||
|
|
|
||
|
|
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
||
|
|
|
||
|
|
|
||
|
|
class LoginRequest(BaseModel):
|
||
|
|
"""POST /api/v1/auth/login request body."""
|
||
|
|
email: EmailStr
|
||
|
|
password: str = Field(..., min_length=1)
|
||
|
|
|
||
|
|
|
||
|
|
class TokenResponse(BaseModel):
|
||
|
|
"""JWT token pair returned after login or refresh."""
|
||
|
|
access_token: str
|
||
|
|
refresh_token: str
|
||
|
|
token_type: str = "bearer"
|
||
|
|
expires_in: int = Field(..., description="Access token TTL in seconds")
|
||
|
|
|
||
|
|
|
||
|
|
class RefreshRequest(BaseModel):
|
||
|
|
"""POST /api/v1/auth/refresh request body."""
|
||
|
|
refresh_token: str
|
||
|
|
|
||
|
|
|
||
|
|
class UserBase(BaseModel):
|
||
|
|
"""Base user fields shared across schemas."""
|
||
|
|
email: EmailStr
|
||
|
|
full_name: str = Field(..., min_length=1, max_length=200)
|
||
|
|
role: Literal["admin", "verkaeufer", "buchhaltung"] = "verkaeufer"
|
||
|
|
language: str = Field(default="de", max_length=5)
|
||
|
|
|
||
|
|
|
||
|
|
class UserCreate(UserBase):
|
||
|
|
"""POST /api/v1/users request body."""
|
||
|
|
password: str = Field(..., min_length=8, max_length=128)
|
||
|
|
|
||
|
|
|
||
|
|
class UserUpdate(BaseModel):
|
||
|
|
"""PUT /api/v1/users/:id request body (all fields optional)."""
|
||
|
|
email: Optional[EmailStr] = None
|
||
|
|
full_name: Optional[str] = Field(None, min_length=1, max_length=200)
|
||
|
|
role: Optional[Literal["admin", "verkaeufer", "buchhaltung"]] = None
|
||
|
|
language: Optional[str] = Field(None, max_length=5)
|
||
|
|
is_active: Optional[bool] = None
|
||
|
|
|
||
|
|
|
||
|
|
class UserResponse(BaseModel):
|
||
|
|
"""User response schema (never exposes password_hash)."""
|
||
|
|
model_config = ConfigDict(from_attributes=True)
|
||
|
|
|
||
|
|
id: uuid.UUID
|
||
|
|
email: str
|
||
|
|
full_name: str
|
||
|
|
role: str
|
||
|
|
language: str
|
||
|
|
is_active: bool
|
||
|
|
created_at: Optional[datetime] = None
|
||
|
|
updated_at: Optional[datetime] = None
|
||
|
|
|
||
|
|
|
||
|
|
class UserListResponse(BaseModel):
|
||
|
|
"""Paginated user list response."""
|
||
|
|
items: list[UserResponse]
|
||
|
|
total: int
|
||
|
|
page: int
|
||
|
|
page_size: int
|
||
|
|
|
||
|
|
|
||
|
|
class ErrorResponse(BaseModel):
|
||
|
|
"""Standard error response format."""
|
||
|
|
error: dict
|
||
|
|
|
||
|
|
|
||
|
|
class HealthResponse(BaseModel):
|
||
|
|
"""Health check response."""
|
||
|
|
status: str = "ok"
|