vtt/src/ttfrog/web.py

105 lines
3.2 KiB
Python
Raw Normal View History

from flask import Response, render_template, request
2025-09-27 16:20:08 -07:00
from tinydb import where
2025-09-28 14:14:16 -07:00
from ttfrog import app, schema
from ttfrog.forms import PageForm
2025-09-21 22:11:56 -07:00
STATIC = ["static"]
2025-09-21 22:11:56 -07:00
def relative_uri(path: str = ""):
"""
The request's URI relative to the VIEW_URI without the leading '/'.
"""
return (path or request.path).replace(app.config.VIEW_URI, "", 1).strip("/") or "/"
def get_parent(uri: str):
try:
parent_uri = uri.strip("/").split("/", -1)[0]
except IndexError:
return None
app.web.logger.debug(f"Looking for parent with {parent_uri = }")
return get_page(parent_uri or "/", create_okay=False)
def get_page(path: str = "", create_okay: bool = False):
2025-09-28 14:14:16 -07:00
"""
Get one page, including its subpages, but not recursively.
"""
uri = path or relative_uri(request.path)
matches = app.db.Page.search(where("uri") == uri, recurse=False)
app.web.logger.debug(f"Found {len(matches)} pages where {uri = }")
2025-09-28 14:14:16 -07:00
if not matches:
if not create_okay:
return None
return schema.Page(stub=uri.split("/")[-1], body="This page does not exist", parent=get_parent(uri))
2025-09-28 14:14:16 -07:00
uids = [pointer.split("::")[-1] for pointer in matches[0].pages]
subpages = app.db.Page.search(where("uid").one_of(uids), recurse=False)
matches[0].pages = subpages
return matches[0]
2025-09-21 22:11:56 -07:00
2025-09-27 16:20:08 -07:00
def rendered(page: schema.Record, template: str = "page.html"):
if not page:
return Response("Page not found", status=404)
return render_template(template, page=page, app=app, breadcrumbs=breadcrumbs())
def get_static(path):
return Response("OK", status=200)
def breadcrumbs():
"""
Return (uri, stub) pairs for the parents leading from the VIEW_URI to the current request.
"""
if app.config.VIEW_URI != "/":
root = get_page()
yield (app.config.VIEW_URI, root.stub)
uri = ""
for stub in relative_uri().split("/"):
uri = "/".join([uri, stub]).lstrip("/")
yield (uri, stub)
2025-09-27 16:20:08 -07:00
@app.web.route("/")
def index():
return rendered(get_page(create_okay=False))
2025-09-27 16:20:08 -07:00
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["GET"])
def view(path):
return rendered(get_page(request.path, create_okay=True))
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["POST"])
def edit(path):
uri = relative_uri()
parent = get_parent(uri)
app.web.logger.debug(f"Handling form submission: {uri = }, {parent = }, {request.form = }")
if not parent:
return Response(f"Parent for {uri} does not exist.", status=403)
page = get_page(uri, create_okay=True)
app.web.logger.debug(f"Editing {page.doc_id} for {uri = }")
if page.doc_id:
if page.uid != request.form["uid"]:
return Response("Invalid UID.", status=403)
form = PageForm(page, request.form)
page = app.db.save(form.prepare())
app.web.logger.debug(f"Saved {page.doc_id}; now updating parent {parent.doc_id}")
parent.pages.append(page)
app.db.save(parent)
return get_page(stub)
2025-09-28 14:14:16 -07:00
@app.web.after_request
def add_header(r):
r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, public, max-age=0"
r.headers["Pragma"] = "no-cache"
r.headers["Expires"] = "0"
return r