import json from datetime import datetime from typing import Optional from pydantic import BaseModel, ConfigDict from core.database import Keypass # ── Auth ────────────────────────────────────────────────────────────────────── class AdminLoginRequest(BaseModel): username: str password: str class KeypassLoginRequest(BaseModel): code: str class TokenResponse(BaseModel): token: str token_type: str = "bearer" # ── Keypasses ───────────────────────────────────────────────────────────────── class KeypassCreate(BaseModel): description: str expires_at: Optional[datetime] = None # None = never expires gate_ids: list[int] = [] # empty = all gates code: Optional[str] = None # None = auto-generate class KeypassPatch(BaseModel): description: Optional[str] = None expires_at: Optional[datetime] = None # None = never expires gate_ids: Optional[list[int]] = None # None = keep unchanged; [] = all gates class KeypassResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: int code: str description: str created_at: datetime expires_at: Optional[datetime] revoked: bool revoked_at: Optional[datetime] = None allowed_gate_ids: list[int] # empty = all gates def keypass_to_response(kp: Keypass) -> KeypassResponse: return KeypassResponse( id=kp.id, code=kp.code, description=kp.description, created_at=kp.created_at, expires_at=kp.expires_at, revoked=kp.revoked, revoked_at=kp.revoked_at, allowed_gate_ids=json.loads(kp.allowed_gates) if kp.allowed_gates else [], ) # ── Gates ───────────────────────────────────────────────────────────────────── class GateResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str gate_type: str avconnect_macro_id: str status: str group_name: Optional[str] = None class GateCreate(BaseModel): name: str gate_type: str # 'car' | 'pedestrian' avconnect_macro_id: str status: str = "enabled" group_name: Optional[str] = None # ── AVConnect Credentials ───────────────────────────────────────────────────── class CredentialRead(BaseModel): id: int username: str class CredentialUpsert(BaseModel): username: str password: str # ── Admin users ─────────────────────────────────────────────────────────────── class AdminUserResponse(BaseModel): id: int username: str role: str # 'admin' | 'manager' class AdminUserCreate(BaseModel): username: str password: str role: str = "admin" # 'admin' | 'manager' class AdminPasswordChange(BaseModel): new_password: str # ── Statistics ──────────────────────────────────────────────────────────────── class AccessLogResponse(BaseModel): model_config = ConfigDict(from_attributes=True) id: int timestamp: datetime keypass_id: int keypass_code: str gate_id: int gate_name: str ip_address: Optional[str] user_agent: Optional[str] success: bool error: Optional[str]