from __future__ import annotations import enum from datetime import datetime from typing import Optional from sqlalchemy import ForeignKey, String, Enum, DateTime, func from sqlalchemy.orm import Mapped, mapped_column from app.db.session import Base class PostType(str, enum.Enum): text = "text" photo = "photo" video = "video" animation = "animation" class PostStatus(str, enum.Enum): draft = "draft" scheduled = "scheduled" sent = "sent" failed = "failed" class Post(Base): __tablename__ = "posts" id: Mapped[int] = mapped_column(primary_key=True) owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE")) bot_id: Mapped[Optional[int]] = mapped_column(ForeignKey("bots.id", ondelete="SET NULL"), nullable=True) channel_id: Mapped[int] = mapped_column(ForeignKey("channels.id", ondelete="CASCADE")) type: Mapped[PostType] = mapped_column() text: Mapped[str | None] = mapped_column(String(4096)) media_file_id: Mapped[Optional[str]] = mapped_column(String(512)) parse_mode: Mapped[Optional[str]] = mapped_column(String(16)) keyboard_id: Mapped[Optional[int]] = mapped_column(ForeignKey("keyboards.id", ondelete="SET NULL")) status: Mapped[PostStatus] = mapped_column(Enum(PostStatus), default=PostStatus.draft) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) sent_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) class ScheduleStatus(str, enum.Enum): pending = "pending" done = "done" cancelled = "cancelled" class Schedule(Base): __tablename__ = "schedules" id: Mapped[int] = mapped_column(primary_key=True) post_id: Mapped[int] = mapped_column(ForeignKey("posts.id", ondelete="CASCADE")) due_at: Mapped[datetime] = mapped_column(DateTime(timezone=True)) timezone: Mapped[str] = mapped_column(String(64)) celery_task_id: Mapped[Optional[str]] = mapped_column(String(128)) status: Mapped[ScheduleStatus] = mapped_column(Enum(ScheduleStatus), default=ScheduleStatus.pending)