diff options
Diffstat (limited to 'docs/source/pluginwriter')
-rw-r--r-- | docs/source/pluginwriter/api.rst | 10 | ||||
-rw-r--r-- | docs/source/pluginwriter/authhooks.rst | 4 | ||||
-rw-r--r-- | docs/source/pluginwriter/database.rst | 92 | ||||
-rw-r--r-- | docs/source/pluginwriter/hooks.rst | 35 | ||||
-rw-r--r-- | docs/source/pluginwriter/quickstart.rst | 2 | ||||
-rw-r--r-- | docs/source/pluginwriter/tests.rst | 8 |
6 files changed, 111 insertions, 40 deletions
diff --git a/docs/source/pluginwriter/api.rst b/docs/source/pluginwriter/api.rst index 29adb691..03761a38 100644 --- a/docs/source/pluginwriter/api.rst +++ b/docs/source/pluginwriter/api.rst @@ -42,7 +42,7 @@ exist yet: what to do then? The plan at present is that we are adding hooks as people need them, with community discussion. If you find that you need a hook and MediaGoblin at present doesn't provide it at present, please -`http://mediagoblin.org/pages/join.html <talk to us>`_! We'll +`talk to us <http://mediagoblin.org/pages/join.html>`_! We'll evaluate what to do from there. @@ -83,7 +83,7 @@ can use a shortcut to get your plugin's config section:: >>> floobie_dir = floobie_config['floobie_dir'] A tip: you have access to the `%(here)s` variable in your config, -which is the directory that the user's mediagoblin config is running +which is the directory that the user's MediaGoblin config is running out of. So for example, your plugin may need a "floobie" directory to store floobs in. You could give them a reasonable default that makes use of the default `user_dev` location, but allow users to override @@ -92,7 +92,7 @@ it, like so:: [plugin_spec] floobie_dir = string(default="%(here)s/user_dev/floobs/") -Note, this is relative to the user's mediagoblin config directory, +Note, this is relative to the user's MediaGoblin config directory, *not* your plugin directory! @@ -178,7 +178,7 @@ Adding static resources ----------------------- It's possible to add static resources for your plugin. Say your -plugin needs some special javascript and images... how to provide +plugin needs some special JavaScript and images... how to provide them? Then how to access them? MediaGoblin has a way! @@ -230,7 +230,7 @@ the MediaGoblin repository. WTForms hooks +++++++++++++ -We haven't totally settled on a way to tranform wtforms form objects, +We haven't totally settled on a way to transform wtforms form objects, but here's one way. In your view:: from mediagoblin.foo.forms import SomeForm diff --git a/docs/source/pluginwriter/authhooks.rst b/docs/source/pluginwriter/authhooks.rst index 9721d729..66d9b9da 100644 --- a/docs/source/pluginwriter/authhooks.rst +++ b/docs/source/pluginwriter/authhooks.rst @@ -44,7 +44,7 @@ This hook is called in ``mediagoblin.auth.views`` in both the ``login`` and if :ref:`basic_auth-chapter` is not enabled, the user will be redirected to the correct login and registration views for your plugin. -The code assumes that it can generate a valid url given +The code assumes that it can generate a valid URL given ``mediagoblin.plugins.{{ your_plugin_here }}.login`` and ``mediagoblin.plugins.{{ your_plugin_here }}.register``. This is only needed if you will not be using the ``login`` and ``register`` views in @@ -82,5 +82,5 @@ the ``stored_hash`` and return either ``True`` or ``False``. This hook is called in ``mediagoblin.auth.tools.check_login_simple``. It is called if a user is not found and should do something that takes the same amount -of time as your ``check_password`` function. This is to help prevent timining +of time as your ``check_password`` function. This is to help prevent timing attacks. diff --git a/docs/source/pluginwriter/database.rst b/docs/source/pluginwriter/database.rst index 603a19eb..90c2cee3 100644 --- a/docs/source/pluginwriter/database.rst +++ b/docs/source/pluginwriter/database.rst @@ -24,7 +24,7 @@ Accessing Existing Data ======================= If your plugin wants to access existing data, this is quite -straight forward. Just import the appropiate models and use +straight forward. Just import the appropriate models and use the full power of SQLAlchemy. Take a look at the (upcoming) database section in the Developer's Chapter. @@ -61,7 +61,39 @@ Here's a simple one: MODELS = [MediaSecurity] -That's it. +Next, you need to make an initial migration. MediaGoblin uses +`Alembic's branching model <http://alembic.readthedocs.org/en/latest/branches.html>`_ +to handle plugins adding their own content. As such, when you are +adding a new plugin, you need to add an initial migration adding +the existing models, and migrate from there. + +You'll need to make a `migrations` subdirectory for migrations and put +your migrations there. If you want to look at some example +migrations, look at `mediagoblin/media_types/image/migrations/`, +especially the "initial" migration. (Plugin authors with plugins that +existed prior to the alembic switchover: you might notice how it +checks for the table and skips the migration if it already exists. +Plugin authors writing brand new plugins, post-Alembic migration +switchover, do not need to do this.) + +Unfortunately, these migrations are a bit tedious to write. +Fortunately, Alembic can do much of the work for us! After adding the +models.py file, run this command (switching out YOUR_PLUGIN_NAME of +course):: + + ./bin/gmg alembic --with-plugins revision \ + --splice --autogenerate \ + --branch-label YOUR_PLUGIN_NAME_plugin \ + -m "YOUR_PLUGIN_NAME plugin initial migration" + +(Note that `--with-plugins` *must* come before any alembic subcommand... +this is a quirk related to the way we handle alembic command dispatching +with the gmg subcommand!) + +This will dump your migration into "the wrong place" (it'll dump it +into the MediaGoblin core migrations directory), so you should move it +to your plugin's migrations directory. Open the file and make adjustments +accordingly! Some notes: @@ -78,37 +110,41 @@ Some notes: Changing the Database Schema Later ================================== -If your plugin is in use and instances use it to store some -data, changing the database design is a tricky thing. +If your plugin is in use and instances use it to store some data, +changing the database design is tricky and must be done with care, +but is not impossible. -1. Make up your mind how the new schema should look like. -2. Change ``models.py`` to contain the new schema. Keep a - copy of the old version around for your personal - reference later. -3. Now make up your mind (possibly using your old and new - ``models.py``) what steps in SQL are needed to convert - the old schema to the new one. - This is called a "migration". -4. Create a file ``migrations.py`` that will contain all - your migrations and add your new migration. +Luckily, Alembic can once again help with autogenerating what is +probably very close to the migration you want. First you will need to +find out what the revision id of your plugin's most recent migrations +is. There are two ways to do this: look in your plugin's migrations/ +directory and figure it out with the hope that it's "obvious" in some +way. The second path: let Alembic give that info for you. -Take a look at the core's ``db/migrations.py`` for some -good examples on what you might be able to do. Here's a -simple one to add one column: +Assuming you've already done the latest dbupdate with your plugin +enabled, do the following: -.. code-block:: python + ./bin/gmg alembic --with-plugins heads + +You should see the latest migration id for your plugin's label. - from mediagoblin.db.migration_tools import RegisterMigration, inspect_table - from sqlalchemy import MetaData, Column, Integer +Make changes to your +plugin's models.py and then run:: - MIGRATIONS = {} + ./bin/gmg alembic --with-plugins revision \ + --head REVISION_HERE \ + --autogenerate \ + -m "YOUR_PLUGIN_NAME: Change explanation here." - @RegisterMigration(1, MIGRATIONS) - def add_license_preference(db): - metadata = MetaData(bind=db.bind) +Once again, this will dump the migration into the wrong place, so move +to your plugin's migrations directory. Open the file, adjust +accordingly, and read carefully! Now you should also test your +migration with some real data. Be sure to test it both on SQLite +*AND* on PostgreSQL! - security_table = inspect_table(metadata, 'yourplugin__media_security') +One last *very critical* note: you must never, never modify core +tables with your plugin. To do that is to put you and all your users +in a dangerous situation. Add data to the database by adding new tables +under the control of your plugin, but never ever modify anyone else's! - col = Column('security_level', Integer) - col.create(security_table) - db.commit() +Whew, you made it! Get yourself a cookie to celebrate! diff --git a/docs/source/pluginwriter/hooks.rst b/docs/source/pluginwriter/hooks.rst new file mode 100644 index 00000000..66fe3b4d --- /dev/null +++ b/docs/source/pluginwriter/hooks.rst @@ -0,0 +1,35 @@ +.. MediaGoblin Documentation + + Written in 2014 by MediaGoblin contributors + + To the extent possible under law, the author(s) have dedicated all + copyright and related and neighboring rights to this software to + the public domain worldwide. This software is distributed without + any warranty. + + You should have received a copy of the CC0 Public Domain + Dedication along with this software. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + + +=============================== +Documentation on Built-in Hooks +=============================== + +This section explains built-in hooks to MediaGoblin. + + +What hooks are available? +========================= + +'collection_add_media' +---------------------- + +This hook is used by ``add_media_to_collection`` +in ``mediagoblin.user_pages.lib``. +It gets a ``CollectionItem`` as its argument. +It's the newly created item just before getting committed. +So the item can be modified by the hook, if needed. +Changing the session regarding this item is currently +undefined behaviour, as the SQL Session might contain other +things. diff --git a/docs/source/pluginwriter/quickstart.rst b/docs/source/pluginwriter/quickstart.rst index 6d45ea36..212c91ad 100644 --- a/docs/source/pluginwriter/quickstart.rst +++ b/docs/source/pluginwriter/quickstart.rst @@ -111,7 +111,7 @@ The code for ``__init__.py`` looks like this: :emphasize-lines: 12,23 import logging - from mediagoblin.tools.pluginapi import Plugin, get_config + from mediagoblin.tools.pluginapi import PluginManager, get_config # This creates a logger that you can use to log information to diff --git a/docs/source/pluginwriter/tests.rst b/docs/source/pluginwriter/tests.rst index fe99688f..560a8899 100644 --- a/docs/source/pluginwriter/tests.rst +++ b/docs/source/pluginwriter/tests.rst @@ -19,7 +19,7 @@ Here's a brief guide to writing unit tests for plugins. However, it isn't really ideal. It also hasn't been well tested... yes, there's some irony there :) -Some notes: we're using py.test and webtest for unit testing stuff. +Some notes: we're using py.test and WebTest for unit testing stuff. Keep that in mind. My suggestion is to mime the behavior of `mediagoblin/tests/` and put @@ -44,7 +44,7 @@ In any test module in your tests directory you can then do:: # real code goes here pass -And you'll get a mediagoblin application wrapped in webtest passed in +And you'll get a MediaGoblin application wrapped in WebTest passed in to your environment. If your plugin needs to define multiple configuration setups, you can @@ -52,8 +52,8 @@ actually set up multiple fixtures very easily for this. You can just set up multiple fixtures with different names that point to different configs and pass them in as that named argument. -To run the tests, from mediagoblin's directory (make sure that your -plugin has been added to your mediagoblin checkout's virtualenv!) do:: +To run the tests, from MediaGoblin's directory (make sure that your +plugin has been added to your MediaGoblin checkout's virtualenv!) do:: ./runtests.sh /path/to/myplugin/tests/ |