This commit is contained in:
evilchili 2025-09-28 14:14:16 -07:00
parent 0ce3845a13
commit 8ce642ba90
6 changed files with 105 additions and 26 deletions

View File

@ -86,12 +86,20 @@ THEME=default
if self.config.IN_MEMORY_DB: if self.config.IN_MEMORY_DB:
self.db = GrungDB.with_schema(schema, storage=MemoryStorage) self.db = GrungDB.with_schema(schema, storage=MemoryStorage)
else: 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 = Flask(self.config.NAME, template_folder=self.theme)
self.web.config["SECRET_KEY"] = self.config.SECRET_KEY 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 self._initialized = True
@ -105,9 +113,17 @@ THEME=default
""" """
self.check_state() self.check_state()
try: try:
self.db.save(schema.Page(parent_id=None, stub="", title="_", body="")) about = self.db.save(schema.Page(title="About", body="About!"))
except UniqueConstraintError: except UniqueConstraintError:
pass 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: try:
admin = self.db.save(schema.User(name=self.config.ADMIN_USERNAME, email=self.config.ADMIN_EMAIL)) admin = self.db.save(schema.User(name=self.config.ADMIN_USERNAME, email=self.config.ADMIN_EMAIL))
except UniqueConstraintError: except UniqueConstraintError:

View File

@ -53,6 +53,7 @@ def init(context: typer.Context, drop: bool = typer.Option(False, help="Drop tab
ttfrog.app.db.close() ttfrog.app.db.close()
ttfrog.app.initialize(force=True) ttfrog.app.initialize(force=True)
ttfrog.app.bootstrap() ttfrog.app.bootstrap()
print(ttfrog.app.db.Page.all())
print(ttfrog.app.db) print(ttfrog.app.db)
@ -62,6 +63,7 @@ def run(context: typer.Context):
The default CLI entrypoint is ttfrog.cli.run(). The default CLI entrypoint is ttfrog.cli.run().
""" """
import ttfrog.web import ttfrog.web
ttfrog.app.web.run() ttfrog.app.web.run()

View File

@ -1,18 +1,34 @@
from grung.types import Collection, Field, Record from grung.types import Collection, Field, Record, Pointer
class User(Record): 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): 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): class Page(Record):
_fields = [ @classmethod
Field("parent_id"), def fields(cls):
Field("stub"), return [
Field("title"), *super().fields(),
Field("body"), 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()

View File

@ -16,6 +16,11 @@
<li><a href="{{ url_for('index') }}">Home</a></li> <li><a href="{{ url_for('index') }}">Home</a></li>
</ul> </ul>
</nav> </nav>
<nav>
<ul>
{% block menu %}{% endblock %}
</ul>
</nav>
<main> <main>
{% for message in get_flashed_messages() %} {% for message in get_flashed_messages() %}

View File

@ -1,6 +1,17 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block menu %}
{% for child in page.pages %}
<li><a href="/{{page.stub}}/{{ child.stub }}">{{ child.title }}</a></li>
{% endfor %}
{% endblock %}
{% block content %} {% block content %}
<h1>{{ page.title }}</h1> <h1>{{ page.title }}</h1>
{{ page.content }} {{ page.body }}
<pre>
{{ page }}
</pre>
{% endblock %} {% endblock %}

View File

@ -1,22 +1,51 @@
from ttfrog import app
from flask import Response, render_template from flask import Response, render_template
from tinydb import where 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("/") @app.web.route("/")
def index(): def index():
page = app.db.Page.search(where('stub') == "") page = get_page("Home")
return render_template("page.html", page=page[0])
@app.web.route("/<stub>")
def page_view(stub):
page = app.db.Page.search(where('stub') == stub)
if not page: if not page:
logger.info(f"No page found for {stub = }") return Response("Home page not found", status=404)
return Response(f"{stub}: not found", status=404) return render_template("page.html", page=page)
return render_template("page.html", page=page[0])
@app.web.route("/view/<path:path>")
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