"""Модель задачи (асинхронная единица работы).""" import secrets from datetime import datetime from enum import Enum from typing import TYPE_CHECKING from uuid import uuid4 from sqlalchemy import JSON, ForeignKey, String, func from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base if TYPE_CHECKING: from app.models.user import User class TaskType(str, Enum): """Тип задачи.""" SEARCH = "search" PLAGIARISM = "plagiarism" SUMMARIZE = "summarize" GOST = "gost" class TaskStatus(str, Enum): """Статус задачи.""" QUEUED = "queued" PROCESSING = "processing" DONE = "done" FAILED = "failed" class Task(Base): """Задача пользователя, обрабатываемая воркерами Celery.""" __tablename__ = "tasks" # Внутренний UUID — не светится в API/URL id: Mapped[str] = mapped_column( String(36), primary_key=True, default=lambda: str(uuid4()), ) # Публичный ID для URL: /tasks/{public_id} # token_urlsafe(16) → 22 символа base64url, не угадываем, не связан с internal UUID public_id: Mapped[str] = mapped_column( String(32), unique=True, index=True, default=lambda: secrets.token_urlsafe(16), ) user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True) type: Mapped[str] = mapped_column(String(20), nullable=False) status: Mapped[str] = mapped_column(String(20), default=TaskStatus.QUEUED) celery_task_id: Mapped[str | None] = mapped_column(String(255), nullable=True) # Входные данные: query, filename, doc_ids и т.д. input_data: Mapped[dict] = mapped_column(JSON, default=dict) # Результат работы воркера result: Mapped[dict | None] = mapped_column(JSON, nullable=True) error: Mapped[str | None] = mapped_column(nullable=True) queue_position: Mapped[int | None] = mapped_column(nullable=True) created_at: Mapped[datetime] = mapped_column(server_default=func.now()) updated_at: Mapped[datetime | None] = mapped_column( nullable=True, onupdate=func.now(), ) # Связи user: Mapped["User"] = relationship(back_populates="tasks") def __repr__(self) -> str: return f""