Move calendar management to /{slug}/admin/ and reserve slug

- Change calendars blueprint prefix from /calendars to /admin
- Simplify routes from /calendars/ to / within blueprint
- Reserve admin, markets, payments, entries as calendar slugs
- Update blog admin nav link to /{slug}/admin/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 16:31:24 +00:00
parent efae7f5533
commit 4fe5afe3e6
4 changed files with 9 additions and 7 deletions

View File

@@ -148,7 +148,7 @@ def _post_admin_nav_html(ctx: dict) -> str:
market_url_fn = ctx.get("market_url") market_url_fn = ctx.get("market_url")
if callable(events_url_fn): if callable(events_url_fn):
for url_fn, path, label in [ for url_fn, path, label in [
(events_url_fn, f"/{slug}/calendars/calendars/", "calendars"), (events_url_fn, f"/{slug}/admin/", "calendars"),
(market_url_fn, f"/{slug}/", "markets"), (market_url_fn, f"/{slug}/", "markets"),
(events_url_fn, f"/{slug}/payments/", "payments"), (events_url_fn, f"/{slug}/payments/", "payments"),
]: ]:

View File

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

View File

@@ -21,7 +21,7 @@ from shared.browser.app.utils.htmx import is_htmx_request
def register(): def register():
bp = Blueprint("calendars", __name__, url_prefix='/calendars') bp = Blueprint("calendars", __name__, url_prefix='/admin')
bp.register_blueprint( bp.register_blueprint(
register_calendar(), register_calendar(),
) )
@@ -32,7 +32,7 @@ def register():
# ---------- Pages ---------- # ---------- Pages ----------
@bp.get("/calendars/") @bp.get("/")
@cache_page(tag="calendars") @cache_page(tag="calendars")
async def home(**kwargs): async def home(**kwargs):
from shared.sexp.page import get_template_context from shared.sexp.page import get_template_context
@@ -46,7 +46,7 @@ def register():
return await make_response(html) return await make_response(html)
@bp.post("/calendars/new/") @bp.post("/new/")
@require_admin @require_admin
@clear_cache(tag="calendars", tag_scope="all") @clear_cache(tag="calendars", tag_scope="all")
async def create_calendar(**kwargs): async def create_calendar(**kwargs):

View File

@@ -86,7 +86,9 @@ async def create_calendar(sess: AsyncSession, post_id: int, name: str) -> Calend
name = (name or "").strip() name = (name or "").strip()
if not name: if not name:
raise CalendarError("Calendar name must not be empty.") raise CalendarError("Calendar name must not be empty.")
slug=slugify(name) slug = slugify(name)
if slug in ("admin", "markets", "payments", "entries"):
raise CalendarError(f'"{slug}" is a reserved name and cannot be used as a calendar name.')
# Ensure post exists (avoid silent FK errors in some DBs) # Ensure post exists (avoid silent FK errors in some DBs)
raw = await fetch_data("blog", "post-by-id", params={"id": post_id}, required=False) raw = await fetch_data("blog", "post-by-id", params={"id": post_id}, required=False)