From ccfe16ffd516bf4726fb3dbe0a4babd8281f3d6d Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 16 May 2012 11:11:46 +0200 Subject: [PATCH] * Documentation update * Cleanup --- INSTALL | 97 ++++++- doc/conf.py | 4 +- doc/plugin_api.rst | 256 ++++++++++-------- .../scripts/upgrade_autoreply.py | 31 --- lib/events.py | 1 - 5 files changed, 233 insertions(+), 156 deletions(-) delete mode 100755 extensions/postfix_autoreply/scripts/upgrade_autoreply.py diff --git a/INSTALL b/INSTALL index d78c1a479..c0733d7a8 100644 --- a/INSTALL +++ b/INSTALL @@ -16,8 +16,8 @@ For extensions (mandatories since 0.8.2): - `lxml python module `_ - `pycrypto python module `_ - `rrdtool python binding `_ -- `ckeditor version 3.4.1+ `_ - `sievelib python module `_ +- `ckeditor version 3.4.1+ `_ .. _howtoinstall: @@ -31,7 +31,7 @@ Download the latest Modoboa's tarball and extract it:: $ cd modoboa Then, enter the *modoboa* directory, create a *settings.py* file (you -can use *settings-sample.py* as a model). Specify database relative +can use *settings-sample.py* as an example). Specify database relative informations. You must choose between *MySQL*, *PostgreSQL* or *sqlite*, other types are not supported by major email projects like *postfix* or *dovecot*. @@ -51,15 +51,11 @@ 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 +* Username: admin +* Password: password You may change its password the first time you log into Modoboa. -Finally, create the ``scripts`` directory:: - - $ mkdir scripts - Time zone and language ---------------------- @@ -192,8 +188,8 @@ Then, all you have to do is to modify the `settings.py` file: AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', + 'modoboa.lib.authbackends.SimpleBackend', 'django.contrib.auth.backends.ModelBackend', - 'modoboa.lib.authbackends.SimpleBackend' ) * Set the required parameters to establish the communication with your @@ -253,12 +249,76 @@ requires a migration. 0.9: global UI refactoring, new *limits* extension and more ----------------------------------------------------------- +.. note:: + Many files have been renamed/removed for this version. I recommend + that you backup important files (*settings.py*, etc.) elsewhere + (ie. */tmp* for example). Then, remove the *modoboa* directory, + extract the new tarball at the same place, rename the new directory + to *modoboa* and copy the files you've just backup into it. +.. note:: + If the first super administrator you created is named ``admin``, + its password will be changed to ``password`` at the end of this + upgrade. Don't forget to modify it! + +#. Edit the *settings.py* file and update the following variables + (just copy/paste their new content):: + + MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'modoboa.lib.middleware.AjaxLoginRedirect', + 'modoboa.lib.middleware.CommonExceptionCatcher', + 'modoboa.lib.middleware.ExtControlMiddleware', + ) + + AUTHENTICATION_BACKENDS = ( + 'modoboa.lib.authbackends.SimpleBackend', + 'django.contrib.auth.backends.ModelBackend', + ) + +#. **For MySQL users only**, add the following option to your database + configuration:: + + DATABASES = { + "default" : { + # ... + # MySQL users only + "OPTIONS" : { + "init_command" : "SET foreign_key_checks = 0;", + }, + } + } + +#. Add ``'modoboa.extensions.limits'`` to ``INSTALLED_APPS`` + +#. Update your database (make sure to create a backup before launching + the following command):: + + $ ./manage.py syncdb --migrate + +#. If you are4 using the *stats* extension, please rename the + */static/stats* directory to */static/graphs* + +#. Restart the python instance(s) that serve *Modoboa* + +#. Log into Modoboa, go to *Modoboa > Extensions*, uncheck all + extensions, save. Then, check the extensions you want to use and + save again. + +#. **For Dovecot users only**, you need to modify the + ``password_query`` (file */etc/dovecot/dovecot-sql.conf* by default + on a Debian system) like this:: + + password_query = SELECT email AS user, password FROM auth_user WHERE email='%u' 0.8.8: CSV import feature and minor fixes ----------------------------------------- -#. Edit the *settings.py* file and +#. Edit the *settings.py* file and add ``'modoboa.lib.middleware.AjaxLoginRedirect'`` to the ``MIDDLEWARE_CLASSES`` variable like this:: @@ -677,7 +737,7 @@ For *MySQL* users, edit your */etc/dovecot/dovecot-sql.conf* and modify followin driver = mysql connect = host= dbname= user= password= default_pass_scheme = CRYPT - password_query = SELECT concat(t1.address, '@', t2.name) AS user, password FROM admin_mailbox AS t1, admin_domain AS t2 WHERE t1.domain_id=t2.id AND t1.address='%n' AND t2.name='%d' + password_query = SELECT email AS user, password FROM auth_user WHERE email='%u' user_query = SELECT concat(t2.name, '/', t1.path) AS home, uid, gid FROM admin_mailbox AS t1, admin_domain AS t2 WHERE t1.domain_id=t2.id AND t1.address='%n' AND t2.name='%d' Enable quotas support @@ -946,6 +1006,19 @@ plugins activation: * To deactivate a plugin, go to the *admin -> settings -> extensions* page, uncheck the corresponding box and click on the *Apply* button. +Per-admin limits +---------------- + +This extension offers a way to define limits about how many objects +(aliases, mailboxes) a domain administrator can create. + +It also brings a new role: ``Reseller``. A reseller is a domain +administrator that can also manipulates domains and assign permissions +to domain administrators. + +If you don't want to limit particular object type, just set the +associated value to -1. + Amavisd-new quarantine ---------------------- @@ -1069,8 +1142,6 @@ Then run the following commands to update Modoboa SQL schema and content:: $ python manage.py syncdb $ python manage.py migrate postfix-autoreply - $ export PYTHONPATH=$PWD/.. - $ DJANGO_SETTINGS_MODULE=modoboa.settings ./scripts/postfix_autoreply/upgrade_autoreply.py The user that executes the autoreply script needs to access *settings.py*. You must apply proper permissions on this file. For diff --git a/doc/conf.py b/doc/conf.py index ba9ba8d6c..5733e4059 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ copyright = u'2012, Antoine Nguyen' # built documents. # # The short X.Y version. -version = '0.8.8' +version = '0.9' # The full version, including alpha/beta/rc tags. -release = '0.8.8' +release = '0.9' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/plugin_api.rst b/doc/plugin_api.rst index e44a99105..711c77613 100644 --- a/doc/plugin_api.rst +++ b/doc/plugin_api.rst @@ -182,32 +182,26 @@ displayed. Possible values are: See :ref:`usermenudisplay` for a description of what callbacks that listen to this event must return. -AdminFooterDisplay ------------------- +GetStaticContent +---------------- -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. +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(user, object_type): pass + def callback(user): 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: +* ``user`` is a ``User`` instance corresponding to the currently + logged in user - * ``domains``: a list of domains - * ``domaliases``: a list of domain aliases - * ``mailboxes``: a list of mailboxes - * ``mbaliases``: a list of mailbox aliases +Callbacks listening to this event must return a list of string. -Registered callbacks must return a list of string objects. +CanCreate +--------- -CanCreateDomain ---------------- - -Raised just before a user tries to access the ``newdomain`` function. +Raised just before a user tries to create a new object. *Callback prototype*:: @@ -241,20 +235,6 @@ Raised when an existing domain is about to be deleted. * ``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 ------------------ @@ -278,20 +258,6 @@ Raised when an existing domain alias is about to be deleted. * ``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 ------------- @@ -327,20 +293,6 @@ Raised when an existing mailbox is modified. * ``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 ------------------- @@ -364,64 +316,115 @@ Raised when an existing mailbox alias is about to be deleted. * ``mailbox_alias`` is an ``Alias`` instance -.. _permsgettables: - -PermsGetTables +AccountCreated -------------- -Raised when the different permission lists (one per role) are about to -be displayed. +Raised when a new account is created. *Callback prototype*:: - def callback(request): pass + def callback(account): pass -* ``request`` is a ``Request`` instance +* ``account`` is the newly created account (``User`` instance) -Callbacks that listen to this event must return a list of -dictionnaries (corresponding to tables). Each dictionnary must contain -at least the following elements:: - {"id" : "table_id", - "title" : _("The title corresponding to this table"), - "rel" : "x y", - "content" : MyPermClass().get(request)} +AccountModified +--------------- -For ``rel``, replace x and y with the *Add form* size (the one that -appears when you click on the ``Add permission`` button. +Raised when an existing account is modified. -For ``content``, replace *MyPermClass* with the appropriate name. +*Callback prototype*:: -.. _permsgetclass: + def callback(oldaccount, newaccount): pass -PermsGetClass +* ``oldaccount`` is the account before it is modified + +* ``newaccount`` is the account after the modification + +AccountDeleted +-------------- + +Raised when an existing account is deleted. + +*Callback prototype*:: + + def callback(account): pass + +* ``oldaccount`` is the account that is going to be deleted + +ExtraAccountForm +---------------- + +Let extensions add new forms to the global 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" : "", + "title" : "", + "cls" : TheFormClassName} + +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. + +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 + +.. _getextraroles: + +GetExtraRoles ------------- -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. - -*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. +Let extensions define new administrative roles. *Callback prototype*:: def callback(user): pass -* ``user`` is a ``User`` instance +* ``user`` is a ``User`` instance corresponding to the currently + logged in user + +Callbacks listening to this event must return a list of 2uple (two +strings) which respect the following format: ``(value, label)``. ExtEnabled ---------- @@ -458,7 +461,41 @@ Some places in the interface let plugins add their own announcement * ``target`` is a string indicating the place where the announcement will appear: - * ``loginpage`` : corresponds to the login page +* ``loginpage`` : corresponds to the login page + +Callbacks listening to this event must return a list of string. + +TopNotifications +---------------- + +Let extensions add custom content into the top bar. + +*Callback prototype*:: + + def callback(user): pass + +* ``user`` is a ``User`` instance corresponding to the currently + logged in user + +Callbacks listening to this event must return a list of string. + +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. @@ -516,16 +553,17 @@ disabled from the interface), use the following function:: ``appname`` corresponds to your plugin's name, ie. the name of the directory containing the source code. -Custom permission levels -======================== +Custom administrative roles +=========================== -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`` class (see file -``admin/permissions.py``) and implement all its methods. +Modoboa uses Django's internal permission system. Administrative roles +are nothing more than groups (``Group`` instances). -.. note:: - See :ref:`permsgettables` and :ref:`permsgetclass` to learn how to - integrate your custom roles. +If an extension needs to add new roles, it needs to follow those steps: +#. Create a new ``Group`` instance. It can be done by providing + `fixtures `_ + or by creating it into the extension ``init`` function +#. A a new listener for the :ref:`getextraroles` event that will return + the group's name diff --git a/extensions/postfix_autoreply/scripts/upgrade_autoreply.py b/extensions/postfix_autoreply/scripts/upgrade_autoreply.py deleted file mode 100755 index 780fa54e3..000000000 --- a/extensions/postfix_autoreply/scripts/upgrade_autoreply.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import sys -from django.conf import settings -from modoboa.admin.models import Domain, Mailbox - -if __name__ == "__main__": - if not "modoboa.extensions.postfix_autoreply" in settings.INSTALLED_APPS: - print "Postfix autoreply extension is not activated" - sys.exit(1) - - import modoboa.extensions.postfix_autoreply.main as par - from modoboa.extensions.postfix_autoreply.models import Transport, Alias - - par.load() - doms = Domain.objects.all() - for dom in doms: - try: - trans = Transport.objects.get(domain="autoreply.%s" % dom.name) - continue - except Transport.DoesNotExist: - par.onCreateDomain(dom=dom) - mboxes = Mailbox.objects.filter(domain=dom.id) - for mb in mboxes: - try: - alias = Alias.objects.get(full_address=mb.full_address) - continue - except Alias.DoesNotExist: - par.onCreateMailbox(mbox=mb) - diff --git a/lib/events.py b/lib/events.py index 4df9cbda3..c4d0a4c28 100644 --- a/lib/events.py +++ b/lib/events.py @@ -32,7 +32,6 @@ events = [ "AccountCreated", "AccountModified", "AccountDeleted", - "DomainAdminActions", "PasswordChange",