Skip to content

Plugin Framework

Andy Byers edited this page Sep 11, 2017 · 1 revision

Janeway comes with a Plugin Framework. It works in a similar fashion to Django Applications and loads them on startup. A generic plugin structure might look like this:

  • generic_plugin

    • docs
    • migrations
    • README.MD
    • init.py
    • hooks.py
    • models.py
    • plugin_settings.py
    • urls.py
    • views.py

    urls, views, models, init and migrations are as they would be for normal django applications so we wont discuss them further here. The only thing to be said is that generating and running migrations for Plugins is the same as normal django apps as much as you can run python3 manage.py migrate generic_plugin and it will run as expected.

docs

Should contain any documentation over and above the README.

plugin_settings

At a bare minimum a plugins plugin_settings module should contain the following:

PLUGIN_NAME = 'Generic Plugin'
DESCRIPTION = 'This is a gerneric plugin and is just a sample, it doesn\'t actually do anything.'
AUTHOR = 'Andy Byers'
VERSION = '1.0'

def install():
	# Install stub, when the revists install_plugins management command is run,
	# this command is run for all plugins that do not have a record in the 
	# plugins table.
	new_plugin, created = models.Plugin.objects.get_or_create(name=SHORT_NAME, version=VERSION, enabled=True)

    if created:
        print('Plugin {0} installed.'.format(PLUGIN_NAME))
    else:
        print('Plugin {0} is already installed.'.format(PLUGIN_NAME))

The install() function should be used to generate any settings required for the plugin. Plugins can use utils.models.PluginSetting which is a translatable key:value table to store generic settings, or they can define their own models for more complex objects.

Additional things that can be defined in plugin_settings:

SHORT_NAME = 'back_content'
MANAGER_URL = 'bc_index' # a URL name defined in urls.py
IS_WORKFLOW_PLUGIN = True # If this plugin is a workflow element set to True, default is False
HANDSHAKE_URL = 'bc_article' # Handshake URL for incoming workflow elements, should take 1 kwarg article_id
STAGE = 'Back Content' # The name of this plugin's stage for display on Dashboard

The plugin_settings module can also define a function to register for template hooks:

def hook_registry():
    # On site load, the load function is run for each installed plugin to generate
    # a list of hooks.
    return {
        'article_js_block': {'module': 'plugins.annotators.hooks', 'function': 'embed_hook'},
        'article_buttons': {'module': 'plugins.annotators.hooks', 'function': 'annotran_button'}
    }

When the hook {% hook 'article_js_block' %} is called in its template, the function plugins.annotators.hooks.embed_hook() is executed allowing the plugin to inject content into a template without altering it.

hooks

This module isn't required, per se, you could define your plugin's hooks in any module within the plugin but we should use hooks.py to follow convention. We defined a hook to inject js into the article block above, here is the functon that goes with it:

def embed_hook(context):
    plugin = plugin_settings.get_self()
    enable_hypothesis = setting_handler.get_plugin_setting(plugin, 'enable_hypothesis', context.get('request').journal,
                                                           create=True,
                                                           pretty='Enable Hypothesis').value
    embed_code = ''

    if enable_hypothesis == 'on':
        embed_code = embed_code + '<script src="https://hypothes.is/embed.js" async></script>'

    return embed_code

For more complex hooks, you could use the render command to call and contextualise a template.

URLs

URLs for plugins are loaded at: /plugins/name_of_plugin/ eg. /plugins/generic_plugin/


Other than hooks and plugin_settings a plugin can behave exactly the same as any other Django application.

Wiki has moved to read the docs.

Clone this wiki locally