From 2c2c94c2eb5df33a1598616a51cc6bb04472b7e3 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 6 Dec 2024 22:47:11 -0600 Subject: [PATCH] Some fixes and updates - Fix some relationships in the models - Set up theming system based on user setting - Use the "/node" endpoint for nodes, rather than "/" which will become problematic. --- src/scribeengine/db/models/node.py | 7 ++++++- src/scribeengine/templating.py | 25 ++++++++++++++++++++----- src/scribeengine/views/nodes.py | 28 +++++++++++++--------------- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/scribeengine/db/models/node.py b/src/scribeengine/db/models/node.py index 6b89381..77b348c 100644 --- a/src/scribeengine/db/models/node.py +++ b/src/scribeengine/db/models/node.py @@ -25,6 +25,8 @@ class NodeType(Model): slug: Mapped[str] = mapped_column(String(255), nullable=False, index=True) description: Mapped[str] = mapped_column(Text) + fields: Mapped[list['NodeField']] = relationship(back_populates='node_type') + class NodeRevision(Model): """A revision of a content node""" @@ -34,6 +36,7 @@ class NodeRevision(Model): node_id: Mapped[int] = mapped_column(Integer, ForeignKey('nodes.id')) revision: Mapped[int] = mapped_column(Integer, default=1) + node: Mapped['Node'] = relationship(back_populates='revisions') fields: Mapped[list['NodeFieldInstance']] = relationship(secondary=revisions_fields_table, back_populates='node_revision') @@ -73,7 +76,7 @@ class NodeField(Model): slug: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True) field_type: Mapped[str] = mapped_column(String(255)) - node_type: Mapped['NodeType'] = relationship(back_populates='node_fields') + node_type: Mapped['NodeType'] = relationship(back_populates='fields') class NodeFieldInstance(Model): @@ -82,6 +85,8 @@ class NodeFieldInstance(Model): id: Mapped[int] = mapped_column(Integer, primary_key=True) node_field_id: Mapped[int] = mapped_column(Integer, ForeignKey('node_fields.id')) + revision_id: Mapped[int] = mapped_column(Integer, ForeignKey('node_revisions.id')) value: Mapped[str] = mapped_column(Text) node_field: Mapped['NodeField'] = relationship() + node_revision: Mapped['NodeRevision'] = relationship(back_populates='fields') diff --git a/src/scribeengine/templating.py b/src/scribeengine/templating.py index b3fde1e..a9e111c 100644 --- a/src/scribeengine/templating.py +++ b/src/scribeengine/templating.py @@ -1,5 +1,13 @@ +from flask_theme import get_theme, render_theme_template, template_exists from quart import Quart, current_app, request -from flask_theme import get_theme, render_theme_template +from sqlalchemy.query import select + +from scribeengine.db.base import Session +from scribeengine.db.models.settings import SettingValue + + +class TemplateNotExistsError(Exception): + pass def register_globals(app: Quart) -> None: @@ -13,11 +21,18 @@ def register_globals(app: Quart) -> None: def get_current_theme(): """Get the current theme""" - ident = current_app.config.get('DEFAULT_THEME', 'quill') - return get_theme(ident) + default_theme = current_app.config.get('DEFAULT_THEME', 'quill') + with Session as session: + theme_setting = session.scalars(select(SettingValue).where(SettingValue.key.slug == 'theme')).first() + if theme_setting: + return get_theme(theme_setting.get_value()) + return get_theme(default_theme) -def render(template, **context): +def render(templates: list[str], **context): """Render the template using the current theme""" theme = get_current_theme() - return render_theme_template(theme, template, **context) + for template in templates: + if template_exists(template): + return render_theme_template(theme, template, **context) + raise TemplateNotExistsError() diff --git a/src/scribeengine/views/nodes.py b/src/scribeengine/views/nodes.py index 13462bd..f9514da 100644 --- a/src/scribeengine/views/nodes.py +++ b/src/scribeengine/views/nodes.py @@ -1,13 +1,14 @@ from typing import Union -from quart import Blueprint, render_template, request, abort +from quart import Blueprint, request, abort from sqlalchemy.sql import select from scribeengine.db.base import Session from scribeengine.db.models.node import Node from scribeengine.util.nodes import get_node, get_node_templates +from scribeengine.templating import render -nodes = Blueprint('nodes', __name__, url_prefix='/') +nodes = Blueprint('nodes', __name__, url_prefix='/node') def _get_node_list(*filters) -> tuple[int, int, list[Node]]: @@ -24,27 +25,24 @@ def _get_node_list(*filters) -> tuple[int, int, list[Node]]: @nodes.route('', methods=['GET']) -async def list_nodes(): - """List all the nodes""" - page, page_size, node_list = _get_node_list() - all_nodes = [get_node(node) for node in node_list] - return await render_template('admin/nodes/list_nodes.html', nodes=all_nodes, page=page, page_size=page_size) - - @nodes.route('/', methods=['GET']) -async def list_nodes_by_type(node_type: str): +async def list_nodes(node_type: str | None = None): """List all the nodes""" - page, page_size, node_list = _get_node_list(Node.node_type.slug == node_type) + if node_type: + page, page_size, node_list = _get_node_list(Node.node_Type.slug == node_type) + else: + page, page_size, node_list = _get_node_list() all_nodes = [get_node(node) for node in node_list] - node_templates = get_node_templates(node_type, 'list') - return await render_template(node_templates, nodes=all_nodes, page=page, page_size=page_size) + node_templates = get_node_templates('node', 'list') + node_templates.insert(0, 'front_page.html') + return await render('nodes/list_nodes.html', nodes=all_nodes, page=page, page_size=page_size) -@nodes.route('', methods=['GET']) +@nodes.route('/by-slug/', methods=['GET']) async def view_node(slug_or_id: Union[str, int]): """View a single node""" node = get_node(slug_or_id) if not node: return await abort(404) node_templates = get_node_templates(node['node_type'], 'view') - return await render_template(node_templates, node=node) + return await render(node_templates, node=node)