""" Admin routes for StarPunk Handles authenticated admin functionality including dashboard, note creation, editing, and deletion. All routes require authentication. """ from flask import Blueprint, flash, g, redirect, render_template, request, url_for from starpunk.auth import require_auth from starpunk.notes import ( create_note, delete_note, list_notes, get_note, update_note, ) # Create blueprint bp = Blueprint("admin", __name__, url_prefix="/admin") @bp.route("/") @require_auth def dashboard(): """ Admin dashboard with note list Displays all notes (published and drafts) with management controls. Requires authentication. Returns: Rendered dashboard template with complete note list Decorator: @require_auth Template: templates/admin/dashboard.html Access: g.user_me (set by require_auth decorator) """ # Get all notes (published and drafts) notes = list_notes() return render_template("admin/dashboard.html", notes=notes, user_me=g.me) @bp.route("/new", methods=["GET"]) @require_auth def new_note_form(): """ Display create note form Shows empty form for creating a new note. Requires authentication. Returns: Rendered new note form template Decorator: @require_auth Template: templates/admin/new.html """ return render_template("admin/new.html") @bp.route("/new", methods=["POST"]) @require_auth def create_note_submit(): """ Handle new note submission Creates a new note from submitted form data. Requires authentication. Form data: content: Markdown content (required) published: Checkbox for published status (optional) Returns: Redirect to dashboard on success, back to form on error Decorator: @require_auth """ content = request.form.get("content", "").strip() published = "published" in request.form if not content: flash("Content cannot be empty", "error") return redirect(url_for("admin.new_note_form")) try: note = create_note(content, published=published) flash(f"Note created: {note.slug}", "success") return redirect(url_for("admin.dashboard")) except ValueError as e: flash(f"Error creating note: {e}", "error") return redirect(url_for("admin.new_note_form")) except Exception as e: flash(f"Unexpected error creating note: {e}", "error") return redirect(url_for("admin.new_note_form")) @bp.route("/edit/", methods=["GET"]) @require_auth def edit_note_form(note_id: int): """ Display edit note form Shows form pre-filled with existing note content for editing. Requires authentication. Args: note_id: Database ID of note to edit Returns: Rendered edit form template or 404 if note not found Decorator: @require_auth Template: templates/admin/edit.html """ note = get_note(id=note_id) if not note: flash("Note not found", "error") return redirect(url_for("admin.dashboard")), 404 return render_template("admin/edit.html", note=note) @bp.route("/edit/", methods=["POST"]) @require_auth def update_note_submit(note_id: int): """ Handle note update submission Updates existing note with submitted form data. Requires authentication. Args: note_id: Database ID of note to update Form data: content: Updated markdown content (required) published: Checkbox for published status (optional) Returns: Redirect to dashboard on success, back to form on error Decorator: @require_auth """ # Check if note exists first existing_note = get_note(id=note_id, load_content=False) if not existing_note: flash("Note not found", "error") return redirect(url_for("admin.dashboard")), 404 content = request.form.get("content", "").strip() published = "published" in request.form if not content: flash("Content cannot be empty", "error") return redirect(url_for("admin.edit_note_form", note_id=note_id)) try: note = update_note(id=note_id, content=content, published=published) flash(f"Note updated: {note.slug}", "success") return redirect(url_for("admin.dashboard")) except ValueError as e: flash(f"Error updating note: {e}", "error") return redirect(url_for("admin.edit_note_form", note_id=note_id)) except Exception as e: flash(f"Unexpected error updating note: {e}", "error") return redirect(url_for("admin.edit_note_form", note_id=note_id)) @bp.route("/delete/", methods=["POST"]) @require_auth def delete_note_submit(note_id: int): """ Handle note deletion Deletes a note after confirmation. Requires authentication. Args: note_id: Database ID of note to delete Form data: confirm: Must be 'yes' to proceed with deletion Returns: Redirect to dashboard with success/error message Decorator: @require_auth """ # Check if note exists first (per ADR-012) existing_note = get_note(id=note_id, load_content=False) if not existing_note: flash("Note not found", "error") return redirect(url_for("admin.dashboard")), 404 # Check for confirmation if request.form.get("confirm") != "yes": flash("Deletion cancelled", "info") return redirect(url_for("admin.dashboard")) try: delete_note(id=note_id, soft=False) flash("Note deleted successfully", "success") except ValueError as e: flash(f"Error deleting note: {e}", "error") except Exception as e: flash(f"Unexpected error deleting note: {e}", "error") return redirect(url_for("admin.dashboard"))