mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
+13
-8
@@ -90,6 +90,8 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
perfomant at all as it will generate one query per quota
|
||||
record to update.
|
||||
"""
|
||||
Mailbox.objects.filter(domain=domain, use_domain_quota=True) \
|
||||
.update(quota=d.quota)
|
||||
for q in Quota.objects.filter(username__contains="@%s" % self.oldname).values('username'):
|
||||
username = q['username'].replace('@%s' % self.oldname, '@%s' % domain.name)
|
||||
Quota.objects.filter(username=q['username']).update(username=username)
|
||||
@@ -99,21 +101,16 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
|
||||
Updating a domain may have consequences on other objects
|
||||
(domain alias, mailbox, quota). The most tricky part concerns
|
||||
quotas update.
|
||||
|
||||
quotas update.
|
||||
|
||||
"""
|
||||
d = super(DomainFormGeneral, self).save(commit=False)
|
||||
if commit:
|
||||
old_mail_homes = None
|
||||
if self.oldname is not None and d.name != self.oldname:
|
||||
self.update_mailbox_quotas(d)
|
||||
old_mail_homes = dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all())
|
||||
old_mail_homes = \
|
||||
dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all())
|
||||
d.save()
|
||||
Mailbox.objects.filter(domain=d, use_domain_quota=True).update(quota=d.quota)
|
||||
if old_mail_homes is not None:
|
||||
for mb in d.mailbox_set.all():
|
||||
mb.rename_dir(old_mail_homes[mb.id])
|
||||
for k, v in self.cleaned_data.iteritems():
|
||||
if not k.startswith("aliases"):
|
||||
continue
|
||||
@@ -133,6 +130,14 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
if not len(filter(lambda name: self.cleaned_data[name] == dalias.name,
|
||||
self.cleaned_data.keys())):
|
||||
dalias.delete()
|
||||
|
||||
self.update_mailbox_quotas(d)
|
||||
if old_mail_homes is not None:
|
||||
for mb in d.mailbox_set.all():
|
||||
MailboxOperation.objects.create(
|
||||
mailbox=mb, type='rename', argument=old_mail_homes[mb.id]
|
||||
)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import logging
|
||||
from optparse import make_option
|
||||
from django.core.management.base import BaseCommand
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.admin.models import MailboxOperation
|
||||
|
||||
|
||||
class OperationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = ''
|
||||
help = 'Handles rename and delete operations on mailboxes'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.logger = logging.getLogger('modoboa.cron')
|
||||
|
||||
def rename_mailbox(self, operation):
|
||||
if not os.path.exists(operation.argument):
|
||||
return
|
||||
new_mail_home = operation.mailbox.mail_home.strip(os.sep)
|
||||
self.logger.info("Renaming %s to %s", operation.argument, new_mail_home)
|
||||
curpath = '/'
|
||||
for part in new_mail_home.split(os.sep)[:-1]:
|
||||
if not part:
|
||||
continue
|
||||
curpath = os.path.join(curpath, part)
|
||||
if not os.path.exists(curpath):
|
||||
os.mkdir(curpath)
|
||||
code, output = exec_cmd(
|
||||
"mv %s %s" % (old_mail_home, new_mail_home)
|
||||
)
|
||||
if code:
|
||||
raise OperationError(output)
|
||||
|
||||
def delete_mailbox(self, operation):
|
||||
if not os.path.exists(operation.argument):
|
||||
return
|
||||
self.logger.info("Deleting %s", operation.argument)
|
||||
code, output = exec_cmd(
|
||||
"rm -r %s" % operation.argument
|
||||
)
|
||||
if code:
|
||||
raise OperationError(output)
|
||||
|
||||
def handle(self):
|
||||
if parameters.get_admin("HANDLE_MAILBOXES") == 'no':
|
||||
return
|
||||
for ope in MailboxOperation.objects.all():
|
||||
try:
|
||||
f = getattr(self, '%s_mailbox' % ope.optype)
|
||||
except AttributeError:
|
||||
continue
|
||||
try:
|
||||
f(ope)
|
||||
except OperationError as e:
|
||||
self.logger.critical('Operation failed: %s', str(e))
|
||||
else:
|
||||
ope.delete()
|
||||
@@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'MailboxOperation'
|
||||
db.create_table(u'admin_mailboxoperation', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('mailbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['admin.Mailbox'], null=True, blank=True)),
|
||||
('type', self.gf('django.db.models.fields.CharField')(max_length=20)),
|
||||
('argument', self.gf('django.db.models.fields.TextField')()),
|
||||
))
|
||||
db.send_create_signal(u'admin', ['MailboxOperation'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'MailboxOperation'
|
||||
db.delete_table(u'admin_mailboxoperation')
|
||||
|
||||
|
||||
models = {
|
||||
u'admin.alias': {
|
||||
'Meta': {'ordering': "['domain__name', 'address']", 'unique_together': "(('address', 'domain'),)", 'object_name': 'Alias'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'aliases': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['admin.Alias']", 'symmetrical': 'False'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'extmboxes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['admin.Mailbox']", 'symmetrical': 'False'})
|
||||
},
|
||||
u'admin.domain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Domain'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'quota': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
u'admin.domainalias': {
|
||||
'Meta': {'object_name': 'DomainAlias'},
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"})
|
||||
},
|
||||
u'admin.extension': {
|
||||
'Meta': {'object_name': 'Extension'},
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
|
||||
},
|
||||
u'admin.mailbox': {
|
||||
'Meta': {'object_name': 'Mailbox'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '252'}),
|
||||
'dates': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.ObjectDates']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'quota': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'use_domain_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"})
|
||||
},
|
||||
u'admin.mailboxoperation': {
|
||||
'Meta': {'object_name': 'MailboxOperation'},
|
||||
'argument': ('django.db.models.fields.TextField', [], {}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.Mailbox']", 'null': 'True', 'blank': 'True'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
u'admin.objectaccess': {
|
||||
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'ObjectAccess'},
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_owner': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['admin.User']"})
|
||||
},
|
||||
u'admin.objectdates': {
|
||||
'Meta': {'object_name': 'ObjectDates'},
|
||||
'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_modification': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'admin.quota': {
|
||||
'Meta': {'object_name': 'Quota'},
|
||||
'bytes': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'mbox': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'quota_value'", 'unique': 'True', 'null': 'True', 'to': u"orm['admin.Mailbox']"}),
|
||||
'messages': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'username': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'primary_key': 'True'})
|
||||
},
|
||||
u'admin.user': {
|
||||
'Meta': {'ordering': "['username']", 'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_local': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'})
|
||||
},
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['admin']
|
||||
+15
-18
@@ -702,7 +702,9 @@ class Domain(DatesAware):
|
||||
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
|
||||
if hm == "yes" and not keepdir:
|
||||
for mb in self.mailbox_set.all():
|
||||
mb.delete_dir()
|
||||
MailboxOperation.objects.create(
|
||||
type='delete', argument=mb.mail_home
|
||||
)
|
||||
if self.alias_set.count():
|
||||
events.raiseEvent("MailboxAliasDelete", self.alias_set.all())
|
||||
ungrant_access_to_objects(self.alias_set.all())
|
||||
@@ -873,15 +875,9 @@ class Mailbox(DatesAware):
|
||||
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
|
||||
if hm is None or hm == "no":
|
||||
return
|
||||
self.__mail_home = None
|
||||
if not os.path.exists(old_mail_home):
|
||||
return
|
||||
code, output = exec_cmd(
|
||||
"mv %s %s" % (old_mail_home, self.mail_home),
|
||||
sudo_user=parameters.get_admin("MAILBOXES_OWNER")
|
||||
MailboxOperation.objects.create(
|
||||
mailbox=self, type='rename', argument=old_mail_home
|
||||
)
|
||||
if code:
|
||||
raise AdminError(_("Failed to rename mailbox: %s" % output))
|
||||
|
||||
def rename(self, address, domain):
|
||||
"""Rename the mailbox
|
||||
@@ -893,21 +889,14 @@ class Mailbox(DatesAware):
|
||||
qs = Quota.objects.filter(username=self.full_address)
|
||||
self.address = address
|
||||
self.domain = domain
|
||||
self.rename_dir(old_mail_home)
|
||||
qs.update(username=self.full_address)
|
||||
self.rename_dir(old_mail_home)
|
||||
|
||||
def delete_dir(self):
|
||||
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
|
||||
if hm is None or hm == "no":
|
||||
return
|
||||
if not os.path.exists(self.mail_home):
|
||||
return
|
||||
code, output = exec_cmd(
|
||||
"rm -r %s" % self.mail_home,
|
||||
sudo_user=parameters.get_admin("MAILBOXES_OWNER")
|
||||
)
|
||||
if code:
|
||||
raise AdminError(_("Failed to remove mailbox: %s" % output))
|
||||
MailboxOperation.objects.create(type='delete', argument=self.mail_home)
|
||||
|
||||
def set_quota(self, value=None, override_rules=False):
|
||||
"""Set or update quota's value for this mailbox.
|
||||
@@ -1017,6 +1006,14 @@ class Quota(models.Model):
|
||||
mbox = models.OneToOneField(Mailbox, related_name="quota_value", null=True)
|
||||
|
||||
|
||||
class MailboxOperation(models.Model):
|
||||
mailbox = models.ForeignKey(Mailbox, blank=True, null=True)
|
||||
type = models.CharField(
|
||||
max_length=20, choices=(('rename', 'rename'), ('delete', 'delete'))
|
||||
)
|
||||
argument = models.TextField()
|
||||
|
||||
|
||||
class Alias(DatesAware):
|
||||
address = models.CharField(
|
||||
ugettext_lazy('address'), max_length=254,
|
||||
|
||||
@@ -125,6 +125,7 @@ def newdomain(request, tplname="common/wizard_forms.html"):
|
||||
|
||||
@login_required
|
||||
@permission_required("admin.view_domains")
|
||||
@transaction.commit_on_success
|
||||
def editdomain(request, dom_id, tplname="admin/editdomainform.html"):
|
||||
domain = Domain.objects.get(pk=dom_id)
|
||||
if not request.user.can_access(domain):
|
||||
@@ -157,11 +158,13 @@ def editdomain(request, dom_id, tplname="admin/editdomainform.html"):
|
||||
error = str(e)
|
||||
else:
|
||||
events.raiseEvent("DomainModified", domain)
|
||||
return ajax_simple_response({"status": "ok", "respmsg": _("Domain modified")})
|
||||
return ajax_simple_response({"status": "ok", "respmsg": _("Domain modified")})
|
||||
|
||||
commonctx["tabs"] = form
|
||||
commonctx["error"] = error
|
||||
return ajax_response(request, status="ko", template=tplname, **commonctx)
|
||||
return ajax_simple_response({
|
||||
"status": "ko", "respmsg": error,
|
||||
"content": _render_to_string(request, tplname, commonctx)
|
||||
})
|
||||
|
||||
commonctx["tabs"] = DomainForm(request.user, instances=instances)
|
||||
commonctx["domadmins"] = domadmins
|
||||
|
||||
@@ -208,6 +208,11 @@ LOGGING = {
|
||||
'facility': SysLogHandler.LOG_AUTH,
|
||||
'formatter': 'syslog'
|
||||
},
|
||||
'syslog-cron': {
|
||||
'class': 'logging.handlers.SysLogHandler',
|
||||
'facility': SysLogHandler.LOG_CRON,
|
||||
'formatter': 'syslog'
|
||||
}
|
||||
'modoboa': {
|
||||
'class': 'modoboa.lib.logutils.SQLHandler',
|
||||
}
|
||||
@@ -227,6 +232,11 @@ LOGGING = {
|
||||
'handlers': ['modoboa'],
|
||||
'level': 'INFO',
|
||||
'propagate': False
|
||||
},
|
||||
'modoboa.cron': {
|
||||
'handlers': ['syslog-cron'],
|
||||
'level': 'INFO',
|
||||
'propagate': False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user