From 4bd65f69c710268404e1b1fdaac68db069558584 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 10 Jun 2012 14:51:13 -0400 Subject: [PATCH] Finish flatpagesplugin; add plugin docs --- docs/source/index.rst | 12 +- docs/source/plugindocs/flatpagesfile.rst | 1 + docs/source/plugindocs/sampleplugin.rst | 1 + mediagoblin/app.py | 2 +- mediagoblin/plugins/flatpagesfile/README | 50 ------- mediagoblin/plugins/flatpagesfile/README.rst | 132 +++++++++++++++++++ mediagoblin/plugins/flatpagesfile/main.py | 42 +++++- mediagoblin/plugins/sampleplugin/README | 6 - mediagoblin/plugins/sampleplugin/README.rst | 8 ++ mediagoblin/routing.py | 5 +- mediagoblin/tools/pluginapi.py | 50 ++++++- 11 files changed, 244 insertions(+), 65 deletions(-) create mode 100644 docs/source/plugindocs/flatpagesfile.rst create mode 100644 docs/source/plugindocs/sampleplugin.rst delete mode 100644 mediagoblin/plugins/flatpagesfile/README create mode 100644 mediagoblin/plugins/flatpagesfile/README.rst delete mode 100644 mediagoblin/plugins/sampleplugin/README create mode 100644 mediagoblin/plugins/sampleplugin/README.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 569eda14..fa637e95 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -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 index 00000000..68965fda --- /dev/null +++ b/docs/source/plugindocs/flatpagesfile.rst @@ -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 index 00000000..aa04e4e9 --- /dev/null +++ b/docs/source/plugindocs/sampleplugin.rst @@ -0,0 +1 @@ +.. include:: ../../../mediagoblin/plugins/sampleplugin/README.rst diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 4870b89c..9ef23ce8 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -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 index 23a675e1..00000000 --- a/mediagoblin/plugins/flatpagesfile/README +++ /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 %} -

About this site

-

- This site is a MediaGoblin instance set up to host media for - me, my family and my friends. -

- {% 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 index 00000000..b31f6017 --- /dev/null +++ b/mediagoblin/plugins/flatpagesfile/README.rst @@ -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 + `_. + + 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 %} +

About this site

+

+ This site is a MediaGoblin instance set up to host media for + me, my family and my friends. +

+ {% 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/main.py b/mediagoblin/plugins/flatpagesfile/main.py index b73f9b90..b0f5ea42 100644 --- a/mediagoblin/plugins/flatpagesfile/main.py +++ b/mediagoblin/plugins/flatpagesfile/main.py @@ -17,7 +17,10 @@ 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 index 15411d8e..00000000 --- a/mediagoblin/plugins/sampleplugin/README +++ /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 index 00000000..73897133 --- /dev/null +++ b/mediagoblin/plugins/sampleplugin/README.rst @@ -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/``. diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py index adbe6253..90e1f3f8 100644 --- a/mediagoblin/routing.py +++ b/mediagoblin/routing.py @@ -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") diff --git a/mediagoblin/tools/pluginapi.py b/mediagoblin/tools/pluginapi.py index 1f5a9887..0c338540 100644 --- a/mediagoblin/tools/pluginapi.py +++ b/mediagoblin/tools/pluginapi.py @@ -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 + `_ 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 -- 2.25.1