Files
flowdeck/app/services/row_pages.py
T
bruno 5951c707eb
FlowDeck CI / lint (push) Successful in 1m27s
FlowDeck CI / test (push) Successful in 10m51s
FlowDeck CI / docker (push) Successful in 1m21s
feat: v6.5.0 Synced blocks production — pages contenu par lignes de DB, résolution serveur à chaque lecture, propagation écrite réelle
2026-09-24 08:28:25 -04:00

124 lines
4.6 KiB
Python

"""FlowDeck — v6.5.0 database row content pages (synced blocks production).
A database row (``collection_pages``) has no block content of its own:
its Notion-style content lives in a shadow ``pages`` row linked via
``pages.collection_row_id``. The full page editor (synced blocks,
versions, realtime, permissions) is reused unchanged on that page.
``ensure_row_page()`` lazily creates (or heals) the shadow page and is
the single entry point used by the row-open endpoint.
"""
from __future__ import annotations
import logging
from app.db import get_conn
logger = logging.getLogger(__name__)
def _host_workspace(conn, coll: dict) -> tuple[str, int | None]:
"""Workspace (key, id) the shadow page should live in.
Resolution order: full-page database host page → inline parent page →
the collection's own ``workspace_id`` (key left empty).
"""
host = conn.execute(
"SELECT workspace, workspace_id FROM pages "
"WHERE collection_id=? AND deleted_at IS NULL "
"AND collection_row_id IS NULL LIMIT 1",
(coll.get("id"),),
).fetchone()
if not host and coll.get("parent_page_id"):
host = conn.execute(
"SELECT workspace, workspace_id FROM pages WHERE id=?",
(coll["parent_page_id"],),
).fetchone()
if host:
return host["workspace"] or "", host["workspace_id"]
if coll.get("gitea_owner") and coll.get("gitea_repo"):
return f"{coll['gitea_owner']}/{coll['gitea_repo']}", coll.get("workspace_id")
return "", coll.get("workspace_id")
def ensure_row_page(row_id: int) -> int:
"""Return the content page id for a database row, creating it if needed.
- existing live page → returned as-is;
- soft-deleted page → restored (title resynced);
- missing → created with the row's title and the collection workspace.
Raises ``KeyError`` when the row does not exist.
"""
with get_conn() as conn:
row = conn.execute(
"SELECT id, collection_id, title FROM collection_pages WHERE id=?",
(row_id,),
).fetchone()
if not row:
raise KeyError(f"row {row_id} not found")
coll_row = conn.execute(
"SELECT id, workspace_id, parent_page_id, gitea_owner, gitea_repo "
"FROM collections WHERE id=?",
(row["collection_id"],),
).fetchone()
coll = dict(coll_row) if coll_row else {"id": row["collection_id"]}
existing = conn.execute(
"SELECT id, deleted_at, title FROM pages WHERE collection_row_id=?",
(row_id,),
).fetchone()
if existing:
if existing["deleted_at"]:
conn.execute(
"UPDATE pages SET deleted_at=NULL, parent_section='DbRow', "
"title=?, updated_at=CURRENT_TIMESTAMP WHERE id=?",
(row["title"] or existing["title"] or "Untitled", existing["id"]),
)
conn.commit()
return existing["id"]
ws_key, ws_id = _host_workspace(conn, coll)
cur = conn.execute(
"""INSERT INTO pages
(workspace, workspace_id, title, content, content_format,
parent_section, collection_id, collection_row_id)
VALUES (?, ?, ?, '', 'blocks', 'DbRow', ?, ?)""",
(ws_key, ws_id, row["title"] or "Untitled",
row["collection_id"], row_id),
)
page_id = cur.lastrowid
conn.commit()
logger.debug("created content page %s for row %s", page_id, row_id)
return page_id
def sync_row_title_to_page(conn, row_id: int) -> None:
"""Row → page: copy the row's title onto its content page (if any)."""
conn.execute(
"""UPDATE pages SET title=(
SELECT title FROM collection_pages WHERE id=pages.collection_row_id
), updated_at=CURRENT_TIMESTAMP
WHERE collection_row_id=? AND EXISTS (
SELECT 1 FROM collection_pages cp
WHERE cp.id=pages.collection_row_id AND cp.title<>pages.title
)""",
(row_id,),
)
def sync_page_title_to_row(conn, page_id: int) -> None:
"""Page → row: a rename inside the editor propagates to the row."""
conn.execute(
"""UPDATE collection_pages SET title=(
SELECT title FROM pages WHERE id=?
), updated_at=CURRENT_TIMESTAMP
WHERE id=(SELECT collection_row_id FROM pages WHERE id=?)
AND EXISTS (
SELECT 1 FROM pages p
WHERE p.id=? AND p.collection_row_id IS NOT NULL
AND p.title<>collection_pages.title
)""",
(page_id, page_id, page_id),
)