From 8ce642ba90b79f3cb51f593faa4e0c9f3f92c981 Mon Sep 17 00:00:00 2001 From: evilchili Date: Sun, 28 Sep 2025 14:14:16 -0700 Subject: [PATCH] WIP --- src/ttfrog/app.py | 22 ++++++++++-- src/ttfrog/cli.py | 2 ++ src/ttfrog/schema.py | 34 +++++++++++++----- src/ttfrog/themes/default/base.html | 5 +++ src/ttfrog/themes/default/page.html | 13 ++++++- src/ttfrog/web.py | 55 ++++++++++++++++++++++------- 6 files changed, 105 insertions(+), 26 deletions(-) diff --git a/src/ttfrog/app.py b/src/ttfrog/app.py index b584c44..de533c4 100644 --- a/src/ttfrog/app.py +++ b/src/ttfrog/app.py @@ -86,12 +86,20 @@ THEME=default if self.config.IN_MEMORY_DB: self.db = GrungDB.with_schema(schema, storage=MemoryStorage) else: - self.db = GrungDB.with_schema(schema, self.path.database) + self.db = GrungDB.with_schema( + schema, + self.path.database, + sort_keys=True, + indent=4, + separators=(',', ': ') + ) - self.theme = Path(__file__).parent / 'themes' / "default" + self.theme = Path(__file__).parent / "themes" / "default" self.web = Flask(self.config.NAME, template_folder=self.theme) self.web.config["SECRET_KEY"] = self.config.SECRET_KEY + self.web.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 + self.web.config["DEBUG"] = True self._initialized = True @@ -105,9 +113,17 @@ THEME=default """ self.check_state() try: - self.db.save(schema.Page(parent_id=None, stub="", title="_", body="")) + about = self.db.save(schema.Page(title="About", body="About!")) except UniqueConstraintError: pass + + try: + home = self.db.save(schema.Page(title="Home", body="This is the home page", pages=[about])) + about.parent = home + self.db.ssave(home) + except UniqueConstraintError: + pass + try: admin = self.db.save(schema.User(name=self.config.ADMIN_USERNAME, email=self.config.ADMIN_EMAIL)) except UniqueConstraintError: diff --git a/src/ttfrog/cli.py b/src/ttfrog/cli.py index 9488851..86e7ec3 100644 --- a/src/ttfrog/cli.py +++ b/src/ttfrog/cli.py @@ -53,6 +53,7 @@ def init(context: typer.Context, drop: bool = typer.Option(False, help="Drop tab ttfrog.app.db.close() ttfrog.app.initialize(force=True) ttfrog.app.bootstrap() + print(ttfrog.app.db.Page.all()) print(ttfrog.app.db) @@ -62,6 +63,7 @@ def run(context: typer.Context): The default CLI entrypoint is ttfrog.cli.run(). """ import ttfrog.web + ttfrog.app.web.run() diff --git a/src/ttfrog/schema.py b/src/ttfrog/schema.py index 3fe4966..8127142 100644 --- a/src/ttfrog/schema.py +++ b/src/ttfrog/schema.py @@ -1,18 +1,34 @@ -from grung.types import Collection, Field, Record +from grung.types import Collection, Field, Record, Pointer class User(Record): - _fields = [Field("name"), Field("email", unique=True)] + @classmethod + def fields(cls): + return [*super().fields(), Field("name"), Field("email", unique=True)] class Group(Record): - _fields = [Field("name", unique=True), Collection("users", User)] + @classmethod + def fields(cls): + return [*super().fields(), Field("name", unique=True), Collection("users", User)] class Page(Record): - _fields = [ - Field("parent_id"), - Field("stub"), - Field("title"), - Field("body"), - ] + @classmethod + def fields(cls): + return [ + *super().fields(), + Field("stub", unique=True), + Field("title"), + Field("body"), + Pointer("parent", value_type=Page), + Collection("pages", Page), + ] + + def before_insert(self): + if not self.stub and not self.title: + raise Exception("Must provide either a stub or a title!") + if not self.stub: + self.stub = self.title.title().replace(" ", "") + if not self.title: + self.title = self.stub.title() diff --git a/src/ttfrog/themes/default/base.html b/src/ttfrog/themes/default/base.html index 73492ce..32519a8 100644 --- a/src/ttfrog/themes/default/base.html +++ b/src/ttfrog/themes/default/base.html @@ -16,6 +16,11 @@
  • Home
  • +
    {% for message in get_flashed_messages() %} diff --git a/src/ttfrog/themes/default/page.html b/src/ttfrog/themes/default/page.html index 33c4c5d..244e0ea 100644 --- a/src/ttfrog/themes/default/page.html +++ b/src/ttfrog/themes/default/page.html @@ -1,6 +1,17 @@ {% extends "base.html" %} +{% block menu %} + {% for child in page.pages %} +
  • {{ child.title }}
  • + {% endfor %} +{% endblock %} {% block content %}

    {{ page.title }}

    - {{ page.content }} + {{ page.body }} + +
    +    {{ page }}
    +    
    + {% endblock %} + diff --git a/src/ttfrog/web.py b/src/ttfrog/web.py index f6cadfe..9d6e914 100644 --- a/src/ttfrog/web.py +++ b/src/ttfrog/web.py @@ -1,22 +1,51 @@ -from ttfrog import app from flask import Response, render_template from tinydb import where -import logging + +from ttfrog import app -logger = logging.getLogger(__name__) +def get_page(stub): + """ + Get one page, including its subpages, but not recursively. + """ + app.web.logger.debug(f"Looking for page with {stub = }") + matches = app.db.Page.search(where("stub") == stub, recurse=False) + if not matches: + return + 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] @app.web.route("/") def index(): - page = app.db.Page.search(where('stub') == "") - return render_template("page.html", page=page[0]) - - -@app.web.route("/") -def page_view(stub): - page = app.db.Page.search(where('stub') == stub) + page = get_page("Home") if not page: - logger.info(f"No page found for {stub = }") - return Response(f"{stub}: not found", status=404) - return render_template("page.html", page=page[0]) + return Response("Home page not found", status=404) + return render_template("page.html", page=page) + + +@app.web.route("/view/") +def page_view(path): + path = path.rstrip("/") + stub = path.split("/")[-1] + page = get_page(stub) + app.web.logger.debug(f"page_view: {path =} {stub =} {page =}") + if not page: + return Response(f"{stub} ({path}) not found", status=404) + return render_template( + "page.html", + page=page, + meta={ + 'uri': path, + } + ) + + +@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