Removed useless fields (full_address) and added associated migrations. SQL queries used by postfix or dovecot will need to be updated. (as the documentation)

see #103

Big refactoring of objects creation and edition. (javascript cleanup, forms factoring, etc.)
This commit is contained in:
tonio
2011-01-01 16:32:52 +01:00
parent 3580ed5204
commit c43fdc2371
30 changed files with 495 additions and 416 deletions
+54 -11
View File
@@ -1,3 +1,4 @@
# coding: utf8
from django import forms
from modoboa.admin.models import *
from django.utils.translation import ugettext as _
@@ -14,12 +15,26 @@ class DomainForm(forms.ModelForm):
for f in ['name', 'quota']:
self.fields[f].widget.attrs['size'] = 14
class DomainAliasForm(forms.ModelForm):
class ProxyForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(ProxyForm, self).__init__(*args, **kwargs)
if user.is_superuser:
self._domain = None
else:
self._domain = user.mailbox_set.all()[0].domain
class DomainAliasForm(ProxyForm):
class Meta:
model = DomainAlias
fields = ('name', 'target', 'enabled')
class MailboxForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DomainAliasForm, self).__init__(*args, **kwargs)
if self._domain is not None:
self.fields["target"].queryset = Domain.objects.filter(pk=self._domain.id)
class MailboxForm(ProxyForm):
quota = forms.IntegerField(label=_("Quota"), required=False,
help_text=_("Mailbox quota in MB (default to domain quota if blank)"))
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput,
@@ -38,6 +53,15 @@ class MailboxForm(forms.ModelForm):
super(MailboxForm, self).__init__(*args, **kwargs)
for f in ['name', 'address', 'quota', 'password1', 'password2']:
self.fields[f].widget.attrs['size'] = 14
if self._domain is not None:
self.fields["domain"].queryset = Domain.objects.filter(pk=self._domain.id)
self.fields["domain"].initial = self._domain
if kwargs.has_key("instance"):
self.fields['quota'].initial = kwargs["instance"].quota
self.fields['enabled'].initial = kwargs["instance"].user.is_active
self.fields['password1'].initial = "é"
self.fields['password2'].initial = "é"
def clean_address(self):
if self.cleaned_data["address"].find('@') != -1:
@@ -57,17 +81,37 @@ class MailboxForm(forms.ModelForm):
quota=self.cleaned_data["quota"])
return m
class AliasForm(forms.ModelForm):
class AliasForm(ProxyForm):
domain = forms.ModelChoiceField(queryset=Domain.objects.all(), label=_("Domain"),
required=True,
empty_label=_("Select a domain"),
help_text=_("Select a domain in the list"))
def __init__(self, *args, **kwargs):
domain = None
if kwargs.has_key("domain"):
domain = kwargs["domain"]
del kwargs["domain"]
super(AliasForm, self).__init__(*args, **kwargs)
self.fields['address'].widget.attrs['size'] = 14
self.fields['mboxes'].widget.attrs['size'] = 5
if domain:
self.fields['mboxes'].queryset = Mailbox.objects.filter(domain=domain.id)
# This part is a little bit tricky. As 'domain' is not a
# member of Alias, we need to fill it manually. if
# self._domain exists, it means a DomainAdmin is going to
# create a new alias, we know how to fill the fields. Else,
# leave them empty (super admin mode).
if self._domain is not None:
self.fields["domain"].queryset = Domain.objects.filter(pk=self._domain.id)
elif len(args) < 2 or args[1]["domain"] == '':
self.fields['mboxes'].queryset = Mailbox.objects.none()
# if 'instance' exists, it means we are modifying an existing
# record, we need to select the right value for
# 'domain'. Finally, if super user is doing the job, we need
# to fill 'mboxes' because it's currently empty (see upper).
if kwargs.has_key("instance") or self._domain is not None:
domain = self._domain is None and kwargs["instance"].domain or self._domain
self.fields["domain"].initial = domain
self.fields['mboxes'].queryset = Mailbox.objects.filter(domain=domain)
self.fields.keyOrder = ['domain', 'address', 'mboxes', 'enabled']
class Meta:
model = Alias
@@ -81,8 +125,7 @@ class AliasForm(forms.ModelForm):
def save(self, force_insert=False, force_update=False, commit=True):
a = super(AliasForm, self).save(commit=False)
if commit:
domain = self.cleaned_data["mboxes"][0].domain
a.full_address = "%s@%s" % (a.address, domain.name)
domain = self.cleaned_data["domain"].name
a.save()
return a
@@ -0,0 +1,112 @@
# encoding: 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):
# Deleting field 'Alias.full_address'
db.delete_column('admin_alias', 'full_address')
# Changing field 'Alias.address'
db.alter_column('admin_alias', 'address', self.gf('django.db.models.fields.CharField')(max_length=254))
# Deleting field 'Mailbox.full_address'
db.delete_column('admin_mailbox', 'full_address')
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'Alias.full_address'
raise RuntimeError("Cannot reverse this migration. 'Alias.full_address' and its values cannot be restored.")
# Changing field 'Alias.address'
db.alter_column('admin_alias', 'address', self.gf('django.db.models.fields.CharField')(max_length=100))
# User chose to not deal with backwards NULL issues for 'Mailbox.full_address'
raise RuntimeError("Cannot reverse this migration. 'Mailbox.full_address' and its values cannot be restored.")
models = {
'admin.alias': {
'Meta': {'object_name': 'Alias'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
},
'admin.domain': {
'Meta': {'object_name': 'Domain'},
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'quota': ('django.db.models.fields.IntegerField', [], {})
},
'admin.domainalias': {
'Meta': {'object_name': 'DomainAlias'},
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'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': "orm['admin.Domain']"})
},
'admin.extension': {
'Meta': {'object_name': 'Extension'},
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
'admin.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
'gid': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'quota': ('django.db.models.fields.IntegerField', [], {}),
'uid': ('django.db.models.fields.IntegerField', [], {}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
},
'auth.group': {
'Meta': {'object_name': 'Group'},
'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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'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'}),
'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']
@@ -1,25 +1,25 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from south.v2 import DataMigration
from django.db import models
class Migration(SchemaMigration):
class Migration(DataMigration):
def forwards(self, orm):
db.alter_column("admin_alias", "full_address",
models.CharField(unique=True, max_length=254))
for mb in orm.Mailbox.objects.all():
mb.path = mb.path.replace(mb.domain.name + "/", "", 1)
mb.save()
def backwards(self, orm):
db.alter_column("admin_alias", "full_address",
models.CharField(max_length=150))
raise RuntimeError("Cannot revert this migration")
models = {
'admin.alias': {
'Meta': {'object_name': 'Alias'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'full_address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '254'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mboxes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['admin.Mailbox']", 'symmetrical': 'False'})
},
@@ -47,7 +47,6 @@ class Migration(SchemaMigration):
'Meta': {'object_name': 'Mailbox'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['admin.Domain']"}),
'full_address': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'gid': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+14 -6
View File
@@ -86,7 +86,6 @@ class Mailbox(models.Model):
help_text=_("First name and last name of mailbox owner"))
address = models.CharField(_('address'), max_length=100,
help_text=_("Mailbox address (without the @domain.tld part)"))
full_address = models.CharField(max_length=150)
password = models.CharField(_('password'), max_length=100)
quota = models.IntegerField()
uid = models.IntegerField()
@@ -106,7 +105,12 @@ class Mailbox(models.Model):
self.mdirroot = parameters.get_admin("MAILDIR_ROOT")
def __str__(self):
return "%s" % (self.full_address)
return self.__full_address()
def __full_address(self):
return "%s@%s" % (self.address, self.domain.name)
full_address = property(__full_address)
def create_dir(self):
relpath = "%s/%s" % (self.domain.name, self.address)
@@ -172,11 +176,11 @@ class Mailbox(models.Model):
self.password = crypt_password(kwargs["password"])
self.uid = pwd.getpwnam(parameters.get_admin("VIRTUAL_UID")).pw_uid
self.gid = pwd.getpwnam(parameters.get_admin("VIRTUAL_GID")).pw_gid
if kwargs.has_key("quota") and int(kwargs["quota"]) < self.domain.quota:
if kwargs.has_key("quota") and kwargs["quota"] is not None \
and int(kwargs["quota"]) < self.domain.quota:
self.quota = kwargs["quota"]
else:
self.quota = self.domain.quota
self.full_address = self.user.email
try:
for kw in ["enabled", "password", "quota"]:
del kwargs[kw]
@@ -207,9 +211,8 @@ class Mailbox(models.Model):
}
class Alias(models.Model):
address = models.CharField(_('address'), max_length=100,
address = models.CharField(_('address'), max_length=254,
help_text=_("The alias address (without the domain part)"))
full_address = models.CharField(max_length=254, unique=True)
mboxes = models.ManyToManyField(Mailbox, verbose_name=_('mailboxes'),
help_text=_("The mailboxes this alias points to"))
enabled = models.BooleanField(_('enabled'),
@@ -220,6 +223,11 @@ class Alias(models.Model):
("view_aliases", "View aliases"),
)
def __domain(self):
return self.mboxes.all()[0].domain
domain = property(__domain)
class Extension(models.Model):
name = models.CharField(max_length=150)
enabled = models.BooleanField(_('enabled'),
+3 -3
View File
@@ -7,7 +7,7 @@ from forms import *
class Permissions(object):
@staticmethod
def is_auhorized(user):
def is_authorized(user):
return True
def get_add_form(self, request):
@@ -27,7 +27,7 @@ class SuperAdminsPerms(Permissions):
role = "super_admins"
@staticmethod
def is_auhorized(user):
def is_authorized(user):
return user.is_superuser
def get_add_form(self, request):
@@ -141,7 +141,7 @@ def get_perms_class(user, role):
cname += p.capitalize()
cname += "Perms"
if globals().has_key(cname):
if globals()[cname].is_auhorized(user):
if globals()[cname].is_authorized(user):
return globals()[cname]
return None
res = events.raiseQueryEvent("PermsGetClass", role=role)
+1 -1
View File
@@ -199,7 +199,7 @@ def mbalias_actions(user, alias):
"img" : static_url("pics/edit.png"),
"title" : _("Edit mailbox alias"),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:300,y:250}}"}
"rel" : "{handler:'iframe',size:{x:300,y:300}}"}
]
return render_actions(actions)
+2 -1
View File
@@ -22,7 +22,8 @@ urlpatterns = patterns('modoboa.admin.views',
(r'^mbaliases/edit/(?P<alias_id>\d+)/$', 'editmbalias'),
(r'^mbaliases/delete/$', 'delmbalias'),
(r'^domains/(?P<dom_id>\d+)/raw/$', 'mailboxes_raw'),
(r'^domains/(?P<dom_id>\d+)/rawmboxes/$', 'mailboxes_raw'),
#url(r'^domains/(?P<dom_id>\d+)/aliases/$', "aliases", name="full-aliases"),
#url(r'^domains/(?P<dom_id>\d+)/aliases/(?P<mbox_id>\d+)/$', "aliases", name="mbox-aliases"),
+132 -150
View File
@@ -14,8 +14,7 @@ from modoboa import admin, userprefs
from models import *
from admin.permissions import *
from modoboa.lib import crypt_password
from modoboa.lib import _render, _render_to_string, _ctx_ok, \
getctx, events, parameters
from modoboa.lib import _render, ajax_response, getctx, events, parameters
from modoboa.lib.models import Parameter
import copy
@@ -69,7 +68,11 @@ def domains(request):
@login_required
@permission_required("admin.add_domain")
def newdomain(request):
def newdomain(request, tplname="admin/adminform.html"):
commonctx = {"title" : _("New domain"),
"submit_label" : _("Create"),
"action" : reverse(newdomain),
"formid" : "domform"}
if request.method == "POST":
form = DomainForm(request.POST)
error = None
@@ -81,26 +84,26 @@ def newdomain(request):
if domain.create_dir():
form.save()
events.raiseEvent("CreateDomain", dom=domain)
ctx = _ctx_ok(reverse(admin.views.domains))
messages.info(request, _("Domain created"), fail_silently=True)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.domains))
error = _("Failed to initialise domain, check permissions")
content = _render_to_string(request, "admin/newdomain.html", {
"form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainForm()
return _render(request, 'admin/newdomain.html', {
"form" : form
})
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@permission_required("admin.change_domain")
def editdomain(request, dom_id):
def editdomain(request, dom_id, tplname="admin/adminform.html"):
domain = Domain.objects.get(pk=dom_id)
commonctx = {"title" : _("Domain editing"),
"submit_label" : _("Update"),
"action" : reverse(editdomain, args=[dom_id]),
"formid" : "domform"}
olddomain = copy.deepcopy(domain)
if request.method == "POST":
form = DomainForm(request.POST, instance=domain)
@@ -114,19 +117,16 @@ def editdomain(request, dom_id):
error = _("Failed to rename domain, check permissions")
if not error:
form.save()
ctx = _ctx_ok(reverse(admin.views.domains))
messages.info(request, _("Domain modified"), fail_silently=True)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
content = _render_to_string(request, "admin/editdomain.html", {
"domain" : domain, "form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.domains))
form = DomainForm(instance=domain)
return _render(request, 'admin/editdomain.html', {
"domain" : domain, "form" : form
})
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainForm(instance=domain)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@permission_required("admin.delete_domain")
@@ -147,10 +147,8 @@ def deldomain(request):
dom.delete(keepdir=keepdir)
msg = ungettext("Domain deleted", "Domains deleted", len(selection))
messages.info(request, msg, fail_silently=True)
ctx = _ctx_ok("")
else:
ctx = getctx("ko", error=error)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request)
return ajax_response(request, status="ko", error=error)
@login_required
@permission_required("admin.view_domaliases")
@@ -167,9 +165,13 @@ def domaliases(request):
@login_required
@good_domain
@permission_required("admin.add_domainalias")
def newdomalias(request):
def newdomalias(request, tplname="admin/adminform.html"):
commonctx = {"title" : _("New domain alias"),
"submit_label" : _("Create"),
"action" : reverse(newdomalias),
"formid" : "domaliasform"}
if request.method == "POST":
form = DomainAliasForm(request.POST)
form = DomainAliasForm(request.user, request.POST)
error = None
if form.is_valid():
domalias = form.save(commit=False)
@@ -181,32 +183,30 @@ def newdomalias(request):
except IntegrityError:
error = _("Alias with this name already exists")
else:
ctx = _ctx_ok(reverse(admin.views.domaliases))
messages.info(request, _("Domain alias created"), fail_silently=True)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
content = _render_to_string(request, "admin/newdomalias.html", {
"form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
form = DomainAliasForm()
if not request.user.is_superuser:
form.fields["target"].queryset = \
Domain.objects.filter(mailbox__user__pk=request.user.id)
return ajax_response(request, url=reverse(admin.views.domaliases))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainAliasForm(request.user)
if request.GET.has_key("domid"):
form.fields["target"].initial = request.GET["domid"]
return _render(request, 'admin/newdomalias.html', {
"form" : form
})
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_domainalias")
def editdomalias(request, alias_id):
def editdomalias(request, alias_id, tplname="admin/adminform.html"):
domalias = DomainAlias.objects.get(pk=alias_id)
commonctx = {"title" : _("Domain alias editing"),
"submit_label" : _("Update"),
"action" : reverse(editdomalias, args=[alias_id]),
"formid" : "domaliasform"}
if request.method == "POST":
form = DomainAliasForm(request.POST, instance=domalias)
form = DomainAliasForm(request.user, request.POST, instance=domalias)
error = None
if form.is_valid():
ndomalias = form.save(commit=False)
@@ -218,20 +218,15 @@ def editdomalias(request, alias_id):
except IntegrityError:
error = _("Alias with this name already exists")
else:
ctx = _ctx_ok(reverse(admin.views.domaliases))
messages.info(request, _("Domain alias updated"), fail_silently=True)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
content = _render_to_string(request, "admin/editdomalias.html", {
"form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.domaliases))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainAliasForm(instance=domalias)
return _render(request, 'admin/editdomalias.html', {
"form" : form, "domalias" : domalias
})
form = DomainAliasForm(request.user, instance=domalias)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@@ -241,8 +236,7 @@ def deldomalias(request):
DomainAlias.objects.filter(id__in=selection).delete()
msg = ungettext("Domain alias deleted", "Domain aliases deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return HttpResponse(simplejson.dumps(_ctx_ok("")),
mimetype="application/json")
return ajax_response(request)
@login_required
@good_domain
@@ -262,17 +256,26 @@ def mailboxes(request):
@good_domain
@permission_required("admin.view_mailboxes")
def mailboxes_raw(request, dom_id=None):
mailboxes = Mailbox.objects.filter(domain=dom_id).exclude(user__id=request.user.id)
target = request.GET.has_key("target") and request.GET["target"] or "permissions"
if target == "permissions":
mailboxes = Mailbox.objects.filter(domain=dom_id).exclude(user__id=request.user.id)
else:
mailboxes = Mailbox.objects.filter(domain=dom_id)
return _render(request, 'admin/mailboxes_raw.html', {
"mailboxes" : mailboxes
"mailboxes" : mailboxes,
"target" : target
})
@login_required
@good_domain
@permission_required("admin.add_mailbox")
def newmailbox(request):
def newmailbox(request, tplname="admin/adminform.html"):
commonctx = {"title" : _("New mailbox"),
"submit_label" : _("Create"),
"action" : reverse(newmailbox),
"formid" : "mboxform"}
if request.method == "POST":
form = MailboxForm(request.POST)
form = MailboxForm(request.user, request.POST)
error = None
if form.is_valid():
try:
@@ -283,34 +286,29 @@ def newmailbox(request):
events.raiseEvent("CreateMailbox", mbox=mb)
messages.info(request, _("Mailbox created"),
fail_silently=True)
ctx = _ctx_ok(reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
content = _render_to_string(request, "admin/newmailbox.html", {
"form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
form = MailboxForm()
if not request.user.is_superuser:
form.fields["domain"].queryset = \
Domain.objects.filter(mailbox__user__pk=request.user.id)
if request.GET.has_key("domid"):
form.fields["domain"].initial = request.GET["domid"]
return _render(request, "admin/newmailbox.html", {
"form" : form
})
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = MailboxForm(request.user)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_mailbox")
@transaction.commit_manually
def editmailbox(request, mbox_id=None):
def editmailbox(request, mbox_id=None, tplname="admin/adminform.html"):
mb = Mailbox.objects.get(pk=mbox_id)
commonctx = {"title" : _("Mailbox editing"),
"submit_label" : _("Create"),
"action" : reverse(editmailbox, args=[mbox_id]),
"formid" : "mboxform"}
if request.method == "POST":
oldmb = copy.deepcopy(mb)
form = MailboxForm(request.POST, instance=mb)
form = MailboxForm(request.user, request.POST, instance=mb)
error = None
if form.is_valid():
try:
@@ -323,25 +321,17 @@ def editmailbox(request, mbox_id=None):
events.raiseEvent("ModifyMailbox", mbox=mb, oldmbox=oldmb)
messages.info(request, _("Mailbox modified"),
fail_silently=True)
ctx = _ctx_ok(reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
error = _("Failed to rename mailbox, check permissions")
if error is not None:
transaction.rollback()
ctx = getctx("ko", content=_render_to_string(request, "admin/editmailbox.html", {
"mbox" : mb, "form" : form, "error" : error
}))
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = MailboxForm(instance=mb)
form.fields['quota'].initial = mb.quota
form.fields['enabled'].initial = mb.user.is_active
form.fields['password1'].initial = "é"
form.fields['password2'].initial = "é"
return _render(request, 'admin/editmailbox.html', {
"form" : form, "mbox" : mb
})
form = MailboxForm(request.user, instance=mb)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@@ -364,11 +354,9 @@ def delmailbox(request):
mb.delete(keepdir=keepdir)
msg = ungettext("Mailbox deleted", "Mailboxes deleted", len(selection))
messages.info(request, msg, fail_silently=True)
ctx = _ctx_ok("")
else:
ctx = getctx("ko", error=error)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
return ajax_response(request)
return ajax_response(request, status="ko", error=error)
@login_required
@good_domain
@@ -385,9 +373,13 @@ def mbaliases(request):
@login_required
@good_domain
@permission_required("admin.add_alias")
def newmbalias(request):
def newmbalias(request, tplname="admin/mbaliasform.html"):
commonctx = {"title" : _("New mailbox alias"),
"submit_label" : _("Create"),
"action" : reverse(newmbalias),
"formid" : "mbaliasform"}
if request.method == "POST":
form = AliasForm(request.POST)
form = AliasForm(request.user, request.POST)
error = None
if form.is_valid():
try:
@@ -396,33 +388,31 @@ def newmbalias(request):
error = _("Alias with this name already exists")
else:
form.save_m2m()
ctx = _ctx_ok(reverse(admin.views.mbaliases) )
messages.info(request, _("Mailbox alias created"), fail_silently=True)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
content = _render_to_string(request, "admin/newmbalias.html", {
"form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.mbaliases))
if request.GET.has_key("domid"):
form = AliasForm(domain=Domain.objects.get(pk=request.GET["domid"]))
else:
form = AliasForm()
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = AliasForm(request.user)
if request.GET.has_key("mbid"):
form.fields["mboxes"].initial = request.GET["mbid"]
return _render(request, 'admin/newmbalias.html', {
"form" : form, "noerrors" : True
})
commonctx["form"] = form
commonctx["noerrors"] = True
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_alias")
def editmbalias(request, alias_id):
def editmbalias(request, alias_id, tplname="admin/mbaliasform.html"):
alias = Alias.objects.get(pk=alias_id)
commonctx = {"title" : _("Mailbox alias editing"),
"submit_label" : _("Update"),
"action" : reverse(editmbalias, args=[alias.id]),
"formid" : "mbaliasform"}
if request.method == "POST":
form = AliasForm(request.POST, instance=alias)
form = AliasForm(request.user, request.POST, instance=alias)
error = None
if form.is_valid():
try:
@@ -431,20 +421,16 @@ def editmbalias(request, alias_id):
error = _("Alias with this name already exists")
else:
form.save_m2m()
ctx = _ctx_ok(reverse(admin.views.mbaliases))
messages.info(request, _("Mailbox alias modified"),
fail_silently=True)
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
content = _render_to_string(request, "admin/editmbalias.html", {
"alias" : alias, "form" : form, "error" : error
})
ctx = getctx("ko", content=content)
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
form = AliasForm(instance=alias)
return _render(request, 'admin/editmbalias.html', {
"form" : form, "alias" : alias
})
return ajax_response(request, url=reverse(admin.views.mbaliases))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = AliasForm(request.user, instance=alias)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@@ -454,12 +440,11 @@ def delmbalias(request):
Alias.objects.filter(id__in=selection).delete()
msg = ungettext("Alias deleted", "Aliases deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return HttpResponse(simplejson.dumps(_ctx_ok("")),
mimetype="application/json")
return ajax_response(request)
@login_required
@permission_required("auth.view_permissions")
def permissions(request):
def permissions(request, tplname='admin/permissions.html'):
permtables = []
if request.user.is_superuser:
permtables += [
@@ -476,7 +461,7 @@ def permissions(request):
"content" : DomainAdminsPerms().get(request)}
]
return _render(request, 'admin/permissions.html', {
return _render(request, tplname, {
"permtables" : permtables
})
@@ -497,9 +482,7 @@ def add_permission(request):
return HttpResponse(simplejson.dumps(data), mimetype="application/json")
messages.info(request, _("Permission added."),
fail_silently=True)
ctx = _ctx_ok(reverse(admin.views.permissions))
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
return ajax_response(request, url=reverse(admin.views.permissions))
@login_required
def delete_permissions(request):
@@ -516,7 +499,7 @@ def delete_permissions(request):
@login_required
@user_passes_test(lambda u: u.is_superuser)
def viewparameters(request):
def viewparameters(request, tplname='admin/parameters.html'):
apps = sorted(parameters._params.keys())
gparams = []
for app in apps:
@@ -533,7 +516,7 @@ def viewparameters(request):
tmp["params"] += [newdef]
gparams += [tmp]
return _render(request, 'admin/parameters.html', {
return _render(request, tplname, {
"gparams" : gparams
})
@@ -545,12 +528,11 @@ def saveparameters(request):
continue
app, name = pname.split('.')
parameters.save_admin(name, v, app=app)
ctx = getctx("ok")
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request)
@login_required
@user_passes_test(lambda u: u.is_superuser)
def viewextensions(request):
def viewextensions(request, tplname='admin/extensions.html'):
from modoboa.extensions import list_extensions
from modoboa.lib import tables
@@ -574,7 +556,7 @@ def viewextensions(request):
ext["selection"] = False
tbl = ExtensionsTable(exts)
return _render(request, 'admin/extensions.html', {
return _render(request, tplname, {
"extensions" : tbl.render(request)
})
+5 -4
View File
@@ -40,10 +40,10 @@ class WMtable(tables.Table):
class EmailAddress(object):
addr_exp = re.compile("([^<\(]+)[<(]([^>)]+)[>)]")
name_exp = re.compile('"([^"]+)"')
name_exp = re.compile('"?([^"]+)"?')
def __init__(self, address):
self.fulladdress = address
self.fulladdress = u2u_decode.u2u_decode(address).strip("\r\t\n")
self.name = self.address = None
m = EmailAddress.addr_exp.match(self.fulladdress)
if m is None:
@@ -75,7 +75,7 @@ class IMAPheader(object):
addr = EmailAddress(value)
if "full" in kwargs.keys() and kwargs["full"]:
return addr.fulladdress
return addr.name and addr.name or value
return addr.name and addr.name or addr.fulladdress
@staticmethod
def parse_address_list(values, **kwargs):
@@ -454,11 +454,12 @@ class ImapEmail(Email):
def render_headers(self, **kwargs):
from django.template.loader import render_to_string
return render_to_string("webmail/headers.html", {
res = render_to_string("webmail/headers.html", {
"headers" : self.headers,
"folder" : kwargs["folder"], "mail_id" : kwargs["mail_id"],
"attachments" : self.attachments != {} and self.attachments or None
})
return res
class ReplyModifier(ImapEmail):
def __init__(self, msg, user, form, all=False, **kwargs):
@@ -154,7 +154,6 @@
var rtimer = null;
window.addEvent("pageRefresh", function() {
console.log("timer : ", rtimer);
if (rtimer) {
clearInterval(rtimer);
rtimer = null;
+36
View File
@@ -4,11 +4,13 @@ import sys
import time
import hashlib, crypt, string
from random import Random
from django.http import HttpResponse
from django.conf import settings
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.utils import simplejson
from modoboa.lib import parameters
def exec_cmd(cmd, **kwargs):
@@ -19,10 +21,19 @@ def exec_cmd(cmd, **kwargs):
return p.returncode, output
def _render(request, tpl, user_context):
"""Custom rendering function
Just a wrapper which automatically adds a RequestContext instance
(useful to use settings variables like MEDIA_URL inside templates)
"""
return render_to_response(tpl, user_context,
context_instance=RequestContext(request))
def _render_to_string(request, tpl, user_context):
"""Custom rendering function
Same a mrender_render.
"""
return render_to_string(tpl, user_context,
context_instance=RequestContext(request))
@@ -63,6 +74,31 @@ def getctx(status, level=1, callback=None, **kwargs):
ctx[kw] = v
return ctx
def ajax_response(request, status="ok", url=None, template=None, **kwargs):
"""Ajax response shortcut
Simple shortcut that sends an JSON response. If a template is
provided, a 'content' field will be added to the response,
containing the result of this template rendering.
:param request: a request object
:param status: the response status ('ok' or 'ko)
:param nexturl: url to display after receiving this response
:param template: eventual template's path
:param kwargs: dict used for template rendering
"""
ctx = {}
for k, v in kwargs.iteritems():
ctx[k] = v
if template is not None:
content = _render_to_string(request, template, ctx)
else:
content = ""
return HttpResponse(simplejson.dumps({"status" : status,
"content" : content,
"url" : url}),
mimetype="application/json")
def decode(s, encodings=('utf8', 'latin1', 'windows-1252', 'ascii'), charset=None):
if charset is not None:
return s.decode(charset, 'ignore')
+1 -1
View File
@@ -9,7 +9,7 @@ class SimpleBackend:
except User.DoesNotExist:
return None
try:
mb = Mailbox.objects.get(full_address=username)
mb = user.mailbox_set.all()[0]
except Exception:
return None
if not _check_password(password, mb.password):
+42 -68
View File
@@ -1,85 +1,59 @@
window.addEvent("domready", function() {
sqbsubmit = function(obj, dest, id, callback, onerror) {
obj.set('send', {
onSuccess: function(responseText) {
var decode = JSON.decode(responseText);
if (decode.status == "ko") {
$(dest).set("html", decode.content);
$(id).addEvent("submit", callback);
if ($defined(onerror)) {
onerror();
}
ajax_submit = function(event, error_callbacks) {
var form = event.target;
var myid = form.get("id");
event.stop();
form.set('send', {
onSuccess: function(responseText) {
var response = JSON.decode(responseText);
if (response.status == "ko") {
$(document.body).set("html", response.content);
$(document.body).addEvent("submit", default_submit);
if ($defined(error_callbacks[myid])) {
error_callbacks[myid]();
}
} else {
if (decode.url != "")
parent.location.href = decode.url;
if (response.url != "") {
parent.location.href = response.url;
}
parent.SqueezeBox.close();
}
},
onFailure: function(xhr) {
parent.document.getElement('iframe').setStyles({width: 800, height: 600});
$(dest).set("html", xhr.responseText);
$(document.body).set("html", xhr.responseText);
}
});
obj.send();
form.send();
};
generic_submit = function(obj, event, id, callback, onerror) {
event.stop();
sqbsubmit(obj, "content", id, callback, onerror);
};
domain_submit = function(event) {
generic_submit(this, event, "domform", domain_submit);
};
domalias_submit = function(event) {
generic_submit(this, event, "domaliasform", domalias_submit);
};
mailbox_submit = function(event) {
generic_submit(this, event, "mboxform", mailbox_submit);
};
alias_submit = function(event) {
generic_submit(this, event, "aliasform", alias_submit);
};
permission_submit = function(event) {
generic_submit(this, event, "permform", permission_submit, function() {
if ($defined($("id_domain"))) {
$("id_domain").options[0].setProperty("selected", "selected");
domadminform_init();
default_submit = function(event) {
var error_callbacks = {
mbaliasform: function() {
if ($("id_domain").value == 0) {
$("id_mboxes").set("html", "");
}
mbaliasform_init();
},
armform: function() {
new Calendar({id_untildate: "Y-m-d"}, {
tweak: {x: -100, y:-100}
});
},
permform: function() {
if ($defined($("id_domain"))) {
$("id_domain").options[0].setProperty("selected", "selected");
domadminform_init();
}
}
});
};
chpassword_submit = function(event) {
generic_submit(this, event, "chpwdform", chpassword_submit);
};
ajax_submit(event, error_callbacks);
};
arm_onerror = function() {
new Calendar({id_untildate: "Y-m-d"}, {
tweak: {x: -100, y:-100}
});
};
arm_submit = function(event) {
generic_submit(this, event, "armform", arm_submit, arm_onerror);
};
if ($("domform"))
$("domform").addEvent("submit", domain_submit);
if ($("domaliasform"))
$("domaliasform").addEvent("submit", domalias_submit);
if ($("mboxform"))
$("mboxform").addEvent("submit", mailbox_submit);
if ($("aliasform"))
$("aliasform").addEvent("submit", alias_submit);
if ($("permform"))
$("permform").addEvent("submit", permission_submit);
if ($("chpwdform"))
$("chpwdform").addEvent("submit", chpassword_submit);
if ($("armform"))
$("armform").addEvent("submit", arm_submit);
$(document.body).addEvent("submit", default_submit);
$$("input[type!=submit]", "select").each(function(elt) {
if ($(elt.name + "_helptext")) {
+38 -11
View File
@@ -1,6 +1,6 @@
// MooTools: the javascript framework.
// Load this file's selection again by visiting: http://mootools.net/more/25f2abaf6eb14bf4513d6443e1c77284
// Or build this file again with packager using: packager build More/More More/URI More/Hash More/Element.Position More/Form.Request More/Fx.Slide More/Drag.Move More/HtmlTable.Select More/Tips
// Load this file's selection again by visiting: http://mootools.net/more/c11b92fc7fef906755509fc9c331de22
// Or build this file again with packager using: packager build More/URI More/Hash More/Form.Request More/Fx.Accordion More/Fx.Slide More/Drag.Move More/HtmlTable.Select More/Tips
/*
---
copyrights:
@@ -35,9 +35,13 @@ a.base=new a(Array.from(document.getElements("base[href]",true)).getLast(),{base
},set:function(b,c){if(!this[b]||this.hasOwnProperty(b)){this[b]=c;}return this;},empty:function(){a.each(this,function(c,b){delete this[b];},this);return this;
},include:function(b,c){if(this[b]==undefined){this[b]=c;}return this;},map:function(b,c){return new a(Object.map(this,b,c));},filter:function(b,c){return new a(Object.filter(this,b,c));
},every:function(b,c){return Object.every(this,b,c);},some:function(b,c){return Object.some(this,b,c);},getKeys:function(){return Object.keys(this);},getValues:function(){return Object.values(this);
},toQueryString:function(b){return Object.toQueryString(this,b);}});a.alias({indexOf:"keyOf",contains:"hasValue"});})();(function(){var a=function(d,c){var e=[];
Object.each(c,function(f){Object.each(f,function(g){d.each(function(h){e.push(h+"-"+g+(h=="border"?"-width":""));});});});return e;};var b=function(e,d){var c=0;
Object.each(d,function(g,f){if(f.test(e)){c=c+g.toInt();}});return c;};Element.implement({measure:function(h){var d=function(j){return !!(!j||j.offsetHeight||j.offsetWidth);
},toQueryString:function(b){return Object.toQueryString(this,b);}});a.alias({indexOf:"keyOf",contains:"hasValue"});})();Class.Mutators.Binds=function(a){return a;
};Class.Mutators.initialize=function(a){return function(){Array.from(this.Binds).each(function(b){var c=this[b];if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments);
};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property);if(a&&this.occluded!=null){return this.occluded=a;
}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});Class.refactor=function(b,a){Object.each(a,function(e,d){var c=b.prototype[d];
if(c&&c.$origin){c=c.$origin;}if(c&&typeof e=="function"){b.implement(d,function(){var f=this.previous;this.previous=c;var g=e.apply(this,arguments);this.previous=f;
return g;});}else{b.implement(d,e);}});return b;};(function(){var a=function(d,c){var e=[];Object.each(c,function(f){Object.each(f,function(g){d.each(function(h){e.push(h+"-"+g+(h=="border"?"-width":""));
});});});return e;};var b=function(e,d){var c=0;Object.each(d,function(g,f){if(f.test(e)){c=c+g.toInt();}});return c;};Element.implement({measure:function(h){var d=function(j){return !!(!j||j.offsetHeight||j.offsetWidth);
};if(d(this)){return h.apply(this);}var g=this.getParent(),i=[],e=[];while(!d(g)&&g!=document.body){e.push(g.expose());g=g.getParent();}var f=this.expose();
var c=h.apply(this);f();e.each(function(j){j();});return c;},expose:function(){if(this.getStyle("display")!="none"){return function(){};}var c=this.style.cssText;
this.setStyles({display:"block",position:"absolute",visibility:"hidden"});return function(){this.style.cssText=c;}.bind(this);},getDimensions:function(c){c=Object.merge({computeSize:false},c);
@@ -62,11 +66,7 @@ var i={left:"x",top:"y"};["minimum","maximum"].each(function(t){["left","top"].e
}});});if(f.getStyle("position")=="fixed"||g.relFixedPosition){var m=window.getScroll();j.top+=m.y;j.left+=m.x;}if(g.ignoreScroll){var p=f.getScroll();
j.top-=p.y;j.left-=p.x;}if(g.ignoreMargins){j.left+=(g.edge.x=="right"?n["margin-right"]:g.edge.x=="center"?-n["margin-left"]+((n["margin-right"]+n["margin-left"])/2):-n["margin-left"]);
j.top+=(g.edge.y=="bottom"?n["margin-bottom"]:g.edge.y=="center"?-n["margin-top"]+((n["margin-bottom"]+n["margin-top"])/2):-n["margin-top"]);}j.left=Math.ceil(j.left);
j.top=Math.ceil(j.top);if(g.returnPos){return j;}else{this.setStyles(j);}return this;}});})();Class.Mutators.Binds=function(a){return a;};Class.Mutators.initialize=function(a){return function(){Array.from(this.Binds).each(function(b){var c=this[b];
if(c){this[b]=c.bind(this);}},this);return a.apply(this,arguments);};};Class.Occlude=new Class({occlude:function(c,b){b=document.id(b||this.element);var a=b.retrieve(c||this.property);
if(a&&this.occluded!=null){return this.occluded=a;}this.occluded=false;b.store(c||this.property,this);return this.occluded;}});Class.refactor=function(b,a){Object.each(a,function(e,d){var c=b.prototype[d];
if(c&&c.$origin){c=c.$origin;}if(c&&typeof e=="function"){b.implement(d,function(){var f=this.previous;this.previous=c;var g=e.apply(this,arguments);this.previous=f;
return g;});}else{b.implement(d,e);}});return b;};var IframeShim=new Class({Implements:[Options,Events,Class.Occlude],options:{className:"iframeShim",src:'javascript:false;document.write("");',display:false,zIndex:null,margin:0,offset:{x:0,y:0},browsers:((Browser.ie&&Browser.version==6)||(Browser.firefox&&Browser.version<3&&Browser.Platform.mac))},property:"IframeShim",initialize:function(b,a){this.element=document.id(b);
j.top=Math.ceil(j.top);if(g.returnPos){return j;}else{this.setStyles(j);}return this;}});})();var IframeShim=new Class({Implements:[Options,Events,Class.Occlude],options:{className:"iframeShim",src:'javascript:false;document.write("");',display:false,zIndex:null,margin:0,offset:{x:0,y:0},browsers:((Browser.ie&&Browser.version==6)||(Browser.firefox&&Browser.version<3&&Browser.Platform.mac))},property:"IframeShim",initialize:function(b,a){this.element=document.id(b);
if(this.occlude()){return this.occluded;}this.setOptions(a);this.makeShim();return this;},makeShim:function(){if(this.options.browsers){var c=this.element.getStyle("zIndex").toInt();
if(!c){c=1;var b=this.element.getStyle("position");if(b=="static"||!b){this.element.setStyle("position","relative");}this.element.setStyle("zIndex",c);
}c=((this.options.zIndex!=null||this.options.zIndex===0)&&c>this.options.zIndex)?this.options.zIndex:c-1;if(c<0){c=1;}this.shim=new Element("iframe",{src:this.options.src,scrolling:"no",frameborder:0,styles:{zIndex:c,position:"absolute",border:"none",filter:"progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"},"class":this.options.className}).store("IframeShim",this);
@@ -135,7 +135,34 @@ var c=a.update||a.updateId;var b=this.retrieve("form.request");if(c){if(b){b.upd
}this.store("form.request:options",a.options);}return this;},get:function(){var a=Array.link(arguments,{options:Type.isObject,update:Type.isElement,updateId:Type.isString});
var b=a.update||a.updateId;if(a.options||b||!this.retrieve("form.request")){if(a.options||!this.retrieve("form.request:options")){this.set("form.request",a.options);
}if(b){this.set("form.request",b);}this.store("form.request",new Form.Request(this,this.retrieve("form.request:update"),this.retrieve("form.request:options")));
}return this.retrieve("form.request");}};Element.implement({formUpdate:function(b,a){this.get("formRequest",b,a).send();return this;}});})();Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical",wrapper:false,hideOverflow:true,resetHeight:false},initialize:function(b,a){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0);
}return this.retrieve("form.request");}};Element.implement({formUpdate:function(b,a){this.get("formRequest",b,a).send();return this;}});})();Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(b,a){this.elements=this.subject=$$(b);
this.parent(a);},compute:function(g,h,j){var c={};for(var d in g){var a=g[d],e=h[d],f=c[d]={};for(var b in a){f[b]=this.parent(a[b],e[b],j);}}return c;
},set:function(b){for(var c in b){if(!this.elements[c]){continue;}var a=b[c];for(var d in a){this.render(this.elements[c],d,a[d],this.options.unit);}}return this;
},start:function(c){if(!this.check(c)){return this;}var h={},j={};for(var d in c){if(!this.elements[d]){continue;}var f=c[d],a=h[d]={},g=j[d]={};for(var b in f){var e=this.prepare(this.elements[d],b,f[b]);
a[b]=e.from;g[b]=e.to;}}return this.parent(h,j);}});Fx.Accordion=new Class({Extends:Fx.Elements,options:{fixedHeight:false,fixedWidth:false,display:0,show:false,height:true,width:false,opacity:true,alwaysHide:false,trigger:"click",initialDisplayFx:true,returnHeightToAuto:true},initialize:function(){var d=function(e){return e!=null;
};var c=Array.link(arguments,{container:Type.isElement,options:Type.isObject,togglers:d,elements:d});this.parent(c.elements,c.options);this.togglers=$$(c.togglers);
this.previous=-1;this.internalChain=new Chain();if(this.options.alwaysHide){this.options.wait=true;}if(this.options.show||this.options.show===0){this.options.display=false;
this.previous=this.options.show;}if(this.options.start){this.options.display=false;this.options.show=false;}this.effects={};if(this.options.opacity){this.effects.opacity="fullOpacity";
}if(this.options.width){this.effects.width=this.options.fixedWidth?"fullWidth":"offsetWidth";}if(this.options.height){this.effects.height=this.options.fixedHeight?"fullHeight":"scrollHeight";
}for(var b=0,a=this.togglers.length;b<a;b++){this.addSection(this.togglers[b],this.elements[b]);}this.elements.each(function(f,e){if(this.options.show===e){this.fireEvent("active",[this.togglers[e],f]);
}else{for(var g in this.effects){f.setStyle(g,0);}}},this);if(this.options.display||this.options.display===0||this.options.initialDisplayFx===false){this.display(this.options.display,this.options.initialDisplayFx);
}if(this.options.fixedHeight!==false){this.options.returnHeightToAuto=false;}this.addEvent("complete",this.internalChain.callChain.bind(this.internalChain));
},addSection:function(e,c){e=document.id(e);c=document.id(c);this.togglers.include(e);this.elements.include(c);var f=this.togglers.contains(e);var a=this.togglers.indexOf(e);
var b=this.display.pass(a,this);e.store("accordion:display",b).addEvent(this.options.trigger,b);if(this.options.height){c.setStyles({"padding-top":0,"border-top":"none","padding-bottom":0,"border-bottom":"none"});
}if(this.options.width){c.setStyles({"padding-left":0,"border-left":"none","padding-right":0,"border-right":"none"});}c.fullOpacity=1;if(this.options.fixedWidth){c.fullWidth=this.options.fixedWidth;
}if(this.options.fixedHeight){c.fullHeight=this.options.fixedHeight;}c.setStyle("overflow","hidden");if(!f){for(var d in this.effects){c.setStyle(d,0);
}}return this;},removeSection:function(e,b){var a=this.togglers.indexOf(e);var c=this.elements[a];var d=function(){this.togglers.erase(e);this.elements.erase(c);
this.detach(e);}.bind(this);if(this.now==a||b!=null){this.display(b!=null?b:(a-1>=0?a-1:0)).chain(d);}else{d();}return this;},detach:function(b){var a=function(c){c.removeEvent(this.options.trigger,c.retrieve("accordion:display"));
}.bind(this);if(!b){this.togglers.each(a);}else{a(b);}return this;},display:function(a,b){if(!this.check(a,b)){return this;}b=b!=null?b:true;a=(typeOf(a)=="element")?this.elements.indexOf(a):a;
if(a==this.previous&&!this.options.alwaysHide){return this;}if(this.options.returnHeightToAuto){var d=this.elements[this.previous];if(d&&!this.selfHidden){for(var c in this.effects){d.setStyle(c,d[this.effects[c]]);
}}}if((this.timer&&this.options.wait)||(a===this.previous&&!this.options.alwaysHide)){return this;}this.previous=a;var e={};this.elements.each(function(h,g){e[g]={};
var f;if(g!=a){f=true;}else{if(this.options.alwaysHide&&((h.offsetHeight>0&&this.options.height)||h.offsetWidth>0&&this.options.width)){f=true;this.selfHidden=true;
}}this.fireEvent(f?"background":"active",[this.togglers[g],h]);for(var j in this.effects){e[g][j]=f?0:h[this.effects[j]];}},this);this.internalChain.clearChain();
this.internalChain.chain(function(){if(this.options.returnHeightToAuto&&!this.selfHidden){var f=this.elements[a];if(f){f.setStyle("height","auto");}}}.bind(this));
return b?this.start(e):this.set(e);}});var Accordion=new Class({Extends:Fx.Accordion,initialize:function(){this.parent.apply(this,arguments);var a=Array.link(arguments,{container:Type.isElement});
this.container=a.container;},addSection:function(c,b,e){c=document.id(c);b=document.id(b);var d=this.togglers.contains(c);var a=this.togglers.length;if(a&&(!d||e)){e=e!=null?e:a-1;
c.inject(this.togglers[e],"before");b.inject(c,"after");}else{if(this.container&&!d){c.inject(this.container);b.inject(this.container);}}return this.parent.apply(this,arguments);
}});Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical",wrapper:false,hideOverflow:true,resetHeight:false},initialize:function(b,a){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0);
if(this.open&&this.options.resetHeight){this.wrapper.setStyle("height","");}},true);this.element=this.subject=document.id(b);this.parent(a);var d=this.element.retrieve("wrapper");
var c=this.element.getStyles("margin","position","overflow");if(this.options.hideOverflow){c=Object.append(c,{overflow:"hidden"});}if(this.options.wrapper){d=document.id(this.options.wrapper).setStyles(c);
}this.wrapper=d||new Element("div",{styles:c}).wraps(this.element);this.element.store("wrapper",this.wrapper).setStyle("margin",0);this.now=[];this.open=true;
+2 -1
View File
@@ -12,9 +12,10 @@ domadminform_init = function() {
}
{% url domains as doms_url %}
new Request({
url: "{{ doms_url }}" + domid + "/raw/",
url: "{% url domains %}" + domid + "/rawmboxes/?target=permissions",
method: "get", onSuccess: function(data) {
$("id_user").set("html", data);
$("id_user").options[0].setProperty("selected", "selected");
}
}).send();
});
@@ -1,19 +1,15 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "New mailbox" %}</h1></div>
<div class="title"><h1>{{ title }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.newmailbox as box_url %}
<form action="{{ box_url }}" method="POST" id="mboxform" name="mboxform">
<form action="{{ action }}" method="POST" id="{{ formid }}" name="{{ formid }}">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Create' %}" />
<input type="submit" name="submit" value="{{ submit_label }}" />
</div>
</form>
{% endblock %}
+2 -2
View File
@@ -21,13 +21,13 @@ window.addEvent("domready", function() {
$$("a[name=remove]").addEvent("click", function(evt) {
evt.stop();
if (objtable.selectedRows.length == 0) {
if (objtable._selectedRows.length == 0) {
return;
}
var type = $("objects").get("name");
var selection = "";
objtable.selectedRows.each(function(item) {
objtable._selectedRows.each(function(item) {
if (selection != "") {
selection += ",";
}
-18
View File
@@ -1,18 +0,0 @@
{% extends "layout_simple.html" %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
{% load i18n %}
<div class="title"><h1>{% trans "Domain" %} {{ domain.name }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.editdomain domain.id as dom_url %}
<form action="{{ dom_url }}" method="post" name="domform" id="domform">
{% include "common/genericform.html" %}
<div class="lastrow" align="center">
<input type="submit" class="button" name="submit" value="{% trans 'Update' %}" />
</div>
</form>
{% endblock %}
-17
View File
@@ -1,17 +0,0 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "Edit domain alias" %}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.editdomalias domalias.id as box_url %}
<form action="{{ box_url }}" method="POST" id="domaliasform" name="domaliasform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Update' %}" />
</div>
</form>
{% endblock %}
-18
View File
@@ -1,18 +0,0 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "Mailbox" %} {{ mbox.name }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.editmailbox mbox.id as box_url %}
<form action="{{ box_url }}" method="POST" id="mboxform" name="mboxform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Update' %}" />
</div>
</form>
{% endblock %}
-17
View File
@@ -1,17 +0,0 @@
{% extends "layout_simple.html" %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
{% load i18n %}
<div class="title"><h1>Mailbox alias {{ alias.address }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.editmbalias alias.id as edit_url %}
<form action="{{ edit_url }}" method="POST" id="aliasform" name="aliasform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Update' %}" />
</div>
</form>
{% endblock %}
+1 -1
View File
@@ -18,7 +18,7 @@
{% for mb in mailboxes %}
<tr class="{% cycle 'odd' 'even' %}" id="{{ mb.id }}">
<td>{{ mb.name }}</td>
<td>{{ mb.address }}@{{ mb.domain.name }}</td>
<td>{{ mb.full_address }}</td>
<td class="center">{{ mb.alias_set.all|length }}</td>
<td class="center">{{ mb.quota }} {% trans "MB" %}</td>
<td class="center">{{ mb.user.is_active|yesno:_("yes,no") }}</td>
+6
View File
@@ -1,5 +1,11 @@
{% load i18n %}
{% if target == "permissions" %}
<option value="">{% trans "Choose a value" %}</option>
{% endif %}
{% for mb in mailboxes %}
{% if target == "permissions" %}
<option value='{{ mb.id }}'>{{ mb.name }}</option>
{% else %}
<option value='{{ mb.id }}'>{{ mb.full_address }}</option>
{% endif %}
{% endfor %}
+2 -2
View File
@@ -2,7 +2,7 @@
{% load i18n admin_extras %}
{% block pagetitle %}{% trans "Mailbox aliases" %}{% endblock %}
{% block subcontent %}
<div id="objects" name="mbaliases" rel="300 260">
<div id="objects" name="mbaliases" rel="300 300">
{% if not aliases %}
<div class="info">{% trans "No mailbox alias defined." %}</div>
{% else %}
@@ -15,7 +15,7 @@
</tr>
{% for alias in aliases %}
<tr class="{% cycle 'odd' 'even' %}" id="{{ alias.id }}">
<td>{{ alias.full_address }}</td>
<td>{{ alias.address }}@{{ alias.domain }}</td>
<td>
{% for mb in alias.mboxes.all %}
{{ mb.full_address }}<br/>
+24
View File
@@ -0,0 +1,24 @@
{% extends "admin/adminform.html" %}
{% block html_head %}
{{ block.super }}
<script type="text/javascript">
window.addEvent("domready", function() {
mbaliasform_init = function() {
$("id_domain").addEvent("change", function(event) {
var domid = this.value;
if (domid == "") {
$("id_mboxes").set("html", "");
return;
}
new Request({
url: "{% url domains %}" + domid + "/rawmboxes/?target=mbaliases",
method: "get", onSuccess: function(data) {
$("id_mboxes").set("html", data);
}
}).send();
});
};
mbaliasform_init();
});
</script>
{% endblock %}
-19
View File
@@ -1,19 +0,0 @@
{% extends "layout_simple.html" %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
{% load i18n %}
<div class="title"><h1>{% trans "New domain" %}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.newdomain as dom_url %}
<form action="{{ dom_url }}" method="post" name="domform" id="domform">
{% include "common/genericform.html" %}
<div class="lastrow" align="center">
<input type="submit" class="button" name="submit" value="{% trans 'Create' %}" />
</div>
</form>
{% endblock %}
-17
View File
@@ -1,17 +0,0 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "New domain alias" %}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.newdomalias domain as box_url %}
<form action="{{ box_url }}" method="POST" id="domaliasform" name="domaliasform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Create' %}" />
</div>
</form>
{% endblock %}
-17
View File
@@ -1,17 +0,0 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/form.js" type="text/javascript"></script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "New mailbox alias" %}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
{% url admin.views.newmbalias as box_url %}
<form action="{{ box_url }}" method="POST" id="aliasform" name="aliasform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" name="submit" value="{% trans 'Create' %}" />
</div>
</form>
{% endblock %}
+1 -1
View File
@@ -20,7 +20,7 @@ def options_menu(user):
"img" : static_url("pics/edit.png"),
"label" : _("Change password"),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:350,y:220}}"},
"rel" : "{handler:'iframe',size:{x:360,y:200}}"},
{"name" : "preferences",
"img" : static_url("pics/user.png"),
"label" : _("Preferences"),
+6 -13
View File
@@ -1,11 +1,10 @@
import copy
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators \
import login_required
from django.utils import simplejson
from django.utils.translation import ugettext as _
from modoboa.lib import _render, _ctx_ok, _ctx_ko, getctx, parameters
from modoboa.lib import _render, ajax_response, parameters
from modoboa.lib import crypt_password
from forms import ChangePasswordForm
from modoboa.admin.models import Mailbox
@@ -15,7 +14,7 @@ def index(request):
return HttpResponseRedirect(reverse(preferences))
@login_required
def changepassword(request):
def changepassword(request, tplname="userprefs/chpassword.html"):
if request.user.id == 1:
target = request.user
else:
@@ -29,13 +28,8 @@ def changepassword(request):
else:
target.set_password(request.POST["confirmation"])
target.save()
ctx = _ctx_ok("")
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
ctx = _ctx_ko("userprefs/chpassword.html", {
"form" : form, "error" : error
})
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request)
return ajax_response(request, status="ko", template=tplname, form=form, error=error)
form = ChangePasswordForm(target)
return _render(request, 'userprefs/chpassword.html', {
@@ -70,6 +64,5 @@ def savepreferences(request):
app, name = pname.split('.')
parameters.save_user(request.user, name, v, app=app)
ctx = getctx("ok")
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
return ajax_response(request)