from datetime import datetime from typing import Optional, Any from pydantic import BaseModel, Field class AuthConfigBearer(BaseModel): token: str = "" class AuthConfigApiKey(BaseModel): key: str = "" header: str = "Authorization" class AuthConfigLoginPassword(BaseModel): email: str = "" password: str = "" login_path: str = "/auth/login" class UpstreamCreate(BaseModel): name: str base_url: str api_prefix: str = "/api/v1" auth_type: str = "login_password" # none | bearer | api_key | login_password auth_config: dict[str, Any] = {} rate_endpoint: str = "/groups/rates" groups_endpoint: str = "/groups/available" enabled: bool = True check_interval_seconds: int = 600 timeout_seconds: int = 30 balance_endpoint: str = "" balance_response_path: str = "" balance_divisor: float = 1.0 class UpstreamUpdate(BaseModel): name: Optional[str] = None base_url: Optional[str] = None api_prefix: Optional[str] = None auth_type: Optional[str] = None auth_config: Optional[dict[str, Any]] = None rate_endpoint: Optional[str] = None groups_endpoint: Optional[str] = None enabled: Optional[bool] = None check_interval_seconds: Optional[int] = None timeout_seconds: Optional[int] = None balance_endpoint: Optional[str] = None balance_response_path: Optional[str] = None balance_divisor: Optional[float] = None class UpstreamResponse(BaseModel): id: int name: str base_url: str api_prefix: str auth_type: str auth_config_masked: dict[str, Any] # secrets replaced with *** rate_endpoint: str groups_endpoint: str enabled: bool check_interval_seconds: int timeout_seconds: int last_status: str last_checked_at: Optional[datetime] last_error: Optional[str] balance: Optional[float] = None balance_updated_at: Optional[datetime] = None balance_endpoint: str = "" balance_response_path: str = "" balance_divisor: float = 1.0 created_at: datetime updated_at: datetime model_config = {"from_attributes": True} class SnapshotResponse(BaseModel): id: int upstream_id: int snapshot: dict[str, Any] captured_at: datetime model_config = {"from_attributes": True} class TestResult(BaseModel): success: bool message: str detail: Optional[str] = None class GenerateKeysByGroupsRequest(BaseModel): group_ids: list[str] = Field(default_factory=list) name_prefix: str = "SmartUp" quota: float = Field(default=0, ge=0) expires_in_days: Optional[int] = Field(default=None, ge=1) rate_limit_5h: float = Field(default=0, ge=0) rate_limit_1d: float = Field(default=0, ge=0) rate_limit_7d: float = Field(default=0, ge=0) endpoint: str = "/keys" class GeneratedUpstreamKeyResponse(BaseModel): id: Optional[int] = None upstream_id: int group_id: str group_name: str = "" key_id: Optional[str] = None key_name: str key_value: Optional[str] = None masked_key: str = "" status: str error: Optional[str] = None imported_website_id: Optional[int] = None imported_account_id: Optional[str] = None imported_at: Optional[datetime] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None class GenerateKeysByGroupsResponse(BaseModel): success: bool message: str items: list[GeneratedUpstreamKeyResponse]