Merge pull request #609 from carragom/1.1.x

Improve the postfixadmin migration code
This commit is contained in:
Antoine Nguyen
2014-10-08 09:01:17 +02:00
2 changed files with 75 additions and 70 deletions
@@ -55,6 +55,7 @@ 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.extensions.admin import grant_access_to_all_objects
from modoboa.tools.pfxadmin_migrate import models as pf_models
@@ -208,74 +209,74 @@ class Command(BaseCommand):
options["mboxes_path"], domain.name, old_mb.maildir)
new_mb.rename_dir(oldpath)
def _migrate_domain(self, old_dom, options, creator):
def _migrate_domain(self, pf_domain, options, creator):
"""Single domain migration."""
print "Migrating domain %s" % old_dom.domain
print "\nMigrating domain %s" % pf_domain.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.name = pf_domain.domain
newdom.enabled = pf_domain.active
newdom.quota = pf_domain.maxquota
newdom.dates = self._migrate_dates(pf_domain)
newdom.save(creator=creator, using=options["_to"])
self._migrate_domain_aliases(newdom, options, creator)
self._migrate_mailboxes(newdom, options, creator)
self._migrate_mailbox_aliases(newdom, options, creator)
self._migrate_domain_aliases(newdom, options, creator)
self._migrate_admins(options, creator, pf_domain, newdom)
def _migrate_admins(self, options, creator):
"""Administrators migration."""
print "Migrating administrators"
def _migrate_admins(self, options, creator, pf_domain, newdom=None):
"""Administrators migration.
:param pf_domain: The ``pf_models.Domain`` to get the admins to migrate.
:param newdom: If None the admins will not be linked to any domain and
they will be SuperAdmins. Otherwise link them to this domain and make them
DomainAdmins.
"""
if (newdom is None):
print "\nMigrating super administrators"
else:
print "\tMigrating 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
for old_admin in pf_domain.admins.all():
if (newdom is None):
print "\tMigrating %s" % old_admin.username
#In postfixadmin, it's possible to have an admin account and a user account with the same username but they are completely different entities, so they do not have a common password. In Modoboa this does not makes sense, so we actually merge these two entities into a single user if both are found. Question is, which password should we use?. The admin password is used to be on the secure side.
try:
user = core_models.User.objects \
.using(options["_to"]).get(username=old_admin.username)
if ("SimpleUsers" == user.group):
print "Warning: Found an admin account with the same username as normal user '%s'. The existing user will be promoted to admin and it's password changed to the admin's account password. " % user.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.password = "{%s}%s" % \
(options["passwords_scheme"].upper(), old_admin.password)
if (newdom is None):
grant_access_to_all_objects(user, "SuperAdmins")
user.is_superuser = True
else:
user.groups.add(dagroup)
domain.add_admin(user)
newdom.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()
pf_domains = pf_models.Domain.objects.using(options["_from"]).exclude(domain = '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 \
@@ -285,7 +286,10 @@ class Command(BaseCommand):
continue
except pf_models.AliasDomain.DoesNotExist:
self._migrate_domain(pf_domain, options, creator)
self._migrate_admins(options, creator)
#Handle the ALL domain
pf_domain = pf_models.Domain.objects.using(options["_from"]).get(domain = 'ALL')
self._migrate_admins(options, creator, pf_domain)
def handle(self, *args, **options):
"""Command entry point."""
+32 -31
View File
@@ -11,8 +11,8 @@
from django.db import models
class Admin(models.Model):
username = models.CharField(max_length=765, primary_key=True)
password = models.CharField(max_length=765)
username = models.CharField(max_length=255, primary_key=True)
password = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
@@ -24,9 +24,9 @@ class Admin(models.Model):
class Alias(models.Model):
address = models.CharField(max_length=765, primary_key=True)
address = models.CharField(max_length=255, primary_key=True)
goto = models.TextField()
domain = models.CharField(max_length=765)
domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
@@ -38,8 +38,8 @@ class Alias(models.Model):
class AliasDomain(models.Model):
alias_domain = models.CharField(max_length=765, primary_key=True)
target_domain = models.CharField(max_length=765)
alias_domain = models.CharField(max_length=255, primary_key=True)
target_domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
@@ -62,17 +62,18 @@ class Config(models.Model):
class Domain(models.Model):
domain = models.CharField(max_length=765, primary_key=True)
description = models.CharField(max_length=765)
domain = models.CharField(max_length=255, primary_key=True)
description = models.CharField(max_length=255)
aliases = models.IntegerField()
mailboxes = models.IntegerField()
maxquota = models.BigIntegerField()
quota = models.BigIntegerField()
transport = models.CharField(max_length=765)
transport = models.CharField(max_length=255)
backupmx = models.IntegerField()
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
admins = models.ManyToManyField(Admin, through='DomainAdmins')
class Meta:
db_table = u'domain'
@@ -81,8 +82,8 @@ class Domain(models.Model):
class DomainAdmins(models.Model):
username = models.CharField(max_length=765)
domain = models.CharField(max_length=765)
username = models.ForeignKey(Admin, db_column='username')
domain = models.ForeignKey(Domain, db_column='domain')
created = models.DateTimeField(primary_key=True)
active = models.IntegerField()
@@ -94,12 +95,12 @@ class DomainAdmins(models.Model):
class Fetchmail(models.Model):
id = models.IntegerField(primary_key=True)
mailbox = models.CharField(max_length=765)
src_server = models.CharField(max_length=765)
mailbox = models.CharField(max_length=255)
src_server = models.CharField(max_length=255)
src_auth = models.CharField(max_length=33, blank=True)
src_user = models.CharField(max_length=765)
src_password = models.CharField(max_length=765)
src_folder = models.CharField(max_length=765)
src_user = models.CharField(max_length=255)
src_password = models.CharField(max_length=255)
src_folder = models.CharField(max_length=255)
poll_time = models.IntegerField()
fetchall = models.IntegerField()
keep = models.IntegerField()
@@ -107,7 +108,7 @@ class Fetchmail(models.Model):
usessl = models.IntegerField()
extra_options = models.TextField(blank=True)
returned_text = models.TextField(blank=True)
mda = models.CharField(max_length=765)
mda = models.CharField(max_length=255)
date = models.DateTimeField()
class Meta:
@@ -118,9 +119,9 @@ class Fetchmail(models.Model):
class Log(models.Model):
timestamp = models.DateTimeField()
username = models.CharField(max_length=765)
domain = models.CharField(max_length=765)
action = models.CharField(max_length=765)
username = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
action = models.CharField(max_length=255)
data = models.TextField()
class Meta:
@@ -130,13 +131,13 @@ class Log(models.Model):
class Mailbox(models.Model):
username = models.CharField(max_length=765, primary_key=True)
password = models.CharField(max_length=765)
name = models.CharField(max_length=765)
maildir = models.CharField(max_length=765)
username = models.CharField(max_length=255, primary_key=True)
password = models.CharField(max_length=255)
name = models.CharField(max_length=255)
maildir = models.CharField(max_length=255)
quota = models.BigIntegerField()
local_part = models.CharField(max_length=765)
domain = models.CharField(max_length=765)
local_part = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
created = models.DateTimeField()
modified = models.DateTimeField()
active = models.IntegerField()
@@ -148,7 +149,7 @@ class Mailbox(models.Model):
class Quota(models.Model):
username = models.CharField(max_length=765, primary_key=True)
username = models.CharField(max_length=255, primary_key=True)
path = models.CharField(max_length=300, primary_key=True)
current = models.BigIntegerField(null=True, blank=True)
@@ -170,11 +171,11 @@ class Quota2(models.Model):
class Vacation(models.Model):
email = models.CharField(max_length=765)
subject = models.CharField(max_length=765)
email = models.CharField(max_length=255)
subject = models.CharField(max_length=255)
body = models.TextField()
cache = models.TextField()
domain = models.CharField(max_length=765)
domain = models.CharField(max_length=255)
created = models.DateTimeField()
active = models.IntegerField()
@@ -186,7 +187,7 @@ class Vacation(models.Model):
class VacationNotification(models.Model):
on_vacation = models.ForeignKey(Vacation, db_column='on_vacation')
notified = models.CharField(max_length=765, primary_key=True)
notified = models.CharField(max_length=255, primary_key=True)
notified_at = models.DateTimeField()
class Meta: