from __future__ import annotations from datetime import UTC, datetime from uuid import uuid4 from sqlalchemy import select from app.core.database import session_scope from app.modules.content.models import ContentPage ALLOWED_PAGE_STATUSES = {"draft", "published"} def _detach(db, instance): db.refresh(instance) db.expunge(instance) return instance def list_published_pages() -> list[ContentPage]: with session_scope() as db: pages = list( db.scalars(select(ContentPage).where(ContentPage.status == "published").order_by(ContentPage.slug)) ) return [_detach(db, page) for page in pages] def list_all_pages() -> list[ContentPage]: with session_scope() as db: pages = list(db.scalars(select(ContentPage).order_by(ContentPage.slug))) return [_detach(db, page) for page in pages] def get_page_by_slug(slug: str, include_draft: bool = False) -> ContentPage | None: with session_scope() as db: page = db.scalar(select(ContentPage).where(ContentPage.slug == slug)) if not page: return None if include_draft or page.status == "published": return _detach(db, page) return None def get_page_by_id(page_id: str) -> ContentPage | None: with session_scope() as db: page = db.get(ContentPage, page_id) if not page: return None return _detach(db, page) def create_page( slug: str, title: str, body: str, status: str, author_id: str, ) -> ContentPage: if status not in ALLOWED_PAGE_STATUSES: raise ValueError("INVALID_STATUS") with session_scope() as db: page = ContentPage( id=str(uuid4()), slug=slug, title=title, body=body, status=status, author_id=author_id, published_at=datetime.now(UTC) if status == "published" else None, ) db.add(page) db.flush() return _detach(db, page) def update_page( page_id: str, title: str | None, body: str | None, status: str | None, ) -> ContentPage: with session_scope() as db: page = db.get(ContentPage, page_id) if not page: raise KeyError(page_id) if title: page.title = title if body: page.body = body if status: if status not in ALLOWED_PAGE_STATUSES: raise ValueError("INVALID_STATUS") page.status = status if status == "published" and page.published_at is None: page.published_at = datetime.now(UTC) page.updated_at = datetime.now(UTC) db.flush() return _detach(db, page) def delete_page(page_id: str) -> None: with session_scope() as db: page = db.get(ContentPage, page_id) if page: db.delete(page)