Auto-mount defpages: eliminate Python route stubs across all 9 services
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 16s
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 16s
Defpages are now declared with absolute paths in .sx files and auto-mounted directly on the Quart app, removing ~850 lines of blueprint mount_pages calls, before_request hooks, and g.* wrapper boilerplate. A new page = one defpage declaration, nothing else. Infrastructure: - async_eval awaits coroutine results from callable dispatch - auto_mount_pages() mounts all registered defpages on the app - g._defpage_ctx pattern passes helper data to layout context Migrated: sx, account, orders, federation, cart, market, events, blog Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,102 +32,6 @@ def register(url_prefix="/social"):
|
||||
actor = await services.federation.get_actor_by_user_id(g.s, g.user.id)
|
||||
g._social_actor = actor
|
||||
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
"""Pre-render content for defpage routes."""
|
||||
endpoint = request.endpoint or ""
|
||||
|
||||
if endpoint.endswith("defpage_home_timeline"):
|
||||
actor = _require_actor()
|
||||
items = await services.federation.get_home_timeline(g.s, actor.id)
|
||||
from sx.sx_components import _timeline_content_sx
|
||||
g.home_timeline_content = _timeline_content_sx(items, "home", actor)
|
||||
|
||||
elif endpoint.endswith("defpage_public_timeline"):
|
||||
actor = getattr(g, "_social_actor", None)
|
||||
items = await services.federation.get_public_timeline(g.s)
|
||||
from sx.sx_components import _timeline_content_sx
|
||||
g.public_timeline_content = _timeline_content_sx(items, "public", actor)
|
||||
|
||||
elif endpoint.endswith("defpage_compose_form"):
|
||||
actor = _require_actor()
|
||||
from sx.sx_components import _compose_content_sx
|
||||
reply_to = request.args.get("reply_to")
|
||||
g.compose_content = _compose_content_sx(actor, reply_to)
|
||||
|
||||
elif endpoint.endswith("defpage_search"):
|
||||
actor = getattr(g, "_social_actor", None)
|
||||
query = request.args.get("q", "").strip()
|
||||
actors_list = []
|
||||
total = 0
|
||||
followed_urls: set[str] = set()
|
||||
if query:
|
||||
actors_list, total = await services.federation.search_actors(g.s, query)
|
||||
if actor:
|
||||
following, _ = await services.federation.get_following(
|
||||
g.s, actor.preferred_username, page=1, per_page=1000,
|
||||
)
|
||||
followed_urls = {a.actor_url for a in following}
|
||||
from sx.sx_components import _search_content_sx
|
||||
g.search_content = _search_content_sx(query, actors_list, total, 1, followed_urls, actor)
|
||||
|
||||
elif endpoint.endswith("defpage_following_list"):
|
||||
actor = _require_actor()
|
||||
actors_list, total = await services.federation.get_following(
|
||||
g.s, actor.preferred_username,
|
||||
)
|
||||
from sx.sx_components import _following_content_sx
|
||||
g.following_content = _following_content_sx(actors_list, total, actor)
|
||||
|
||||
elif endpoint.endswith("defpage_followers_list"):
|
||||
actor = _require_actor()
|
||||
actors_list, total = await services.federation.get_followers_paginated(
|
||||
g.s, actor.preferred_username,
|
||||
)
|
||||
following, _ = await services.federation.get_following(
|
||||
g.s, actor.preferred_username, page=1, per_page=1000,
|
||||
)
|
||||
followed_urls = {a.actor_url for a in following}
|
||||
from sx.sx_components import _followers_content_sx
|
||||
g.followers_content = _followers_content_sx(actors_list, total, followed_urls, actor)
|
||||
|
||||
elif endpoint.endswith("defpage_actor_timeline"):
|
||||
actor = getattr(g, "_social_actor", None)
|
||||
actor_id = request.view_args.get("id")
|
||||
from shared.models.federation import RemoteActor
|
||||
from sqlalchemy import select as sa_select
|
||||
remote = (
|
||||
await g.s.execute(
|
||||
sa_select(RemoteActor).where(RemoteActor.id == actor_id)
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
if not remote:
|
||||
abort(404)
|
||||
from shared.services.federation_impl import _remote_actor_to_dto
|
||||
remote_dto = _remote_actor_to_dto(remote)
|
||||
items = await services.federation.get_actor_timeline(g.s, actor_id)
|
||||
is_following = False
|
||||
if actor:
|
||||
from shared.models.federation import APFollowing
|
||||
existing = (
|
||||
await g.s.execute(
|
||||
sa_select(APFollowing).where(
|
||||
APFollowing.actor_profile_id == actor.id,
|
||||
APFollowing.remote_actor_id == actor_id,
|
||||
)
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
is_following = existing is not None
|
||||
from sx.sx_components import _actor_timeline_content_sx
|
||||
g.actor_timeline_content = _actor_timeline_content_sx(remote_dto, items, is_following, actor)
|
||||
|
||||
elif endpoint.endswith("defpage_notifications"):
|
||||
actor = _require_actor()
|
||||
items = await services.federation.get_notifications(g.s, actor.id)
|
||||
await services.federation.mark_notifications_read(g.s, actor.id)
|
||||
from sx.sx_components import _notifications_content_sx
|
||||
g.notifications_content = _notifications_content_sx(items)
|
||||
|
||||
# -- Timeline pagination ---------------------------------------------------
|
||||
|
||||
@bp.get("/timeline")
|
||||
@@ -170,7 +74,7 @@ def register(url_prefix="/social"):
|
||||
form = await request.form
|
||||
content = form.get("content", "").strip()
|
||||
if not content:
|
||||
return redirect(url_for("social.defpage_compose_form"))
|
||||
return redirect(url_for("defpage_compose_form"))
|
||||
|
||||
visibility = form.get("visibility", "public")
|
||||
in_reply_to = form.get("in_reply_to") or None
|
||||
@@ -181,13 +85,13 @@ def register(url_prefix="/social"):
|
||||
visibility=visibility,
|
||||
in_reply_to=in_reply_to,
|
||||
)
|
||||
return redirect(url_for("social.defpage_home_timeline"))
|
||||
return redirect(url_for("defpage_home_timeline"))
|
||||
|
||||
@bp.post("/delete/<int:post_id>")
|
||||
async def delete_post(post_id: int):
|
||||
actor = _require_actor()
|
||||
await services.federation.delete_local_post(g.s, actor.id, post_id)
|
||||
return redirect(url_for("social.defpage_home_timeline"))
|
||||
return redirect(url_for("defpage_home_timeline"))
|
||||
|
||||
# -- Search + Follow -------------------------------------------------------
|
||||
|
||||
@@ -223,7 +127,7 @@ def register(url_prefix="/social"):
|
||||
)
|
||||
if request.headers.get("SX-Request") or request.headers.get("HX-Request"):
|
||||
return await _actor_card_response(actor, remote_actor_url, is_followed=True)
|
||||
return redirect(request.referrer or url_for("social.defpage_search"))
|
||||
return redirect(request.referrer or url_for("defpage_search"))
|
||||
|
||||
@bp.post("/unfollow")
|
||||
async def unfollow():
|
||||
@@ -236,7 +140,7 @@ def register(url_prefix="/social"):
|
||||
)
|
||||
if request.headers.get("SX-Request") or request.headers.get("HX-Request"):
|
||||
return await _actor_card_response(actor, remote_actor_url, is_followed=False)
|
||||
return redirect(request.referrer or url_for("social.defpage_search"))
|
||||
return redirect(request.referrer or url_for("defpage_search"))
|
||||
|
||||
async def _actor_card_response(actor, remote_actor_url, is_followed):
|
||||
"""Re-render a single actor card after follow/unfollow via HTMX."""
|
||||
@@ -414,6 +318,6 @@ def register(url_prefix="/social"):
|
||||
async def mark_read():
|
||||
actor = _require_actor()
|
||||
await services.federation.mark_notifications_read(g.s, actor.id)
|
||||
return redirect(url_for("social.defpage_notifications"))
|
||||
return redirect(url_for("defpage_notifications"))
|
||||
|
||||
return bp
|
||||
|
||||
Reference in New Issue
Block a user