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 suma_browser.app.authz import require_login from suma_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("//") @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("//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