Browse Source

Just playing around a bit

sh4nks 11 years ago
parent
commit
480be11acb

+ 13 - 1
flaskbb/app.py

@@ -36,7 +36,8 @@ from flaskbb.utils.helpers import format_date, time_since, crop_title, \
 # permission checks (here they are used for the jinja filters)
 from flaskbb.utils.permissions import can_post_reply, can_post_topic, \
     can_delete_topic, can_delete_post, can_edit_post, can_lock_topic, \
-    can_move_topic, can_moderate
+    can_move_topic
+from flaskbb.plugins.manager import PluginManager
 
 
 def create_app(config=None):
@@ -60,6 +61,17 @@ def create_app(config=None):
     configure_errorhandlers(app)
     configure_logging(app)
 
+    app.logger.debug("Loading plugins...")
+
+    plugin_manager = PluginManager(app)
+    plugin_manager.load_plugins()
+
+    app.logger.debug(
+        "({}) {} Plugins loaded."
+        .format(len(plugin_manager.plugins),
+                plugin_manager.plugins)
+    )
+
     return app
 
 

+ 4 - 1
flaskbb/forum/views.py

@@ -27,7 +27,7 @@ from flaskbb.forum.models import (Category, Forum, Topic, Post, ForumsRead,
 from flaskbb.forum.forms import (QuickreplyForm, ReplyForm, NewTopicForm,
                                  ReportForm, UserSearchForm, SearchPageForm)
 from flaskbb.user.models import User
-
+from flaskbb.plugins import hooks
 
 forum = Blueprint("forum", __name__)
 
@@ -42,6 +42,9 @@ def index():
     post_count = Post.query.count()
     newest_user = User.query.order_by(User.id.desc()).first()
 
+    current_app.logger.debug("Runnnig beforeIndex hook...")
+    hooks.runHook(hooks.registered.beforeIndex)
+
     # Check if we use redis or not
     if not current_app.config["REDIS_ENABLED"]:
         online_users = User.query.filter(User.lastseen >= time_diff()).count()

+ 31 - 12
flaskbb/plugins/__init__.py

@@ -24,30 +24,49 @@ class Plugin(object):
     #: in here.
     models = []
 
-    #: The name of the plugin
-    #: E.g. "Example Plugin"
-    name = None
-
-    #: A small description of the plugin
-    description = None
-
-    def install(self, app=None):
+    @property
+    def name(self):
+        return self.__class__.__name__
+
+    @property
+    def description(self):
+        return ""
+
+    @property
+    def version(self):
+        return "0.0.0"
+
+    def enable(self):
+        """Enable the plugin."""
+        #raise NotImplemented()
+        # Just temporary
+        self.install()
+
+    def disable(self):  # pragma: no cover
+        """Disable the plugin."""
+        #pass
+        # Just temporary
+        self.uninstall()
+
+    def install(self):
         """The plugin should specify here what needs to be installed.
         For example, create the database and register the hooks."""
-        raise NotImplementedError
+        raise NotImplemented()
 
-    def uninstall(self, app=None):
+    def uninstall(self):
         """Uninstalls the plugin and deletes the things that
         the plugin has installed."""
-        raise NotImplementedError
+        raise NotImplemented()
 
+    # Some helpers
     def create_table(self, model, db):
         """Creates the table for the model
 
         :param model: The Model which should be created
         :param db: The database instance.
         """
-        model.__table__.create(bind=db.engine)
+        if not model.__table__.exists(bind=db.engine):
+            model.__table__.create(bind=db.engine)
 
     def drop_table(self, model, db):
         """Drops the table for the bounded model.

+ 27 - 0
flaskbb/plugins/example/__init__.py

@@ -0,0 +1,27 @@
+from flask import flash
+from flaskbb.plugins import Plugin, hooks
+
+
+#: The name of your plugin class
+__plugin__ = "ExamplePlugin"
+
+
+def hello_world():
+    flash("Hello World from {}".format(__plugin__), "success")
+
+
+class ExamplePlugin(Plugin):
+    @property
+    def description(self):
+        return "Example plugin"
+
+    @property
+    def version(self):
+        return "1.0.0"
+
+    def install(self):
+        # register hooks and blueprints/routes here
+        hooks.registered.beforeIndex.append(hello_world)
+
+    def uninstall(self):
+        pass

+ 21 - 0
flaskbb/plugins/hooks.py

@@ -0,0 +1,21 @@
+#import hooks
+# inspired fromhttp://stackoverflow.com/questions/932069/building-a-minimal-plugin-architecture-in-python
+#hooks.registered.beforeIndex.append(hello_world)
+#hooks.runHook(hooks.registered.beforeIndex)
+
+
+class HookError(Exception):
+    pass
+
+
+class registered(object):
+    beforeIndex = []
+    afterIndex = []
+
+
+def runHook(hook):
+    for h in hook:
+        try:
+            h()
+        except Exception as e:
+            raise HookError("An error occured %s", e)

+ 0 - 60
flaskbb/plugins/loader.py

@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.plugins.loader
-    ~~~~~~~~~~~~~~~~~~~~~~
-
-    The Plugin loader.
-
-    :copyright: (c) 2014 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-import os
-
-
-class PluginLoader(object):
-
-    #: Stores all founded plugins in the plugins folder
-    plugins = list()
-
-    def __init__(self, app):
-        self.app = app
-        self.plugin_folder = os.path.join(self.app.root_path, "plugins")
-        self.base_plugin_package = ".".join([self.app.name, "plugins"])
-
-    def load_plugins(self):
-        """Loads all plugins"""
-        #from flaskbb.plugins.pluginname import PluginName
-        #__import__(plugin, globals(), locals(), [tmp.__plugin__], -1)
-        pass
-
-    def check_plugin(self, plugin):
-        """Checks if a plugin is appropriate.
-
-        :param plugin:
-        """
-        pass
-
-    def find_plugins(self):
-        for item in os.listdir(self.plugin_folder):
-
-            if os.path.isdir(os.path.join(self.plugin_folder, item)) and \
-                    os.path.exists(
-                        os.path.join(self.plugin_folder, item, "__init__.py")):
-
-                plugin = ".".join([self.base_plugin_package, item])
-
-                # Same like from flaskbb.plugins.pluginname import __plugin__
-                tmp = __import__(
-                    plugin, globals(), locals(), ['__plugin__'], -1
-                )
-
-                self.plugins.append(tmp.__plugin__)
-
-"""
-for ipython:
-from flask import current_app
-from flaskbb.plugins.loader import PluginLoader
-loader = PluginLoader(current_app)
-loader.find_plugins()
-loader.plugins
-"""

+ 94 - 0
flaskbb/plugins/manager.py

@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.plugins.manager
+    ~~~~~~~~~~~~~~~~~~~~~~~
+
+    The Plugin loader.
+
+    :copyright: (c) 2014 by the FlaskBB Team.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+from werkzeug.utils import import_string
+
+
+class PluginManager(object):
+
+    def __init__(self, app):
+        self.app = app
+        self.plugin_folder = os.path.join(self.app.root_path, "plugins")
+        self.base_plugin_package = ".".join([self.app.name, "plugins"])
+
+        self.found_plugins = []
+        self.plugins = []
+
+    def __getitem__(self, name):
+        for plugin in self.plugins:
+            if plugin.name == name:
+                return plugin
+        raise KeyError("Plugin %s is not known" % name)
+
+    def register_blueprints(self, blueprint):
+        self.app.register_blueprints(blueprint)
+
+    def load_plugins(self):
+        """Loads and install all found plugins.
+        TODO: Only load/install activated plugins
+        """
+        self.find_plugins()
+
+        for plugin in self.iter_plugins():
+            with self.app.app_context():
+                plugin().install()
+
+        #self.enable_plugins(self.plugins)
+
+    def iter_plugins(self):
+        for plugin in self.found_plugins:
+            plugin_class = import_string(plugin)
+
+            if plugin_class is not None:
+                self.plugins.append(plugin)
+                yield plugin_class
+
+    def find_plugins(self):
+        for item in os.listdir(self.plugin_folder):
+
+            if os.path.isdir(os.path.join(self.plugin_folder, item)) and \
+                    os.path.exists(
+                        os.path.join(self.plugin_folder, item, "__init__.py")):
+
+                plugin = ".".join([self.base_plugin_package, item])
+
+                # Same like from flaskbb.plugins.pluginname import __plugin__
+                tmp = __import__(
+                    plugin, globals(), locals(), ["__plugin__"], -1
+                )
+                try:
+                    plugin = "{}.{}".format(plugin, tmp.__plugin__)
+                    self.found_plugins.append(plugin)
+                except AttributeError:
+                    pass
+
+    def enable_plugins(self, plugins=None):
+        """Enable all or selected plugins."""
+
+        for plugin in plugins or self.plugins:
+            plugin.enable()
+
+    def disable_plugins(self, plugins=None):
+        """Disable all or selected plugins."""
+
+        for plugin in plugins or self.plugins:
+            plugin.disable()
+
+
+"""
+for ipython:
+from flask import current_app
+from flaskbb.plugins import Plugin
+from flaskbb.plugins.manager import PluginManager
+manager = PluginLoader(current_app)
+manager.find_plugins()
+manager.plugins
+"""

+ 11 - 4
flaskbb/plugins/portal/__init__.py

@@ -1,7 +1,8 @@
+from flask import current_app
 from flaskbb.extensions import db
 from flaskbb.plugins import Plugin
 
-from .portal import PortalModel
+from .portal import PortalModel, portal
 
 
 #: The name of your plugin class
@@ -9,14 +10,20 @@ __plugin__ = "PortalPlugin"
 
 
 class PortalPlugin(Plugin):
+    # Register the models
     models = [PortalModel]
 
-    name = "Portal Plugin"
-    description = "A simple Portal"
+    @property
+    def description(self):
+        return "A simple portal plugin"
+
+    @property
+    def version(self):
+        return "0.0.1"
 
     def install(self):
         self.create_all_tables(db)
-        #
+        current_app.register_blueprint(portal)
         # register hooks and blueprints/routes here
 
     def uninstall(self):

+ 10 - 0
flaskbb/plugins/portal/portal.py

@@ -9,9 +9,19 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
 """
+from flask import Blueprint
 from flaskbb.extensions import db
+from flaskbb.utils.helpers import render_template
+
+
+portal = Blueprint("portal", __name__, template_folder="templates")
 
 
 class PortalModel(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     forum_id = db.Column(db.Integer, db.ForeignKey("forums.id"))
+
+
+@portal.route("/portal")
+def portal_index():
+    return render_template("portal.html")

+ 5 - 0
flaskbb/plugins/portal/templates/portal.html

@@ -0,0 +1,5 @@
+{% extends theme('layout.html') %}
+
+{% block content %}
+Portal Plugin
+{% endblock %}