diff --git a/modoboa/admin/forms.py b/modoboa/admin/forms.py index dd8228ec0..fd2054107 100644 --- a/modoboa/admin/forms.py +++ b/modoboa/admin/forms.py @@ -8,7 +8,6 @@ from modoboa.admin.templatetags.admin_extras import gender from modoboa.lib.emailutils import split_mailbox from modoboa.lib.permissions import get_account_roles from modoboa.lib.formutils import * -from modoboa.lib.permissions import * class DomainFormGeneral(forms.ModelForm, DynamicForm): @@ -101,9 +100,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): continue events.raiseEvent("CanCreate", user, "domain_aliases") al = DomainAlias(name=v, target=d, enabled=d.enabled) - al.save() - grant_access_to_object(user, al, is_owner=True) - events.raiseEvent("DomainAliasCreated", user, al) + al.save(creator=user) for dalias in d.domainalias_set.all(): if not len(filter(lambda name: self.cleaned_data[name] == dalias.name, @@ -112,6 +109,67 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): return d +class DomainFormOptions(forms.Form): + create_dom_admin = YesNoField( + label=ugettext_lazy("Create a domain administrator"), + initial="no", + help_text=ugettext_lazy("Automatically create an administrator for this domain") + ) + + dom_admin_username = forms.CharField( + label=ugettext_lazy("Name"), + initial="admin", + help_text=ugettext_lazy("The administrator's name. Don't include the domain's name here, it will be automatically appended."), + widget=forms.widgets.TextInput(attrs={"class": "input-small"}), + required=False + ) + + create_aliases = YesNoField( + label=ugettext_lazy("Create aliases"), + initial="yes", + help_text=ugettext_lazy("Automatically create standard aliases for this domain"), + required=False + ) + + def __init__(self, *args, **kwargs): + super(DomainFormOptions, self).__init__(*args, **kwargs) + if args: + if args[0].get("create_dom_admin", "no") == "yes": + self.fields["dom_admin_username"].required = True + self.fields["create_aliases"].required = True + + def clean_dom_admin_username(self): + if '@' in self.cleaned_data["dom_admin_username"]: + raise forms.ValidationError(_("Invalid format")) + return self.cleaned_data["dom_admin_username"] + + def save(self, user, domain): + if self.cleaned_data["create_dom_admin"] == "no": + return + username = "%s@%s" % (self.cleaned_data["dom_admin_username"], domain.name) + try: + da = User.objects.get(username=username) + except User.DoesNotExist: + pass + else: + raise AdminError(_("User '%s' already exists" % username)) + da = User(username=username, email=username, is_active=True) + da.set_password("password") + da.save() + da.set_role("DomainAdmins") + da.post_create(user) + mb = Mailbox(address=self.cleaned_data["dom_admin_username"], domain=domain, + user=da, use_domain_quota=True) + mb.set_quota() + mb.save(creator=user) + + if self.cleaned_data["create_aliases"] == "yes": + al = Alias(address="postmaster", domain=domain, enabled=True) + al.save([mb], [], creator=user) + + domain.add_admin(da) + + class DomainForm(TabForms): def __init__(self, user, *args, **kwargs): self.user = user @@ -464,19 +522,6 @@ class AccountFormGeneral(forms.ModelForm): raise forms.ValidationError(_("The two password fields didn't match.")) return password2 - def give_all_accesses(self, account): - """Give access to all objects defined in the database - - Must be used when an account is promoted as a super user. - - :param account: a ``User`` instance - """ - grant_access_to_objects(account, User.objects.all(), get_content_type(User)) - grant_access_to_objects(account, Domain.objects.all(), get_content_type(Domain)) - grant_access_to_objects(account, DomainAlias.objects.all(), get_content_type(DomainAlias)) - grant_access_to_objects(account, Mailbox.objects.all(), get_content_type(Mailbox)) - grant_access_to_objects(account, Alias.objects.all(), get_content_type(Alias)) - def save(self, commit=True): account = super(AccountFormGeneral, self).save(commit=False) if self.user == account and not self.cleaned_data["is_active"]: @@ -490,20 +535,7 @@ class AccountFormGeneral(forms.ModelForm): role = self.cleaned_data["role"] elif self.user.group == "DomainAdmins" and self.user != account: role = "SimpleUsers" - - if role is None or account.group == role: - return account - - account.groups.clear() - if role == "SuperAdmins": - account.is_superuser = True - self.give_all_accesses(account) - else: - if account.is_superuser: - ObjectAccess.objects.filter(user=account).delete() - account.is_superuser = False - account.groups.add(Group.objects.get(name=role)) - account.save() + account.set_role(role) return account @@ -576,18 +608,7 @@ class AccountFormMail(forms.Form, DynamicForm): use_domain_quota=self.cleaned_data["quota_act"]) self.mb.set_quota(self.cleaned_data["quota"], user.has_perm("admin.add_domain")) - self.mb.save() - grant_access_to_object(user, self.mb, is_owner=True) - events.raiseEvent("CreateMailbox", user, self.mb) - if user.is_superuser and not self.mb.user.has_perm("admin.add_domain"): - # A super user is creating a new mailbox. Give - # access to that mailbox (and the associated - # account) to the appropriate domain admins, - # except if the new account has a more important - # role (SuperAdmin, Reseller) - for admin in self.mb.domain.admins: - grant_access_to_object(admin, self.mb) - grant_access_to_object(admin, self.mb.user) + self.mb.save(creator=user) else: newaddress = None if self.cleaned_data["email"] != self.mb.full_address: @@ -627,20 +648,13 @@ class AccountFormMail(forms.Form, DynamicForm): events.raiseEvent("CanCreate", user, "mailbox_aliases") al = Alias(address=local_part, enabled=account.is_active) al.domain = Domain.objects.get(name=domname) - al.save([self.mb], []) - grant_access_to_object(user, al, is_owner=True) - events.raiseEvent("MailboxAliasCreated", user, al) - if user.is_superuser: - for admin in al.domain.admins: - grant_access_to_object(admin, al) + al.save([self.mb], [], creator=user) for alias in self.mb.alias_set.all(): if len(alias.get_recipients()) >= 2: continue if not len(filter(lambda name: self.cleaned_data[name] == alias.full_address, self.cleaned_data.keys())): - events.raiseEvent("MailboxAliasDeleted", alias) - ungrant_access_to_object(alias) alias.delete() return self.mb @@ -677,26 +691,12 @@ class AccountPermissionsForm(forms.Form, DynamicForm): continue if not value in current_domains: domain = Domain.objects.get(name=value) - grant_access_to_object(self.account, domain) - for mb in domain.mailbox_set.all(): - if mb.user.has_perm("admin.add_domain"): - continue - grant_access_to_object(self.account, mb) - grant_access_to_object(self.account, mb.user) - for al in Alias.objects.filter(domain=domain): - grant_access_to_object(self.account, al) + domain.add_admin(self.account) for domain in self.account.get_domains(): if not len(filter(lambda name: self.cleaned_data[name] == domain.name, self.cleaned_data.keys())): - ungrant_access_to_object(domain, self.account) - for mb in domain.mailbox_set.all(): - if mb.user.has_perm("admin.add_domain"): - continue - ungrant_access_to_object(mb, self.account) - ungrant_access_to_object(mb.user, self.account) - for al in Alias.objects.filter(domain=domain): - ungrant_access_to_object(al, self.account) + domain.remove_admin(self.account) class AccountForm(TabForms): diff --git a/modoboa/admin/models.py b/modoboa/admin/models.py index e754d0239..d632b8de4 100644 --- a/modoboa/admin/models.py +++ b/modoboa/admin/models.py @@ -14,8 +14,9 @@ from modoboa.lib.exceptions import PermDeniedException from modoboa.lib.sysutils import exec_cmd, exec_as_vuser from modoboa.lib.emailutils import split_mailbox from modoboa.extensions import exts_pool -from exceptions import * -import os, sys +from exceptions import AdminError +import os +import sys import pwd import re import crypt, hashlib, string, base64 @@ -27,6 +28,7 @@ try: except ImportError: ldap_available = False + class User(DUser): """Proxy for the ``User`` model. @@ -216,7 +218,7 @@ class User(DUser): return self.groups.all()[0].name except IndexError: return "?" - + @property def enabled(self): return self.is_active @@ -269,7 +271,7 @@ class User(DUser): else: q &= Q(groups__name__in=grpfilter) accounts = User.objects.select_related().filter(q) - + aliases = [] if not idtfilter or ("alias" in idtfilter or "forward" in idtfilter @@ -290,7 +292,6 @@ class User(DUser): return chain(accounts, aliases) - def get_domains(self): """Return the domains belonging to this user @@ -408,6 +409,54 @@ class User(DUser): return True return False + def grant_access_to_all_objects(self): + """Give access to all objects defined in the database + + Must be used when an account is promoted as a super user. + """ + from modoboa.lib.permissions import grant_access_to_objects, get_content_type + grant_access_to_objects(self, User.objects.all(), get_content_type(User)) + grant_access_to_objects(self, Domain.objects.all(), get_content_type(Domain)) + grant_access_to_objects(self, DomainAlias.objects.all(), get_content_type(DomainAlias)) + grant_access_to_objects(self, Mailbox.objects.all(), get_content_type(Mailbox)) + grant_access_to_objects(self, Alias.objects.all(), get_content_type(Alias)) + + def set_role(self, role): + """Set administrative role for this account + + :param string role: the role to set + """ + if role is None or self.group == role: + return + self.groups.clear() + if role == "SuperAdmins": + self.is_superuser = True + self.grant_access_to_all_objects() + else: + if self.is_superuser: + ObjectAccess.objects.filter(user=self).delete() + self.is_superuser = False + try: + self.groups.add(Group.objects.get(name=role)) + except Group.DoesNotExist: + self.groups.add(Group.objects.get(name="SimpleUsers")) + self.save() + + def post_create(self, creator): + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(creator, self, is_owner=True) + events.raiseEvent("AccountCreated", self) + + def save(self, *args, **kwargs): + if "creator" in kwargs: + creator = kwargs["creator"] + del kwargs["creator"] + else: + creator = None + super(User, self).save(*args, **kwargs) + if creator is not None: + self.post_create(creator) + def from_csv(self, user, row, crypt_password=True): """Create a new account from a CSV file entry @@ -419,8 +468,6 @@ class User(DUser): :param row: a list containing the expected information :param crypt_password: """ - from modoboa.lib.permissions import grant_access_to_object - if len(row) < 6: raise AdminError(_("Invalid line")) self.username = row[1].strip() @@ -431,17 +478,8 @@ class User(DUser): self.first_name = row[3].strip() self.last_name = row[4].strip() self.is_active = (row[5].strip() == 'True') - grpname = row[6].strip() - if grpname == "SuperAdmins": - self.is_superuser = True - self.save() - else: - self.save() - try: - self.groups.add(Group.objects.get(name=grpname)) - except Group.DoesNotExist: - self.groups.add(Group.objects.get(name="SimpleUsers")) - self.save() + self.save(creator=user) + self.set_role(row[6].strip()) self.email = row[7].strip() if self.email != "": @@ -454,12 +492,11 @@ class User(DUser): raise PermDeniedException mb = Mailbox(address=mailbox, domain=domain, user=self, use_domain_quota=True) mb.set_quota(override_rules=user.has_perm("admin.change_domain")) - mb.save() - self.save() - if grpname == "DomainAdmins": + mb.save(creator=user) + if self.group == "DomainAdmins": for domname in row[8:]: try: - grant_access_to_object(self, Domain.objects.get(name=domname)) + Domain.objects.get(name=domname).add_admin(self) except Domain.DoesNotExist: pass @@ -470,7 +507,8 @@ class User(DUser): if self.group == "DomainAdmins": row += [dom.name for dom in self.get_domains()] csvwriter.writerow(row) - + + class ObjectAccess(models.Model): user = models.ForeignKey(User) content_type = models.ForeignKey(ContentType) @@ -483,7 +521,8 @@ class ObjectAccess(models.Model): def __unicode__(self): return "%s => %s (%s)" % (self.user, self.content_object, self.content_type) - + + class ObjectDates(models.Model): """Dates recording for admin objects @@ -530,21 +569,26 @@ class DatesAware(models.Model): def last_modification(self): return self.dates.last_modification + class Domain(DatesAware): name = models.CharField(ugettext_lazy('name'), max_length=100, unique=True, help_text=ugettext_lazy("The domain name")) - quota = models.IntegerField(help_text=ugettext_lazy("Default quota in MB applied to mailboxes")) - enabled = models.BooleanField(ugettext_lazy('enabled'), - help_text=ugettext_lazy("Check to activate this domain")) + quota = models.IntegerField( + help_text=ugettext_lazy("Default quota in MB applied to mailboxes") + ) + enabled = models.BooleanField( + ugettext_lazy('enabled'), + help_text=ugettext_lazy("Check to activate this domain") + ) owners = generic.GenericRelation(ObjectAccess) class Meta: permissions = ( ("view_domain", "View domain"), ("view_domains", "View domains"), - ) + ) ordering = ["name"] - + @property def domainalias_count(self): return self.domainalias_set.count() @@ -559,8 +603,42 @@ class Domain(DatesAware): @property def admins(self): + """Return the domain administrators of this domain + + :return: a list of User objects + """ return [oa.user for oa in self.owners.filter(user__is_superuser=False)] + def add_admin(self, account): + """Add a new administrator for this domain + + :param User account: the administrotor to add + """ + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(account, self) + for mb in self.mailbox_set.all(): + if mb.user.has_perm("admin.add_domain"): + continue + grant_access_to_object(account, mb) + grant_access_to_object(account, mb.user) + for al in self.alias_set.all(): + grant_access_to_object(account, al) + + def remove_admin(self, account): + """Remove an administrator for this domain + + :param User account: the administrotor to remove + """ + from modoboa.lib.permissions import ungrant_access_to_object + ungrant_access_to_object(account, self) + for mb in self.mailbox_set.all(): + if mb.user.has_perm("admin.add_domain"): + continue + ungrant_access_to_object(mb, account) + ungrant_access_to_object(mb.user, account) + for al in self.alias_set.all(): + ungrant_access_to_object(al, account) + def delete(self, fromuser, keepdir=False): from modoboa.lib.permissions import ungrant_access_to_object, ungrant_access_to_objects @@ -588,13 +666,28 @@ class Domain(DatesAware): def __str__(self): return self.name + def post_create(self, creator): + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(creator, self, is_owner=True) + events.raiseEvent("CreateDomain", creator, self) + + def save(self, *args, **kwargs): + if "creator" in kwargs: + creator = kwargs["creator"] + del kwargs["creator"] + else: + creator = None + super(Domain, self).save(*args, **kwargs) + if creator is not None: + self.post_create(creator) + def from_csv(self, user, row): if len(row) < 4: raise AdminError(_("Invalid line")) self.name = row[1].strip() self.quota = int(row[2].strip()) self.enabled = (row[3].strip() == 'True') - self.save() + self.save(creator=user) def to_csv(self, csvwriter): csvwriter.writerow(["domain", self.name, self.quota, self.enabled]) @@ -603,21 +696,38 @@ class Domain(DatesAware): class DomainAlias(DatesAware): name = models.CharField(ugettext_lazy("name"), max_length=100, unique=True, help_text=ugettext_lazy("The alias name")) - target = models.ForeignKey(Domain, verbose_name=ugettext_lazy('target'), - help_text=ugettext_lazy("The domain this alias points to")) + target = models.ForeignKey( + Domain, verbose_name=ugettext_lazy('target'), + help_text=ugettext_lazy("The domain this alias points to") + ) enabled = models.BooleanField( ugettext_lazy('enabled'), help_text=ugettext_lazy("Check to activate this alias") - ) + ) class Meta: permissions = ( ("view_domaliases", "View domain aliases"), - ) + ) def __unicode__(self): return self.name + def post_create(self, creator): + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(creator, self, is_owner=True) + events.raiseEvent("DomainAliasCreated", creator, self) + + def save(self, *args, **kwargs): + if "creator" in kwargs: + creator = kwargs["creator"] + del kwargs["creator"] + else: + creator = None + super(DomainAlias, self).save(*args, **kwargs) + if creator is not None: + self.post_create(creator) + def delete(self): from modoboa.lib.permissions import ungrant_access_to_object events.raiseEvent("DomainAliasDeleted", self) @@ -628,7 +738,7 @@ class DomainAlias(DatesAware): """Create a domain alias from a CSV row Expected format: ["domainalias", domain alias name, targeted domain, enabled] - + :param user: a ``User`` object :param row: a list containing the alias definition """ @@ -641,7 +751,7 @@ class DomainAlias(DatesAware): except Domain.DoesNotExist: raise AdminError(_("Unknown domain %s" % domname)) self.enabled = row[3].strip() == 'True' - self.save() + self.save(creator=user) def to_csv(self, csvwriter): """Export a domain alias using CSV format @@ -650,11 +760,12 @@ class DomainAlias(DatesAware): """ csvwriter.writerow(["domainalias", self.name, self.target.name, self.enabled]) + class Mailbox(DatesAware): address = models.CharField( ugettext_lazy('address'), max_length=100, help_text=ugettext_lazy("Mailbox address (without the @domain.tld part)") - ) + ) quota = models.PositiveIntegerField() use_domain_quota = models.BooleanField(default=False) domain = models.ForeignKey(Domain) @@ -671,10 +782,10 @@ class Mailbox(DatesAware): def __str__(self): return self.full_address - + def __full_address(self, localpart): return "%s@%s" % (localpart, self.domain.name) - + @property def full_address(self): return self.__full_address(self.address) @@ -776,8 +887,29 @@ class Mailbox(DatesAware): q = Quota.objects.get(username=self.full_address) return int(q.bytes / float(self.quota * 1048576) * 100) + def post_create(self, creator): + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(creator, self, True) + events.raiseEvent("CreateMailbox", creator, self) + if creator.is_superuser and not self.user.has_perm("admin.add_domain"): + # A super user is creating a new mailbox. Give + # access to that mailbox (and the associated + # account) to the appropriate domain admins, + # except if the new account has a more important + # role (SuperAdmin, Reseller) + for admin in self.domain.admins: + grant_access_to_object(admin, self) + grant_access_to_object(admin, self.user) + def save(self, *args, **kwargs): + if "creator" in kwargs: + creator = kwargs["creator"] + del kwargs["creator"] + else: + creator = None super(Mailbox, self).save(*args, **kwargs) + if creator is not None: + self.post_create(creator) try: q = self.quota_value except Quota.DoesNotExist: @@ -889,12 +1021,27 @@ class Alias(DatesAware): altype = self.type return [{"name" : altype, "label" : labels[altype], "type" : "idt"}] + def post_create(self, creator): + from modoboa.lib.permissions import grant_access_to_object + grant_access_to_object(creator, self, is_owner=True) + events.raiseEvent("MailboxAliasCreated", creator, self) + if creator.is_superuser: + for admin in self.domain.admins: + grant_access_to_object(admin, self) + def save(self, int_rcpts, ext_rcpts, *args, **kwargs): if len(ext_rcpts): self.extmboxes = ",".join(ext_rcpts) else: self.extmboxes = "" + if "creator" in kwargs: + creator = kwargs["creator"] + del kwargs["creator"] + else: + creator = None super(Alias, self).save(*args, **kwargs) + if creator is not None: + self.post_create(creator) curmboxes = self.mboxes.all() for t in int_rcpts: if not t in curmboxes: @@ -961,7 +1108,7 @@ class Alias(DatesAware): domain__name=domname)] except Mailbox.DoesNotExist: raise AdminError(_("Mailbox %s does not exist" % rcpt)) - self.save(int_rcpts, ext_rcpts) + self.save(int_rcpts, ext_rcpts, creator=user) def to_csv(self, csvwriter): row = [self.type, self.full_address, self.enabled] @@ -1032,11 +1179,8 @@ def populate_callback(user): from modoboa.lib.permissions import grant_access_to_object sadmins = User.objects.filter(is_superuser=True) - - user.groups.add(Group.objects.get(name="SimpleUsers")) - user.save() - events.raiseEvent("AccountCreated", user) - grant_access_to_object(sadmins[0], user, True) + user.set_role("SimpleUsers") + user.post_create(sadmins[0]) for su in sadmins[1:]: grant_access_to_object(su, user) @@ -1044,13 +1188,8 @@ def populate_callback(user): try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: - domain = Domain() - domain.name = domname - domain.enabled = True - domain.quota = 0 - domain.save() - events.raiseEvent("CreateDomain", sadmins[0], domain) - grant_access_to_object(sadmins[0], domain, True) + domain = Domain(name=domname, enabled=True, quota=0) + domain.save(creator=sadmin[0]) for su in sadmins[1:]: grant_access_to_object(su, domain) try: @@ -1058,8 +1197,6 @@ def populate_callback(user): except Mailbox.DoesNotExist: mb = Mailbox(address=localpart, domain=domain, user=user, use_domain_quota=True) mb.set_quota() - mb.save() - events.raiseEvent("CreateMailbox", sadmins[0], mb) - grant_access_to_object(sadmins[0], mb, True) + mb.save(creator=sadmins[0]) for su in sadmins[1:]: - grant_access_to_object(su, domain) + grant_access_to_object(su, mb) diff --git a/modoboa/admin/static/admin/js/admin.js b/modoboa/admin/static/admin/js/admin.js index 42619504d..71203bdd1 100644 --- a/modoboa/admin/static/admin/js/admin.js +++ b/modoboa/admin/static/admin/js/admin.js @@ -161,17 +161,35 @@ Domains.prototype = { }); }, - domainform_cb: function() { + change_inputs_state: function(value) { + $("#id_dom_admin_username").attr("disabled", value); + $("input[name=create_aliases]").attr("disabled", value); + }, + + create_dom_admin_changed: function(e) { + var $target = $(e.target); + this.change_inputs_state(($target.attr("value") == "yes") ? false : true); + }, + + generalform_init: function() { $('input:text:visible:first').focus(); $("#id_aliases").dynamic_input(); - $(".submit").one('click', $.proxy(function(e) { - simple_ajax_form_post(e, { - formid: "domform", - error_cb: $.proxy(this.domainform_cb, this), - reload_on_success: false, - success_cb: $.proxy(this.reload_listing, this) - }); - }, this)); + }, + + optionsform_init: function() { + $("input[name=create_dom_admin]").click($.proxy(this.create_dom_admin_changed, this)); + this.change_inputs_state( + $("input[name=create_dom_admin]:checked").attr("value") == "yes" ? false : true + ); + this.optionsform_prefill(); + }, + + optionsform_prefill: function() { + var $span = $("#id_dom_admin_username").next("span"); + $span.html("@" + $("#id_name").attr("value")); + }, + + domadminsform_init: function() { $("a[name=removeperm]").click(function(e) { var $tr = $(this).parent().parent(); simple_ajax_request.apply(this, [e, { @@ -184,6 +202,35 @@ Domains.prototype = { } }]); }); + }, + + newdomain_cb: function() { + this.generalform_init(); + this.optionsform_init(); + $("#wizard").cwizard({ + formid: "domform", + transition_callbacks: { + 1: this.optionsform_prefill + }, + error_callbacks: { + 1: this.generalform_init, + 2: $.proxy(this.optionsform_init, this) + }, + success_callback: $.proxy(this.reload_listing, this) + }); + }, + + domainform_cb: function() { + this.generalform_init(); + this.domadminsform_init(); + $(".submit").one('click', $.proxy(function(e) { + simple_ajax_form_post(e, { + formid: "domform", + error_cb: $.proxy(this.domainform_cb, this), + reload_on_success: false, + success_cb: $.proxy(this.reload_listing, this) + }); + }, this)); $(document).trigger('domform_init'); } diff --git a/modoboa/admin/templates/admin/domain_options_form.html b/modoboa/admin/templates/admin/domain_options_form.html new file mode 100644 index 000000000..800f7110d --- /dev/null +++ b/modoboa/admin/templates/admin/domain_options_form.html @@ -0,0 +1,4 @@ +{% load i18n libextras %} +{% render_field form.create_dom_admin %} +{% render_field_appended form.dom_admin_username "@" %} +{% render_field form.create_aliases %} diff --git a/modoboa/admin/templates/admin/identities.html b/modoboa/admin/templates/admin/identities.html index 1ba08cdd9..6e664ec8a 100644 --- a/modoboa/admin/templates/admin/identities.html +++ b/modoboa/admin/templates/admin/identities.html @@ -2,10 +2,7 @@ {% block pagetitle %}{% trans "Identities" %}{% endblock %} {% block html_head %} {{ block.super }} - - - + diff --git a/modoboa/admin/templatetags/admin_extras.py b/modoboa/admin/templatetags/admin_extras.py index 1f0ecb3dc..8ae188ad2 100644 --- a/modoboa/admin/templatetags/admin_extras.py +++ b/modoboa/admin/templatetags/admin_extras.py @@ -76,7 +76,7 @@ def domains_menu(selection, user): "label" : _("Add domain"), "img" : "icon-plus", "modal" : True, - "modalcb" : "admin.domainform_cb", + "modalcb" : "admin.newdomain_cb", "url" : reverse("modoboa.admin.views.newdomain")}, {"name" : "import", "label" : _("Import"), diff --git a/modoboa/admin/views.py b/modoboa/admin/views.py index f2f205ff9..e421bd0f8 100644 --- a/modoboa/admin/views.py +++ b/modoboa/admin/views.py @@ -20,7 +20,8 @@ from modoboa.lib.webutils \ import _render, ajax_response, ajax_simple_response, _render_to_string from modoboa.lib.emailutils import split_mailbox from modoboa.lib.models import Parameter -from modoboa.lib.permissions import * +from modoboa.lib.formutils import CreationWizard + @login_required def index(request): @@ -67,8 +68,6 @@ def _validate_domain(request, form, successmsg, commonctx, tplname, domain = form.save(request.user) except AdminError, e: error = str(e) - # except IntegrityError: - # error = _("An alias with this name already exists") else: if callback is not None: callback(request.user, domain) @@ -81,23 +80,49 @@ def _validate_domain(request, form, successmsg, commonctx, tplname, @login_required @permission_required("admin.add_domain") @transaction.commit_on_success -def newdomain(request, tplname="admin/newdomainform.html"): +def newdomain(request, tplname="common/wizard_forms.html"): events.raiseEvent("CanCreate", request.user, "domains") - def newdomain_cb(user, domain): - grant_access_to_object(user, domain, is_owner=True) - events.raiseEvent("CreateDomain", user, domain) + + def newdomain_cb(steps): + genform = steps[0]["form"] + genform.is_valid() + domain = genform.save(request.user) + domain.post_create(request.user) + steps[1]["form"].save(request.user, domain) commonctx = {"title" : _("New domain"), "action_label" : _("Create"), "action_classes" : "submit", "action" : reverse(newdomain), "formid" : "domform"} + cwizard = CreationWizard(newdomain_cb) + cwizard.add_step(DomainFormGeneral, _("General"), + [dict(classes="btn-inverse next", label=_("Next"))], + formtpl="admin/domain_general_form.html") + cwizard.add_step(DomainFormOptions, _("Options"), + [dict(classes="btn-primary submit", label=_("Create")), + dict(classes="btn-inverse prev", label=_("Previous"))], + formtpl="admin/domain_options_form.html") + if request.method == "POST": - form = DomainFormGeneral(request.POST) - return _validate_domain(request, form, _("Domain created"), commonctx, - tplname, callback=newdomain_cb) - form = DomainFormGeneral() - commonctx["form"] = form + retcode, data = cwizard.validate_step(request) + if retcode == -1: + raise AdminError(data) + if retcode == 1: + return ajax_simple_response(dict( + status="ok", title=cwizard.get_title(data + 1), stepid=data + )) + if retcode == 2: + return ajax_simple_response(dict(status="ok", respmsg=_("Domain created"))) + + from modoboa.lib.templatetags.libextras import render_form + return ajax_simple_response(dict( + status="ko", stepid=data, form=render_form(cwizard.steps[data]["form"]) + )) + + cwizard.create_forms() + commonctx.update(steps=cwizard.steps) + commonctx.update(subtitle="1. %s" % cwizard.steps[0]['title']) return render(request, tplname, commonctx) @login_required @@ -188,11 +213,7 @@ def _new_alias(request, tplname, formclass, ctx, successmsg): ctx.update(action_label=_("Create"), action_classes="submit") if request.method == "POST": def callback(user, alias): - grant_access_to_object(user, alias, is_owner=True) - events.raiseEvent("MailboxAliasCreated", user, alias) - if user.is_superuser: - for admin in alias.domain.admins: - grant_access_to_object(admin, alias) + alias.post_create(user) form = formclass(request.user, request.POST) return _validate_alias(request, form, successmsg, tplname, ctx, callback) @@ -382,9 +403,7 @@ def list_quotas(request, tplname="admin/quotas.html"): @login_required @permission_required("auth.add_user") @transaction.commit_on_success -def newaccount(request, tplname='admin/newaccount.html'): - from modoboa.lib.formutils import CreationWizard - +def newaccount(request, tplname='common/wizard_forms.html'): def create_account(steps): """Account creation callback @@ -395,8 +414,7 @@ def newaccount(request, tplname='admin/newaccount.html'): genform = steps[0]["form"] genform.is_valid() account = genform.save() - grant_access_to_object(request.user, account, is_owner=True) - events.raiseEvent("AccountCreated", account) + account.post_create(request.user) mailform = steps[1]["form"] mb = mailform.save(request.user, account) @@ -508,7 +526,7 @@ def remove_permission(request): raise AdminError(_("Invalid request")) if not request.user.can_access(account) or not request.user.can_access(domain): raise PermDeniedException - ungrant_access_to_object(domain, account) + domain.remove_admin(account) return ajax_simple_response(dict(status="ok")) @login_required @@ -598,39 +616,24 @@ def import_domain(user, row, formopts): """Specific code for domains import""" dom = Domain() dom.from_csv(user, row) - grant_access_to_object(user, dom, is_owner=True) - events.raiseEvent("CreateDomain", user, dom) @transaction.commit_on_success def import_domainalias(user, row, formopts): """Specific code for domain aliases import""" domalias = DomainAlias() domalias.from_csv(user, row) - grant_access_to_object(user, domalias, is_owner=True) - events.raiseEvent("DomainAliasCreated", user, domalias) @transaction.commit_on_success def import_account(user, row, formopts): """Specific code for accounts import""" account = User() account.from_csv(user, row, formopts["crypt_password"]) - grant_access_to_object(user, account, is_owner=True) - if account.is_superuser: - # Give access to the existing user - grant_access_to_object(account, user) - events.raiseEvent("AccountCreated", account) - if account.mailbox_set.count(): - mb = account.mailbox_set.all()[0] - grant_access_to_object(user, mb, is_owner=True) - events.raiseEvent("CreateMailbox", user, mb) @transaction.commit_on_success def _import_alias(user, row, **kwargs): """Specific code for aliases import""" alias = Alias() alias.from_csv(user, row, **kwargs) - grant_access_to_object(user, alias, is_owner=True) - events.raiseEvent("MailboxAliasCreated", user, alias) def import_alias(user, row, formopts): _import_alias(user, row, expected_elements=4) diff --git a/modoboa/lib/permissions.py b/modoboa/lib/permissions.py index 5f19e4685..aaddd2d55 100644 --- a/modoboa/lib/permissions.py +++ b/modoboa/lib/permissions.py @@ -3,7 +3,7 @@ from functools import wraps from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ from django.db import IntegrityError -from modoboa.admin.models import ObjectAccess, IntegrityError +from modoboa.admin.models import ObjectAccess import events from exceptions import ModoboaException @@ -89,7 +89,8 @@ def grant_access_to_objects(user, objects, ct): ObjectAccess.objects.create(user=user, content_type=ct, object_id=obj.id) except IntegrityError: pass - + + def ungrant_access_to_object(obj, user=None): """Ungrant access to an object for a specific user diff --git a/modoboa/static/js/creation_wizard.js b/modoboa/static/js/creation_wizard.js index d15701611..25c4d2cce 100644 --- a/modoboa/static/js/creation_wizard.js +++ b/modoboa/static/js/creation_wizard.js @@ -98,7 +98,7 @@ }; $.fn.cwizard.defaults = { - + transition_callbacks: {} }; })(jQuery); \ No newline at end of file diff --git a/modoboa/admin/templates/admin/newaccount.html b/modoboa/templates/common/wizard_forms.html similarity index 91% rename from modoboa/admin/templates/admin/newaccount.html rename to modoboa/templates/common/wizard_forms.html index 3fda0f5fb..fb12c609f 100644 --- a/modoboa/admin/templates/admin/newaccount.html +++ b/modoboa/templates/common/wizard_forms.html @@ -7,13 +7,11 @@