All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m4s
- Context processor: get_navigation_tree() replaces get_all_menu_items() - Menu admin service: MenuItem → MenuNode (container_type/container_id pattern) - Remove /internal/menu-items endpoint (other apps query menu_nodes directly) - Remove menu_items relationship from Post model - Templates: item.post.X → item.X - Add glue submodule Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
"""
|
|
Internal JSON API for the coop app.
|
|
|
|
These endpoints are called by other apps (market, cart) over HTTP
|
|
to fetch Ghost CMS content without importing blog services.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from quart import Blueprint, g, jsonify
|
|
|
|
from shared.browser.app.csrf import csrf_exempt
|
|
|
|
|
|
def register() -> Blueprint:
|
|
bp = Blueprint("coop_api", __name__, url_prefix="/internal")
|
|
|
|
@bp.get("/post/<slug>")
|
|
@csrf_exempt
|
|
async def post_by_slug(slug: str):
|
|
"""
|
|
Return a Ghost post's key fields by slug.
|
|
Called by market app for the landing page.
|
|
"""
|
|
from bp.blog.ghost_db import DBClient
|
|
|
|
client = DBClient(g.s)
|
|
posts = await client.posts_by_slug(slug, include_drafts=False)
|
|
|
|
if not posts:
|
|
return jsonify(None), 404
|
|
|
|
post, original_post = posts[0]
|
|
|
|
return jsonify(
|
|
{
|
|
"post": {
|
|
"id": post.get("id"),
|
|
"title": post.get("title"),
|
|
"html": post.get("html"),
|
|
"custom_excerpt": post.get("custom_excerpt"),
|
|
"feature_image": post.get("feature_image"),
|
|
"slug": post.get("slug"),
|
|
},
|
|
"original_post": {
|
|
"id": getattr(original_post, "id", None),
|
|
"title": getattr(original_post, "title", None),
|
|
},
|
|
}
|
|
)
|
|
|
|
return bp
|