Fix market and calendar URL routing

Market: blog links now use market_url('/{slug}/') instead of
events_url('/{slug}/markets/'), matching the market service's
actual route structure /<page_slug>/<market_slug>/.

Calendar: flatten route from /<slug>/calendars/<calendar_slug>/
to /<slug>/<calendar_slug>/ by changing the events app blueprint
prefix and moving listing routes to explicit /calendars/ paths.
Update all hardcoded calendar URL paths across blog and events
services (Python + Jinja templates).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 13:58:05 +00:00
parent 5c6d83f474
commit 16da08ff05
16 changed files with 40 additions and 36 deletions

View File

@@ -165,15 +165,18 @@ def _post_admin_nav_html(ctx: dict) -> str:
parts = []
# External links to events service
# External links to events / market services
events_url_fn = ctx.get("events_url")
market_url_fn = ctx.get("market_url")
if callable(events_url_fn):
for path, label in [
(f"/{slug}/calendars/", "calendars"),
(f"/{slug}/markets/", "markets"),
(f"/{slug}/payments/", "payments"),
for url_fn, path, label in [
(events_url_fn, f"/{slug}/calendar/", "calendar"),
(market_url_fn, f"/{slug}/", "markets"),
(events_url_fn, f"/{slug}/payments/", "payments"),
]:
href = events_url_fn(path)
if not callable(url_fn):
continue
href = url_fn(path)
parts.append(sexp(
'(div :class "relative nav-group" (a :href h :class c l))',
h=href, c=nav_btn, l=label,
@@ -2573,7 +2576,7 @@ def render_nav_entries_oob(associated_entries, calendars, post: dict, ctx: dict
if e_start:
entry_path = (
f"/{post_slug}/calendars/{cal_slug}/"
f"/{post_slug}/{cal_slug}/"
f"{e_start.year}/{e_start.month}/{e_start.day}"
f"/entries/{getattr(entry, 'id', '')}/"
)
@@ -2581,7 +2584,7 @@ def render_nav_entries_oob(associated_entries, calendars, post: dict, ctx: dict
if e_end:
date_str += f" \u2013 {e_end.strftime('%H:%M')}"
else:
entry_path = f"/{post_slug}/calendars/{cal_slug}/"
entry_path = f"/{post_slug}/{cal_slug}/"
date_str = ""
href = events_url_fn(entry_path) if events_url_fn else entry_path
@@ -2599,7 +2602,7 @@ def render_nav_entries_oob(associated_entries, calendars, post: dict, ctx: dict
for calendar in (calendars or []):
cal_name = getattr(calendar, "name", "")
cal_slug = getattr(calendar, "slug", "")
cal_path = f"/{post_slug}/calendars/{cal_slug}/"
cal_path = f"/{post_slug}/{cal_slug}/"
href = events_url_fn(cal_path) if events_url_fn else cal_path
item_parts.append(sexp(

View File

@@ -4,7 +4,7 @@
{% set has_more_entries = has_more if has_more is defined else (associated_entries.has_more if associated_entries is defined else False) %}
{% for entry in entry_list %}
{% set _entry_path = '/' + post.slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
{% set _entry_path = '/' + post.slug + '/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="{{styles.nav_button_less_pad}}"

View File

@@ -1,11 +1,11 @@
{% import 'macros/links.html' as links %}
<div class="relative nav-group">
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="{{styles.nav_button}}">
calendars
<a href="{{ events_url('/' + post.slug + '/calendar/') }}" class="{{styles.nav_button}}">
calendar
</a>
</div>
<div class="relative nav-group">
<a href="{{ events_url('/' + post.slug + '/markets/') }}" class="{{styles.nav_button}}">
<a href="{{ market_url('/' + post.slug + '/') }}" class="{{styles.nav_button}}">
markets
</a>
</div>

View File

@@ -5,7 +5,7 @@
{% call nav_entries_oob(has_items) %}
{% if associated_entries and associated_entries.entries %}
{% for entry in associated_entries.entries %}
{% set _entry_path = '/' + post.slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
{% set _entry_path = '/' + post.slug + '/' +entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="{{styles.nav_button_less_pad}}">
@@ -22,7 +22,7 @@
{% endif %}
{% if calendars %}
{% for calendar in calendars %}
{% set local_href=events_url('/' + post.slug + '/calendars/' + calendar.slug + '/') %}
{% set local_href=events_url('/' + post.slug + '/' +calendar.slug + '/') %}
<a
href="{{ local_href }}"
class="{{styles.nav_button_less_pad}}">

View File

@@ -1,7 +1,7 @@
{% import 'macros/links.html' as links %}
{% macro header_row(oob=False) %}
{% call links.menu_row(id='post_data-row', oob=oob) %}
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="flex gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
<a href="{{ events_url('/' + post.slug + '/calendar/') }}" class="flex gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
<i class="fa fa-database" aria-hidden="true"></i>
<div>data</div>
</a>

View File

@@ -90,10 +90,11 @@ def create_app() -> "Quart":
url_prefix="/<slug>",
)
# Calendars nested under post slug: /<slug>/calendars/...
# Calendars nested under post slug: /<slug>/<calendar_slug>/...
# Listing stays at /<slug>/calendars/, individual at /<slug>/<calendar_slug>/
app.register_blueprint(
register_calendars(),
url_prefix="/<slug>/calendars",
url_prefix="/<slug>",
)
# Markets nested under post slug: /<slug>/markets/...

View File

@@ -32,7 +32,7 @@ def register():
# ---------- Pages ----------
@bp.get("/")
@bp.get("/calendars/")
@cache_page(tag="calendars")
async def home(**kwargs):
from shared.sexp.page import get_template_context
@@ -46,7 +46,7 @@ def register():
return await make_response(html)
@bp.post("/new/")
@bp.post("/calendars/new/")
@require_admin
@clear_cache(tag="calendars", tag_scope="all")
async def create_calendar(**kwargs):

View File

@@ -58,7 +58,7 @@ def register():
)
for entry in entries:
entry_path = (
f"/{post_slug}/calendars/{entry.calendar_slug}/"
f"/{post_slug}/{entry.calendar_slug}/"
f"{entry.start_at.year}/{entry.start_at.month}/"
f"{entry.start_at.day}/entries/{entry.id}/"
)
@@ -87,7 +87,7 @@ def register():
g.s, container_type, container_id,
)
for cal in calendars:
href = events_url(f"/{post_slug}/calendars/{cal.slug}/")
href = events_url(f"/{post_slug}/{cal.slug}/")
html_parts.append(render_sexp(
'(~calendar-link-nav :href href :name name :nav-class nav-class)',
href=href, name=cal.name, **{"nav-class": nav_class},

View File

@@ -1250,7 +1250,7 @@ def _entry_card_html(entry, page_info: dict, pending_tickets: dict,
day_href = ""
if page_slug and entry.start_at:
day_href = events_url_fn(f"/{page_slug}/calendars/{entry.calendar_slug}/day/{entry.start_at.strftime('%Y/%-m/%-d')}/")
day_href = events_url_fn(f"/{page_slug}/{entry.calendar_slug}/day/{entry.start_at.strftime('%Y/%-m/%-d')}/")
entry_href = f"{day_href}entries/{entry.id}/" if day_href else ""
# Title (linked or plain)
@@ -1332,7 +1332,7 @@ def _entry_card_tile_html(entry, page_info: dict, pending_tickets: dict,
day_href = ""
if page_slug and entry.start_at:
day_href = events_url_fn(f"/{page_slug}/calendars/{entry.calendar_slug}/day/{entry.start_at.strftime('%Y/%-m/%-d')}/")
day_href = events_url_fn(f"/{page_slug}/{entry.calendar_slug}/day/{entry.start_at.strftime('%Y/%-m/%-d')}/")
entry_href = f"{day_href}entries/{entry.id}/" if day_href else ""
# Title
@@ -2762,7 +2762,7 @@ def render_post_nav_entries_oob(associated_entries, calendars, post) -> str:
if has_entries:
for entry in associated_entries.entries:
entry_path = (
f"/{slug}/calendars/{entry.calendar_slug}/"
f"/{slug}/{entry.calendar_slug}/"
f"{entry.start_at.year}/{entry.start_at.month}/{entry.start_at.day}/"
f"entries/{entry.id}/"
)
@@ -2781,7 +2781,7 @@ def render_post_nav_entries_oob(associated_entries, calendars, post) -> str:
if calendars:
for cal in calendars:
cs = getattr(cal, "slug", "")
local_href = events_url(f"/{slug}/calendars/{cs}/")
local_href = events_url(f"/{slug}/{cs}/")
items += sexp(
'(a :href lh :class nb'
' (i :class "fa fa-calendar" :aria-hidden "true")'

View File

@@ -7,7 +7,7 @@
{# Left: event info #}
<div class="flex-1 min-w-0">
{% if page_slug %}
{% set day_href = events_url('/' ~ page_slug ~ '/calendars/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set day_href = events_url('/' ~ page_slug ~ '/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% else %}
{% set day_href = '' %}
{% endif %}

View File

@@ -4,7 +4,7 @@
{% set page_title = pi.get('title') %}
<article class="rounded-xl bg-white shadow-sm border border-stone-200 overflow-hidden">
{% if page_slug %}
{% set day_href = events_url('/' ~ page_slug ~ '/calendars/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set day_href = events_url('/' ~ page_slug ~ '/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% else %}
{% set day_href = '' %}
{% endif %}

View File

@@ -6,7 +6,7 @@
<div class="flex flex-col sm:flex-row sm:items-start justify-between gap-3">
{# Left: event info #}
<div class="flex-1 min-w-0">
{% set day_href = events_url('/' ~ page_slug ~ '/calendars/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set day_href = events_url('/' ~ page_slug ~ '/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set entry_href = day_href ~ 'entries/' ~ entry.id ~ '/' %}
<a href="{{ entry_href }}" class="hover:text-emerald-700">
<h2 class="text-lg font-semibold text-stone-900">{{ entry.name }}</h2>

View File

@@ -3,7 +3,7 @@
{% set page_slug = pi.get('slug', post.slug) %}
{% set page_title = pi.get('title') %}
<article class="rounded-xl bg-white shadow-sm border border-stone-200 overflow-hidden">
{% set day_href = events_url('/' ~ page_slug ~ '/calendars/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set day_href = events_url('/' ~ page_slug ~ '/' ~ entry.calendar_slug ~ '/day/' ~ entry.start_at.strftime('%Y/%-m/%-d') ~ '/') %}
{% set entry_href = day_href ~ 'entries/' ~ entry.id ~ '/' %}
<div class="p-3">
<a href="{{ entry_href }}" class="hover:text-emerald-700">

View File

@@ -1,11 +1,11 @@
{% import 'macros/links.html' as links %}
<div class="relative nav-group">
<a href="{{ events_url('/' + post.slug + '/calendars/') }}" class="{{styles.nav_button}}">
calendars
<a href="{{ events_url('/' + post.slug + '/calendar/') }}" class="{{styles.nav_button}}">
calendar
</a>
</div>
<div class="relative nav-group">
<a href="{{ events_url('/' + post.slug + '/markets/') }}" class="{{styles.nav_button}}">
<a href="{{ market_url('/' + post.slug + '/') }}" class="{{styles.nav_button}}">
markets
</a>
</div>

View File

@@ -5,7 +5,7 @@
{% call nav_entries_oob(has_items) %}
{% if associated_entries and associated_entries.entries %}
{% for entry in associated_entries.entries %}
{% set _entry_path = '/' + post.slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
{% set _entry_path = '/' + post.slug + '/' +entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="{{styles.nav_button_less_pad}}">
@@ -22,7 +22,7 @@
{% endif %}
{% if calendars %}
{% for calendar in calendars %}
{% set local_href=events_url('/' + post.slug + '/calendars/' + calendar.slug + '/') %}
{% set local_href=events_url('/' + post.slug + '/' +calendar.slug + '/') %}
<a
href="{{ local_href }}"
class="{{styles.nav_button_less_pad}}">

View File

@@ -11,7 +11,7 @@
<div class="flex gap-2 px-2">
{% for entry in widget_entries %}
{% set _post_slug = slug_map.get(post_id, '') %}
{% set _entry_path = '/' + _post_slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
{% set _entry_path = '/' + _post_slug + '/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="flex flex-col gap-1 px-3 py-2 bg-stone-50 hover:bg-stone-100 rounded border border-stone-200 transition text-sm whitespace-nowrap flex-shrink-0 min-w-[180px]">