Finish flatpagesplugin; add plugin docs
authorWill Kahn-Greene <willg@bluesock.org>
Sun, 10 Jun 2012 18:51:13 +0000 (14:51 -0400)
committerWill Kahn-Greene <willg@bluesock.org>
Mon, 16 Jul 2012 13:26:28 +0000 (09:26 -0400)
docs/source/index.rst
docs/source/plugindocs/flatpagesfile.rst [new file with mode: 0644]
docs/source/plugindocs/sampleplugin.rst [new file with mode: 0644]
mediagoblin/app.py
mediagoblin/plugins/flatpagesfile/README [deleted file]
mediagoblin/plugins/flatpagesfile/README.rst [new file with mode: 0644]
mediagoblin/plugins/flatpagesfile/main.py
mediagoblin/plugins/sampleplugin/README [deleted file]
mediagoblin/plugins/sampleplugin/README.rst [new file with mode: 0644]
mediagoblin/routing.py
mediagoblin/tools/pluginapi.py

index 569eda14a73619ff012c082c9ba3e5d9e4e26669..fa637e95eaae7dbfbf5b54dd7367a86c90fbd32c 100644 (file)
@@ -47,7 +47,17 @@ MediaGoblin website.  It is written for site administrators.
    siteadmin/codebase
 
 
-Part 2: Plugin Writer's Guide
+Part 2: Core plugin documentation
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   plugindocs/flatpagesfile
+   plugindocs/sampleplugin
+
+
+Part 3: Plugin Writer's Guide
 =============================
 
 This guide covers writing new GNU MediaGoblin plugins.
diff --git a/docs/source/plugindocs/flatpagesfile.rst b/docs/source/plugindocs/flatpagesfile.rst
new file mode 100644 (file)
index 0000000..68965fd
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../mediagoblin/plugins/flatpagesfile/README.rst
diff --git a/docs/source/plugindocs/sampleplugin.rst b/docs/source/plugindocs/sampleplugin.rst
new file mode 100644 (file)
index 0000000..aa04e4e
--- /dev/null
@@ -0,0 +1 @@
+.. include:: ../../../mediagoblin/plugins/sampleplugin/README.rst
index 4870b89c4d0fe7e4648cb0a24d79c6598176a69d..9ef23ce893e6a9443950f1eb4c7269b93f71287a 100644 (file)
@@ -89,7 +89,7 @@ class MediaGoblinApp(object):
         self.public_store, self.queue_store = setup_storage()
 
         # set up routing
-        self.routing = routing.get_mapper()
+        self.routing = routing.get_mapper(PluginCache().get_routes())
 
         # set up staticdirector tool
         self.staticdirector = get_staticdirector(app_config)
diff --git a/mediagoblin/plugins/flatpagesfile/README b/mediagoblin/plugins/flatpagesfile/README
deleted file mode 100644 (file)
index 23a675e..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-========
- README
-========
-
-This is the flatpages file plugin. It allows you to add pages to your
-MediaGoblin instance which are not generated from user content. For
-example, this is useful for these pages:
-
-* About this site
-* Terms of service
-* Privacy policy
-* How to get an account here
-* ...
-
-
-How to add pages
-================
-
-To add pages, you must edit template files on the file system in your
-`local_templates` directory.
-
-The directory structure looks kind of like this::
-
-    local_templates
-    |- flatpagesfile
-       |- flatpage1.html
-       |- flatpage2.html
-       |- ...
-
-
-The ``.html`` file contains the content of your page. It's just a
-template like all the other templates you have.
-
-Here's an example::
-
-   {% extends "flatpagesfile/base.html" %}
-   {% block mediagoblin_content %}
-   <h1>About this site</h1>
-   <p>
-     This site is a MediaGoblin instance set up to host media for
-     me, my family and my friends.
-   </p>
-   {% endblock %}
-
-
-.. Note::
-
-   If you have a bunch of flatpages that kind of look like one
-   another, take advantage of Jinja2 template extending and create a
-   base template that the others extend.
diff --git a/mediagoblin/plugins/flatpagesfile/README.rst b/mediagoblin/plugins/flatpagesfile/README.rst
new file mode 100644 (file)
index 0000000..b31f601
--- /dev/null
@@ -0,0 +1,132 @@
+======================
+ flatpagesfile plugin
+======================
+
+This is the flatpages file plugin. It allows you to add pages to your
+MediaGoblin instance which are not generated from user content. For
+example, this is useful for these pages:
+
+* About this site
+* Terms of service
+* Privacy policy
+* How to get an account here
+* ...
+
+
+How to configure
+================
+
+Add the following to your MediaGoblin .ini file in the ``[plugins]``
+section::
+
+    [[mediagoblin.plugins.flatpagesfile]]
+
+
+This tells MediaGoblin to load the flatpagesfile plugin. This is the
+subsection that you'll do all flatpagesfile plugin configuration in.
+
+
+How to add pages
+================
+
+To add a new page to your site, you need to do two things:
+
+1. add a route to the MediaGoblin .ini file in the flatpagesfile
+   subsection
+
+2. write a template that will get served when that route is requested
+
+
+Routes
+------
+
+First, let's talk about the route.
+
+A route is a key/value in your configuration file.
+
+The key starts with ``path`` and then has a number after that. For
+example: ``path1``, ``path2``, ... ``path15``, ...
+
+The value has three parts separated by commas:
+
+1. **route name**: You can use this with `url()` in templates to have
+   MediaGoblin automatically build the urls for you. It's very handy.
+
+   It should be "unique" and it should be alphanumeric characters and
+   hyphens. I wouldn't put spaces in there.
+
+   Examples: ``flatpages-about``, ``about-view``, ``contact-view``, ...
+
+2. **route path**: This is the url that this route matches.
+
+   Examples: ``/about``, ``/contact``, ``/pages/about``, ...
+
+   Technically, this is a regular expression and you can do anything
+   with this that you can do with the routepath parameter of
+   `routes.Route`. For more details, see `the routes documentation
+   <http://routes.readthedocs.org/en/latest/>`_.
+
+   Example: ``/siteadmin/{adminname:\w+}``
+
+   .. Note::
+
+      If you're doing something fancy, enclose the route in single
+      quotes.
+
+      For example: ``'/siteadmin/{adminname:\w+}'``
+
+3. **template**: The template to use for this url. The template is in
+   the flatpagesfile template directory, so you just need to specify
+   the file name.
+
+   Like with other templates, if it's an HTML file, it's good to use
+   the ``.html`` extensions.
+
+   Examples: ``index.html``, ``about.html``, ``contact.html``, ...
+
+
+Here's an example configuration that adds two flat pages: one for an
+"About this site" page and one for a "Terms of service" page::
+
+    [[mediagoblin.plugins.flatpagesfile]]
+    page1 = about-view, '/about', about.html
+    page2 = terms-view, '/terms', terms.html
+
+
+Templates
+---------
+
+To add pages, you must edit template files on the file system in your
+`local_templates` directory.
+
+The directory structure looks kind of like this::
+
+    local_templates
+    |- flatpagesfile
+       |- flatpage1.html
+       |- flatpage2.html
+       |- ...
+
+
+The ``.html`` file contains the content of your page. It's just a
+template like all the other templates you have.
+
+Here's an example that extends the `flatpagesfile/base.html`
+template::
+
+   {% extends "flatpagesfile/base.html" %}
+   {% block mediagoblin_content %}
+   <h1>About this site</h1>
+   <p>
+     This site is a MediaGoblin instance set up to host media for
+     me, my family and my friends.
+   </p>
+   {% endblock %}
+
+
+.. Note::
+
+   If you have a bunch of flatpages that kind of look like one
+   another, take advantage of Jinja2 template extending and create a
+   base template that the others extend.
+
index b73f9b90c2c26873d140abad98720d08609fed76..b0f5ea42c0d252c9c52ffd033d06c63229254f6a 100644 (file)
 import logging
 import os
 
+from routes.route import Route
+
 from mediagoblin.tools import pluginapi
+from mediagoblin.tools.response import render_to_response
 
 
 PLUGIN_DIR = os.path.dirname(__file__)
@@ -26,16 +29,45 @@ PLUGIN_DIR = os.path.dirname(__file__)
 _log = logging.getLogger(__name__)
 
 
-class FlatpagesPlugin(pluginapi.Plugin):
+def flatpage_handler(template):
+    """Flatpage view generator
+
+    Given a template, generates the controller function for handling that
+    route.
+
+    """
+    def _flatpage_handler(request, *args, **kwargs):
+        return render_to_response(
+            request, 'flatpagesfile/%s' % template,
+            {'args': args, 'kwargs': kwargs})
+    return _flatpage_handler
+
+
+class FlatpagesFilePlugin(pluginapi.Plugin):
     """
     This is the flatpages plugin class. See the README for how to use
     flatpages.
     """
-    def __init__(self):
-        self._setup_plugin_called = 0
-
     def setup_plugin(self):
         self.config = pluginapi.get_config('mediagoblin.plugins.flatpagesfile')
 
-        _log.info('Setting up flatpages....')
+        _log.info('Setting up flatpagesfile....')
+
+        # Register the template path.
         pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
+
+        # Set up and register routes.
+        pages = [(int(key.replace('page', '')), val)
+                 for key, val in self.config.items()
+                 if key.startswith('page')]
+
+        pages = [mapping for index, mapping in sorted(pages)]
+        routes = []
+        for name, url, template in pages:
+            name = 'flatpagesfile.%s' % name.strip()
+            controller = flatpage_handler(template)
+            routes.append(
+                Route(name, url, controller=controller))
+
+        pluginapi.register_routes(routes)
+        _log.info('Done setting up flatpagesfile!')
diff --git a/mediagoblin/plugins/sampleplugin/README b/mediagoblin/plugins/sampleplugin/README
deleted file mode 100644 (file)
index 15411d8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-========
- README
-========
-
-This is a sample plugin. It does nothing interesting other than show
-one way to structure a MediaGoblin plugin.
\ No newline at end of file
diff --git a/mediagoblin/plugins/sampleplugin/README.rst b/mediagoblin/plugins/sampleplugin/README.rst
new file mode 100644 (file)
index 0000000..7389713
--- /dev/null
@@ -0,0 +1,8 @@
+==============
+ sampleplugin
+==============
+
+This is a sample plugin. It does nothing interesting other than show
+one way to structure a MediaGoblin plugin.
+
+The code for this plugin is in ``mediagoblin/plugins/sampleplugin/``.
index adbe62537313b8ff2aa06a4807ad4c71f9766374..90e1f3f88dc6079378ad5d9e9dfbc337fe5c84c8 100644 (file)
@@ -26,10 +26,13 @@ from mediagoblin.webfinger.routing import webfinger_well_known_routes, \
 from mediagoblin.admin.routing import admin_routes
 
 
-def get_mapper():
+def get_mapper(plugin_routes):
     mapping = Mapper()
     mapping.minimization = False
 
+    # Plugin routes go first so they can override default routes.
+    mapping.extend(plugin_routes)
+
     mapping.connect(
         "index", "/",
         controller="mediagoblin.views:root_view")
index 1f5a988706c6444195ec701faf6e0d461d1d840d..0c338540b9dfe4273a55fa0cae67fde770021c40 100644 (file)
@@ -80,6 +80,9 @@ class PluginCache(object):
 
         # list of registered template paths
         "template_paths": set(),
+
+        # list of registered routes
+        "routes": [],
         }
 
     def clear(self):
@@ -106,6 +109,13 @@ class PluginCache(object):
         """Returns a tuple of registered template paths"""
         return tuple(self.template_paths)
 
+    def register_route(self, route):
+        """Registers a single route"""
+        self.routes.append(route)
+
+    def get_routes(self):
+        return tuple(self.routes)
+
 
 class MetaPluginClass(type):
     """Metaclass for PluginBase derivatives"""
@@ -119,7 +129,7 @@ class MetaPluginClass(type):
 
 
 class Plugin(object):
-    """Exttend this class for plugins.
+    """Extend this class for plugins.
 
     Example::
 
@@ -139,6 +149,44 @@ class Plugin(object):
         pass
 
 
+def register_routes(routes):
+    """Registers one or more routes
+
+    If your plugin handles requests, then you need to call this with
+    the routes your plugin handles.
+
+    A "route" is a `routes.Route` object. See `the routes.Route
+    documentation
+    <http://routes.readthedocs.org/en/latest/modules/route.html>`_ for
+    more details.
+
+    Example passing in a single route:
+
+    >>> from routes import Route
+    >>> register_routes(Route('about-view', '/about',
+    ...     controller=about_view_handler))
+
+    Example passing in a list of routes:
+
+    >>> from routes import Route
+    >>> register_routes([
+    ...     Route('contact-view', '/contact', controller=contact_handler),
+    ...     Route('about-view', '/about', controller=about_handler)
+    ... ])
+
+
+    .. Note::
+
+       Be careful when designing your route urls. If they clash with
+       core urls, then it could result in DISASTER!
+    """
+    if isinstance(routes, (tuple, list)):
+        for route in routes:
+            PluginCache().register_route(route)
+    else:
+        PluginCache().register_route(routes)
+
+
 def register_template_path(path):
     """Registers a path for template loading