From edac9e71984fe37ccbc7973598a759bedce7e70f Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Sat, 28 Jan 2012 11:32:39 +0100 Subject: [PATCH] Documentation update. --- INSTALL | 28 +++- doc/plugin_api.rst | 373 +++++++++++++++++++++++++++++++++++---------- lib/events.py | 1 - 3 files changed, 317 insertions(+), 85 deletions(-) diff --git a/INSTALL b/INSTALL index 7093f3e46..8f958d161 100644 --- a/INSTALL +++ b/INSTALL @@ -43,13 +43,19 @@ need to install a python database backend (like *MySQLdb*). Initialize the database by running the following command:: - $ python manage.py syncdb --migrate - -It will let you create the default super administrator. + $ python manage.py syncdb --migrate --noinput Since version 0.8, Modoboa uses *south* to handle schema migrations, this is the reason why you must add the ``--migrate`` option. +At the end of this command, a default super administrator is +available: + + * Username: admin + * Password: password + +You may change its password the first time you log into Modoboa. + Finally, create the ``scripts`` directory:: $ mkdir scripts @@ -83,6 +89,12 @@ Throught the *Admin > Configuration* panel, you can customize the way Modoboa stores mailboxes on the filesystem. Here is the list of editable parameters with their default value:: + The authentication type + AUTHENTICATION_TYPE = Local + + Does Modoboa need to handle the creation of directories on the file system? + CREATE_DIRECTORIES = Yes + Where Modoboa stores mailboxes STORAGE_PATH = /var/vmail @@ -97,12 +109,20 @@ editable parameters with their default value:: potential sub-directory MAILDIR_ROOT = .maildir - Which encryption method is used to store passwords + The encryption method used to store passwords PASSWORD_SCHEME = crypt + The number of displayed items per page for listing pages + ITEMS_PER_PAGE = 30 + Host configuration ------------------ +.. note:: + + You can skip this part in case you set the ``CREATE_DIRECTORIES`` + parameter to ``No``. + Before using Modoboa, you must create a group and a user that will be used to store emails on the host filesystem. There is only one group/user needed because we are in a virtual hosting configuration diff --git a/doc/plugin_api.rst b/doc/plugin_api.rst index 13c1e61ea..e44a99105 100644 --- a/doc/plugin_api.rst +++ b/doc/plugin_api.rst @@ -11,12 +11,12 @@ implementation provides the following possibilities: * Access and modify administrative objects (domains, mailboxes, etc.) * Register callback actions for specific events -Plugins are nothing more than Django applications with an extra file -called ``main.py``. This file contains a complete description of the -plugin: +Plugins are nothing more than Django applications using a specific +structure. The ``__init__.py`` file contains a complete description of +the plugin: * Admin and user parameters -* Registered events +* Observed events * Custom menu entries The communication between both applications is provided by @@ -32,15 +32,19 @@ Adding a custom plugin All Modoboa plugins must be located inside the ``extensions`` directory. To create a new plugin, execute the following steps: -* Run ``python manage.py startapp`` to get some basefiles for your plugin, -* Move the resulting directory inside the ``extensions`` one, -* Create a file called ``main.py`` inside your plugin's directory. +* Run ``python manage.py startapp`` to get some basefiles for your plugin +* Move the resulting directory inside the ``extensions`` one -The last file you created (ie. ``main.py``) must follow a specific -structure in order to be interpreted by Modoboa. The following -functions are mandatory:: +The ``__init__.py`` file created inside your module's directory must +follow a specific structure in order to be interpreted by Modoboa. The +following functions are mandatory:: def init(): + """This function is called when the extension is activated. + """ + pass + + def load(): """This function is called when Modoboa loads available and activated plugins. Declare parameters and register events here. @@ -67,20 +71,9 @@ functions are mandatory:: "description" : "Example description" } - def urls(prefix): - """This function is used to update the global urls table. - - It must return a sequence that corresponds to those used - inside the main ``urls.py`` file. (ie. a classical - Django construction) - - :param prefix: the global url prefix (the part after the hostname) - """ - return (r'^%sexample/' % prefix, include('modoboa.extensions.example.urls')) - -Once you have filled ``main.py``, simply add your plugin's name to the -``INSTALLED_APPS`` variable located inside ``settings.py``. (use the -same format as other plugins). Eventually, run ``python manage.py +Once you have filled ``__init__.py``, simply add your plugin's name to +the ``INSTALLED_APPS`` variable located inside ``settings.py``. (use +the same format as other plugins). Eventually, run ``python manage.py syncdb`` if your plugin provides custom tables. Events @@ -92,59 +85,77 @@ Playing with events Modoboa provides a simple API to interact with events. It understands two kinds of events: -* Those that return a value, -* Those that return nothing. +* Those that return a value +* Those that return nothing Listening to a specific event is achieved as follow:: - from modoboa.lib import events + from modoboa.lib import events + + def callback(*args): + pass + + events.register('event', callback) - events.register(event, callback) +You can also use the custom decorator ``events.observe``:: -``event`` is the event's name you want to listen to, ``callback`` is -the function that will be called when this event is raised. Its -prototype must be as follow:: - - def callback(*args, **kwargs): + @events.observe('event') + def callback(*args): pass -It is very generic, it allows events to provide arguments if needed. +``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. -You can also stop listening to an event like this:: +To stop listening to as specific event, you must use the +``unregister`` function:: - events.unregister(event, callback) + events.unregister('event', callback) -The parameters are the same as those used with ``register``. +The parameters are the same than those used with ``register``. -Read further to get a complete list and description of the available events. +Read further to get a complete list and description of all available events. UserLogin --------- -Raised when a user logs in. This event provides a ``request`` argument -that corresponds to the ``Request`` object used inside the associated -view function. +Raised when a user logs in. + +*Callback prototype*:: + + def callback(request, username, password): pass + UserLogout ---------- -Raised when a user logs out. This event provides a ``request`` argument -that corresponds to the ``Request`` object used inside the associated -view function. +Raised when a user logs out. + +*Callback prototype*:: + + def callback(request): pass + .. _usermenudisplay: UserMenuDisplay --------------- -Raised when a user menu is about to be displayed. It provides a -``target`` argument that indicates which menu is being +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: -* ``uprefs_menu`` : corresponds to the menu bar available inside the *User preferences* page +* ``uprefs_menu`` : corresponds to the menu bar available inside the + *User preferences* page * ``top_menu`` : corresponds to the top blue bar -All callbacks that listen to this event must return a list of +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:: @@ -156,8 +167,13 @@ contain at least the following keys:: AdminMenuDisplay ---------------- -Raised when an admin menu is about to be displayed. It provides a -``target`` argument that indicates which menu is being +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 @@ -166,36 +182,187 @@ displayed. Possible values are: See :ref:`usermenudisplay` for a description of what callbacks that listen to this event must return. +AdminFooterDisplay +------------------ + +Raised when the footer (ie. bottom of the page) of listing pages +inside the ``admin`` application is displayed. Plugins can listen to +this event when they want to add specific information into that place. + +*Callback prototype*:: + + def callback(user, object_type): pass + +* ``user`` is a ``User`` instance (the one that is displaying the page) +* ``object_type`` is a string indicating which kind of object is + displayed. Possible values are: + + * ``domains``: a list of domains + * ``domaliases``: a list of domain aliases + * ``mailboxes``: a list of mailboxes + * ``mbaliases``: a list of mailbox aliases + +Registered callbacks must return a list of string objects. + +CanCreateDomain +--------------- + +Raised just before a user tries to access the ``newdomain`` function. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance + +Return ``True`` or ``False`` to indicate if this user can respectively +create or not create a new ``Domain`` object. + CreateDomain ------------ -Raised when a new domain is created. The new domain object is -available inside the ``dom`` argument. +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 DeleteDomain ------------ -Raised when an existing domain is about to be deleted. The domain -object is available inside the ``dom`` argument. +Raised when an existing domain is about to be deleted. + +*Callback prototype*:: + + def callback(domain): pass + +* ``domain`` is a ``Domain`` instance + +CanCreateDomainAlias +-------------------- + +Raised just before a user tries to access the ``newdomalias`` function. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance + +Return ``True`` or ``False`` to indicate that the user can +respectively create or not create a new domain alias. + +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 + +CanCreateMailbox +---------------- + +Raised just before a user tries to access the ``newmailbox`` function. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance + +Return ``True`` or ``False`` to indicate that the user can +respectively create or not create a new mailbox. CreateMailbox ------------- -Raised when a new mailbox is created. The new mailbox object is -available inside the ``mbox`` argument. +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) DeleteMailbox ------------- -Raised when an existing mailbox is about to be deleted. The mailbox -object is available inside the ``mbox`` argument. +Raised when an existing mailbox is about to be deleted. + +*Callback prototype*:: + + def callback(mailbox): pass + +* ``mailbox`` is a ``Mailbox`` instance ModifyMailbox ------------- -Raised when an existing mailbox is modified. The old mailbox and the -new mailbox objects are respectively available inside the ``oldmbox`` -and ``mbox`` arguments. +Raised when an existing mailbox is modified. + +*Callback prototype*:: + + def callback(newmailbox, oldmailbox): pass + +* ``newmailbox`` is a ``Mailbox`` instance containing the new values +* ``oldmailbox`` is a ``Mailbox`` instance containing the old values + +CanCreateMailboxAlias +--------------------- + +Raised just before a user tries to access the ``newmbalias`` function. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance + +Return ``True`` or ``False`` to indicate that the user can +respectively create or not create a new mailbox alias. + +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 .. _permsgettables: @@ -203,8 +370,13 @@ PermsGetTables -------------- Raised when the different permission lists (one per role) are about to -be displayed. The current *User* object is available inside the -``user`` argument. +be displayed. + +*Callback prototype*:: + + def callback(request): pass + +* ``request`` is a ``Request`` instance Callbacks that listen to this event must return a list of dictionnaries (corresponding to tables). Each dictionnary must contain @@ -215,8 +387,8 @@ at least the following elements:: "rel" : "x y", "content" : MyPermClass().get(request)} -For ``rel``, replace x and y with the the *Add form* size (the -one that appears when you click on the ``Add permission`` button. +For ``rel``, replace x and y with the *Add form* size (the one that +appears when you click on the ``Add permission`` button. For ``content``, replace *MyPermClass* with the appropriate name. @@ -227,40 +399,79 @@ PermsGetClass Raised to retrieve the class (inheriting from ``Permissions``) implementing a specific role. This event is used to add or delete or -new instance of this role. The role's name is available inside the -``role`` argument. +new instance of this role. + +*Callback prototype*:: + + def callback(role): pass + +* ``role`` is a string indicating the role beeing added Callbacks listening to this event must return the class object corresponding to the given ``role`` argument. +SuperAdminPromotion +------------------- + +Raised when an existing user becomes a super administrator. Each group +that user belongs to is still available (inside the ``user.groups`` +queryset) at the time the event is raised. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance + ExtEnabled ---------- -Raised just after an extension has been activated. The Extension -object is available inside the ``ext`` keyword argument. +Raised just after an extension has been activated. + +*Callback prototype*:: + + def callback(extension): pass + +* ``extension`` is an ``Extension`` instance ExtDisabled ----------- -Raised just after an extension has been disabled. The Extension -object is available inside the ``ext`` keyword argument. +Raised just after an extension has been disabled. + +*Callback prototype*:: + + def callback(extension): pass + +* ``extension`` is an ``Extension`` instance GetAnnouncement --------------- Some places in the interface let plugins add their own announcement -(ie. message). A keyword argument ``target`` is provided to registered -callbacks and indicates the place where the announcement will appear: +(ie. message). -* ``loginpage`` : corresponds to the login page +*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. PasswordChange -------------- -Raised just before a *password change* action. The associated ``User`` -object is provided inside the ``user`` keyword argument. +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 @@ -272,8 +483,10 @@ Parameters A plugin can declare its own parameters. There are two levels available: -* 'Administration' 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. +* 'Administration' 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. Playing with parameters ----------------------- @@ -308,8 +521,8 @@ Custom permission levels Custom permissions roles can be added to Modoboa. If you to want to integrate the default permissions panel (*Admin > Permissions*), each -role you add must inherit from the ``Permissions`` (file -``admin/permissions.py``) class and implement all its methods. +role you add must inherit from the ``Permissions`` class (see file +``admin/permissions.py``) and implement all its methods. .. note:: See :ref:`permsgettables` and :ref:`permsgetclass` to learn how to diff --git a/lib/events.py b/lib/events.py index 8264375c4..260bca306 100644 --- a/lib/events.py +++ b/lib/events.py @@ -18,7 +18,6 @@ events = [ "CanCreateDomain", "CreateDomain", "DeleteDomain", - "DomainAssigned", "CanCreateDomainAlias", "DomainAliasCreated",