Merge branch '1.1.x'

Conflicts:
	modoboa/locale/cs_CZ/LC_MESSAGES/django.po
	modoboa/locale/de/LC_MESSAGES/django.po
	modoboa/locale/en/LC_MESSAGES/django.po
	modoboa/locale/es/LC_MESSAGES/django.po
	modoboa/locale/fr/LC_MESSAGES/django.po
	modoboa/locale/it/LC_MESSAGES/django.po
	modoboa/locale/nl_NL/LC_MESSAGES/django.po
	modoboa/locale/pt_PT/LC_MESSAGES/django.po
	modoboa/locale/ru/LC_MESSAGES/django.po
	modoboa/locale/sv/LC_MESSAGES/django.po
This commit is contained in:
Antoine Nguyen
2014-08-24 14:51:30 +02:00
37 changed files with 3980 additions and 3349 deletions
+21 -24
View File
@@ -6,7 +6,7 @@ Migrating from other software
PostfixAdmin
************
Since version 0.8.5, Modoboa provides a simple script to migrate an
Modoboa provides a simple script to migrate an
existing `PostfixAdmin (version 2.3.3+)
<http://postfixadmin.sourceforge.net/>`_ database to a Modoboa one.
@@ -21,40 +21,37 @@ connection named ``pfxadmin`` into the ``DATABASES`` variable
corresponding to your PostfixAdmin setup::
DATABASES = {
"default" : {
# default connection definition
},
"pfxadmin" : {
"ENGINE" : "<engine>",
"NAME" : "<database name>",
"USER" : "<database user>",
"PASSWORD" : "<user password>",
}
"default" : {
# default connection definition
},
"pfxadmin" : {
"ENGINE" : "<engine>",
"NAME" : "<database name>",
"USER" : "<database user>",
"PASSWORD" : "<user password>",
}
}
This connection should correspond to the one defined in PostfixAdmin's
configuration file.
You are now ready to start the migration. Enter Modoboa's root
directory and execute the following command::
Then, uncomment the line containing
``'modoboa.tools.pfxadmin_migrate'`` inside the ``MODOBOA_APPS``
variable and save your changes.
$ PYTHONPATH=$PWD/.. DJANGO_SETTINGS_MODULE=modoboa.settings \
./tools/pfxadmin_migrate/migrate.py -r -p <directory that stores mailboxes>
You are now ready to start the migration so run the following commands::
$ cd <modoboa_site>
$ python manage.py migrate_from_postfixadmin -r -p <directory that stores mailboxes>
Depending on how many domains/mailboxes your existing setup contains,
the migration can be long. Just wait for the script's ending.
Once the migration has succeed, go the *Admin > Configuration* panel,
click on the *admin* row and modify the value of ``MAILDIR_ROOT`` as
follow::
.. note::
MAILDIR_ROOT =
The corresponding field must be empty. Don't touch other fields except
``PASSWORD_SCHEME``, if needed. (set it to the same method as the one
used by PostfixAdmin, check its configuration file if you're not sure)
Click on the *Save* button.
The rename operation is not synchronous. If you choose this option,
you must enable **Handle mailboxes on filesystem** option. See
:ref:`fs_operations`.
The procedure is over, edit the :file:`settings.py` file and:
+8
View File
@@ -274,6 +274,14 @@ Modoboa should connect to your LDAP server. They are described just below:
| | | |
| | | |
+--------------------+---------------------------------+--------------------+
|Domain/mailbox |Automatically create a domain and|yes |
|creation |a mailbox when a new user is | |
| |created just after the first | |
| |successful authentication. You | |
| |will generally want to disable | |
| |this feature when the relay | |
| |domains extension is in use | |
+--------------------+---------------------------------+--------------------+
If you need additional parameters, you will find a detailled
+11
View File
@@ -48,6 +48,17 @@ Finally, follow the common procedure::
$ python manage.py syncdb --migrate
$ python manage.py collectstatic
1.1.6: Few bugfixes
===================
Catchall aliases were not really functional until this version as they
were eating all domain traffic.
To fix them, a postfix map file (``sql-mailboxes-self-aliases.cf``)
has been re-introduced and must be listed into the
``virtual_alias_maps`` setting. See :ref:`postfix_config` for the
order.
1.1.2: Audit trail issues
=========================
+1
View File
@@ -443,6 +443,7 @@ Use the following configuration in the :file:`/etc/postfix/main.cf` file
virtual_alias_domains = <driver>:/etc/postfix/sql-domain-aliases.cf
virtual_alias_maps = <driver>:/etc/postfix/sql-aliases.cf,
<driver>:/etc/postfix/sql-domain-aliases-mailboxes.cf,
<driver>:/etc/postfix/sql-mailboxes-self-aliases.cf,
<driver>:/etc/postfix/sql-catchall-aliases.cf
smtpd_recipient_restrictions =
+42 -10
View File
@@ -31,6 +31,9 @@ def enabled_applications():
class GeneralParametersForm(parameters.AdminParametersForm):
"""General parameters."""
app = "core"
sep1 = SeparatorField(label=ugettext_lazy("Authentication"))
@@ -78,7 +81,8 @@ class GeneralParametersForm(parameters.AdminParametersForm):
ldap_server_address = forms.CharField(
label=ugettext_lazy("Server address"),
initial="localhost",
help_text=ugettext_lazy("The IP address of the DNS name of the LDAP server")
help_text=ugettext_lazy(
"The IP address of the DNS name of the LDAP server")
)
ldap_server_port = forms.IntegerField(
@@ -90,7 +94,8 @@ class GeneralParametersForm(parameters.AdminParametersForm):
ldap_secured = YesNoField(
label=ugettext_lazy("Use a secured connection"),
initial="no",
help_text=ugettext_lazy("Use an SSL/TLS connection to access the LDAP server")
help_text=ugettext_lazy(
"Use an SSL/TLS connection to access the LDAP server")
)
ldap_auth_method = forms.ChoiceField(
@@ -105,14 +110,20 @@ class GeneralParametersForm(parameters.AdminParametersForm):
ldap_bind_dn = forms.CharField(
label=ugettext_lazy("Bind DN"),
initial='',
help_text=ugettext_lazy("The distinguished name to use when binding to the LDAP server. Leave empty for an anonymous bind"),
help_text=ugettext_lazy(
"The distinguished name to use when binding to the LDAP server. "
"Leave empty for an anonymous bind"
),
required=False
)
ldap_bind_password = forms.CharField(
label=ugettext_lazy("Bind password"),
initial='',
help_text=ugettext_lazy("The password to use when binding to the LDAP server (with 'Bind DN')"),
help_text=ugettext_lazy(
"The password to use when binding to the LDAP server "
"(with 'Bind DN')"
),
widget=forms.PasswordInput(render_value=True),
required=False
)
@@ -120,21 +131,29 @@ class GeneralParametersForm(parameters.AdminParametersForm):
ldap_search_base = forms.CharField(
label=ugettext_lazy("Users search base"),
initial="",
help_text=ugettext_lazy("The distinguished name of the search base used to find users"),
help_text=ugettext_lazy(
"The distinguished name of the search base used to find users"
),
required=False
)
ldap_search_filter = forms.CharField(
label=ugettext_lazy("Search filter"),
initial="(mail=%(user)s)",
help_text=ugettext_lazy("An optional filter string (e.g. '(objectClass=person)'). In order to be valid, it must be enclosed in parentheses."),
help_text=ugettext_lazy(
"An optional filter string (e.g. '(objectClass=person)'). "
"In order to be valid, it must be enclosed in parentheses."
),
required=False
)
ldap_user_dn_template = forms.CharField(
label=ugettext_lazy("User DN template"),
initial="",
help_text=ugettext_lazy("The template used to construct a user's DN. It should contain one placeholder (ie. %(user)s)"),
help_text=ugettext_lazy(
"The template used to construct a user's DN. It should contain "
"one placeholder (ie. %(user)s)"
),
required=False
)
@@ -147,7 +166,8 @@ class GeneralParametersForm(parameters.AdminParametersForm):
ldap_is_active_directory = YesNoField(
label=ugettext_lazy("Active Directory"),
initial="no",
help_text=ugettext_lazy("Tell if the LDAP server is an Active Directory one")
help_text=ugettext_lazy(
"Tell if the LDAP server is an Active Directory one")
)
ldap_admin_groups = forms.CharField(
@@ -169,6 +189,15 @@ class GeneralParametersForm(parameters.AdminParametersForm):
required=False
)
ldap_create_domain_mailbox = YesNoField(
label=ugettext_lazy("Domain/mailbox creation"),
initial="yes",
help_text=ugettext_lazy(
"Automatically create a domain and a mailbox when a new user "
"is created just after the first successful authentication."
)
)
sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous"))
top_notifications_check_interval = forms.IntegerField(
@@ -200,7 +229,9 @@ class GeneralParametersForm(parameters.AdminParametersForm):
label=ugettext_lazy("Default top redirection"),
choices=[],
initial="user",
help_text=ugettext_lazy("The default redirection used when no application is specified")
help_text=ugettext_lazy(
"The default redirection used when no application is specified"
)
)
# Visibility rules
@@ -292,7 +323,8 @@ class GeneralParametersForm(parameters.AdminParametersForm):
"last_name": "sn"
})
ldap_uri = 'ldaps://' if values["ldap_secured"] == "yes" else "ldap://"
ldap_uri += "%s:%s" % (values["ldap_server_address"], values["ldap_server_port"])
ldap_uri += "%s:%s" % (
values["ldap_server_address"], values["ldap_server_port"])
setattr(settings, "AUTH_LDAP_SERVER_URI", ldap_uri)
setattr(settings, "AUTH_LDAP_GROUP_TYPE", PosixGroupType())
setattr(settings, "AUTH_LDAP_GROUP_SEARCH", LDAPSearch(
+7
View File
@@ -133,6 +133,13 @@ class DomainAliasesMailboxesMap(MapFile):
sqlite = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')"
class MailboxesSelfAliasesMap(MapFile):
filename = "sql-mailboxes-self-aliases.cf"
mysql = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active=1"
postgres = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active"
sqlite = "SELECT email FROM core_user u INNER JOIN admin_mailbox mb ON mb.user_id=u.id WHERE u.email='%s' AND u.is_active=1"
class CatchallAliasesMap(MapFile):
filename = 'sql-catchall-aliases.cf'
mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled=1 AND al.address='*' AND dom.name='%d' AND dom.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled='1' AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled=1)"
@@ -175,6 +175,9 @@ MODOBOA_APPS = (
'modoboa.extensions.sievefilters',
'modoboa.extensions.radicale',
{% if not amavis_conn %}#{% endif %}'modoboa.extensions.amavis',
# Tools from here
#'modoboa.tools.pfxadmin_migrate',
)
INSTALLED_APPS += MODOBOA_APPS
+7
View File
@@ -196,8 +196,11 @@ def import_account_mailbox(user, account, row):
@events.observe("AccountAutoCreated")
def account_auto_created(user):
from modoboa.core.models import User
from modoboa.extensions.admin.lib import check_if_domain_exists
from modoboa.lib.permissions import grant_access_to_object
if parameters.get_admin("LDAP_CREATE_DOMAIN_MAILBOX", app="core") == "no":
return
localpart, domname = split_mailbox(user.username)
if user.group != 'SimpleUsers' and domname is None:
return
@@ -205,6 +208,10 @@ def account_auto_created(user):
try:
domain = Domain.objects.get(name=domname)
except Domain.DoesNotExist:
label = check_if_domain_exists(
domname, [(DomainAlias, _('domain alias'))])
if label is not None:
return
domain = Domain(name=domname, enabled=True, quota=0)
domain.save(creator=sadmins[0])
for su in sadmins[1:]:
+12 -18
View File
@@ -10,6 +10,7 @@ from modoboa.lib.formutils import (
)
from modoboa.lib.webutils import render_to_json_response
from modoboa.core.models import User
from modoboa.extensions.admin.lib import check_if_domain_exists
from modoboa.extensions.admin.models import (
Domain, DomainAlias, Mailbox, Alias, Quota
)
@@ -74,34 +75,27 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
cleaned_data = self.cleaned_data
name = cleaned_data["name"]
dtypes = events.raiseQueryEvent('CheckDomainName')
for dtype, label in [(DomainAlias, _('domain alias'))] + dtypes:
try:
dtype.objects.get(name=name)
except dtype.DoesNotExist:
pass
else:
self._errors["name"] = self.error_class(
[_("A %s with this name already exists" % unicode(label))]
)
del cleaned_data["name"]
break
label = check_if_domain_exists(name, [(DomainAlias, _('domain alias'))])
if label is not None:
self._errors["name"] = self.error_class(
[_("A %s with this name already exists" % unicode(label))]
)
del cleaned_data["name"]
for k in cleaned_data.keys():
if not k.startswith("aliases"):
continue
if cleaned_data[k] == "":
del cleaned_data[k]
continue
for dtype, label in [(Domain, _('domain'))] + dtypes:
try:
dtype.objects.get(name=cleaned_data[k])
except dtype.DoesNotExist:
continue
label = check_if_domain_exists(
cleaned_data[k], [(Domain, _('domain'))])
if label is not None:
self._errors[k] = self.error_class(
[_("A %s with this name already exists" % unicode(label))]
)
del cleaned_data[k]
break
return cleaned_data
def update_mailbox_quotas(self, domain):
+20
View File
@@ -96,3 +96,23 @@ def get_domains(user, domfilter=None, searchquery=None, **extrafilters):
'ExtraDomainEntries', user, domfilter, searchquery, **extrafilters
)
return chain(domains, extra_domain_entries)
def check_if_domain_exists(name, extra_checks=None):
"""Check if a domain already exists.
We not only look for domains, we also look for every object that
could conflict with a domain (domain alias, etc.)
"""
dtypes = events.raiseQueryEvent('CheckDomainName')
if extra_checks is not None:
dtypes = extra_checks + dtypes
for dtype, label in dtypes:
try:
dtype.objects.get(name=name)
except dtype.DoesNotExist:
pass
else:
return label
return None
+11 -7
View File
@@ -61,13 +61,15 @@ class SQLconnector(object):
"""
if self.user.group == 'SimpleUsers':
rcpts = [self.user.email] \
+ self.user.mailbox_set.all()[0].alias_addresses
flt &= Q(rid__email__in=rcpts)
rcpts = [self.user.email]
if self.user.mailbox_set.count():
rcpts += self.user.mailbox_set.all()[0].alias_addresses
return flt & Q(rid__email__in=rcpts)
elif not self.user.is_superuser:
doms = Domain.objects.get_for_admin(self.user)
regexp = "(%s)" % '|'.join([dom.name for dom in doms])
flt &= Q(rid__email__regex=regexp)
return flt & Q(rid__email__regex=regexp)
return flt
def _apply_extra_search_filter(self, crit, pattern):
"""Apply search filters using additional criterias.
@@ -90,7 +92,7 @@ class SQLconnector(object):
"""
flt = Q(rs__in=[' ', 'V', 'R', 'p']) \
if self.navparams.get('viewrequests', '0') != '1' else Q(rs='p')
self._apply_msgrcpt_filters(flt)
flt = self._apply_msgrcpt_filters(flt)
pattern = self.navparams.get("pattern", "")
if pattern:
criteria = self.navparams.get('criteria')
@@ -226,8 +228,9 @@ class PgSQLconnector(SQLconnector):
"""
self._where = []
if self.user.group == 'SimpleUsers':
rcpts = [self.user.email] \
+ self.user.mailbox_set.all()[0].alias_addresses
rcpts = [self.user.email]
if self.user.mailbox_set.count():
rcpts += self.user.mailbox_set.all()[0].alias_addresses
self._where.append(
"convert_from(maddr.email, 'UTF8') IN (%s)" \
% (','.join(["'%s'" % rcpt for rcpt in rcpts])))
@@ -236,6 +239,7 @@ class PgSQLconnector(SQLconnector):
regexp = "(%s)" % '|'.join([dom.name for dom in doms])
self._where.append(
"convert_from(maddr.email, 'UTF8') ~ '%s'" % regexp)
return flt
def _apply_extra_search_filter(self, crit, pattern):
"""Apply search filters using additional criterias.
@@ -136,9 +136,16 @@ Quarantine.prototype = {
* Filter listing by message type (spam, virus, etc.)
*/
filter_by_type: function(evt) {
var msgtype = $(evt.target).html().trim();
var $target = $(evt.target);
var msgtype;
if (msgtype != 'All') {
if ($target.is("span")) {
msgtype = $target.html().trim();
} else {
msgtype = $target.attr("name").replace("msgtype_", "");
}
if (msgtype != 'all') {
this.navobj.setparam('msgtype', msgtype);
} else {
this.navobj.delparam('msgtype');
+3 -1
View File
@@ -102,7 +102,9 @@ def viewmail_selfservice(request, mail_id,
@selfservice(viewmail_selfservice)
def viewmail(request, mail_id):
rcpt = request.GET["rcpt"]
if request.user.mailbox_set.count():
if request.user.email == rcpt:
get_connector().set_msgrcpt_status(rcpt, mail_id, 'V')
elif request.user.mailbox_set.count():
mb = Mailbox.objects.get(user=request.user)
if rcpt == mb.full_address or rcpt in mb.alias_addresses:
get_connector().set_msgrcpt_status(rcpt, mail_id, 'V')
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: modoboa-1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:33+0200\n"
"PO-Revision-Date: 2013-09-29 22:13+0100\n"
"Last-Translator: Miroslav Abrahám <miris@kunago.com>\n"
"Language-Team: CS <miris@kunago.com>\n"
@@ -108,11 +108,11 @@ msgstr "Odstranit vybranou schránku?"
msgid "Mailbox removed"
msgstr "Schránka odstraněna"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Zpráva odeslána"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
@@ -120,7 +120,7 @@ msgstr[0] "%s soubor"
msgstr[1] "%s soubory"
msgstr[2] "%s souborů"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa-0.9\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:33+0200\n"
"PO-Revision-Date: 2013-12-08 23:34+0100\n"
"Last-Translator: Patrick Ben Koetter <p@sys4.de>\n"
"Language-Team: DE <p@state-of-mind.fr>\n"
@@ -108,18 +108,18 @@ msgstr "Ausgewählte Mailbox entfernen?"
msgid "Mailbox removed"
msgstr "Mailbox entfernt"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Nachricht gesendet"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s Datei"
msgstr[1] "%s Dateien"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:32+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -106,18 +106,18 @@ msgstr ""
msgid "Mailbox removed"
msgstr ""
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr ""
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] ""
msgstr[1] ""
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:32+0200\n"
"PO-Revision-Date: 2013-06-03 16:32+0000\n"
"Last-Translator: Pedro Gracia <lasarux@neuroomante.com>\n"
"Language-Team: Spanish (http://www.transifex.com/projects/p/modoboa/language/"
@@ -111,18 +111,18 @@ msgstr "¿Eliminar el mailbox seleccionado?"
msgid "Mailbox removed"
msgstr "Mailbox eliminado"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Mensaje enviado"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s fichero"
msgstr[1] "%s ficheros"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: modoboa-1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:33+0200\n"
"PO-Revision-Date: 2011-01-07 10:00+0100\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: FR <tonio@ngyn.org>\n"
@@ -108,18 +108,18 @@ msgstr "Supprimer la boite sélectionnée?"
msgid "Mailbox removed"
msgstr "Boite aux lettres supprimées"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Message envoyé"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s fichier"
msgstr[1] "%s fichiers"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-22 23:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:32+0200\n"
"PO-Revision-Date: 2013-12-23 00:58+0100\n"
"Last-Translator: Alberto Berti <alberto@metapensiero.it>\n"
"Language-Team: Italiano <LL@li.org>\n"
@@ -108,18 +108,18 @@ msgstr "Rimuovere la casella di posta selezionata?"
msgid "Mailbox removed"
msgstr "Casella di posta rimossa"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Messaggio inviato"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s file"
msgstr[1] "%s file"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+14 -9
View File
@@ -1,21 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# TuxBrother <vrijwilligerswerk@wij.rs>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:33+0200\n"
"PO-Revision-Date: 2014-04-16 12:58+0000\n"
"Last-Translator: TuxBrother <vrijwilligerswerk@wij.rs>\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/modoboa/language/nl_NL/)\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/"
"modoboa/language/nl_NL/)\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nl_NL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: extensions/admin/static/admin/js/admin.js:32
@@ -28,13 +29,17 @@ msgstr "De map van dit domein niet verwijderen (Zal de data ervan behouden)"
#: extensions/admin/static/admin/js/admin.js:173
msgid "This operation will remove ALL data associated to this domain."
msgstr "Deze actie zal ALLE data verwijderen die bij dit domein hoort. Wilt u doorgaan?"
msgstr ""
"Deze actie zal ALLE data verwijderen die bij dit domein hoort. Wilt u "
"doorgaan?"
#: extensions/admin/static/admin/js/admin.js:174
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr "Deze actie zal alle data die bij dit domein hoort verwijderen, behalve de gebruikers."
msgstr ""
"Deze actie zal alle data die bij dit domein hoort verwijderen, behalve de "
"gebruikers."
#: extensions/admin/static/admin/js/admin.js:222
msgid "No domain administrator defined"
@@ -107,18 +112,18 @@ msgstr "Geselecteerde mailbox verwijderen?"
msgid "Mailbox removed"
msgstr "Mailbox verwijderd"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Bericht verstuurd"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s bestanden"
msgstr[1] "%s bestanden"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# lusitan <lusitan@hushmail.com>, 2013
# mikec <miguelmclara@gmail.com>, 2012
@@ -10,14 +10,15 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:33+0200\n"
"PO-Revision-Date: 2013-12-23 11:22+0000\n"
"Last-Translator: lusitan <lusitan@hushmail.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/modoboa/language/pt_PT/)\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_PT/)\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_PT\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: extensions/admin/static/admin/js/admin.js:32
@@ -36,7 +37,9 @@ msgstr "Esta operação irá remover TODOS os dados associados a este domínio."
msgid ""
"This operation will remove all data associated to this domain, excepting "
"accounts."
msgstr "Esta operação irá remover TODOS os dados associados a este domínio, excepto as contas."
msgstr ""
"Esta operação irá remover TODOS os dados associados a este domínio, excepto "
"as contas."
#: extensions/admin/static/admin/js/admin.js:222
msgid "No domain administrator defined"
@@ -109,18 +112,18 @@ msgstr "Remover a caixa de correio seleccionada"
msgid "Mailbox removed"
msgstr "Caixa removida"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Mensagem enviada"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s ficheiro"
msgstr[1] "%s ficheiros"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:32+0200\n"
"PO-Revision-Date: 2013-12-03 09:35+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/modoboa/language/"
@@ -110,11 +110,11 @@ msgstr "Удалить выбранные почтовые ящики?"
msgid "Mailbox removed"
msgstr "Почтовый ящик удален"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Сообщение послано"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
@@ -122,7 +122,7 @@ msgstr[0] "%s файл"
msgstr[1] "%s файла"
msgstr[2] "%s файлов"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-15 10:16+0100\n"
"POT-Creation-Date: 2014-08-24 12:32+0200\n"
"PO-Revision-Date: 2013-05-23 08:22+0000\n"
"Last-Translator: ogg1980 <olle@dalnix.se>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/modoboa/language/"
@@ -110,18 +110,18 @@ msgstr "Radera markerad brevlåda?"
msgid "Mailbox removed"
msgstr "Brevlåda raderad"
#: extensions/webmail/static/webmail/js/webmail.js:746
#: extensions/webmail/static/webmail/js/webmail.js:752
msgid "Message sent"
msgstr "Meddelande sänt"
#: extensions/webmail/static/webmail/js/webmail.js:997
#: extensions/webmail/static/webmail/js/webmail.js:1003
#, c-format
msgid "%s file"
msgid_plural "%s files"
msgstr[0] "%s fil"
msgstr[1] "%s filer"
#: extensions/webmail/static/webmail/js/webmail.js:1031
#: extensions/webmail/static/webmail/js/webmail.js:1037
#, c-format
msgid "Moving %s message"
msgid_plural "Moving %s messages"
@@ -0,0 +1,296 @@
# coding: utf-8
"""Automatic postfixadmin to Modoboa migration
===========================================
This script provides an easy way to migrate an existing postfixadmin
database to a Modoboa one.
As the two products do not share the same schema, some information
will be lost on the new database. Here is the list:
* Description, transport and backup MX for domains
* Logs
* Fetchmail table
Mailboxes organisation on the filesystem will change. PostfixAdmin
uses the following layout::
<topdir>/domain.tld/user@domain.tld/
Whereas Modoboa uses the following::
<topdir>/domain.tld/user/
To rename directories, you'll need the appropriate permissions.
Domain administrators that manage more than one domain will not be
completly restored. They will only be administrator of the domain that
corresponds to their username.
Vacation messages will not be migrated by this script. Users will have
to define new messages by using Modoboa's autoreply plugin. (if
activated)
One last point about passwords. PostfixAdmin uses different hash
algorithms to store passwords so this script does not modify
them. They are copied "as is" in the new database. In order to use
them, use the ``--passwords-scheme`` to tell Modoboa which scheme was
used by PostfixAdmin.
.. note::
Actually, it appears that the ``crypt`` scheme is compatible with
PostfixAdmin ``md5crypt`` algorithm...
"""
from optparse import make_option
import os
import sys
from django.contrib.auth.models import Group
from django.core.management.base import BaseCommand
from django.db import transaction
from django.db.models import Q
import modoboa.core.models as core_models
import modoboa.extensions.admin.models as admin_models
from modoboa.lib.emailutils import split_mailbox
from modoboa.tools.pfxadmin_migrate import models as pf_models
class Command(BaseCommand):
"""Migration from postfixadmin."""
help = "This command eases the migration from a postfixadmin database."
option_list = BaseCommand.option_list + (
make_option(
"-f", "--from", dest="_from", default="pfxadmin",
help="Name of postfixadmin db connection declared in settings.py"
"(default is pfxadmin)"
),
make_option(
"-t", "--to", dest="_to", default="default",
help="Name of the Modoboa db connection declared in settings.py"
" (default is default)"
),
make_option(
"-r", "--rename-dirs", action="store_true", default=False,
help="Rename mailbox directories (default is no)"
),
make_option(
"-p", "--mboxes-path", default=None,
help="Path where directories are stored on the filesystem"
"(used only if --rename-dirs)"
),
make_option(
"-s", "--passwords-scheme", default="crypt",
help="Scheme used to crypt user passwords"
)
)
def _migrate_dates(self, oldobj):
"""Creates a new ObjectDates instance.
Due to Django limitations, we only retrieve the creation date. The
modification date will be set to 'now' because the corresponding
field in Modoboa's schema has the 'auto_now' attribute to True.
(see https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField).
:param oldobj: the PostfixAdmin record which is beeing migrated.
"""
dates = admin_models.base.ObjectDates()
dates.save()
dates.creation = oldobj.created
dates.save()
return dates
def _migrate_domain_aliases(self, domain, options, creator):
"""Migrate aliases of a single domain."""
print "\tMigrating domain aliases"
old_domain_aliases = pf_models.AliasDomain.objects.using(
options["_from"]
).filter(target_domain=domain.name)
for old_da in old_domain_aliases:
try:
target_domain = admin_models.Domain.objects \
.using(options["_to"]).get(name=old_da.target_domain)
new_da = admin_models.DomainAlias()
new_da.name = old_da.alias_domain
new_da.target = target_domain
new_da.enabled = old_da.active
new_da.dates = self._migrate_dates(old_da)
new_da.save(using=options["_to"])
new_da.post_create(creator)
except core_models.Domain.DoesNotExist:
print ("Warning: target domain %s does not exists, "
"not creating alias domain %s"
% old_da.target_domain, old_da.alias_domain)
continue
def _migrate_mailbox_aliases(self, domain, options, creator):
"""Migrate mailbox aliases of a single domain."""
print "\tMigrating mailbox aliases"
old_aliases = pf_models.Alias.objects \
.using(options["_from"]).filter(domain=domain.name)
for old_al in old_aliases:
if old_al.address == old_al.goto:
continue
new_al = admin_models.Alias()
local_part, tmp = split_mailbox(old_al.address)
if local_part is None or not len(local_part):
if tmp is None or not len(tmp):
print (
"Warning: skipping alias %s (cannot retrieve local "
"part). You will need to recreate it manually."
% old_al.address
)
continue
new_al.address = "*"
else:
new_al.address = local_part
new_al.domain = domain
new_al.enabled = old_al.active
extmboxes = []
intmboxes = []
for goto in old_al.goto.split(","):
try:
mb = admin_models.Mailbox.objects \
.using(options["_to"]).get(user__username=goto)
except admin_models.Mailbox.DoesNotExist:
extmboxes += [goto]
else:
intmboxes += [mb]
new_al.dates = self._migrate_dates(old_al)
new_al.save(
int_rcpts=intmboxes, ext_rcpts=extmboxes, creator=creator,
using=options["_to"]
)
def _migrate_mailboxes(self, domain, options, creator):
"""Migrate mailboxes of a single domain.
.. note::
Mailboxes rename will be done later by the
handle_mailboxes_operation script.
"""
print "\tMigrating mailboxes"
old_mboxes = pf_models.Mailbox.objects \
.using(options["_from"]).filter(domain=domain.name)
for old_mb in old_mboxes:
new_user = core_models.User()
new_user.username = old_mb.username
new_user.first_name = old_mb.name.partition(' ')[0]
new_user.last_name = old_mb.name.partition(' ')[2]
new_user.email = old_mb.username
new_user.is_active = old_mb.active
new_user.date_joined = old_mb.created
new_user.password = "{%s}%s" % \
(options["passwords_scheme"].upper(), old_mb.password)
new_user.dates = self._migrate_dates(old_mb)
new_user.save(creator=creator, using=options["_to"])
new_user.set_role("SimpleUsers")
new_mb = admin_models.Mailbox()
new_mb.user = new_user
new_mb.address = old_mb.local_part
new_mb.domain = domain
new_mb.dates = self._migrate_dates(old_mb)
new_mb.set_quota(old_mb.quota / 1024000, override_rules=True)
new_mb.save(creator=creator, using=options["_to"])
if options["rename_dirs"]:
oldpath = os.path.join(
options["mboxes_path"], domain.name, old_mb.maildir)
new_mb.rename_dir(oldpath)
def _migrate_domain(self, old_dom, options, creator):
"""Single domain migration."""
print "Migrating domain %s" % old_dom.domain
newdom = admin_models.Domain()
newdom.name = old_dom.domain
newdom.enabled = old_dom.active
newdom.quota = old_dom.maxquota
newdom.dates = self._migrate_dates(old_dom)
newdom.save(creator=creator, using=options["_to"])
self._migrate_mailboxes(newdom, options, creator)
self._migrate_mailbox_aliases(newdom, options, creator)
self._migrate_domain_aliases(newdom, options, creator)
def _migrate_admins(self, options, creator):
"""Administrators migration."""
print "Migrating administrators"
dagroup = Group.objects.using(options["_to"]).get(name="DomainAdmins")
for old_admin in pf_models.Admin.objects.using(options["_from"]).all():
local_part, domname = split_mailbox(old_admin.username)
try:
query = Q(username=old_admin.username) & \
(Q(domain="ALL") | Q(domain=domname))
creds = pf_models.DomainAdmins.objects \
.using(options["_from"]).get(query)
except pf_models.DomainAdmins.DoesNotExist:
print (
"Warning: skipping useless admin %s" % (old_admin.username)
)
continue
try:
domain = admin_models.Domain.objects \
.using(options["_to"]).get(name=domname)
except admin_models.Domain.DoesNotExist:
print (
"Warning: skipping domain admin %s, domain not found"
% old_admin.username
)
continue
try:
user = core_models.User.objects \
.using(options["_to"]).get(username=old_admin.username)
except core_models.User.DoesNotExist:
user = core_models.User()
user.username = old_admin.username
user.email = old_admin.username
user.password = old_admin.password
user.is_active = old_admin.active
user.save(creator=creator, using=options["_to"])
user.date_joined = old_admin.modified
if creds.domain == "ALL":
user.is_superuser = True
else:
user.groups.add(dagroup)
domain.add_admin(user)
user.save(using=options["_to"])
def _do_migration(self, options, creator_username='admin'):
"""Run the complete migration."""
pf_domains = pf_models.Domain.objects.using(options["_from"]).all()
creator = core_models.User.objects.using(options["_to"]).get(
username=creator_username)
for pf_domain in pf_domains:
if pf_domain.domain == "ALL":
continue
try:
# Skip this domain if it's an alias
is_domain_alias = pf_models.AliasDomain.objects \
.using(options["_from"]).get(alias_domain=pf_domain.domain)
print "Info: %s looks like an alias domain, skipping it" \
% pf_domain.domain
continue
except pf_models.AliasDomain.DoesNotExist:
self._migrate_domain(pf_domain, options, creator)
self._migrate_admins(options, creator)
def handle(self, *args, **options):
"""Command entry point."""
if options["rename_dirs"] and options["mboxes_path"] is None:
print "Error: you must provide the --mboxes-path option"
sys.exit(1)
with transaction.commit_on_success():
self._do_migration(options)
-214
View File
@@ -1,214 +0,0 @@
#!/usr/bin/env python
# coding: utf-8
"""
Automatic postfixadmin to Modoboa migration
===========================================
This script provides an easy way to migrate an existing postfixadmin
database to a Modoboa one.
As the two products do not share the same schema, some informations
will be lost on the new database. Here is the list:
* Description, transport and backup MX for domains
* Logs
* Fetchmail table
Mailboxes organisation on the filesystem will change. PostfixAdmin
uses the following layout::
<topdir>/domain.tld/user@domain.tld/
Whereas Modoboa uses the following::
<topdir>/domain.tld/user/
To rename directories, you'll need the appropriate permissions.
Domain administrators that manage more than one domain will not be
completly restored. They will only be administrator of the domain that
corresponds to their username.
Vacation messages will not be migrated by this script. Users will have
to define new messages by using Modoboa's autoreply plugin. (if
activated)
One last point about passwords. PostfixAdmin uses different hash
algorithms to store passwords so this script does not modify
them. They are copied "as is" is the new database. In order to use
them, you'll have to adapt the ``PASSWORD_SCHEME`` parameter in the
admin. panel. Currently, it appears that the ``crypt`` scheme is
compatible with PostfixAdmin ``md5crypt`` algorithm...
"""
import os
import sys
from django.db.utils import ConnectionDoesNotExist
from django.db.models import Q
from django.contrib.auth.models import Group
import modoboa.admin.models as md_models
import models as pf_models
from modoboa.lib.sysutils import exec_cmd
from modoboa.lib.emailutils import split_mailbox
def migrate_dates(oldobj):
"""Creates a new ObjectDates instance
Due to Django limitations, we only retrieve the creation date. The
modification date will be set to 'now' because the corresponding
field in Modoboa's schema has the 'auto_now' attribute to True.
(see https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField).
:param oldobj: the PostfixAdmin record which is beeing migrated.
"""
dates = md_models.ObjectDates()
dates.save()
dates.creation = oldobj.created
dates.save()
return dates
def migrate_domain_aliases(domain, options):
print "\tMigrating domain aliases"
old_domain_aliases = pf_models.AliasDomain.objects.using(options._from).filter(target_domain=domain.name)
for old_da in old_domain_aliases:
new_da = md_models.DomainAlias()
new_da.name = old_da.alias_domain
new_da.target = old_da.target_domain
new_da.enabled = new_da.active
new_da.dates = migrate_dates(old_da)
new_da.save(using=options.to)
def migrate_mailbox_aliases(domain, options):
print "\tMigrating mailbox aliases"
old_aliases = pf_models.Alias.objects.using(options._from).filter(domain=domain.name)
for old_al in old_aliases:
if old_al.address == old_al.goto:
continue
new_al = md_models.Alias()
local_part, tmp = split_mailbox(old_al.address)
if local_part is None or not len(local_part):
if tmp is None or not len(tmp):
print """Warning: skipping alias %s (cannot retrieve local part).
You will need to recreate it manually.
""" % old_al.address
continue
new_al.address = "*"
else:
new_al.address = local_part
new_al.domain = domain
new_al.enabled = old_al.active
extmboxes = []
intmboxes = []
for goto in old_al.goto.split(","):
try:
mb = md_models.Mailbox.objects.using(options.to).get(user__username=goto)
except md_models.Mailbox.DoesNotExist:
extmboxes += [goto]
else:
intmboxes += [mb]
new_al.dates = migrate_dates(old_al)
new_al.save(intmboxes, extmboxes, using=options.to)
def migrate_mailboxes(domain, options):
print "\tMigrating mailboxes"
old_mboxes = pf_models.Mailbox.objects.using(options._from).filter(domain=domain.name)
for old_mb in old_mboxes:
new_mb = md_models.Mailbox()
new_mb.address = old_mb.local_part
new_mb.domain = domain
new_mb.dates = migrate_dates(old_mb)
if old_mb.quota:
new_mb.quota = old_mb.quota / 1024000
new_mb.path = "%s/" % old_mb.local_part
if options.rename_dirs:
oldpath = os.path.join(options.mboxes_path, domain.name, old_mb.maildir)
newpath = os.path.join(options.mboxes_path, domain.name, new_mb.path)
code, output = exec_cmd("mv %s %s" % (oldpath, newpath))
if code:
print "Error: cannot rename mailbox directory\n%s" % output
sys.exit(1)
new_mb.save(name=old_mb.name, password=old_mb.password, using=options.to)
def migrate_domain(old_dom, options):
print "Migrating domain %s" % old_dom.domain
newdom = md_models.Domain()
newdom.name = old_dom.domain
newdom.enabled = old_dom.active
newdom.quota = old_dom.maxquota
newdom.dates = migrate_dates(old_dom)
newdom.save(using=options.to)
migrate_mailboxes(newdom, options)
migrate_mailbox_aliases(newdom, options)
migrate_domain_aliases(newdom, options)
def migrate_admins(options):
print "Migrating administrators"
dagroup = Group.objects.using(options.to).get(name="DomainAdmins")
for old_admin in pf_models.Admin.objects.using(options._from).all():
local_part, domname = split_mailbox(old_admin.username)
try:
query = Q(username=old_admin.username) & \
(Q(domain="ALL") | Q(domain=domname))
creds = pf_models.DomainAdmins.objects.using(options._from).get(query)
except pf_models.DomainAdmins.DoesNotExist:
print "Warning: skipping useless admin %s" % (old_admin.username)
continue
try:
user = md_models.User.objects.using(options.to).get(username=old_admin.username)
except md_models.User.DoesNotExist:
try:
domain = md_models.Domain.objects.using(options.to).get(name=domname)
except md_models.Domain.DoesNotExist:
print "Warning: skipping domain admin %s, domain not found" \
% old_admin.username
continue
user = md_models.User()
user.username = old_admin.username
user.email = old_admin.username
user.password = old_admin.password
user.is_active = old_admin.active
user.save(using=options.to)
user.date_joined = old_admin.modified
if creds.domain == "ALL":
user.is_superuser = True
else:
user.groups.add(dagroup)
user.save(using=options.to)
def do_migration(options):
pf_domains = pf_models.Domain.objects.using(options._from).all()
for olddom in pf_domains:
if olddom.domain == "ALL":
continue
migrate_domain(olddom, options)
migrate_admins(options)
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--from", dest="_from", default="pfxadmin",
help="Name of postfixadmin db connection declared in settings.py")
parser.add_option("-t", "--to", default="default",
help="Name of the Modoboa db connection declared in settings.py")
parser.add_option("-r", "--rename-dirs", action="store_true",
help="Rename mailbox directories (default is no)")
parser.add_option("-p", "--mboxes-path", default=None,
help="Path where directories are stored on the filesystem (used only if --rename-dirs)")
options, args = parser.parse_args()
if options.rename_dirs and options.mboxes_path is None:
print "Error: you must provide the --mboxes-path option"
sys.exit(1)
try:
do_migration(options)
except ConnectionDoesNotExist, e:
print e