Replace every direct cross-app services.* call with HTTP-based communication: call_action() for writes, fetch_data() for reads. Each app now registers only its own domain service. Infrastructure: - shared/infrastructure/actions.py — POST client for /internal/actions/ - shared/infrastructure/data_client.py — GET client for /internal/data/ - shared/contracts/dtos.py — dto_to_dict/dto_from_dict serialization Action endpoints (writes): - events: 8 handlers (ticket adjust, claim/confirm, toggle, adopt) - market: 2 handlers (create/soft-delete marketplace) - cart: 1 handler (adopt cart for user) Data endpoints (reads): - blog: 4 (post-by-slug/id, posts-by-ids, search-posts) - events: 10 (pending entries/tickets, entries/tickets for page/order, entry-ids, associated-entries, calendars, visible-entries-for-period) - market: 1 (marketplaces-for-container) - cart: 1 (cart-summary) Service registration cleanup: - blog→blog+federation, events→calendar+federation, market→market+federation, cart→cart only, federation→federation only, account→nothing - Stubs reduced to minimal StubFederationService Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
"""Events app action endpoints.
|
|
|
|
Exposes write operations at ``/internal/actions/<action_name>`` for
|
|
cross-app callers (cart, blog) via the internal action client.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from quart import Blueprint, g, jsonify, request
|
|
|
|
from shared.infrastructure.actions import ACTION_HEADER
|
|
from shared.services.registry import services
|
|
|
|
|
|
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
|
|
|
|
_handlers: dict[str, object] = {}
|
|
|
|
@bp.post("/<action_name>")
|
|
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)
|
|
|
|
# --- adjust-ticket-quantity ---
|
|
async def _adjust_ticket_quantity():
|
|
data = await request.get_json()
|
|
await services.calendar.adjust_ticket_quantity(
|
|
g.s,
|
|
data["entry_id"],
|
|
data["count"],
|
|
user_id=data.get("user_id"),
|
|
session_id=data.get("session_id"),
|
|
ticket_type_id=data.get("ticket_type_id"),
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["adjust-ticket-quantity"] = _adjust_ticket_quantity
|
|
|
|
# --- claim-entries-for-order ---
|
|
async def _claim_entries():
|
|
data = await request.get_json()
|
|
await services.calendar.claim_entries_for_order(
|
|
g.s,
|
|
data["order_id"],
|
|
data.get("user_id"),
|
|
data.get("session_id"),
|
|
data.get("page_post_id"),
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["claim-entries-for-order"] = _claim_entries
|
|
|
|
# --- claim-tickets-for-order ---
|
|
async def _claim_tickets():
|
|
data = await request.get_json()
|
|
await services.calendar.claim_tickets_for_order(
|
|
g.s,
|
|
data["order_id"],
|
|
data.get("user_id"),
|
|
data.get("session_id"),
|
|
data.get("page_post_id"),
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["claim-tickets-for-order"] = _claim_tickets
|
|
|
|
# --- confirm-entries-for-order ---
|
|
async def _confirm_entries():
|
|
data = await request.get_json()
|
|
await services.calendar.confirm_entries_for_order(
|
|
g.s,
|
|
data["order_id"],
|
|
data.get("user_id"),
|
|
data.get("session_id"),
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["confirm-entries-for-order"] = _confirm_entries
|
|
|
|
# --- confirm-tickets-for-order ---
|
|
async def _confirm_tickets():
|
|
data = await request.get_json()
|
|
await services.calendar.confirm_tickets_for_order(
|
|
g.s, data["order_id"],
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["confirm-tickets-for-order"] = _confirm_tickets
|
|
|
|
# --- toggle-entry-post ---
|
|
async def _toggle_entry_post():
|
|
data = await request.get_json()
|
|
is_associated = await services.calendar.toggle_entry_post(
|
|
g.s,
|
|
data["entry_id"],
|
|
data["content_type"],
|
|
data["content_id"],
|
|
)
|
|
return {"is_associated": is_associated}
|
|
|
|
_handlers["toggle-entry-post"] = _toggle_entry_post
|
|
|
|
# --- adopt-entries-for-user ---
|
|
async def _adopt_entries():
|
|
data = await request.get_json()
|
|
await services.calendar.adopt_entries_for_user(
|
|
g.s, data["user_id"], data["session_id"],
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["adopt-entries-for-user"] = _adopt_entries
|
|
|
|
# --- adopt-tickets-for-user ---
|
|
async def _adopt_tickets():
|
|
data = await request.get_json()
|
|
await services.calendar.adopt_tickets_for_user(
|
|
g.s, data["user_id"], data["session_id"],
|
|
)
|
|
return {"ok": True}
|
|
|
|
_handlers["adopt-tickets-for-user"] = _adopt_tickets
|
|
|
|
return bp
|