Enhance node rendering, add template selection logic, add menu items to models and helpers.
This commit is contained in:
parent
a966f018f7
commit
2e853e4c5c
@ -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 #
|
||||
# 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
|
||||
|
@ -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 #
|
||||
# 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
|
||||
|
@ -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 #
|
||||
# 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
|
||||
|
@ -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 #
|
||||
# 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]))
|
||||
|
@ -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)
|
44
scribeengine/views/node.py
Normal file
44
scribeengine/views/node.py
Normal 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)
|
Reference in New Issue
Block a user