"""ORM-модели: User, VkAccount, Publication.""" from __future__ import annotations import datetime from typing import Optional from sqlalchemy import ( Boolean, DateTime, ForeignKey, Integer, String, Text, func, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) name: Mapped[str] = mapped_column(String(255), nullable=False) email: Mapped[Optional[str]] = mapped_column(String(255), nullable=True, unique=True) api_key_hash: Mapped[str] = mapped_column(String(64), nullable=False, unique=True) api_key_prefix: Mapped[str] = mapped_column(String(12), nullable=False, comment="Первые ~10 символов ключа для идентификации") is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False) updated_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False) vk_accounts: Mapped[list[VkAccount]] = relationship(back_populates="user", cascade="all, delete-orphan") class VkAccount(Base): __tablename__ = "vk_accounts" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False, index=True) vk_user_id: Mapped[int] = mapped_column(Integer, nullable=False, comment="VK owner_id (положительный — пользователь, отрицательный — сообщество)") display_name: Mapped[str] = mapped_column(String(255), nullable=False, comment="Отображаемое имя (например, 'Моя стена')") access_token_enc: Mapped[str] = mapped_column(Text, nullable=False, comment="Зашифрованный VK-токен") token_type: Mapped[str] = mapped_column(String(10), default="user", nullable=False, comment="user | group") is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) expires_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, nullable=True) last_used_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, nullable=True) created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False) user: Mapped[User] = relationship(back_populates="vk_accounts") publications: Mapped[list[Publication]] = relationship(back_populates="vk_account", cascade="all, delete-orphan") class Publication(Base): __tablename__ = "publications" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) vk_account_id: Mapped[int] = mapped_column(ForeignKey("vk_accounts.id"), nullable=False, index=True) status: Mapped[str] = mapped_column( String(20), default="draft", nullable=False, comment="draft | scheduled | published | error", ) # Входные данные markdown_original: Mapped[str] = mapped_column(Text, nullable=False, comment="Исходный Markdown") # Результат конвертации vk_text: Mapped[str] = mapped_column(Text, nullable=False, comment="Текст для VK") vk_format_data: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="JSON format_data") # Результат публикации vk_post_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) vk_owner_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) attachments: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="JSON attachments") # Отложенная публикация scheduled_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, nullable=True) published_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, nullable=True) # Ошибки error_message: Mapped[Optional[str]] = mapped_column(Text, nullable=True) created_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False) updated_at: Mapped[datetime.datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False) vk_account: Mapped[VkAccount] = relationship(back_populates="publications")