Browse Source

Refactor modules into a plugin-based system

All modules are now plugins. The config.py calls load_plugin for each
plugin it needs (some plugins may load others automatically). Also each
plugin keeps its own template folder which gets added to the template
search path, so i.e. if the photo plugin is unloaded completely, the URL
endpoints won't work either (with the old system, since the HTML
templates still existed in the default root the endpoints would still
serve pages, just without any Python logic behind them).
pull/2/head
Noah Petherbridge 5 years ago
parent
commit
8a2d6a7c04
42 changed files with 98 additions and 29 deletions
  1. +19
    -0
      config-sample.py
  2. +1
    -1
      kirsle_legacy.py
  3. +43
    -28
      rophako/app.py
  4. +0
    -0
      rophako/modules/account/__init__.py
  5. +0
    -0
      rophako/modules/account/templates/account/login.html
  6. +0
    -0
      rophako/modules/account/templates/account/setup.html
  7. +0
    -0
      rophako/modules/admin/__init__.py
  8. +0
    -0
      rophako/modules/admin/templates/admin/edit_user.html
  9. +0
    -0
      rophako/modules/admin/templates/admin/index.html
  10. +0
    -0
      rophako/modules/admin/templates/admin/users.html
  11. +2
    -0
      rophako/modules/blog/__init__.py
  12. +0
    -0
      rophako/modules/blog/templates/blog/categories.inc.html
  13. +0
    -0
      rophako/modules/blog/templates/blog/delete.html
  14. +0
    -0
      rophako/modules/blog/templates/blog/entry.html
  15. +0
    -0
      rophako/modules/blog/templates/blog/entry.inc.html
  16. +0
    -0
      rophako/modules/blog/templates/blog/index.html
  17. +0
    -0
      rophako/modules/blog/templates/blog/index.inc.html
  18. +0
    -0
      rophako/modules/blog/templates/blog/nav-links.inc.html
  19. +0
    -0
      rophako/modules/blog/templates/blog/sibling-links.html
  20. +0
    -0
      rophako/modules/blog/templates/blog/update.html
  21. +2
    -0
      rophako/modules/comment/__init__.py
  22. +0
    -0
      rophako/modules/comment/templates/comment/form.inc.html
  23. +0
    -0
      rophako/modules/comment/templates/comment/index.inc.html
  24. +0
    -0
      rophako/modules/comment/templates/comment/preview.html
  25. +0
    -0
      rophako/modules/comment/templates/comment/privacy.html
  26. +0
    -0
      rophako/modules/comment/templates/comment/unsubscribed.html
  27. +0
    -0
      rophako/modules/contact/__init__.py
  28. +0
    -0
      rophako/modules/contact/templates/contact/index.html
  29. +0
    -0
      rophako/modules/emoticons/__init__.py
  30. +0
    -0
      rophako/modules/emoticons/templates/emoticons/index.html
  31. +2
    -0
      rophako/modules/photo/__init__.py
  32. +0
    -0
      rophako/modules/photo/templates/photos/album.html
  33. +0
    -0
      rophako/modules/photo/templates/photos/albums.html
  34. +0
    -0
      rophako/modules/photo/templates/photos/arrange_albums.html
  35. +0
    -0
      rophako/modules/photo/templates/photos/arrange_photos.html
  36. +0
    -0
      rophako/modules/photo/templates/photos/crop.html
  37. +0
    -0
      rophako/modules/photo/templates/photos/delete.html
  38. +0
    -0
      rophako/modules/photo/templates/photos/delete_album.html
  39. +0
    -0
      rophako/modules/photo/templates/photos/edit.html
  40. +0
    -0
      rophako/modules/photo/templates/photos/upload.html
  41. +0
    -0
      rophako/modules/photo/templates/photos/view.html
  42. +29
    -0
      rophako/plugin.py

+ 19
- 0
config-sample.py View File

@@ -5,6 +5,7 @@
import os
_basedir = os.path.abspath(os.path.dirname(__file__))
import datetime
from rophako.plugin import load_plugin

DEBUG = True

@@ -116,3 +117,21 @@ COMMENT_TIME_FORMAT = "%A, %B %d %Y @ %I:%M %p"
# We use Gravatar for comments if the user provides an e-mail address. Specify
# the URL to a fallback image to use in case they don't have a gravatar.
COMMENT_DEFAULT_AVATAR = ""

################################################################################
## Enabled Plugins ##
################################################################################

# Place all the load_plugin calls down here. Some of the plugins need to refer
# to config params above so those need to get declared before the plugin begins
# to initialize itself.
#
# Some plugins will automatically load others as dependencies, i.e. the blog
# and photo will load comment, and comment will load emoticons. But it doesn't
# hurt to list them all out here to be explicit anyway.

load_plugin("rophako.modules.blog")
load_plugin("rophako.modules.photo")
load_plugin("rophako.modules.comment")
load_plugin("rophako.modules.emoticons")
load_plugin("rophako.modules.contact")

rophako/modules/kirsle_legacy.py → kirsle_legacy.py View File

@@ -8,7 +8,7 @@ import os
import json

import config
from rophako import app
from rophako.app import app
from rophako.utils import template, login_required
import rophako.model.blog as Blog
import rophako.jsondb as JsonDB

+ 43
- 28
rophako/app.py View File

@@ -1,3 +1,7 @@
#!/usr/bin/env python

"""Flask app for Rophako."""

from flask import Flask, g, request, session, render_template, send_file, abort
from flask_sslify import SSLify
import jinja2
@@ -5,13 +9,25 @@ import os.path
import time
import sys

# Get the Flask app object ready right away so other modules can import it
# without getting a circular import error.
app = Flask(__name__,
static_url_path="/.static",
)

# We use a custom Jinja loader to support multiple template paths for custom
# and default templates. The base list of template paths to check includes
# your custom path (from config.SITE_ROOT), the "rophako/www" path for normal
# pages, and then the blueprint paths for all imported plugins. This list will
# be extended while blueprints are being loaded and passed in below to the
# jinja2.ChoiceLoader.
BLUEPRINT_PATHS = []

import config
from rophako import __version__
from rophako.plugin import load_plugin
import rophako.utils

app = Flask(__name__,
static_url_path="/.static",
)
app.DEBUG = config.DEBUG
app.secret_key = config.SECRET_KEY

@@ -20,28 +36,32 @@ if config.FORCE_SSL:
app.config['SESSION_COOKIE_SECURE'] = True
sslify = SSLify(app)

# Load all the blueprints!
from rophako.modules.admin import mod as AdminModule
from rophako.modules.account import mod as AccountModule
from rophako.modules.blog import mod as BlogModule
from rophako.modules.photo import mod as PhotoModule
from rophako.modules.comment import mod as CommentModule
from rophako.modules.emoticons import mod as EmoticonsModule
from rophako.modules.contact import mod as ContactModule
app.register_blueprint(AdminModule)
app.register_blueprint(AccountModule)
app.register_blueprint(BlogModule)
app.register_blueprint(PhotoModule)
app.register_blueprint(CommentModule)
app.register_blueprint(EmoticonsModule)
app.register_blueprint(ContactModule)
# Load all the built-in essential plugins.
load_plugin("rophako.modules.admin")
load_plugin("rophako.modules.account")
# from rophako.modules.admin import mod as AdminModule
# from rophako.modules.account import mod as AccountModule
# from rophako.modules.blog import mod as BlogModule
# from rophako.modules.photo import mod as PhotoModule
# from rophako.modules.comment import mod as CommentModule
# from rophako.modules.emoticons import mod as EmoticonsModule
# from rophako.modules.contact import mod as ContactModule
# app.register_blueprint(AdminModule)
# app.register_blueprint(AccountModule)
# app.register_blueprint(BlogModule)
# app.register_blueprint(PhotoModule)
# app.register_blueprint(CommentModule)
# app.register_blueprint(EmoticonsModule)
# app.register_blueprint(ContactModule)

# Custom Jinja handler to support custom- and default-template folders for
# rendering templates.
app.jinja_loader = jinja2.ChoiceLoader([
jinja2.FileSystemLoader(config.SITE_ROOT), # Site specific.
jinja2.FileSystemLoader("rophako/www"), # Default/fall-back
])
template_paths = [
config.SITE_ROOT, # Site specific.
"rophako/www", # Default/fall-back
]
template_paths.extend(BLUEPRINT_PATHS)
app.jinja_loader = jinja2.ChoiceLoader([ jinja2.FileSystemLoader(x) for x in template_paths])

app.jinja_env.globals["csrf_token"] = rophako.utils.generate_csrf_token
app.jinja_env.globals["include_page"] = rophako.utils.include
@@ -152,9 +172,4 @@ def not_found(error):

@app.errorhandler(403)
def forbidden(error):
return render_template('errors/403.html', **g.info), 403


# Domain specific endpoints.
if config.SITE_NAME == "kirsle.net":
import rophako.modules.kirsle_legacy
return render_template('errors/403.html', **g.info), 403

rophako/modules/account.py → rophako/modules/account/__init__.py View File


rophako/www/account/login.html → rophako/modules/account/templates/account/login.html View File


rophako/www/account/setup.html → rophako/modules/account/templates/account/setup.html View File


rophako/modules/admin.py → rophako/modules/admin/__init__.py View File


rophako/www/admin/edit_user.html → rophako/modules/admin/templates/admin/edit_user.html View File


rophako/www/admin/index.html → rophako/modules/admin/templates/admin/index.html View File


rophako/www/admin/users.html → rophako/modules/admin/templates/admin/users.html View File


rophako/modules/blog.py → rophako/modules/blog/__init__.py View File

@@ -14,10 +14,12 @@ import rophako.model.blog as Blog
import rophako.model.comment as Comment
import rophako.model.emoticons as Emoticons
from rophako.utils import template, render_markdown, pretty_time, login_required
from rophako.plugin import load_plugin
from rophako.log import logger
from config import *

mod = Blueprint("blog", __name__, url_prefix="/blog")
load_plugin("rophako.modules.comment")

@mod.route("/")
def index():

rophako/www/blog/categories.inc.html → rophako/modules/blog/templates/blog/categories.inc.html View File


rophako/www/blog/delete.html → rophako/modules/blog/templates/blog/delete.html View File


rophako/www/blog/entry.html → rophako/modules/blog/templates/blog/entry.html View File


rophako/www/blog/entry.inc.html → rophako/modules/blog/templates/blog/entry.inc.html View File


rophako/www/blog/index.html → rophako/modules/blog/templates/blog/index.html View File


rophako/www/blog/index.inc.html → rophako/modules/blog/templates/blog/index.inc.html View File


rophako/www/blog/nav-links.inc.html → rophako/modules/blog/templates/blog/nav-links.inc.html View File


rophako/www/blog/sibling-links.html → rophako/modules/blog/templates/blog/sibling-links.html View File


rophako/www/blog/update.html → rophako/modules/blog/templates/blog/update.html View File


rophako/modules/comment.py → rophako/modules/comment/__init__.py View File

@@ -9,10 +9,12 @@ import time
import rophako.model.user as User
import rophako.model.comment as Comment
from rophako.utils import template, pretty_time, login_required, sanitize_name
from rophako.plugin import load_plugin
from rophako.log import logger
from config import *

mod = Blueprint("comment", __name__, url_prefix="/comments")
load_plugin("rophako.modules.emoticons")


@mod.route("/")

rophako/www/comment/form.inc.html → rophako/modules/comment/templates/comment/form.inc.html View File


rophako/www/comment/index.inc.html → rophako/modules/comment/templates/comment/index.inc.html View File


rophako/www/comment/preview.html → rophako/modules/comment/templates/comment/preview.html View File


rophako/www/comment/privacy.html → rophako/modules/comment/templates/comment/privacy.html View File


rophako/www/comment/unsubscribed.html → rophako/modules/comment/templates/comment/unsubscribed.html View File


rophako/modules/contact.py → rophako/modules/contact/__init__.py View File


rophako/www/contact/index.html → rophako/modules/contact/templates/contact/index.html View File


rophako/modules/emoticons.py → rophako/modules/emoticons/__init__.py View File


rophako/www/emoticons/index.html → rophako/modules/emoticons/templates/emoticons/index.html View File


rophako/modules/photo.py → rophako/modules/photo/__init__.py View File

@@ -7,10 +7,12 @@ from flask import Blueprint, g, request, redirect, url_for, session, flash
import rophako.model.user as User
import rophako.model.photo as Photo
from rophako.utils import template, pretty_time, login_required, ajax_response
from rophako.plugin import load_plugin
from rophako.log import logger
from config import *

mod = Blueprint("photo", __name__, url_prefix="/photos")
load_plugin("rophako.modules.comment")

@mod.route("/")
def index():

rophako/www/photos/album.html → rophako/modules/photo/templates/photos/album.html View File


rophako/www/photos/albums.html → rophako/modules/photo/templates/photos/albums.html View File


rophako/www/photos/arrange_albums.html → rophako/modules/photo/templates/photos/arrange_albums.html View File


rophako/www/photos/arrange_photos.html → rophako/modules/photo/templates/photos/arrange_photos.html View File


rophako/www/photos/crop.html → rophako/modules/photo/templates/photos/crop.html View File


rophako/www/photos/delete.html → rophako/modules/photo/templates/photos/delete.html View File


rophako/www/photos/delete_album.html → rophako/modules/photo/templates/photos/delete_album.html View File


rophako/www/photos/edit.html → rophako/modules/photo/templates/photos/edit.html View File


rophako/www/photos/upload.html → rophako/modules/photo/templates/photos/upload.html View File


rophako/www/photos/view.html → rophako/modules/photo/templates/photos/view.html View File


+ 29
- 0
rophako/plugin.py View File

@@ -0,0 +1,29 @@
#!/usr/bin/env python

"""Dynamic CMS plugin loader."""

import os
from importlib import import_module
from rophako.app import app, BLUEPRINT_PATHS

def load_plugin(name, as_blueprint=True, template_path=None):
"""Load a Rophako CMS plugin.

* `name` is a Python module name, i.e. `rophako.modules.blog`
* `as_blueprint` is True if the module exports a blueprint object called
`mod` that can be attached to the Flask app. Set this value to False if
you simply need to include a Python module that isn't a blueprint.
* `template_path` is a filesystem path where the blueprint's templates
can be found. If not provided, the path is automatically determined
based on the module name, which is suitable for the built-in plugins."""
module = import_module(name)
if as_blueprint:
mod = getattr(module, "mod")
app.register_blueprint(mod)

# Get the template path to add to the BLUEPRINT_PATHS.
if template_path is None:
module_path = name.replace(".", "/")
template_path = os.path.join(module_path, "templates")

BLUEPRINT_PATHS.append(template_path)

Loading…
Cancel
Save