This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blog/bp/snippets/routes.py
giles a01016d8d5 feat: decouple blog from shared_lib, add app-owned models
Phase 1-3 of decoupling:
- path_setup.py adds project root to sys.path
- Blog-owned models in blog/models/ (ghost_content, snippet, tag_group)
- Re-export shims for shared models (user, kv, magic_link, menu_item)
- All imports updated: shared.infrastructure, shared.db, shared.browser, etc.
- No more cross-app post_id FKs in calendar/market/page_config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:46:31 +00:00

108 lines
3.1 KiB
Python

from __future__ import annotations
from quart import Blueprint, render_template, make_response, request, g, abort
from sqlalchemy import select, or_
from sqlalchemy.orm import selectinload
from shared.browser.app.authz import require_login
from shared.browser.app.utils.htmx import is_htmx_request
from models import Snippet
VALID_VISIBILITY = frozenset({"private", "shared", "admin"})
async def _visible_snippets(session):
"""Return snippets visible to the current user (own + shared + admin-if-admin)."""
uid = g.user.id
is_admin = g.rights.get("admin")
filters = [Snippet.user_id == uid, Snippet.visibility == "shared"]
if is_admin:
filters.append(Snippet.visibility == "admin")
rows = (await session.execute(
select(Snippet).where(or_(*filters)).order_by(Snippet.name)
)).scalars().all()
return rows
def register():
bp = Blueprint("snippets", __name__, url_prefix="/settings/snippets")
@bp.get("/")
@require_login
async def list_snippets():
"""List snippets visible to the current user."""
snippets = await _visible_snippets(g.s)
is_admin = g.rights.get("admin")
if not is_htmx_request():
html = await render_template(
"_types/snippets/index.html",
snippets=snippets,
is_admin=is_admin,
)
else:
html = await render_template(
"_types/snippets/_oob_elements.html",
snippets=snippets,
is_admin=is_admin,
)
return await make_response(html)
@bp.delete("/<int:snippet_id>/")
@require_login
async def delete_snippet(snippet_id: int):
"""Delete a snippet. Owners delete their own; admins can delete any."""
snippet = await g.s.get(Snippet, snippet_id)
if not snippet:
abort(404)
is_admin = g.rights.get("admin")
if snippet.user_id != g.user.id and not is_admin:
abort(403)
await g.s.delete(snippet)
await g.s.flush()
snippets = await _visible_snippets(g.s)
html = await render_template(
"_types/snippets/_list.html",
snippets=snippets,
is_admin=is_admin,
)
return await make_response(html)
@bp.patch("/<int:snippet_id>/visibility/")
@require_login
async def patch_visibility(snippet_id: int):
"""Change snippet visibility. Admin only."""
if not g.rights.get("admin"):
abort(403)
snippet = await g.s.get(Snippet, snippet_id)
if not snippet:
abort(404)
form = await request.form
visibility = form.get("visibility", "").strip()
if visibility not in VALID_VISIBILITY:
abort(400)
snippet.visibility = visibility
await g.s.flush()
snippets = await _visible_snippets(g.s)
html = await render_template(
"_types/snippets/_list.html",
snippets=snippets,
is_admin=True,
)
return await make_response(html)
return bp