from datetime import datetime, timezone from enum import Enum from typing import Any from sqlmodel import SQLModel, Field, Column from sqlalchemy import JSON def utcnow() -> datetime: return datetime.now(timezone.utc) class PageContext(str, Enum): healthcare = "healthcare" civic = "civic" class Channel(str, Enum): messenger = "messenger" comment = "comment" page_post = "page_post" reel = "reel" lead = "lead" unknown = "unknown" class DraftStatus(str, Enum): draft = "draft" needs_review = "needs_review" approved = "approved" rejected = "rejected" sent = "sent" published = "published" scheduled = "scheduled" failed = "failed" class PublishMode(str, Enum): now = "now" scheduled = "scheduled" validation_only = "validation_only" class RiskLevel(str, Enum): low = "low" medium = "medium" high = "high" blocked = "blocked" class InboundEvent(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) page_context: PageContext = Field(index=True) platform_page_id: str = Field(index=True) channel: Channel = Field(index=True) event_type: str = Field(index=True) sender_id_hash: str | None = Field(default=None, index=True) object_id: str | None = Field(default=None, index=True) parent_id: str | None = Field(default=None, index=True) permalink_url: str | None = None message_text: str | None = None raw_payload: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON)) normalized_payload: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON)) forwarded_at: datetime | None = None forward_error: str | None = None created_at: datetime = Field(default_factory=utcnow, index=True) class Draft(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) page_context: PageContext = Field(index=True) source_event_id: int | None = Field(default=None, foreign_key="inboundevent.id") channel: Channel = Field(index=True) target_object_id: str | None = Field(default=None, index=True) recipient_psid: str | None = Field(default=None, index=True) draft_text: str sources: list[str] = Field(default_factory=list, sa_column=Column(JSON)) media_attachments: list[dict[str, Any]] = Field(default_factory=list, sa_column=Column(JSON)) media_required: bool = Field(default=False, index=True) publish_mode: PublishMode = Field(default=PublishMode.now, index=True) scheduled_publish_time: datetime | None = Field(default=None, index=True) risk_level: RiskLevel = Field(default=RiskLevel.medium, index=True) status: DraftStatus = Field(default=DraftStatus.needs_review, index=True) created_by: str = "openclaw" approved_by: str | None = None rejection_reason: str | None = None meta_response: dict[str, Any] | None = Field(default=None, sa_column=Column(JSON)) created_at: datetime = Field(default_factory=utcnow, index=True) approved_at: datetime | None = None published_at: datetime | None = None class AuditLog(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) page_context: PageContext | None = Field(default=None, index=True) actor: str = Field(index=True) action: str = Field(index=True) draft_id: int | None = Field(default=None, index=True) event_id: int | None = Field(default=None, index=True) details: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON)) created_at: datetime = Field(default_factory=utcnow, index=True)