130 lines
3.8 KiB
Python
130 lines
3.8 KiB
Python
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]
|