"""Blog app action endpoints. Exposes write operations at ``/internal/actions/`` for cross-app callers via the internal action client. """ from __future__ import annotations from quart import Blueprint, g, jsonify, request from shared.infrastructure.actions import ACTION_HEADER def register() -> Blueprint: bp = Blueprint("actions", __name__, url_prefix="/internal/actions") @bp.before_request async def _require_action_header(): if not request.headers.get(ACTION_HEADER): return jsonify({"error": "forbidden"}), 403 from shared.infrastructure.internal_auth import validate_internal_request if not validate_internal_request(): return jsonify({"error": "forbidden"}), 403 _handlers: dict[str, object] = {} @bp.post("/") async def handle_action(action_name: str): handler = _handlers.get(action_name) if handler is None: return jsonify({"error": "unknown action"}), 404 result = await handler() return jsonify(result or {"ok": True}) # --- update-page-config --- async def _update_page_config(): """Create or update a PageConfig (page_configs now lives in db_blog).""" from shared.models.page_config import PageConfig from sqlalchemy import select from sqlalchemy.orm.attributes import flag_modified data = await request.get_json(force=True) container_type = data.get("container_type", "page") container_id = data.get("container_id") if container_id is None: return {"error": "container_id required"}, 400 pc = (await g.s.execute( select(PageConfig).where( PageConfig.container_type == container_type, PageConfig.container_id == container_id, ) )).scalar_one_or_none() if pc is None: pc = PageConfig( container_type=container_type, container_id=container_id, features=data.get("features", {}), ) g.s.add(pc) await g.s.flush() if "features" in data: features = dict(pc.features or {}) for key, val in data["features"].items(): if isinstance(val, bool): features[key] = val elif val in ("true", "1", "on"): features[key] = True elif val in ("false", "0", "off", None): features[key] = False pc.features = features flag_modified(pc, "features") if "sumup_merchant_code" in data: pc.sumup_merchant_code = data["sumup_merchant_code"] or None if "sumup_checkout_prefix" in data: pc.sumup_checkout_prefix = data["sumup_checkout_prefix"] or None if "sumup_api_key" in data: pc.sumup_api_key = data["sumup_api_key"] or None await g.s.flush() return { "id": pc.id, "container_type": pc.container_type, "container_id": pc.container_id, "features": pc.features or {}, "sumup_merchant_code": pc.sumup_merchant_code, "sumup_checkout_prefix": pc.sumup_checkout_prefix, "sumup_configured": bool(pc.sumup_api_key), } _handlers["update-page-config"] = _update_page_config return bp