vtt/src/ttfrog/web.py

119 lines
3.6 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
2025-10-04 01:26:09 -07:00
from ttfrog import app, schema, forms
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 "/"
2025-10-04 01:26:09 -07:00
def get_parent(table: str, uri: str):
try:
parent_uri = uri.strip("/").rsplit("/", 1)[0]
except IndexError:
return None
2025-10-04 01:26:09 -07:00
return get_page(parent_uri, table=table if '/' in parent_uri else 'Page', create_okay=False)
2025-10-04 01:26:09 -07:00
def get_page(path: str = "", table: str = "Page", create_okay: bool = False):
2025-09-28 14:14:16 -07:00
"""
2025-10-04 01:26:09 -07:00
Get one page, including its members, but not recursively.
2025-09-28 14:14:16 -07:00
"""
2025-10-04 01:26:09 -07:00
uri = path.strip("/") or relative_uri(request.path)
app.web.logger.debug(f"Need a page in {table} for {uri = }")
if table not in app.db.tables():
return None
matches = app.db.table(table).search(where("uri") == uri, recurse=False)
2025-09-28 14:14:16 -07:00
if not matches:
if not create_okay:
return None
2025-10-04 01:26:09 -07:00
return getattr(schema, table)(
name=uri.split("/")[-1],
body="This page does not exist",
parent=get_parent(table, uri)
)
page = matches[0]
if hasattr(page, 'members'):
subpages = []
for pointer in matches[0].members:
table, uid = pointer.split("::")
subpages += app.db.table(table).search(where("uid") == uid, recurse=False)
page.members = subpages
return page
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():
"""
2025-10-04 01:26:09 -07:00
Return (uri, name) pairs for the parents leading from the VIEW_URI to the current request.
"""
if app.config.VIEW_URI != "/":
root = get_page()
2025-10-04 01:26:09 -07:00
yield (app.config.VIEW_URI, root.name)
uri = ""
2025-10-04 01:26:09 -07:00
for name in relative_uri().split("/"):
uri = "/".join([uri, name]).lstrip("/")
yield (uri, name)
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
2025-10-04 01:26:09 -07:00
@app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["GET"])
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["GET"], defaults={'table': 'Page'})
def view(table, path):
parent = get_parent(table, relative_uri())
return rendered(get_page(request.path, table=table, create_okay=parent.doc_id is not None))
2025-10-04 01:26:09 -07:00
@app.web.route(f"{app.config.VIEW_URI}/<path:table>/<path:path>", methods=["POST"])
@app.web.route(f"{app.config.VIEW_URI}/<path:path>", methods=["POST"], defaults={'table': 'Page'})
def edit(table, path):
uri = relative_uri()
2025-10-04 01:26:09 -07:00
parent = get_parent(table, uri)
if not parent:
return Response("You cannot create a page at this location.", status=403)
2025-10-04 01:26:09 -07:00
# get or create the docoument at this uri
page = get_page(uri, table=table, create_okay=True)
save_data = getattr(forms, table)(page, request.form).prepare()
# editing existing document
if page.doc_id:
if page.uid != request.form["uid"]:
return Response("Invalid UID.", status=403)
2025-10-04 01:26:09 -07:00
return rendered(app.db.save(save_data))
2025-10-04 01:26:09 -07:00
# saving a new document
return rendered(app.add_member(parent, save_data))
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