Decoupling audit: remove coop_api, fix blog admin calendar imports
Some checks are pending
Build and Deploy / build-and-deploy (push) Waiting to run

- Delete coop_api.py (dead internal API endpoint)
- Replace cross-app calendar imports with shared service calls
- Update shared submodule

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-20 11:15:23 +00:00
parent 2dc9bf220b
commit a8e0d8f257
5 changed files with 12 additions and 71 deletions

4
app.py
View File

@@ -16,7 +16,6 @@ from bp import (
register_admin,
register_menu_items,
register_snippets,
register_coop_api,
)
@@ -78,9 +77,6 @@ def create_app() -> "Quart":
app.register_blueprint(register_menu_items())
app.register_blueprint(register_snippets())
# Internal API (server-to-server, CSRF-exempt)
app.register_blueprint(register_coop_api())
# --- KV admin endpoints ---
@app.get("/settings/kv/<key>")
async def kv_get(key: str):

View File

@@ -3,4 +3,3 @@ from .blog.routes import register as register_blog_bp
from .admin.routes import register as register_admin
from .menu_items.routes import register as register_menu_items
from .snippets.routes import register as register_snippets
from .coop_api import register as register_coop_api

View File

@@ -1,51 +0,0 @@
"""
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

View File

@@ -191,13 +191,12 @@ def register():
@require_admin
async def calendar_view(slug: str, calendar_id: int):
"""Show calendar month view for browsing entries"""
from shared.models.calendars import Calendar # TODO: service method when admin UI is reworked
from shared.models.calendars import Calendar
from shared.utils.calendar_helpers import parse_int_arg, add_months, build_calendar_weeks
from shared.services.registry import services
from sqlalchemy import select
from datetime import datetime, timezone
from quart import request
import calendar as pycalendar
from ...calendar.services.calendar_view import parse_int_arg, add_months, build_calendar_weeks
from ...calendar.services import get_visible_entries_for_period
from quart import session as qsession
from ..services.entry_associations import get_post_entry_ids
@@ -235,15 +234,13 @@ def register():
period_end = datetime(next_y, next_m, 1, tzinfo=timezone.utc)
user = getattr(g, "user", None)
user_id = user.id if user else None
is_admin = bool(user and getattr(user, "is_admin", False))
session_id = qsession.get("calendar_sid")
visible = await get_visible_entries_for_period(
sess=g.s,
calendar_id=calendar_obj.id,
period_start=period_start,
period_end=period_end,
user=user,
session_id=session_id,
month_entries = await services.calendar.visible_entries_for_period(
g.s, calendar_obj.id, period_start, period_end,
user_id=user_id, is_admin=is_admin, session_id=session_id,
)
# Get associated entry IDs for this post
@@ -264,7 +261,7 @@ def register():
next_month_year=next_month_year,
prev_year=prev_year,
next_year=next_year,
month_entries=visible.merged_entries,
month_entries=month_entries,
associated_entry_ids=associated_entry_ids,
)
return await make_response(html)
@@ -273,7 +270,7 @@ def register():
@require_admin
async def entries(slug: str):
from ..services.entry_associations import get_post_entry_ids
from shared.models.calendars import Calendar # TODO: service method when admin UI is reworked
from shared.models.calendars import Calendar
from sqlalchemy import select
post_id = g.post_data["post"]["id"]
@@ -309,7 +306,7 @@ def register():
@require_admin
async def toggle_entry(slug: str, entry_id: int):
from ..services.entry_associations import toggle_entry_association, get_post_entry_ids, get_associated_entries
from shared.models.calendars import Calendar # TODO: service method when admin UI is reworked
from shared.models.calendars import Calendar
from sqlalchemy import select
from quart import jsonify

2
shared

Submodule shared updated: 7ee8638d6e...e83df2f742