Convert social and federation profile from Jinja to SX rendering
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 14m34s

Add primitives (replace, strip-tags, slice, csrf-token), convert all
social blueprint routes and federation profile to SX content builders,
delete 12 unused Jinja templates and social_lite layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 17:43:47 +00:00
parent 0c9dbd6657
commit 0a81a2af01
18 changed files with 760 additions and 503 deletions

View File

@@ -2,13 +2,15 @@
Lightweight social UI for blog/market/events. Federation keeps the full
social hub (timeline, compose, notifications, interactions).
All rendering uses s-expressions (no Jinja templates).
"""
from __future__ import annotations
import logging
from datetime import datetime
from quart import Blueprint, request, g, redirect, url_for, abort, render_template, Response
from quart import Blueprint, request, g, redirect, url_for, abort, Response
from shared.services.registry import services
@@ -77,15 +79,36 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
abort(403, "You need to choose a federation username first")
return actor
async def _render_social_page(content: str, actor=None, title: str = "Social"):
"""Render a full social page or OOB response depending on request type."""
from shared.browser.app.utils.htmx import is_htmx_request
from shared.sx.page import get_template_context
from shared.sx.helpers import full_page_sx, oob_page_sx, sx_response
from shared.infrastructure.ap_social_sx import (
_social_full_headers, _social_oob_headers,
)
tctx = await get_template_context()
kw = {"actor": actor}
if is_htmx_request():
oob_headers = _social_oob_headers(tctx, **kw)
return sx_response(oob_page_sx(
oobs=oob_headers,
content=content,
))
else:
header_rows = _social_full_headers(tctx, **kw)
return full_page_sx(tctx, header_rows=header_rows, content=content)
# -- Index ----------------------------------------------------------------
@bp.get("/")
async def index():
actor = getattr(g, "_social_actor", None)
return await render_template(
"social/index.html",
actor=actor,
)
from shared.infrastructure.ap_social_sx import social_index_content_sx
content = social_index_content_sx(actor)
return await _render_social_page(content, actor, title="Social")
# -- Search ---------------------------------------------------------------
@@ -103,15 +126,9 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
g._ap_s, actor.preferred_username, page=1, per_page=1000,
)
followed_urls = {a.actor_url for a in following}
return await render_template(
"social/search.html",
query=query,
actors=actors,
total=total,
page=1,
followed_urls=followed_urls,
actor=actor,
)
from shared.infrastructure.ap_social_sx import social_search_content_sx
content = social_search_content_sx(query, actors, total, 1, followed_urls, actor)
return await _render_social_page(content, actor, title="Search")
@bp.get("/search/page")
async def search_page():
@@ -130,15 +147,10 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
g._ap_s, actor.preferred_username, page=1, per_page=1000,
)
followed_urls = {a.actor_url for a in following}
return await render_template(
"social/_search_results.html",
actors=actors,
total=total,
page=page,
query=query,
followed_urls=followed_urls,
actor=actor,
)
from shared.infrastructure.ap_social_sx import search_results_sx
from shared.sx.helpers import sx_response
content = search_results_sx(actors, total, page, query, followed_urls, actor)
return sx_response(content)
# -- Follow / Unfollow ----------------------------------------------------
@@ -169,7 +181,7 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
return redirect(request.referrer or url_for("ap_social.search"))
async def _actor_card_response(actor, remote_actor_url, is_followed):
"""Re-render a single actor card after follow/unfollow via HTMX."""
"""Re-render a single actor card after follow/unfollow."""
remote_dto = await services.federation.get_or_fetch_remote_actor(
g._ap_s, remote_actor_url,
)
@@ -181,15 +193,12 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
list_type = "followers"
else:
list_type = "following"
return await render_template(
"social/_actor_list_items.html",
actors=[remote_dto],
total=0,
page=1,
list_type=list_type,
followed_urls=followed_urls,
actor=actor,
from shared.infrastructure.ap_social_sx import actor_list_items_sx
from shared.sx.helpers import sx_response
content = actor_list_items_sx(
[remote_dto], 0, 1, list_type, followed_urls, actor,
)
return sx_response(content)
# -- Followers ------------------------------------------------------------
@@ -203,14 +212,9 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
g._ap_s, actor.preferred_username, page=1, per_page=1000,
)
followed_urls = {a.actor_url for a in following}
return await render_template(
"social/followers.html",
actors=actors,
total=total,
page=1,
followed_urls=followed_urls,
actor=actor,
)
from shared.infrastructure.ap_social_sx import social_followers_content_sx
content = social_followers_content_sx(actors, total, 1, followed_urls, actor)
return await _render_social_page(content, actor, title="Followers")
@bp.get("/followers/page")
async def followers_list_page():
@@ -223,15 +227,10 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
g._ap_s, actor.preferred_username, page=1, per_page=1000,
)
followed_urls = {a.actor_url for a in following}
return await render_template(
"social/_actor_list_items.html",
actors=actors,
total=total,
page=page,
list_type="followers",
followed_urls=followed_urls,
actor=actor,
)
from shared.infrastructure.ap_social_sx import actor_list_items_sx
from shared.sx.helpers import sx_response
content = actor_list_items_sx(actors, total, page, "followers", followed_urls, actor)
return sx_response(content)
# -- Following ------------------------------------------------------------
@@ -241,13 +240,9 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
actors, total = await services.federation.get_following(
g._ap_s, actor.preferred_username,
)
return await render_template(
"social/following.html",
actors=actors,
total=total,
page=1,
actor=actor,
)
from shared.infrastructure.ap_social_sx import social_following_content_sx
content = social_following_content_sx(actors, total, 1, actor)
return await _render_social_page(content, actor, title="Following")
@bp.get("/following/page")
async def following_list_page():
@@ -256,15 +251,10 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
actors, total = await services.federation.get_following(
g._ap_s, actor.preferred_username, page=page,
)
return await render_template(
"social/_actor_list_items.html",
actors=actors,
total=total,
page=page,
list_type="following",
followed_urls=set(),
actor=actor,
)
from shared.infrastructure.ap_social_sx import actor_list_items_sx
from shared.sx.helpers import sx_response
content = actor_list_items_sx(actors, total, page, "following", set(), actor)
return sx_response(content)
# -- Actor timeline -------------------------------------------------------
@@ -295,13 +285,9 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
)
).scalar_one_or_none()
is_following = existing is not None
return await render_template(
"social/actor_timeline.html",
remote_actor=remote_dto,
items=items,
is_following=is_following,
actor=actor,
)
from shared.infrastructure.ap_social_sx import social_actor_timeline_content_sx
content = social_actor_timeline_content_sx(remote_dto, items, is_following, actor)
return await _render_social_page(content, actor)
@bp.get("/actor/<int:id>/timeline")
async def actor_timeline_page(id: int):
@@ -316,12 +302,9 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
items = await services.federation.get_actor_timeline(
g._ap_s, id, before=before,
)
return await render_template(
"social/_timeline_items.html",
items=items,
timeline_type="actor",
actor_id=id,
actor=actor,
)
from shared.infrastructure.ap_social_sx import timeline_items_sx
from shared.sx.helpers import sx_response
content = timeline_items_sx(items, "actor", id, actor)
return sx_response(content)
return bp