From 5957bd894113a34b58e4dd591bb13e177075c139 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 28 Feb 2026 16:50:13 +0000 Subject: [PATCH] Move calendar blueprint to app level for correct URL routing The calendar blueprint was nested under calendars (admin), making URLs /{slug}/admin/{calendar_slug}/ instead of /{slug}/{calendar_slug}/. Register calendar blueprint directly on the app and update all endpoint references from calendars.calendar.* to calendar.* (37 in Python, ~50 in templates). Co-Authored-By: Claude Opus 4.6 --- events/app.py | 9 ++- events/bp/__init__.py | 1 + events/bp/calendars/routes.py | 5 -- events/sexp/sexp_components.py | 74 +++++++++---------- .../_types/calendar/_main_panel.html | 20 ++--- events/templates/_types/calendar/_nav.html | 4 +- .../_types/calendar/admin/_description.html | 2 +- .../calendar/admin/_description_edit.html | 4 +- .../_types/calendar/header/_header.html | 2 +- .../_types/calendars/_calendars_list.html | 4 +- events/templates/_types/day/_add.html | 4 +- events/templates/_types/day/_add_button.html | 2 +- events/templates/_types/day/_nav.html | 4 +- events/templates/_types/day/_row.html | 4 +- .../_types/day/admin/_nav_entries_oob.html | 2 +- .../_types/day/admin/header/_header.html | 2 +- .../templates/_types/day/header/_header.html | 2 +- events/templates/_types/entry/_edit.html | 4 +- .../templates/_types/entry/_main_panel.html | 2 +- events/templates/_types/entry/_nav.html | 2 +- events/templates/_types/entry/_options.html | 6 +- .../_types/entry/_post_search_results.html | 4 +- events/templates/_types/entry/_posts.html | 4 +- events/templates/_types/entry/_tickets.html | 2 +- events/templates/_types/entry/admin/_nav.html | 2 +- .../_types/entry/admin/header/_header.html | 2 +- .../_types/entry/header/_header.html | 2 +- events/templates/_types/post/_nav.html | 2 +- events/templates/_types/slot/_edit.html | 4 +- events/templates/_types/slot/_main_panel.html | 2 +- events/templates/_types/slots/_add.html | 4 +- .../templates/_types/slots/_add_button.html | 2 +- events/templates/_types/slots/_row.html | 2 +- .../templates/_types/ticket_type/_edit.html | 4 +- .../_types/ticket_type/_main_panel.html | 2 +- .../_types/ticket_type/header/_header.html | 2 +- .../templates/_types/ticket_types/_add.html | 4 +- .../_types/ticket_types/_add_button.html | 2 +- .../templates/_types/ticket_types/_row.html | 4 +- .../_types/ticket_types/header/_header.html | 2 +- 40 files changed, 106 insertions(+), 105 deletions(-) diff --git a/events/app.py b/events/app.py index 09478a8..154ff21 100644 --- a/events/app.py +++ b/events/app.py @@ -9,7 +9,7 @@ from jinja2 import FileSystemLoader, ChoiceLoader from shared.infrastructure.factory import create_base_app -from bp import register_all_events, register_calendars, register_markets, register_payments, register_page, register_fragments, register_actions, register_data +from bp import register_all_events, register_calendar, register_calendars, register_markets, register_payments, register_page, register_fragments, register_actions, register_data async def events_context() -> dict: @@ -90,8 +90,13 @@ def create_app() -> "Quart": url_prefix="/", ) - # Calendar admin under post slug: //admin/ # Individual calendars at /// + app.register_blueprint( + register_calendar(), + url_prefix="/", + ) + + # Calendar admin under post slug: //admin/ app.register_blueprint( register_calendars(), url_prefix="/", diff --git a/events/bp/__init__.py b/events/bp/__init__.py index c7a6ed2..8f6bb2b 100644 --- a/events/bp/__init__.py +++ b/events/bp/__init__.py @@ -1,4 +1,5 @@ from .all_events.routes import register as register_all_events +from .calendar.routes import register as register_calendar from .calendars.routes import register as register_calendars from .markets.routes import register as register_markets from .payments.routes import register as register_payments diff --git a/events/bp/calendars/routes.py b/events/bp/calendars/routes.py index 53625b1..4d83de2 100644 --- a/events/bp/calendars/routes.py +++ b/events/bp/calendars/routes.py @@ -12,8 +12,6 @@ from .services.calendars import ( create_calendar as svc_create_calendar, ) -from ..calendar.routes import register as register_calendar - from shared.browser.app.redis_cacher import cache_page, clear_cache from shared.browser.app.authz import require_admin @@ -22,9 +20,6 @@ from shared.browser.app.utils.htmx import is_htmx_request def register(): bp = Blueprint("calendars", __name__, url_prefix='/admin') - bp.register_blueprint( - register_calendar(), - ) @bp.context_processor async def inject_root(): # Must always return a dict diff --git a/events/sexp/sexp_components.py b/events/sexp/sexp_components.py index 6e73a23..09aba6e 100644 --- a/events/sexp/sexp_components.py +++ b/events/sexp/sexp_components.py @@ -77,7 +77,7 @@ def _post_nav_html(ctx: dict) -> str: for cal in calendars: cal_slug = getattr(cal, "slug", "") if hasattr(cal, "slug") else cal.get("slug", "") cal_name = getattr(cal, "name", "") if hasattr(cal, "name") else cal.get("name", "") - href = url_for("calendars.calendar.get", calendar_slug=cal_slug) + href = url_for("calendar.get", calendar_slug=cal_slug) is_sel = (cal_slug == current_cal_slug) parts.append(render("nav-link", href=href, icon="fa fa-calendar", label=cal_name, select_colours=select_colours, @@ -122,7 +122,7 @@ def _calendar_header_html(ctx: dict, *, oob: bool = False) -> str: cal_name = getattr(calendar, "name", "") cal_desc = getattr(calendar, "description", "") or "" - link_href = url_for("calendars.calendar.get", calendar_slug=cal_slug) + link_href = url_for("calendar.get", calendar_slug=cal_slug) label_html = render("events-calendar-label", name=cal_name, description=cal_desc) @@ -146,11 +146,11 @@ def _calendar_nav_html(ctx: dict) -> str: select_colours = ctx.get("select_colours", "") parts = [] - slots_href = url_for("calendars.calendar.slots.get", calendar_slug=cal_slug) + slots_href = url_for("calendar.slots.get", calendar_slug=cal_slug) parts.append(render("nav-link", href=slots_href, icon="fa fa-clock", label="Slots", select_colours=select_colours)) if is_admin: - admin_href = url_for("calendars.calendar.admin.admin", calendar_slug=cal_slug) + admin_href = url_for("calendar.admin.admin", calendar_slug=cal_slug) parts.append(render("nav-link", href=admin_href, icon="fa fa-cog", select_colours=select_colours)) return "".join(parts) @@ -172,7 +172,7 @@ def _day_header_html(ctx: dict, *, oob: bool = False) -> str: return "" link_href = url_for( - "calendars.calendar.day.show_day", + "calendar.day.show_day", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, @@ -206,7 +206,7 @@ def _day_nav_html(ctx: dict) -> str: entry_links = [] for entry in confirmed_entries: href = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.get", + "calendar.day.calendar_entries.calendar_entry.get", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, @@ -223,7 +223,7 @@ def _day_nav_html(ctx: dict) -> str: if is_admin and day_date: admin_href = url_for( - "calendars.calendar.day.admin.admin", + "calendar.day.admin.admin", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, @@ -249,7 +249,7 @@ def _day_admin_header_html(ctx: dict, *, oob: bool = False) -> str: return "" link_href = url_for( - "calendars.calendar.day.admin.admin", + "calendar.day.admin.admin", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, @@ -274,8 +274,8 @@ def _calendar_admin_header_html(ctx: dict, *, oob: bool = False) -> str: nav_parts = [] if cal_slug: for endpoint, label in [ - ("calendars.calendar.slots.get", "slots"), - ("calendars.calendar.admin.calendar_description_edit", "description"), + ("calendar.slots.get", "slots"), + ("calendar.admin.calendar_description_edit", "description"), ]: href = url_for(endpoint, calendar_slug=cal_slug) nav_parts.append(render("nav-link", href=href, label=label, @@ -357,8 +357,8 @@ def _calendars_list_html(ctx: dict, calendars: list) -> str: for cal in calendars: cal_slug = getattr(cal, "slug", "") cal_name = getattr(cal, "name", "") - href = prefix + url_for("calendars.calendar.get", calendar_slug=cal_slug) - del_url = url_for("calendars.calendar.delete", calendar_slug=cal_slug) + href = prefix + url_for("calendar.get", calendar_slug=cal_slug) + del_url = url_for("calendar.delete", calendar_slug=cal_slug) csrf_hdr = f'{{"X-CSRFToken":"{csrf}"}}' parts.append(render("events-calendars-item", href=href, cal_name=cal_name, cal_slug=cal_slug, @@ -399,7 +399,7 @@ def _calendar_main_panel_html(ctx: dict) -> str: qs = qsession if "qsession" not in ctx else ctx["qsession"] def nav_link(y, m): - return url_for("calendars.calendar.get", calendar_slug=cal_slug, year=y, month=m) + return url_for("calendar.get", calendar_slug=cal_slug, year=y, month=m) # Month navigation arrows nav_arrows = [] @@ -449,7 +449,7 @@ def _calendar_main_panel_html(ctx: dict) -> str: day_short_html = "" if day_date: day_href = url_for( - "calendars.calendar.day.show_day", + "calendar.day.show_day", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, day=day_date.day, ) @@ -519,7 +519,7 @@ def _day_main_panel_html(ctx: dict) -> str: rows_html = render("events-day-empty-row") add_url = url_for( - "calendars.calendar.day.calendar_entries.add_form", + "calendar.day.calendar_entries.add_form", calendar_slug=cal_slug, day=day, month=month, year=year, ) @@ -543,7 +543,7 @@ def _day_row_html(ctx: dict, entry) -> str: tr_cls = getattr(styles, "tr", "") if hasattr(styles, "tr") else styles.get("tr", "") entry_href = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.get", + "calendar.day.calendar_entries.calendar_entry.get", calendar_slug=cal_slug, day=day, month=month, year=year, entry_id=entry.id, ) @@ -554,7 +554,7 @@ def _day_row_html(ctx: dict, entry) -> str: # Slot/Time slot = getattr(entry, "slot", None) if slot: - slot_href = url_for("calendars.calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=slot.id) + slot_href = url_for("calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=slot.id) time_start = slot.time_start.strftime("%H:%M") if slot.time_start else "" time_end = f" \u2192 {slot.time_end.strftime('%H:%M')}" if slot.time_end else "" slot_html = render("events-day-row-slot", @@ -633,7 +633,7 @@ def _calendar_admin_main_panel_html(ctx: dict) -> str: desc = getattr(calendar, "description", "") or "" hx_select = ctx.get("hx_select_search", "#main-panel") - desc_edit_url = url_for("calendars.calendar.admin.calendar_description_edit", calendar_slug=cal_slug) + desc_edit_url = url_for("calendar.admin.calendar_description_edit", calendar_slug=cal_slug) description_html = _calendar_description_display_html(calendar, desc_edit_url) return render("events-calendar-admin-panel", @@ -1769,7 +1769,7 @@ def _entry_main_panel_html(ctx: dict) -> str: # Options and Edit Button edit_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.get_edit", + "calendar.day.calendar_entries.calendar_entry.get_edit", entry_id=eid, calendar_slug=cal_slug, day=day, month=month, year=year, ) @@ -1805,7 +1805,7 @@ def _entry_header_html(ctx: dict, *, oob: bool = False) -> str: year = ctx.get("year") link_href = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.get", + "calendar.day.calendar_entries.calendar_entry.get", calendar_slug=cal_slug, year=year, month=month, day=day, entry_id=entry.id, @@ -1879,7 +1879,7 @@ def _entry_nav_html(ctx: dict) -> str: # Admin link if is_admin: admin_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.admin.admin", + "calendar.day.calendar_entries.calendar_entry.admin.admin", calendar_slug=cal_slug, day=day, month=month, year=year, entry_id=entry.id, @@ -1954,7 +1954,7 @@ def _entry_options_html(entry, calendar, day, month, year) -> str: def _make_button(action_name, label, confirm_title, confirm_text, *, trigger_type="submit"): url = url_for( - f"calendars.calendar.day.calendar_entries.calendar_entry.{action_name}", + f"calendar.day.calendar_entries.calendar_entry.{action_name}", calendar_slug=cal_slug, day=day, month=month, year=year, entry_id=eid, ) btn_type = "button" if trigger_type == "button" else "submit" @@ -2013,7 +2013,7 @@ def render_entry_tickets_config(entry, calendar, day, month, year) -> str: display_html = render("events-ticket-config-none", show_js=show_js) update_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.update_tickets", + "calendar.day.calendar_entries.calendar_entry.update_tickets", entry_id=eid, calendar_slug=cal_slug, day=day, month=month, year=year, ) hidden_cls = "" if tp is None else "hidden" @@ -2052,7 +2052,7 @@ def render_entry_posts_panel(entry_posts, entry, calendar, day, month, year) -> if feat else render("events-post-img-placeholder")) del_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.remove_post", + "calendar.day.calendar_entries.calendar_entry.remove_post", calendar_slug=cal_slug, day=day, month=month, year=year, entry_id=eid, post_id=ep_id, ) @@ -2065,7 +2065,7 @@ def render_entry_posts_panel(entry_posts, entry, calendar, day, month, year) -> posts_html = render("events-entry-posts-none") search_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.search_posts", + "calendar.day.calendar_entries.calendar_entry.search_posts", calendar_slug=cal_slug, day=day, month=month, year=year, entry_id=eid, ) @@ -2121,7 +2121,7 @@ def render_day_entries_nav_oob(confirmed_entries, calendar, day_date) -> str: items = "" for entry in confirmed_entries: href = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.get", + "calendar.day.calendar_entries.calendar_entry.get", calendar_slug=cal_slug, year=day_date.year, month=day_date.month, day=day_date.day, entry_id=entry.id, @@ -2195,7 +2195,7 @@ def render_calendar_description(calendar, *, oob: bool = False) -> str: from quart import url_for cal_slug = getattr(calendar, "slug", "") - edit_url = url_for("calendars.calendar.admin.calendar_description_edit", calendar_slug=cal_slug) + edit_url = url_for("calendar.admin.calendar_description_edit", calendar_slug=cal_slug) html = _calendar_description_display_html(calendar, edit_url) if oob: @@ -2213,8 +2213,8 @@ def render_calendar_description_edit(calendar) -> str: cal_slug = getattr(calendar, "slug", "") desc = getattr(calendar, "description", "") or "" - save_url = url_for("calendars.calendar.admin.calendar_description_save", calendar_slug=cal_slug) - cancel_url = url_for("calendars.calendar.admin.calendar_description_view", calendar_slug=cal_slug) + save_url = url_for("calendar.admin.calendar_description_save", calendar_slug=cal_slug) + cancel_url = url_for("calendar.admin.calendar_description_view", calendar_slug=cal_slug) return render("events-calendar-description-edit-form", save_url=save_url, cancel_url=cancel_url, @@ -2270,7 +2270,7 @@ def render_slot_main_panel(slot, calendar, *, oob: bool = False) -> str: cost_str = f"{cost:.2f}" if cost is not None else "" desc = getattr(slot, "description", "") or "" - edit_url = url_for("calendars.calendar.slots.slot.get_edit", slot_id=slot.id, calendar_slug=cal_slug) + edit_url = url_for("calendar.slots.slot.get_edit", slot_id=slot.id, calendar_slug=cal_slug) # Days pills if days and days[0] != "\u2014": @@ -2319,8 +2319,8 @@ def render_slots_table(slots, calendar) -> str: rows_html = "" if slots: for s in slots: - slot_href = url_for("calendars.calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=s.id) - del_url = url_for("calendars.calendar.slots.slot.slot_delete", calendar_slug=cal_slug, slot_id=s.id) + slot_href = url_for("calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=s.id) + del_url = url_for("calendar.slots.slot.slot_delete", calendar_slug=cal_slug, slot_id=s.id) desc = getattr(s, "description", "") or "" days_display = getattr(s, "days_display", "\u2014") @@ -2351,7 +2351,7 @@ def render_slots_table(slots, calendar) -> str: else: rows_html = render("events-slots-empty-row") - add_url = url_for("calendars.calendar.slots.add_form", calendar_slug=cal_slug) + add_url = url_for("calendar.slots.add_form", calendar_slug=cal_slug) return render("events-slots-table", list_container=list_container, rows_html=rows_html, @@ -2377,7 +2377,7 @@ def render_ticket_type_main_panel(ticket_type, entry, calendar, day, month, year tid = str(ticket_type.id) edit_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_edit", + "calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_edit", ticket_type_id=ticket_type.id, calendar_slug=cal_slug, year=year, month=month, day=day, entry_id=entry.id, ) @@ -2416,12 +2416,12 @@ def render_ticket_types_table(ticket_types, entry, calendar, day, month, year) - if ticket_types: for tt in ticket_types: tt_href = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get", + "calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get", calendar_slug=cal_slug, year=year, month=month, day=day, entry_id=eid, ticket_type_id=tt.id, ) del_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete", + "calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete", calendar_slug=cal_slug, year=year, month=month, day=day, entry_id=eid, ticket_type_id=tt.id, ) @@ -2439,7 +2439,7 @@ def render_ticket_types_table(ticket_types, entry, calendar, day, month, year) - rows_html = render("events-ticket-types-empty-row") add_url = url_for( - "calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.add_form", + "calendar.day.calendar_entries.calendar_entry.ticket_types.add_form", calendar_slug=cal_slug, entry_id=eid, year=year, month=month, day=day, ) diff --git a/events/templates/_types/calendar/_main_panel.html b/events/templates/_types/calendar/_main_panel.html index 7c0ffde..6da9573 100644 --- a/events/templates/_types/calendar/_main_panel.html +++ b/events/templates/_types/calendar/_main_panel.html @@ -6,11 +6,11 @@ {# Outer left: -1 year #} {% import 'macros/links.html' as links %} {% call links.link( - url_for('calendars.calendar.slots.get', calendar_slug=calendar.slug), + url_for('calendar.slots.get', calendar_slug=calendar.slug), hx_select_search, select_colours, True, @@ -14,5 +14,5 @@ {% endcall %} {% if g.rights.admin %} {% from 'macros/admin_nav.html' import admin_nav_item %} - {{ admin_nav_item(url_for('calendars.calendar.admin.admin', calendar_slug=calendar.slug)) }} + {{ admin_nav_item(url_for('calendar.admin.admin', calendar_slug=calendar.slug)) }} {% endif %} \ No newline at end of file diff --git a/events/templates/_types/calendar/admin/_description.html b/events/templates/_types/calendar/admin/_description.html index 46d99cb..8997b85 100644 --- a/events/templates/_types/calendar/admin/_description.html +++ b/events/templates/_types/calendar/admin/_description.html @@ -13,7 +13,7 @@ type="button" class="mt-2 text-xs underline" hx-get="{{ url_for( - 'calendars.calendar.admin.calendar_description_edit', + 'calendar.admin.calendar_description_edit', calendar_slug=calendar.slug, ) }}" hx-target="#calendar-description" diff --git a/events/templates/_types/calendar/admin/_description_edit.html b/events/templates/_types/calendar/admin/_description_edit.html index 4ab7a7b..212c218 100644 --- a/events/templates/_types/calendar/admin/_description_edit.html +++ b/events/templates/_types/calendar/admin/_description_edit.html @@ -1,7 +1,7 @@
diff --git a/events/templates/_types/calendars/_calendars_list.html b/events/templates/_types/calendars/_calendars_list.html index 87d482c..1db0a6f 100644 --- a/events/templates/_types/calendars/_calendars_list.html +++ b/events/templates/_types/calendars/_calendars_list.html @@ -3,7 +3,7 @@
- {% set calendar_href = url_for('calendars.calendar.get', calendar_slug=cal.slug)|host %} + {% set calendar_href = url_for('calendar.get', calendar_slug=cal.slug)|host %} {% call links.link( url_for( - 'calendars.calendar.day.calendar_entries.calendar_entry.get', + 'calendar.day.calendar_entries.calendar_entry.get', calendar_slug=calendar.slug, day=day, month=month, @@ -23,7 +23,7 @@ {% call links.link( url_for( - 'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get', + 'calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get', calendar_slug=calendar.slug, year=year, month=month, @@ -35,7 +35,7 @@ data-confirm-confirm-text="Yes, delete it" data-confirm-cancel-text="Cancel" data-confirm-event="confirmed" - hx-delete="{{ url_for('calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete', + hx-delete="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete', calendar_slug=calendar.slug, year=year, month=month, diff --git a/events/templates/_types/ticket_types/header/_header.html b/events/templates/_types/ticket_types/header/_header.html index 2a95316..979954a 100644 --- a/events/templates/_types/ticket_types/header/_header.html +++ b/events/templates/_types/ticket_types/header/_header.html @@ -2,7 +2,7 @@ {% macro header_row(oob=False) %} {% call links.menu_row(id='ticket_types-row', oob=oob) %} {% call links.link(url_for( - 'calendars.calendar.day.calendar_entries.calendar_entry.ticket_types.get', + 'calendar.day.calendar_entries.calendar_entry.ticket_types.get', calendar_slug=calendar.slug, entry_id=entry.id, year=year,