mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Documentation updated.
This commit is contained in:
@@ -21,4 +21,3 @@ Table of contents
|
||||
|
||||
contributing/getting_started
|
||||
contributing/plugin_api
|
||||
contributing/events
|
||||
|
||||
@@ -1,907 +0,0 @@
|
||||
.. _events:
|
||||
|
||||
################
|
||||
Available events
|
||||
################
|
||||
|
||||
************
|
||||
Introduction
|
||||
************
|
||||
|
||||
Modoboa provides a simple API to interact with events. It understands
|
||||
two kinds of events:
|
||||
|
||||
* Those returning a value
|
||||
* Those returning nothing
|
||||
|
||||
Listening to a specific event is achieved as follows::
|
||||
|
||||
from modoboa.lib import events
|
||||
|
||||
def callback(*args):
|
||||
pass
|
||||
|
||||
events.register('event', callback)
|
||||
|
||||
You can also use the custom decorator ``events.observe``::
|
||||
|
||||
@events.observe('event')
|
||||
def callback(*args):
|
||||
pass
|
||||
|
||||
``event`` is the event's name you want to listen to, ``callback`` is
|
||||
the function that will be called each time this event is raised. Each
|
||||
event impose to callbacks a specific prototype to respect. See below
|
||||
for a detailled list.
|
||||
|
||||
To stop listening to as specific event, you must use the
|
||||
``unregister`` function::
|
||||
|
||||
events.unregister('event', callback)
|
||||
|
||||
The parameters are the same than those used with ``register``.
|
||||
|
||||
To unregister all events declared by a specific extension, use the
|
||||
``unregister_extension`` function::
|
||||
|
||||
events.unregister_extension([name])
|
||||
|
||||
``name`` is the extension's name but it is optional. Leave it empty to
|
||||
let the function guess the name.
|
||||
|
||||
Read further to get a complete list and description of all available events.
|
||||
|
||||
****************
|
||||
Supported events
|
||||
****************
|
||||
|
||||
AccountAutoCreated
|
||||
==================
|
||||
|
||||
Raised when a new account is automatically created (example: LDAP
|
||||
synchronization).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account): pass
|
||||
|
||||
* ``account`` is the newly created account (``User`` instance)
|
||||
|
||||
AccountCreated
|
||||
==============
|
||||
|
||||
Raised when a new account is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account): pass
|
||||
|
||||
* ``account`` is the newly created account (``User`` instance)
|
||||
|
||||
AccountDeleted
|
||||
==============
|
||||
|
||||
Raised when an existing account is deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account, byuser, **options): pass
|
||||
|
||||
* ``account`` is the account that is going to be deleted
|
||||
* ``byuser`` is the adminstrator deleting ``account``
|
||||
|
||||
AccountExported
|
||||
===============
|
||||
|
||||
Raised when an account is exported to CSV.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account): pass
|
||||
|
||||
* ``account`` is the account being exported
|
||||
|
||||
Must return a list of values to include in the export.
|
||||
|
||||
AccountImported
|
||||
===============
|
||||
|
||||
Raised when an account is imported from CSV.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, account, row): pass
|
||||
|
||||
* ``user`` is the user importing the account
|
||||
* ``account`` is the account being imported
|
||||
* ``row`` is a list containing what remains from the CSV definition
|
||||
|
||||
AccountModified
|
||||
===============
|
||||
|
||||
Raised when an existing account is modified.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(oldaccount, newaccount): pass
|
||||
|
||||
* ``oldaccount`` is the account before it is modified
|
||||
|
||||
* ``newaccount`` is the account after the modification
|
||||
|
||||
AdminMenuDisplay
|
||||
================
|
||||
|
||||
Raised when an admin menu is about to be displayed.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(target, user): pass
|
||||
|
||||
The ``target`` argument indicates which menu is being
|
||||
displayed. Possible values are:
|
||||
|
||||
* ``admin_menu_box`` : corresponds to the menu bar available inside administration pages
|
||||
* ``top_menu`` : corresponds to the top black bar
|
||||
|
||||
See :ref:`usermenudisplay` for a description of what callbacks that
|
||||
listen to this event must return.
|
||||
|
||||
CheckDomainName
|
||||
===============
|
||||
|
||||
Raised before the unicity of a domain name is checked. By default,
|
||||
modoboa prevents duplicate names between domains and domain aliases
|
||||
but extensions have the possibility to extend this rule using this
|
||||
event.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(): pass
|
||||
|
||||
Must return a list of 2uple, each one containing a model class and an
|
||||
associated label.
|
||||
|
||||
.. _event_checkextraaccountform:
|
||||
|
||||
CheckExtraAccountForm
|
||||
=====================
|
||||
|
||||
When an account is being modified, this event lets extensions check if
|
||||
this account is concerned by a specific form.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account, form): pass
|
||||
|
||||
* ``account`` is the ``User`` instance beeing modified
|
||||
|
||||
* ``form`` is a dictionnary (same content as for ``ExtraAccountForm``)
|
||||
|
||||
Callbacks listening to this event must return a list containing one
|
||||
Boolean.
|
||||
|
||||
DomainAliasCreated
|
||||
==================
|
||||
|
||||
Raised when a new domain alias is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, domain_alias): pass
|
||||
|
||||
* ``user`` is the new domain alias owner (``User`` instance)
|
||||
* ``domain_alias`` is the new domain alias (``DomainAlias`` instance)
|
||||
|
||||
DomainAliasDeleted
|
||||
==================
|
||||
|
||||
Raised when an existing domain alias is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(domain_alias): pass
|
||||
|
||||
* ``domain_alias`` is a ``DomainAlias`` instance
|
||||
|
||||
DomainCreated
|
||||
=============
|
||||
|
||||
Raised when a new domain is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, domain): pass
|
||||
|
||||
* ``user`` corresponds to the ``User`` object creating the domain (its owner)
|
||||
* ``domain`` is a ``Domain`` instance
|
||||
|
||||
DomainDeleted
|
||||
=============
|
||||
|
||||
Raised when an existing domain is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(domain): pass
|
||||
|
||||
* ``domain`` is a ``Domain`` instance
|
||||
|
||||
DomainModified
|
||||
==============
|
||||
|
||||
Raised when a domain has been modified.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(domain): pass
|
||||
|
||||
* ``domain`` is the modified ``Domain`` instance, it contains an extra
|
||||
``oldname`` field which contains the old name
|
||||
|
||||
DomainOwnershipRemoved
|
||||
======================
|
||||
|
||||
Raised before the ownership of a domain is removed from its original
|
||||
creator.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(owner, domain): pass
|
||||
|
||||
* ``owner`` is the original creator
|
||||
* ``domain`` is the ``Domain`` instance being modified
|
||||
|
||||
ExtraAccountActions
|
||||
===================
|
||||
|
||||
Raised when the account list is displayed. Let developers define new
|
||||
actions to act on a specific user.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account): pass
|
||||
|
||||
* ``account`` is the account being listed
|
||||
|
||||
.. _event_extraaccountform:
|
||||
|
||||
ExtraAccountForm
|
||||
================
|
||||
|
||||
Let extensions add new forms to the account edition form (the one with
|
||||
tabs).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, account): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``account`` is the account beeing modified (``User`` instance)
|
||||
|
||||
Callbacks listening to the event must return a list of dictionnaries,
|
||||
each one must contain at least three keys::
|
||||
|
||||
{"id" : "<the form's id>",
|
||||
"title" : "<the title used to present the form>",
|
||||
"cls" : TheFormClassName}
|
||||
|
||||
ExtraAdminContent
|
||||
=================
|
||||
|
||||
Let extensions add extra content into the admin panel.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, target, currentpage): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``target`` is a string indicating the place where the content will
|
||||
be displayed. Possible values are : ``leftcol``
|
||||
|
||||
* ``currentpage`` is a string indicating which page (or section) is
|
||||
displayed. Possible values are : ``domains``, ``identities``
|
||||
|
||||
Callbacks listening to this event must return a list of string.
|
||||
|
||||
ExtraDomainEntries
|
||||
==================
|
||||
|
||||
Raised to request extra entries to display inside the *domains*
|
||||
listing.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, domfilter, searchquery, **extrafilters): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``domfilter`` is a string indicating which domain type the user needs
|
||||
* ``searchquery`` is a string containing a search query
|
||||
* ``extrafilters`` is a set of keyword arguments that may contain additional filters
|
||||
|
||||
Must return a valid ``QuerySet``.
|
||||
|
||||
ExtraDomainFilters
|
||||
==================
|
||||
|
||||
Raised to request extra filters for the *domains* listing page. For
|
||||
example, the *postfix_relay_domains* extension let users filter
|
||||
entries based on service types.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(): pass
|
||||
|
||||
Must return a list of valid filter names (string).
|
||||
|
||||
.. _event_extradomainform:
|
||||
|
||||
ExtraDomainForm
|
||||
===============
|
||||
|
||||
Let extensions add new forms to the domain edition form (the one with
|
||||
tabs).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, domain): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``domain`` is the domain beeing modified (``Domain`` instance)
|
||||
|
||||
Callbacks listening to the event must return a list of dictionnaries,
|
||||
each one must contain at least three keys::
|
||||
|
||||
{"id" : "<the form's id>",
|
||||
"title" : "<the title used to present the form>",
|
||||
"cls" : TheFormClassName}
|
||||
|
||||
ExtraDomainImportHelp
|
||||
=====================
|
||||
|
||||
Raised to request extra help text to display inside the domain import
|
||||
form.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(): pass
|
||||
|
||||
Must return a list a string.
|
||||
|
||||
ExtraDomainMenuEntries
|
||||
======================
|
||||
|
||||
Raised to request extra entries to include in the left menu of the
|
||||
*domains* listing page.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
Must return a list of dictionaries. Each dictionary must contain at
|
||||
least three keys::
|
||||
|
||||
{"name": "<menu name>",
|
||||
"label": "<menu label>",
|
||||
"url": "<menu url>"}
|
||||
|
||||
.. _extraformfields:
|
||||
|
||||
ExtraFormFields
|
||||
===============
|
||||
|
||||
Raised to request extra fields to include in a django form.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(form_name, instance=None): pass
|
||||
|
||||
* ``form_name`` is a string used to distinguish a specific form
|
||||
* ``instance`` is a django model instance related to ``form_name``
|
||||
|
||||
Must return a list of 2uple, each one containing the following
|
||||
information::
|
||||
|
||||
('field name', <Django form field instance>)
|
||||
|
||||
ExtraRelayDomainForm
|
||||
====================
|
||||
|
||||
Let extensions add new forms to the relay domain edition form (the one
|
||||
with tabs).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, rdomain): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``rdomain`` is the relay domain being modified (``RelayDomain`` instance)
|
||||
|
||||
Callbacks listening to the event must return a list of dictionnaries,
|
||||
each one must contain at least three keys::
|
||||
|
||||
{"id" : "<the form's id>",
|
||||
"title" : "<the title used to present the form>",
|
||||
"cls" : TheFormClassName}
|
||||
|
||||
.. _event_fillaccountinstances:
|
||||
|
||||
FillAccountInstances
|
||||
====================
|
||||
|
||||
When an account is beeing modified, this event is raised to fill extra
|
||||
forms.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, account, instances): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``account`` is the ``User`` instance beeing modified
|
||||
|
||||
* ``instances`` is a dictionnary where the callback will add
|
||||
information needed to fill a specific form
|
||||
|
||||
.. _event_filldomaininstances:
|
||||
|
||||
FillDomainInstances
|
||||
===================
|
||||
|
||||
When a domain is beeing modified, this event is raised to fill extra
|
||||
forms.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, domain, instances): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``domain`` is the ``Domain`` instance beeing modified
|
||||
|
||||
* ``instances`` is a dictionnary where the callback will add
|
||||
information needed to fill a specific form
|
||||
|
||||
FillRelayDomainInstances
|
||||
========================
|
||||
|
||||
When a relay domain is being modified, this event is raised to fill extra
|
||||
forms.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, rdomain, instances): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
* ``rdomain`` is the ``RelayDomain`` instance being modified
|
||||
|
||||
* ``instances`` is a dictionnary where the callback will add
|
||||
information needed to fill a specific form
|
||||
|
||||
GetAnnouncement
|
||||
===============
|
||||
|
||||
Some places in the interface let plugins add their own announcement
|
||||
(ie. message).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(target): pass
|
||||
|
||||
* ``target`` is a string indicating the place where the announcement
|
||||
will appear:
|
||||
|
||||
* ``loginpage`` : corresponds to the login page
|
||||
|
||||
Callbacks listening to this event must return a list of string.
|
||||
|
||||
GetDomainActions
|
||||
================
|
||||
|
||||
Raised to request the list of actions available for the *domains*
|
||||
listing entry being displayed.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, rdomain): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``rdomain`` is the ``RelayDomain`` instance being displayed
|
||||
|
||||
Must return a list of dictionaries, each dictionary containing at
|
||||
least the following entries::
|
||||
|
||||
{"name": "<action name>",
|
||||
"url": "<action url>",
|
||||
"title": "<action title>",
|
||||
"img": "<action icon>"}
|
||||
|
||||
GetDomainModifyLink
|
||||
===================
|
||||
|
||||
Raised to request the modification url of the *domains* listing entry
|
||||
being displayed.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(domain): pass
|
||||
|
||||
* ``domain`` is a model instance (``RelayDomain`` for example)
|
||||
|
||||
Must return a dictionary containing at least the following entry::
|
||||
|
||||
{'url': '<modification url>'}
|
||||
|
||||
GetExtraLimitTemplates
|
||||
======================
|
||||
|
||||
Raised to request extra limit templates. For example, the
|
||||
*postfix_relay_domains* extension define a template to limit the
|
||||
number of relay domains an administrator can create.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(): pass
|
||||
|
||||
Must return a list of set. Each set must contain at least three entries::
|
||||
|
||||
[('<limit_name>', '<limit label>', '<limit help text>')]
|
||||
|
||||
.. _getextrarolepermissions:
|
||||
|
||||
GetExtraRolePermissions
|
||||
=======================
|
||||
|
||||
Let extensions define new permissions for a given role.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(rolename): pass
|
||||
|
||||
* ``rolename`` is the role's name (str)
|
||||
|
||||
Callbacks listening to this event must return a list of list. The
|
||||
second list level must contain exactly 3 strings: the application
|
||||
name, the model name and the permission name. Example::
|
||||
|
||||
[
|
||||
["core", "user", "add_user"],
|
||||
["core", "user", "change_user"],
|
||||
["core", "user", "delete_user"],
|
||||
]
|
||||
|
||||
.. _getextraroles:
|
||||
|
||||
GetExtraRoles
|
||||
=============
|
||||
|
||||
Let extensions define new administrative roles (will be used to create
|
||||
or modify an account).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, account): pass
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``account`` is the account being modified (None on creation)
|
||||
|
||||
Callbacks listening to this event must return a list of 2uple (two
|
||||
strings) which respect the following format: ``(value, label)``.
|
||||
|
||||
GetStaticContent
|
||||
================
|
||||
|
||||
Let extensions add static content (ie. CSS or javascript) to default
|
||||
pages. It is pretty useful for functionalities that don't need a
|
||||
template but need javascript stuff.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(caller, st_type, user): pass
|
||||
|
||||
* ``caller`` is name of the application (or the location) responsible
|
||||
for the call
|
||||
|
||||
* ``st_type`` is the expected static content type (``css`` or ``js``)
|
||||
|
||||
* ``user`` is a ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
|
||||
Callbacks listening to this event must return a list of string.
|
||||
|
||||
ImportObject
|
||||
============
|
||||
|
||||
Raised to request the function handling an object being imported from CSV.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(objtype): pass
|
||||
|
||||
``objtype`` is the type of object being imported
|
||||
|
||||
Must return a list of function. A valid import function must respect
|
||||
the following prototype::
|
||||
|
||||
def import_function(user, row, formopts): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``row`` is a string containing the object's definition (CSV format)
|
||||
* ``formopts`` is a dictionary that may contain options
|
||||
|
||||
InitialDataLoaded
|
||||
=================
|
||||
|
||||
Raised a initial data has been loaded for a given extension.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(extname); pass
|
||||
|
||||
``extname`` is the extension name (str)
|
||||
|
||||
MailboxAliasCreated
|
||||
===================
|
||||
|
||||
Raised when a new mailbox alias is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, mailbox_alias): pass
|
||||
|
||||
* ``user`` is the new domain alias owner (``User`` instance)
|
||||
* ``mailbox_alias`` is the new mailbox alias (``Alias`` instance)
|
||||
|
||||
MailboxAliasDeleted
|
||||
===================
|
||||
|
||||
Raised when an existing mailbox alias is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(mailbox_alias): pass
|
||||
|
||||
* ``mailbox_alias`` is an ``Alias`` instance
|
||||
|
||||
MailboxCreated
|
||||
==============
|
||||
|
||||
Raised when a new mailbox is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, mailbox): pass
|
||||
|
||||
* ``user`` is the new mailbox's owner (``User`` instance)
|
||||
* ``mailbox`` is the new mailbox (``Mailbox`` instance)
|
||||
|
||||
MailboxDeleted
|
||||
==============
|
||||
|
||||
Raised when an existing mailbox is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(mailbox): pass
|
||||
|
||||
* ``mailbox`` is a ``Mailbox`` instance
|
||||
|
||||
MailboxModified
|
||||
===============
|
||||
|
||||
Raised when an existing mailbox is modified.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(mailbox): pass
|
||||
|
||||
* ``mailbox`` is the ``Mailbox`` modified instance. It contains a
|
||||
``old_full_address`` extra field to check if the address was
|
||||
modified.
|
||||
|
||||
PasswordChange
|
||||
==============
|
||||
|
||||
Raised just before a *password change* action.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user): pass
|
||||
|
||||
* ``user`` is a ``User`` instance
|
||||
|
||||
Callbacks listening to this event must return a list containing either
|
||||
``True`` or ``False``. If at least one ``True`` is returned, the
|
||||
*password change* will be cancelled (ie. changing the password for
|
||||
this user is disabled).
|
||||
|
||||
TopNotifications
|
||||
================
|
||||
|
||||
Lets extensions subscribe to the global notification service (located
|
||||
inside the top bar).
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, include_all): pass
|
||||
|
||||
* ``request`` is a ``Request`` instance
|
||||
* ``include_all`` is a boolean indicating if empty notifications must
|
||||
be included into the result or not
|
||||
|
||||
Callbacks listening to this event must return a list of dictionary,
|
||||
each dictionary containing at least the following entries::
|
||||
|
||||
{"id": "<notification entry ID>",
|
||||
"url": "<associated URL>",
|
||||
"text": "<text to display>"}
|
||||
|
||||
If your notification needs a counter, you can specify it by adding the
|
||||
two following entries in the dictionary:
|
||||
|
||||
{"counter": <associated counter>,
|
||||
"level": "<info|success|warning|error>"}
|
||||
|
||||
UserLogin
|
||||
=========
|
||||
|
||||
Raised when a user logs in.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(request, username, password): pass
|
||||
|
||||
UserLogout
|
||||
==========
|
||||
|
||||
Raised when a user logs out.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(request): pass
|
||||
|
||||
.. _usermenudisplay:
|
||||
|
||||
UserMenuDisplay
|
||||
===============
|
||||
|
||||
Raised when a user menu is about to be displayed.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(target, user): pass
|
||||
|
||||
The ``target`` argument indicates which menu is being
|
||||
displayed. Possible values are:
|
||||
|
||||
* ``options_menu``: corresponds to the top-right user menu
|
||||
* ``uprefs_menu``: corresponds to the menu bar available inside the
|
||||
*User preferences* page
|
||||
* ``top_menu``: corresponds to the top black bar
|
||||
|
||||
All the callbacks that listen to this event must return a list of
|
||||
dictionnaries (corresponding to menu entries). Each dictionnary must
|
||||
contain at least the following keys::
|
||||
|
||||
{"name" : "a_name_without_spaces",
|
||||
"label" : _("The menu label"),
|
||||
"url" : reverse("your_view")}
|
||||
|
||||
RelayDomainAliasCreated
|
||||
=======================
|
||||
|
||||
Raised when a new relay domain alias is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, rdomain_alias): pass
|
||||
|
||||
* ``user`` is the new relay domain alias owner (``User`` instance)
|
||||
* ``rdomain_alias`` is the new relay domain alias (``DomainAlias`` instance)
|
||||
|
||||
RelayDomainAliasDeleted
|
||||
=======================
|
||||
|
||||
Raised when an existing relay domain alias is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(rdomain_alias): pass
|
||||
|
||||
* ``rdomain_alias`` is a ``RelayDomainAlias`` instance
|
||||
|
||||
RelayDomainCreated
|
||||
==================
|
||||
|
||||
Raised when a new relay domain is created.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, rdomain): pass
|
||||
|
||||
* ``user`` corresponds to the ``User`` object creating the relay domain (its owner)
|
||||
* ``rdomain`` is a ``RelayDomain`` instance
|
||||
|
||||
RelayDomainDeleted
|
||||
==================
|
||||
|
||||
Raised when an existing relay domain is about to be deleted.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(rdomain): pass
|
||||
|
||||
* ``rdomain`` is a ``RelayDomain`` instance
|
||||
|
||||
RelayDomainModified
|
||||
===================
|
||||
|
||||
Raised when a relay domain has been modified.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(rdomain): pass
|
||||
|
||||
* ``rdomain`` is the modified ``RelayDomain`` instance, it contains an
|
||||
extra ``oldname`` field which contains the old name
|
||||
|
||||
RoleChanged
|
||||
===========
|
||||
|
||||
Raised when the role of an account is about to be changed.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(account, role): pass
|
||||
|
||||
* ``account`` is the account being modified
|
||||
* ``role`` is the new role (string)
|
||||
|
||||
SaveExtraFormFields
|
||||
===================
|
||||
|
||||
Raised to save extra fields declared using :ref:`extraformfields`.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(form_name, instance, values): pass
|
||||
|
||||
* ``form_name`` is a string used to distinguish a specific form
|
||||
* ``instance`` is a django model instance related to ``form_name``
|
||||
* ``values`` is a dictionary containing the form's values
|
||||
|
||||
UserCanSetRole
|
||||
==============
|
||||
|
||||
Raised to check if a user is allowed to set a given role to an
|
||||
account.
|
||||
|
||||
*Callback prototype*::
|
||||
|
||||
def callback(user, role, account): pass
|
||||
|
||||
* ``user`` is the ``User`` instance corresponding to the currently
|
||||
logged in user
|
||||
* ``role`` is the role ``user`` tries to set
|
||||
* ``account`` is the account being modified (None on creation)
|
||||
|
||||
Must return a list containing ``True`` or ``False`` to indicate if
|
||||
this user can is allowed to set ``role``.
|
||||
@@ -19,12 +19,11 @@ of code that integrates them into Modoboa. The
|
||||
the plugin:
|
||||
|
||||
* Admin and user parameters
|
||||
* Observed events
|
||||
* Custom menu entries
|
||||
|
||||
The communication between both applications is provided by
|
||||
:ref:`events`. Modoboa offers some kind of hooks to let plugins add
|
||||
custom actions.
|
||||
The communication between both applications is provided by `Django
|
||||
signals
|
||||
<https://docs.djangoproject.com/en/1.9/topics/signals/>`_.
|
||||
|
||||
The following subsections describe the plugin architecture and explain
|
||||
how you can create your own.
|
||||
@@ -81,7 +80,7 @@ Parameters
|
||||
|
||||
A plugin can declare its own parameters. There are two levels available:
|
||||
|
||||
* 'Administration' parameters : used to configure the plugin, editable
|
||||
* 'Global' parameters : used to configure the plugin, editable
|
||||
inside the *Admin > Settings > Parameters* page
|
||||
* 'User' parameters : per-user parameters (or preferences), editable
|
||||
inside the *Options > Preferences* page
|
||||
@@ -89,100 +88,118 @@ A plugin can declare its own parameters. There are two levels available:
|
||||
Playing with parameters
|
||||
=======================
|
||||
|
||||
To declare a new administration parameter, use the following function::
|
||||
Parameters are defined using `Django forms
|
||||
<https://docs.djangoproject.com/en/1.9/topics/forms/>`_ and Modoboa
|
||||
adds two special forms you can inherit depending on the level of
|
||||
parameter(s) you want to add:
|
||||
|
||||
from modoboa.lib import parameters
|
||||
* ``modoboa.parameters.forms.AdminParametersForm``: for general parameters
|
||||
|
||||
parameters.register_admin(name, **kwargs)
|
||||
* ``modoboa.parameters.forms.UserParametersForm``: for user parameters
|
||||
|
||||
To declare a new user parameter, use the following function::
|
||||
To register new parameters, add the following line into the ``load``
|
||||
method of your plugin class::
|
||||
|
||||
parameter.register_user(name, **kwargs)
|
||||
from modoboa.parameters import tools as param_tools
|
||||
param_tools.registry.add(
|
||||
LEVEL, YourForm, ugettext_lazy("Title"))
|
||||
|
||||
Both functions accept extra arguments listed here:
|
||||
Replace ``LEVEL`` by ``"global"`` or ``"user"``.
|
||||
|
||||
* ``type`` : parameter's type, possible values are : ``int``, ``string``, ``list``, ``list_yesno``,
|
||||
* ``deflt`` : default value,
|
||||
* ``help`` : help text,
|
||||
* ``values`` : list of possible values if ``type`` is ``list``.
|
||||
|
||||
***************************
|
||||
Custom administrative roles
|
||||
***************************
|
||||
***********************
|
||||
Custom role permissions
|
||||
***********************
|
||||
|
||||
Modoboa uses Django's internal permission system. Administrative roles
|
||||
are nothing more than groups (``Group`` instances).
|
||||
|
||||
If an extension needs to add new roles, the following steps are required:
|
||||
An extension can add new permissions to a group by listening to the
|
||||
``extra_role_permissions`` signal. Here is an example:
|
||||
|
||||
#. Listen to the :ref:`getextraroles` event that will return
|
||||
the group's name
|
||||
.. sourcecode:: python
|
||||
|
||||
#. Listen to the :ref:`getextrarolepermissions` event that will return
|
||||
the new group's permissions
|
||||
from django.dispatch import receiver
|
||||
from modoboa.core import signals as core_signals
|
||||
|
||||
The group will automatically be created the next time you run the
|
||||
``load_initial_data`` command.
|
||||
PERMISSIONS = {
|
||||
"Resellers": [
|
||||
("relaydomains", "relaydomain", "add_relaydomain"),
|
||||
("relaydomains", "relaydomain", "change_relaydomain"),
|
||||
("relaydomains", "relaydomain", "delete_relaydomain"),
|
||||
("relaydomains", "service", "add_service"),
|
||||
("relaydomains", "service", "change_service"),
|
||||
("relaydomains", "service", "delete_service")
|
||||
]
|
||||
}
|
||||
|
||||
@receiver(core_signals.extra_role_permissions)
|
||||
def extra_role_permissions(sender, role, **kwargs):
|
||||
"""Add permissions to the Resellers group."""
|
||||
return constants.PERMISSIONS.get(role, [])
|
||||
|
||||
*********************
|
||||
Extending admin forms
|
||||
*********************
|
||||
|
||||
the forms used to edit objects (account, domain, etc.) through the admin
|
||||
panel are composed of tabs. You can extend those forms (ie. add new
|
||||
tabs) in a pretty easy way by defining events.
|
||||
The forms used to edit objects (account, domain, etc.) through the admin
|
||||
panel are composed of tabs. You can extend them (ie. add new
|
||||
tabs) in a pretty easy way thanks to custom signals.
|
||||
|
||||
Account
|
||||
=======
|
||||
|
||||
To add a new tab to the account edition form, define new listeners
|
||||
(handlers) for the following events:
|
||||
(handlers) for the following signals:
|
||||
|
||||
* :ref:`event_extraaccountform`
|
||||
* ``modoboa.admin.signals.extra_account_forms``
|
||||
|
||||
* :ref:`event_fillaccountinstances`
|
||||
* ``modoboa.admin.signals.get_account_form_instances``
|
||||
|
||||
* :ref:`event_checkextraaccountform` (optional)
|
||||
* ``modoboa.admin.signals.check_extra_account_form`` (optional)
|
||||
|
||||
Example:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from modoboa.lib import events
|
||||
from django.dispatch import receiver
|
||||
from modoboa.admin import signals as admin_signals
|
||||
|
||||
@events.observe("ExtraAccountForm")
|
||||
def extra_account_form(user, account=None):
|
||||
|
||||
@receiver(admin_signals.extra_account_forms)
|
||||
def extra_account_form(sender, user, account, **kwargs):
|
||||
return [
|
||||
{"id": "tabid", "title": "Title", "cls": MyFormClass}
|
||||
]
|
||||
|
||||
@events.observe("FillAccountInstances")
|
||||
def fill_my_tab(user, account, instances):
|
||||
instances["id"] = my_instance
|
||||
|
||||
@receiver(admin_signals.get_account_form_instances)
|
||||
def fill_my_tab(sender, user, account, **kwargs):
|
||||
return {"id": my_instance}
|
||||
|
||||
|
||||
Domain
|
||||
======
|
||||
|
||||
To add a new tab to the domain edition form, define new listeners
|
||||
(handlers) for the following events:
|
||||
(handlers) for the following signals:
|
||||
|
||||
* :ref:`event_extradomainform`
|
||||
* ``modoboa.admin.signals.extra_domain_forms``
|
||||
|
||||
* :ref:`event_filldomaininstances`
|
||||
* ``modoboa.admin.signals.get_domain_form_instances``
|
||||
|
||||
Example:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
from modoboa.lib import events
|
||||
from django.dispatch import receiver
|
||||
from modoboa.admin import signals as admin_signals
|
||||
|
||||
@events.observe("ExtraDomainForm")
|
||||
def extra_domain_form(user, domain):
|
||||
|
||||
@receiver(admin_signals.extra_domain_forms)
|
||||
def extra_account_form(sender, user, domain, **kwargs):
|
||||
return [
|
||||
{"id": "tabid", "title": "Title", "cls": MyFormClass}
|
||||
]
|
||||
|
||||
@events.observe("FillDomainInstances")
|
||||
def fill_my_tab(user, domain, instances):
|
||||
instances["id"] = my_instance
|
||||
@receiver(admin_signals.get_domain_form_instances)
|
||||
def fill_my_tab(sender, user, domain, **kwargs):
|
||||
return {"id": my_instance}
|
||||
|
||||
Reference in New Issue
Block a user