.. _topics-plugins-index:

===================
Plugins development
===================

.. highlightlang:: html+django

.. _topics-plugins-overview:


Overview
========

(( to be completed ))

.. _topics-plugins-configuration:


Configuration
=============

Plugin configuration is defined in a ``PluginConfig`` class in a ``config.py`` module inside your plugin directory. This class is readed when plugin is loaded in merengue.


Example plugin config
---------------------

This is a ``config.py`` file code fragment:

.. code-block:: python

    from merengue.pluggable import Plugin

    class PluginConfig(Plugin):
        url_prefixes = (
            ('fooplugin', 'plugins.fooplugin.urls'),
        )

        @classmethod
        def get_actions(cls):
            return [...]

        @classmethod
        def get_blocks(cls):
            return [...]

        @classmethod
        def section_models(cls):
            return [...]

        # ... etcetera

Parameters reference
--------------------

``url_prefixes``
~~~~~~~~~~~~~~~~

Default value: ``None``

This parameter is mandatory. This is the URL prefix for all your plugin urls.

Example:

.. code-block:: python

    class PluginConfig(Plugin):
        url_prefixes = (
            ('fooplugin', 'plugins.fooplugin.urls'),
            ...
        )


With this example, if plugin was activated, all urls below ``fooplugin`` will
be handled by ``plugins.fooplugin.urls`` module. Internally, merengue plugin
system will perform a operation like this:

.. code-block:: python

    urlpatterns += patterns('',
      (r'^fooplugin/', include('plugins.fooplugin.urls')),
    )

Method reference
----------------

(( to be completed ))

.. _topics-plugins-development:


Development
===========

Writing a custom plugin
-----------------------

To write a merengue custom plugin, you need to create an Django application with several conventions:

* A defined directory layout.
* Write a configuration file.
* Extend some components.
* Extend some base models.


Plugin tree
-----------

All plugins will be placed below ``plugins`` merengue directory.

This is a conventional plugin tree:

.. code-block:: python

     /plugins/
         |-- fooplugin/
         |   |-- __init__.py
         |   |-- config.py
         |   |-- models.py
         |   |-- views.py
         |   |-- urls.py
         |   `-- templates/
         |       `-- fooplugin/
         |   `-- media/
         |       `-- fooplugin/
         |
         ...

.. admonition:: Note

    Only ``__init__.py`` and ``config.py`` files are mandatory.

Let's explain every part listed before:

* ``__init__.py`` is a needed file (usually empty) that makes plugin to be a python module.
* ``models.py`` is conventional Django app model file. See :ref:`base models <topics-models-base>` to get more info about base models you can extend of.
* ``config.py`` is the configuration file for plugin. See :ref:`plugin configuration reference <topics-plugins-configuration>`.
* ``actions.py`` is portal actions file. See :ref:`actions reference <topics-actions>`.
* ``views.py`` is conventional `Django views`_ file.
* ``urls.py`` is conventional `Django urls`_ file. You can use it for control a URL namespace (i.e. all ``/fooplugin/.*`` urls).
* ``templates/fooplugin/`` is a directory for ``fooplugin`` template namespace.
* ``media/fooplugin/`` is a directory for media resources like icons, css, etc.

.. _`Django views`: http://docs.djangoproject.com/en/dev/topics/http/views/#topics-http-views
.. _`Django URLs`: http://docs.djangoproject.com/en/dev/topics/http/urls/#topics-http-urls

Example "news" plugin
---------------------

You can see an `example plugin`_.

.. _`example plugin`: http://tracpub.yaco.es/merengue/browser/trunk/merengueproj/plugins/news/


Required plugins in a project
-----------------------------

Sometimes your project requires that some plugins were activated by default and
user cannot deactivated them. For example project logic may rely in existence
of certains models defined in a plugin.

You can define plugins that will be installed and activated by default including
next setting in your project settings:

.. code-block:: python

    REQUIRED_PLUGINS = ('core', 'fooplugin', )

Default: ``('core', )`` (``core`` plugin)

.. admonition:: About ``core`` plugin

    ``core`` plugin have to be included in ``REQUIRED_PLUGINS`` to maintain all
    merengue features.

After changing ``REQUIRED_PLUGINS`` setting, you have to register plugin with this
command to get new plugins activated (and also get their models created if exist)::

    python manage.py migrate


Media files in plugins
======================

(( to be completed. Talk about media conventions taken in Merengue,
merengue.views.static.serve view and sync_plugins_media command ))


Broken plugins
==============

Merengue detects broken plugins that are downloaded in ``plugins``directory.
You can see it in plugins admin view:

    .. image:: _images/broken_plugins.png

Merengue broken plugin detection tries to avoid break entire system when you
download a third party plugin. Broken plugin cannot be installed but if you
have a broken plugin activated, the exception will break whole system.

Plugins can be broken because one of this causes:

* **Removed from file system:** some times ago, plugin was in file system,
  and Merengue registered it, but later was deleted.

* **Models are wrong:** models does not validate.
 
* **Syntax error:** you have a syntax error in some code of the plugin. Merengue
  tried to import plugin and a ``SyntaxError`` was raised.
