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