mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
* Documentation update
* Cleanup
This commit is contained in:
@@ -16,8 +16,8 @@ For extensions (mandatories since 0.8.2):
|
||||
- `lxml python module <http://codespeak.net/lxml/>`_
|
||||
- `pycrypto python module <http://www.dlitz.net/software/pycrypto/>`_
|
||||
- `rrdtool python binding <http://oss.oetiker.ch/rrdtool/>`_
|
||||
- `ckeditor version 3.4.1+ <http://ckeditor.com/>`_
|
||||
- `sievelib python module <http://pypi.python.org/pypi/sievelib>`_
|
||||
- `ckeditor version 3.4.1+ <http://ckeditor.com/>`_
|
||||
|
||||
.. _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
|
||||
*<modoboa_dir>/static/stats* directory to *<modoboa_dir>/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=<mysqld socket> dbname=<database> user=<user> password=<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
|
||||
|
||||
+2
-2
@@ -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.
|
||||
|
||||
+147
-109
@@ -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" : "<the form's id>",
|
||||
"title" : "<the title used to present the form>",
|
||||
"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 <https://docs.djangoproject.com/en/dev/howto/initial-data/>`_
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -32,7 +32,6 @@ events = [
|
||||
"AccountCreated",
|
||||
"AccountModified",
|
||||
"AccountDeleted",
|
||||
"DomainAdminActions",
|
||||
|
||||
"PasswordChange",
|
||||
|
||||
|
||||
Reference in New Issue
Block a user