Enhance node rendering, add template selection logic, add menu items to models and helpers.

This commit is contained in:
Raoul Snyman 2021-06-11 14:31:14 -07:00
parent a966f018f7
commit 2e853e4c5c
6 changed files with 217 additions and 123 deletions

View File

@ -1,23 +1,23 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# ScribeEngine - Open Source Blog Software #
# ScribeEngine - Open Source Content Management System #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2017 Raoul Snyman #
# Copyright (c) 2010-2021 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# This file is part of ScribeEngine. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ScribeEngine is free software: you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# ScribeEngine is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# with ScribeEngine. If not, see <https://www.gnu.org/licenses/>. #
###############################################################################
"""
The :mod:`~scribeengine` module sets up and runs ScribeEngine
@ -34,7 +34,7 @@ from scribeengine.config import read_config_from_file
from scribeengine.db import db
from scribeengine.models import User
from scribeengine.views.account import account
from scribeengine.views.blog import blog
from scribeengine.views.node import node_views
def _scribeengine_themes_loader(app):
@ -69,7 +69,7 @@ def create_app(config_file=None):
UserManager(application, db, User)
# Register all the blueprints
application.register_blueprint(admin)
application.register_blueprint(blog)
application.register_blueprint(node_views)
application.register_blueprint(account)
# Return the application object
return application

View File

@ -1,23 +1,23 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# ScribeEngine - Open Source Blog Software #
# ScribeEngine - Open Source Content Management System #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2017 Raoul Snyman #
# Copyright (c) 2010-2021 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# This file is part of ScribeEngine. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ScribeEngine is free software: you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# ScribeEngine is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# with ScribeEngine. If not, see <https://www.gnu.org/licenses/>. #
###############################################################################
"""
The :mod:`~scribeengine.db` module sets up SQLAlchemy
@ -27,7 +27,7 @@ from flask_sqlalchemy import SQLAlchemy
# Get the db object
db = SQLAlchemy()
# Extract the classes to make them prettier
# Extract the objects to make them prettier
Model = db.Model
Table = db.Table
Column = db.Column
@ -39,4 +39,5 @@ Boolean = db.Boolean
DateTime = db.DateTime
relationship = db.relationship
backref = db.backref
inspect = db.inspect
session = db.session

View File

@ -1,40 +1,76 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# ScribeEngine - Open Source Blog Software #
# ScribeEngine - Open Source Content Management System #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2017 Raoul Snyman #
# Copyright (c) 2010-2021 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# This file is part of ScribeEngine. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ScribeEngine is free software: you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# ScribeEngine is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# with ScribeEngine. If not, see <https://www.gnu.org/licenses/>. #
###############################################################################
"""
The :mod:`~scribeengine.helpers` module contains some theme helper methods
"""
from flask import current_app
from flask_themes2 import get_theme, render_theme_template
from flask_themes2 import get_theme, render_theme_template, template_exists as ft2_template_exists
from jinja2.loaders import TemplateNotFound, contextfunction
from scribeengine.models import Site
from scribeengine.models import Menu, Site, Variable
@contextfunction
def template_exists(context, template_name):
"""
Add the template_exists() method into the template context
"""
return ft2_template_exists(template_name)
def get_variable(name, default_value=None):
def _type_cast(type_, value, default_value):
try:
return type_(var.value)
except (TypeError, ValueError):
return default_value
var = Variable.get(name)
if var:
if var.type.lower().startswith('int'):
return _type_cast(int, var.value, default_value)
elif var.type.lower().startswith('float'):
return _type_cast(float, var.value, default_value)
elif var.type.lower().startswith('bool'):
return var.value.lower().strip() in ['yes', 'y', '1', 'true', 't']
return var.value
else:
return default_value
def get_site_details():
"""
Returns an object with the details of the site
"""
return Site(current_app.config.get('SITE_NAME', 'Example Blog'),
current_app.config.get('SITE_SLOGAN', 'From the Firehose'),
current_app.config.get('SITE_ABOUT', ''))
return Site(get_variable('site-name', 'Example Site'),
get_variable('site-slogan', 'From the Firehose'),
get_variable('site-about', ''))
def get_navigation(block='primary'):
"""
Get the navigation
"""
return Menu.query.filter(Menu.block == block).first()
def get_current_theme():
@ -49,10 +85,36 @@ def render(template, **context):
"""
Render a template, after selecting a theme
"""
context.update({'site': get_site_details(), 'archives': []})
context.update({'site': get_site_details(), 'navigation': get_navigation()})
return render_theme_template(get_current_theme(), template, **context)
def render_node(node):
"""
Render a template, after selecting a theme
"""
context = {'node': node.complete}
template_names = ['/node-{}.html'.format(node.type), '/node.html']
for template in template_names:
if ft2_template_exists(template):
return render(template, **context)
raise TemplateNotFound('Could not find a node template')
def render_node_list(nodes):
"""
Render a list of nodes
"""
context = {'nodes': [node.complete for node in nodes]}
template_names = ['/node-list.html']
if nodes:
template_names.insert(0, '/node-{}-list.html'.format(nodes[0].type))
for template in template_names:
if ft2_template_exists(template):
return render(template, **context)
raise TemplateNotFound('Could not find a node-list template')
def render_admin(template, **context):
"""
Render a template, after selecting a theme

View File

@ -1,23 +1,23 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# ScribeEngine - Open Source Blog Software #
# ScribeEngine - Open Source Content Management System #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2017 Raoul Snyman #
# Copyright (c) 2010-2021 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# This file is part of ScribeEngine. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ScribeEngine is free software: you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# ScribeEngine is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# with ScribeEngine. If not, see <https://www.gnu.org/licenses/>. #
###############################################################################
"""
The :mod:`~scribeengine.models` module contains all the database models
@ -28,7 +28,7 @@ from box import Box
from flask_user import UserMixin
from scribeengine.db import Model, Table, Column, ForeignKey, String, Text, Integer, Boolean, DateTime, \
relationship
backref, inspect, relationship
permissions_roles = Table(
@ -52,7 +52,15 @@ roles_users = Table(
)
class Taxonomy(Model):
class DictMixin(object):
"""
A mixin class to add a "to_dict" method to each model
"""
def to_dict(self):
return Box({c.key: getattr(self, c.key) for c in inspect(self).mapper.column_attrs})
class Taxonomy(Model, DictMixin):
"""
This is a grouping of related terms, like a tags or categories
"""
@ -67,7 +75,7 @@ class Taxonomy(Model):
return self.name
class Node(Model):
class Node(Model, DictMixin):
"""
Nodes are the basic content type
"""
@ -85,27 +93,18 @@ class Node(Model):
@property
def complete(self):
"""Return a "full" or "complete" node, with all fields and data"""
node_dict = Box({
'id': self.id,
'slug': self.slug,
'type': self.type,
'created': self.created,
'modified': self.modified,
'title': self.current_revision.title,
'body': self.current_revision.body,
'format': self.current_revision.format
})
node_dict = self.to_dict()
for field in self.fields:
node_dict[field.name] = {
node_dict[field.name] = Box({
'name': field.name,
'type': field.type,
'title': field.field.title,
'data': field.data
}
})
return node_dict
class Field(Model):
class Field(Model, DictMixin):
"""
A field is a model for field types on nodes
"""
@ -120,7 +119,7 @@ class Field(Model):
modified = Column(DateTime, nullable=False, default=datetime.utcnow)
class FieldRevision(Model):
class FieldRevision(Model, DictMixin):
"""
A revision of a field on a node
"""
@ -136,7 +135,7 @@ class FieldRevision(Model):
node_id = Column(Integer, ForeignKey('nodes.id'), nullable=False)
class NodeField(Model):
class NodeField(Model, DictMixin):
"""
A node field is a field on a particular node
"""
@ -155,7 +154,7 @@ class NodeField(Model):
field = relationship('Field', backref='node_field')
class File(Model):
class File(Model, DictMixin):
"""
A file in the media library.
"""
@ -173,7 +172,7 @@ class File(Model):
return self.filename
class MediaType(Model):
class MediaType(Model, DictMixin):
"""
Distinguishes between different types of media.
"""
@ -188,7 +187,7 @@ class MediaType(Model):
return self.title
class Permission(Model):
class Permission(Model, DictMixin):
"""
A single permission.
"""
@ -202,7 +201,7 @@ class Permission(Model):
return self.name
class Role(Model):
class Role(Model, DictMixin):
"""
A role defines a set of permissions.
"""
@ -218,7 +217,7 @@ class Role(Model):
return self.name
class Term(Model):
class Term(Model, DictMixin):
"""
A term is an item in a taxonomy. A term can be a category name, or a tag in a blog post.
"""
@ -233,7 +232,7 @@ class Term(Model):
return self.name
class User(Model, UserMixin):
class User(Model, UserMixin, DictMixin):
"""
The user.
"""
@ -283,15 +282,15 @@ class User(Model, UserMixin):
return str(id(self))
class Variable(Model):
class Variable(Model, DictMixin):
"""
System variables.
"""
__tablename__ = 'variables'
key = Column(String(100), primary_key=True, index=True)
value = Column(String(100), nullable=False)
type = Column(String(10), default='string')
key = Column(String, primary_key=True, index=True)
value = Column(Text, nullable=False)
type = Column(String, default='string')
class Site(object):
@ -306,3 +305,33 @@ class Site(object):
self.name = name
self.slogan = slogan
self.about = about
class Menu(Model, DictMixin):
"""
A menu
"""
__tablename__ = 'menus'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
description = Column(Text)
block = Column(String)
items = relationship('MenuItem', backref='menu')
class MenuItem(Model, DictMixin):
"""
A menu item
"""
__tablename__ = 'menu_items'
id = Column(Integer, primary_key=True)
title = Column(String, nullable=False)
url = Column(String, nullable=False)
weight = Column(Integer, default=0)
menu_id = Column(Integer, ForeignKey('menus.id'))
parent_id = Column(Integer, ForeignKey('menu_items.id'))
items = relationship('MenuItem', backref=backref('parent', remote_side=[id]))

View File

@ -1,42 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# ScribeEngine - Open Source Blog Software #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2017 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~scribeengine.views.blog` module contains the blog post views
"""
from flask import Blueprint
from scribeengine.helpers import render
from scribeengine.models import Post
blog = Blueprint('blog', __name__, url_prefix='/')
@blog.route('', methods=['GET'])
def index():
posts = Post.query.limit(10).all()
return render('/blog.html', title='ScribeEngine', posts=posts)
@blog.route('/<int:year>/<int:month>', methods=['GET'])
def archive(year, month=None):
posts = Post.query.limit(10).all()
return render('/blog.html', title='ScribeEngine', posts=posts)

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
###############################################################################
# ScribeEngine - Open Source Content Management System #
# --------------------------------------------------------------------------- #
# Copyright (c) 2010-2021 Raoul Snyman #
# --------------------------------------------------------------------------- #
# This file is part of ScribeEngine. #
# #
# ScribeEngine is free software: you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation, either version 3 of the License, or (at your option) #
# any later version. #
# #
# ScribeEngine is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with ScribeEngine. If not, see <https://www.gnu.org/licenses/>. #
###############################################################################
"""
The :mod:`~scribeengine.views.node` module contains methods that actually render content nodes
"""
from flask import Blueprint
from scribeengine.helpers import render
from scribeengine.models import Node
node_views = Blueprint('node', __name__, url_prefix='/')
@node_views.route('', methods=['GET'])
def index():
nodes = Node.query.limit(10).all()
return render('/node-list.html', title='ScribeEngine', nodes=[n.complete for n in nodes])
@node_views.route('/node/<node_id>', methods=['GET'])
def view(node_id):
node = Node.get(node_id)
if not node:
return render('/404.html', title='ScribeEngine'), 404
return render('/blog.html', title='ScribeEngine', node=node.complete)