"""Pydantic-схемы для админ-панели.""" from datetime import datetime from typing import Any from pydantic import BaseModel, Field # ─── Сессия доступа ─────────────────────────────────────────────────────────── class AdminSessionResponse(BaseModel): code: str url: str expires_at: datetime # ─── Клиенты ────────────────────────────────────────────────────────────────── class AdminUserResponse(BaseModel): id: int email: str name: str plan: str is_verified: bool is_admin: bool created_at: datetime tasks_count: int = 0 model_config = {"from_attributes": True} class AdminUserUpdate(BaseModel): plan: str | None = None is_verified: bool | None = None is_admin: bool | None = None # ─── Работы ───────────────────────────────────────────────────────────────── class AdminTaskResponse(BaseModel): public_id: str user_id: int type: str status: str error: str | None = None created_at: datetime model_config = {"from_attributes": True} # ─── Документы базы ─────────────────────────────────────────────────────────── class AdminDocumentResponse(BaseModel): id: int source: str ext_id: str title: str authors: list = Field(default_factory=list) year: int | None = None lang: str | None = None doi: str | None = None url: str | None = None indexed_at: datetime model_config = {"from_attributes": True} # ─── Источники парсинга ─────────────────────────────────────────────────────── class ParseSourceCreate(BaseModel): source_type: str = Field(description="openalex / cyberleninka / arxiv") name: str = Field(min_length=1, max_length=255) query: str | None = None lang: str | None = None year_from: int | None = None year_to: int | None = None limit: int = Field(default=1000, ge=1, le=100000) enabled: bool = True class ParseSourceUpdate(BaseModel): name: str | None = None query: str | None = None lang: str | None = None year_from: int | None = None year_to: int | None = None limit: int | None = Field(default=None, ge=1, le=100000) enabled: bool | None = None class ParseSourceResponse(BaseModel): id: int source_type: str name: str query: str | None = None lang: str | None = None year_from: int | None = None year_to: int | None = None limit: int enabled: bool last_status: str last_error: str | None = None last_run_at: datetime | None = None docs_added: int created_at: datetime model_config = {"from_attributes": True} # ─── Отстойник ──────────────────────────────────────────────────────────────── class StagedWorkResponse(BaseModel): id: int user_id: int | None = None task_id: str | None = None filename: str | None = None title: str | None = None authors: list = Field(default_factory=list) year: int | None = None lang: str | None = None word_count: int | None = None status: str document_id: int | None = None created_at: datetime model_config = {"from_attributes": True} class StagedWorkDetail(StagedWorkResponse): text_preview: str | None = None # ─── Дашборд ────────────────────────────────────────────────────────────────── class ServiceHealth(BaseModel): name: str ok: bool detail: str | None = None class AdminStats(BaseModel): users_total: int tasks_by_status: dict[str, int] documents_total: int documents_by_source: dict[str, int] staging_pending: int storage: dict[str, Any] queues: dict[str, Any]