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:
@@ -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(
|
||||
|
||||
@@ -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}}"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}}">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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/...
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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")'
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}}">
|
||||
|
||||
@@ -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]">
|
||||
|
||||
Reference in New Issue
Block a user