Jul 28 - Update the demo request button, and add demo registration page

This commit is contained in:
2026-07-28 14:18:22 -04:00
parent 6b904aead9
commit ea9458395d
17 changed files with 905 additions and 13 deletions
+81 -2
View File
@@ -11,7 +11,10 @@ from flask import (
)
from werkzeug.security import check_password_hash
from app import db, log_action, sanitize_html, AuditLog, Section, Topic
from app import (
db, log_action, sanitize_html, AuditLog, DemoRequest, DEMO_STATUSES,
Section, Topic,
)
admin_bp = Blueprint("admin", __name__, url_prefix="/admin")
@@ -40,6 +43,19 @@ def _sniff_image(head):
return None
@admin_bp.context_processor
def inject_pending_demos():
"""Badge count on the nav. Only queried for a signed-in admin, so the login
page never touches the database."""
if not session.get("admin"):
return {"pending_demos": 0}
try:
return {"pending_demos": DemoRequest.query.filter(
DemoRequest.status == "new").count()}
except Exception: # noqa: BLE001 - a missing table must not 500 the panel
return {"pending_demos": 0}
# ------------------------------------------------------------------ auth
def login_required(view):
@wraps(view)
@@ -130,6 +146,69 @@ def dashboard():
return render_template("admin/dashboard.html", sections=sections)
# ------------------------------------------------------------------ demo requests
@admin_bp.route("/demos")
@login_required
def demos():
"""Appointment requests from the public /demo form, soonest first."""
page = _int(request.args.get("page"), 1)
if page < 1:
page = 1
status = request.args.get("status", "")
q = DemoRequest.query
if status in DEMO_STATUSES:
q = q.filter(DemoRequest.status == status)
elif status == "":
# Default view hides what's already dealt with.
q = q.filter(DemoRequest.status.in_(("new", "scheduled")))
pagination = (
q.order_by(DemoRequest.preferred_date.asc(),
DemoRequest.preferred_time.asc(), DemoRequest.id.asc())
.paginate(page=page, per_page=50, error_out=False)
)
new_count = DemoRequest.query.filter(DemoRequest.status == "new").count()
return render_template(
"admin/demos.html",
pagination=pagination,
requests=pagination.items,
status=status,
statuses=DEMO_STATUSES,
new_count=new_count,
)
@admin_bp.route("/demo/<int:req_id>/status", methods=["POST"])
@login_required
def demo_status(req_id):
req = DemoRequest.query.get_or_404(req_id)
new_status = request.form.get("status", "")
if new_status not in DEMO_STATUSES:
abort(400)
req.status = new_status
db.session.commit()
log_action(session.get("admin"), "update", "demo", req.id,
f"{new_status}: {req.name} · {req.when}")
flash(f"Request from {req.name} marked {new_status}.", "ok")
# Come back to the same filtered view (never trust Referer for a redirect).
back = request.form.get("back_status", "")
return redirect(url_for("admin.demos",
status=back if back in DEMO_STATUSES else ""))
@admin_bp.route("/demo/<int:req_id>/delete", methods=["POST"])
@login_required
def demo_delete(req_id):
req = DemoRequest.query.get_or_404(req_id)
name, rid, when = req.name, req.id, req.when
db.session.delete(req)
db.session.commit()
log_action(session.get("admin"), "delete", "demo", rid, f"{name} · {when}")
flash(f"Request from {name} deleted.", "ok")
return redirect(url_for("admin.demos"))
# ------------------------------------------------------------------ audit log
@admin_bp.route("/audit")
@login_required
@@ -143,7 +222,7 @@ def audit():
q = AuditLog.query
if action in ("create", "update", "delete"):
q = q.filter(AuditLog.action == action)
if entity in ("section", "topic"):
if entity in ("section", "topic", "demo"):
q = q.filter(AuditLog.entity == entity)
pagination = (