Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user