plugindev.rst 8.1 KB

.. _plugin-dev:

Plugin Developer Documentation
====================================

Getting Started
---------------

Signals
----------
Implement signals in plugins is optional! You may follow this steps only if you
want to communicate with another plugins.

In order to configure a plugin to able to listen and send signals using Colab
signals structure, some steps are required:

* In the apps.py file it is necessary to declare a list variable containing all
the signals that the plugin will dispatch. It is suggested to name the
variable "registered_signals", but that nomenclature not strictly necessary.
* It is also necessary to declare a variable containing the name of the plugin
that will send the signal. It must be said that the name of the plugin cannot
contain any special character, such as dot or comma. It is suggested to name
the variable "short_name", but that nomenclature is not strictly
necessary.
* Finally, the variable namespace should also be defined. This variable is the
url namespace for django reverse.
* In order to actually register the signals, it is necessary to implement the
method register_signal, which require the name of the plugin that is
registering the signals and a list of signals to be registered as parameters.
You must not call this method nowhere.
* In order to listen for a given signal, it is required to create a handling
method. This method should be located at a file named tasks.py in the same
directory as the plugins files. It also must be said that this method need to
receive at least a \*\*kwargs parameter. An example of a handling method can
be seen below:

.. code-block:: python

from colab.celery import app

@app.task(bind=True)
def handling_method(self, **kwargs):
# DO SOMETHING

* With signals registered and handling method defined you must connect them.
To do it you must call connect_signal passing signal name, sender and handling
method as arguments. These should be implemented on plugin's apps.py. It must
be said that the plugin app class must extend ColabPluginAppConfig. An
example of this configuration can be seen below:

.. code-block:: python

from colab.plugins.utils.apps import ColabPluginAppConfig
from colab.signals.signals import register_signal, connect_signal
from colab.plugins.PLUGIN.tasks import HANDLING_METHOD

class PluginApps(ColabPluginAppConfig):
short_name = PLUGIN_NAME
signals_list = [SIGNAL1, SIGNAL2]
namespace = PLUGIN_NAMESPACE

def registered_signal(self):
register_signal(self.short_name, self.signals_list)

def connect_signal(self):
connect_signal(self.signals_list[0], self.short_name,
HANDLING_METHOD)
connect_signal(self.signals_list[1], self.short_name,
HANDLING_METHOD)

* To send a broadcast signal you must call send method anywhere passing signal
name and sender as arguments. If necessary you can pass another parameters in
\*\*kwargs. As you can see below:

.. code-block:: python

from colab.signals.signals import send

send(signal_name, sender)

* If you want to run celery manually to make some tests, you should execute:

.. code-block:: shell

colab-admin celeryC worker --loglevel=debug

Search
----------

In order to make some plugin model's searchable, it is necessary to create
some files. First of all, it is necessary to create a directory named "search"
inside the templates directory, that should be found on the plugin root
directory.

Once the search folder exist, it is necessary to create a html file that will
describe how a model item will be displayed on the colab search page. This file
name must follow the pattern:

MODELNAME_search_preview.html

Where the MODELNAME should be the name of the model object that will be
represented on the html file. An example for this file can be seen bellow:

.. code-block:: guess

{% load i18n tz highlight gravatar date_format %}




{% if query %}

{% highlight result.name with query %}


{% else %}

{{ result.name }}


{% endif %}


{% trans "Since" %}: {% date_format result.date_joined %}

{% trans "Registered in" %}: {% trans "User" %}






As can be seen in the above example, it also possible to highlight the elements being searched. This can be seen on
the following example:

.. code-block:: html

{% if query %}

{% highlight result.name with query %}


{% else %}

{{ result.name }}


{% endif %}

It can be seen that if a query text was used on the search, it will highlight the element if it is present on the query, if not,
the element will be displayed without a highlight. Therefore, in order to highlight some fields, it is necessary
to first check if there is a query search. If there is, use the tag "highlight" before the field name. However, it
must be said that the highlight tag should be followed by a complement, such as "with query", as can be seen on the example
above. This complement is used to allow the highlight only if the attribute is actually present on the query used to perform a search.

Also a another file that must be created is the search_index.py one. This file
must be placed at the plugin root directory. This file dictates how haystack
will index the plugins models. If there is any doubt about how to create this
file, it's possible to check the official haystack documentation that can be
seen on the bellow link.

`Guide to create a SearchIndexesFiles`_

.. _`Guide to create a SearchIndexesFiles`: http://django-haystack.readthedocs.org/en/v2.4.0/tutorial.html#creating-searchindexes

It can also be seen in the guide above that an indexes directory should be
created. This directory should be placed inside the search directory originally
created in this tutorial. Inside this directory, create a txt file for each
model that can be queried. Each of this files must contain the model fields that
will be search if no filter is applied. If there is any doubts to create these
files, please check the `Guide to create a SearchIndexesFiles`_.

Storing TimeStamp
---------------
TimeStamp is a parameter to control the last time a model was updated, you should use it
when you want the data updated after a given time. To do that the colab's model (colab.plugins.models) have a
TimeStampPlugin class, used to store all last updates from timestamp from all plugins.

Class Methods:
update_timestamp(cls,class_name): allow store a current datetime.

get_last_updated_timestamp(cls,class_name): allow get a datetime with last timestamp stored from class_name.

Example Usage:

.. code-block:: python
from colab.plugins.models import TimeStampPlugin

class TestPlugin():

def update_timestamp(self):
TimeStampPlugin.update_timestamp('TestPlugin')

def get_last_updated_timestamp(self):
return TimeStampPlugin.get_last_updated_timestamp('TestPlugin')

Password Validation
-------------------

Allows the plugin to define rules to set the password. The validators
are functions which receive the password as only argument and if it
doesn't match the desired rules raises a `ValidationError`. The message
sent in the validation error will be displayed to user in the HTML form.

Example:

.. code-block:: python

## myplugin/password_validators.py

def has_uppercase_char(password):
for char in password:
if char.isupper():
return

raise ValidationError('Password must have at least one upper case char')

## /etc/colab/plugins.d/myplugin.py

password_validators = (
'myplugin.password_validators.has_uppercase_char',
)