"""Federation defpage setup — registers layouts and loads .sx pages.""" from __future__ import annotations from typing import Any def setup_federation_pages() -> None: """Register federation-specific layouts and load page definitions.""" _register_federation_layouts() _load_federation_page_files() def _load_federation_page_files() -> None: import os from shared.sx.pages import load_page_dir load_page_dir(os.path.dirname(__file__), "federation") # --------------------------------------------------------------------------- # Layouts — .sx defcomps read free variables from env # --------------------------------------------------------------------------- def _register_federation_layouts() -> None: from shared.sx.layouts import register_custom_layout register_custom_layout("social", _social_full, _social_oob) def _actor_data(ctx: dict) -> dict | None: actor = ctx.get("actor") if not actor: return None from services.federation_page import _serialize_actor return _serialize_actor(actor) async def _social_full(ctx: dict, **kw: Any) -> str: from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env env = _ctx_to_env(ctx) env["actor"] = kw.get("actor") or _actor_data(ctx) return await render_to_sx_with_env("social-layout-full", env) async def _social_oob(ctx: dict, **kw: Any) -> str: from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env env = _ctx_to_env(ctx, oob=True) env["actor"] = kw.get("actor") or _actor_data(ctx) return await render_to_sx_with_env("social-layout-oob", env) # --------------------------------------------------------------------------- # Helpers still used by route handlers # --------------------------------------------------------------------------- def _serialize_actor(actor) -> dict | None: """Serialize an actor profile to a dict for sx defcomps.""" from services.federation_page import _serialize_actor as _impl return _impl(actor) def _serialize_timeline_item(item) -> dict: """Serialize a timeline item DTO to a dict for sx defcomps.""" from services.federation_page import _serialize_timeline_item as _impl return _impl(item) def _serialize_remote_actor(a) -> dict: """Serialize a remote actor DTO to a dict for sx defcomps.""" from services.federation_page import _serialize_remote_actor as _impl return _impl(a) async def _social_page(ctx: dict, actor, *, content: str, title: str = "Rose Ash", meta_html: str = "") -> str: """Build a full social page with social header.""" from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, full_page_sx from markupsafe import escape env = _ctx_to_env(ctx) env["actor"] = _serialize_actor(actor) if actor else None header_rows = await render_to_sx_with_env("social-layout-full", env) return await full_page_sx(ctx, header_rows=header_rows, content=content, meta_html=meta_html or f'{escape(title)}') def _get_actor(): """Return current user's actor or None.""" from quart import g return getattr(g, "_social_actor", None) def _require_actor(): """Return current user's actor or abort 403.""" from quart import abort actor = _get_actor() if not actor: abort(403, "You need to choose a federation username first") return actor