Exemple #1
0
class AliasForm(forms.ModelForm, DynamicForm):
    """A form to create/modify an alias."""

    random_address = forms.BooleanField(label=ugettext_lazy("Random address"),
                                        required=False)
    address = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Email address"),
        help_text=ugettext_lazy(
            "The alias address. To create a catchall alias, just enter the "
            "domain name (@domain.tld)."),
        widget=forms.TextInput(attrs={"class": "form-control"}))
    recipients = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Recipients"),
        required=False,
        help_text=ugettext_lazy(
            "Addresses this alias will point to. Indicate only one address "
            "per input, press ENTER to add a new input."),
        widget=forms.TextInput(attrs={"class": "form-control"}))

    class Meta:
        model = Alias
        fields = ("address", "domain", "enabled", "expire_at", "description")
        labels = {"domain": ugettext_lazy("Domain")}
        widgets = {
            "domain":
            forms.widgets.Select(attrs={
                "class": "selectpicker",
                "data-live-search": "true"
            })
        }

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(AliasForm, self).__init__(*args, **kwargs)
        self.fields = OrderedDict((key, self.fields[key]) for key in [
            "random_address", "address", "domain", "recipients", "enabled",
            "expire_at", "description"
        ])
        if self.instance.pk:
            del self.fields["random_address"]
            del self.fields["domain"]
        else:
            self.fields["address"].required = False
            self.fields["domain"].required = False
            self.fields["domain"].queryset = Domain.objects.get_for_admin(user)
        if len(args) and isinstance(args[0], QueryDict):
            if "instance" in kwargs:
                if not kwargs["instance"].domain.enabled:
                    del self.fields["enabled"]
            self._load_from_qdict(args[0], "recipients", forms.EmailField)
        elif "instance" in kwargs:
            alias = kwargs["instance"]
            if not alias.domain.enabled:
                self.fields["enabled"].widget.attrs["disabled"] = "disabled"
            cpt = 1
            for rcpt in alias.aliasrecipient_set.filter(alias__internal=False):
                name = "recipients_%d" % cpt
                self._create_field(forms.EmailField, name, rcpt.address, 2)
                cpt += 1

    def clean_address(self):
        """Check if address points to a local domain."""
        if not self.cleaned_data["address"]:
            return self.cleaned_data["address"]
        localpart, domname = split_mailbox(self.cleaned_data["address"])
        try:
            domain = Domain.objects.get(name=domname)
        except Domain.DoesNotExist:
            raise forms.ValidationError(_("Domain does not exist"))
        if not self.user.can_access(domain):
            raise forms.ValidationError(
                _("You don't have access to this domain"))
        if not self.instance.pk:
            try:
                core_signals.can_create_object.send(
                    sender=self.__class__,
                    context=domain,
                    object_type="mailbox_aliases")
            except lib_exceptions.ModoboaException as inst:
                raise forms.ValidationError(inst)
        return self.cleaned_data["address"].lower()

    def clean(self):
        """Check it there is at least one recipient."""
        super(AliasForm, self).clean()
        random_address = self.cleaned_data.get("random_address")
        if not random_address:
            if not self.cleaned_data.get("address"):
                self.add_error("address", _("This field is required"))
        elif not self.cleaned_data.get("domain"):
            self.add_error("domain", _("This field is required"))
        for field, value in self.cleaned_data.items():
            if field.startswith("recipients") and value:
                return self.cleaned_data
        self.add_error("recipients", _("No recipient defined"))
        return self.cleaned_data

    def save(self, commit=True):
        """Custom save method."""
        alias = super(AliasForm, self).save(commit=False)
        if self.cleaned_data.get("random_address"):
            alias.address = "{}@{}".format(Alias.generate_random_address(),
                                           alias.domain)
        else:
            local_part, domname = split_mailbox(self.cleaned_data["address"])
            alias.domain = Domain.objects.get(name=domname)
        if commit:
            alias.save()
            address_list = [
                value for field, value in self.cleaned_data.items()
                if field.startswith("recipients") and value
            ]
            alias.set_recipients(address_list)
        return alias
Exemple #2
0
class AccountFormMail(forms.Form, DynamicForm):
    """Form to handle mail part."""

    email = lib_fields.UTF8EmailField(label=ugettext_lazy("E-mail"),
                                      required=False)
    quota = forms.IntegerField(
        label=ugettext_lazy("Quota"),
        required=False,
        help_text=_("Quota in MB for this mailbox. Define a custom value or "
                    "use domain's default one. Leave empty to define an "
                    "unlimited value (not allowed for domain "
                    "administrators)."),
        widget=forms.widgets.TextInput(attrs={"class": "form-control"}))
    quota_act = forms.BooleanField(required=False)
    aliases = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Alias(es)"),
        required=False,
        help_text=ugettext_lazy(
            "Alias(es) of this mailbox. Indicate only one address per input, "
            "press ENTER to add a new input. Use the '*' character to create "
            "a 'catchall' alias (ex: *@domain.tld)."))

    def __init__(self, *args, **kwargs):
        self.mb = kwargs.pop("instance", None)
        super(AccountFormMail, self).__init__(*args, **kwargs)
        self.field_widths = {"quota": 3}
        self.extra_fields = []
        result = events.raiseQueryEvent('ExtraFormFields', 'mailform', self.mb)
        for fname, field in result:
            self.fields[fname] = field
            self.extra_fields.append(fname)
        if self.mb is not None:
            self.fields["email"].required = True
            cpt = 1
            qset = self.mb.aliasrecipient_set.select_related("alias")
            for ralias in qset:
                name = "aliases_%d" % cpt
                self._create_field(lib_fields.UTF8AndEmptyUserEmailField, name,
                                   ralias.alias.address)
                cpt += 1
            self.fields["email"].initial = self.mb.full_address
            self.fields["quota_act"].initial = self.mb.use_domain_quota
            if not self.mb.use_domain_quota and self.mb.quota:
                self.fields["quota"].initial = self.mb.quota
        else:
            self.fields["quota_act"].initial = True

        if len(args) and isinstance(args[0], QueryDict):
            self._load_from_qdict(args[0], "aliases",
                                  lib_fields.UTF8AndEmptyUserEmailField)

    def clean_email(self):
        """Ensure lower case emails"""
        email = self.cleaned_data["email"].lower()
        self.locpart, domname = split_mailbox(email)
        if not domname:
            return email
        try:
            self.domain = Domain.objects.get(name=domname)
        except Domain.DoesNotExist:
            raise forms.ValidationError(_("Domain does not exist"))
        if not self.mb:
            try:
                core_signals.can_create_object.send(sender=self.__class__,
                                                    context=self.domain,
                                                    object_type="mailboxes")
            except lib_exceptions.ModoboaException as inst:
                raise forms.ValidationError(inst)
        return email

    def clean(self):
        """Custom fields validation.

        Check if quota is >= 0 only when the domain value is not used.
        """
        super(AccountFormMail, self).clean()
        if not self.cleaned_data["quota_act"] \
                and self.cleaned_data['quota'] is not None:
            if self.cleaned_data["quota"] < 0:
                self.add_error("quota", _("Must be a positive integer"))
        self.aliases = []
        for name, value in self.cleaned_data.iteritems():
            if not name.startswith("aliases"):
                continue
            if value == "":
                continue
            local_part, domname = split_mailbox(value)
            if not Domain.objects.filter(name=domname).exists():
                self.add_error(name, _("Local domain does not exist"))
                break
            self.aliases.append(value.lower())
        return self.cleaned_data

    def create_mailbox(self, user, account):
        """Create a mailbox associated to :kw:`account`."""
        if not user.can_access(self.domain):
            raise lib_exceptions.PermDeniedException
        core_signals.can_create_object.send(self.__class__,
                                            context=user,
                                            object_type="mailboxes")
        self.mb = Mailbox(address=self.locpart,
                          domain=self.domain,
                          user=account,
                          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(creator=user)

    def _update_aliases(self, user, account):
        """Update mailbox aliases."""
        qset = self.mb.aliasrecipient_set.select_related("alias").filter(
            alias__internal=False)
        for ralias in qset:
            if ralias.alias.address not in self.aliases:
                alias = ralias.alias
                ralias.delete()
                if alias.recipients_count > 0:
                    continue
                alias.delete()
            else:
                self.aliases.remove(ralias.alias.address)
        if not self.aliases:
            return
        core_signals.can_create_object.send(self.__class__,
                                            context=user,
                                            object_type="mailbox_aliases",
                                            count=len(self.aliases))
        core_signals.can_create_object.send(self.__class__,
                                            context=self.mb.domain,
                                            object_type="mailbox_aliases",
                                            count=len(self.aliases))
        for alias in self.aliases:
            if self.mb.aliasrecipient_set.select_related("alias").filter(
                    alias__address=alias).exists():
                continue
            local_part, domname = split_mailbox(alias)
            al = Alias(address=alias, enabled=account.is_active)
            al.domain = Domain.objects.get(name=domname)
            al.save()
            al.set_recipients([self.mb.full_address])
            al.post_create(user)

    def save(self, user, account):
        """Save or update account mailbox."""
        if self.cleaned_data["email"] == "":
            return None

        if self.cleaned_data["quota_act"]:
            self.cleaned_data["quota"] = None

        if not hasattr(self, "mb") or self.mb is None:
            self.create_mailbox(user, account)
        else:
            self.cleaned_data["use_domain_quota"] = (
                self.cleaned_data["quota_act"])
            self.mb.update_from_dict(user, self.cleaned_data)
        events.raiseEvent('SaveExtraFormFields', 'mailform', self.mb,
                          self.cleaned_data)

        account.email = self.cleaned_data["email"]
        account.save()

        self._update_aliases(user, account)

        return self.mb
Exemple #3
0
class AccountFormMail(forms.Form, DynamicForm):
    """Form to handle mail part."""

    email = lib_fields.UTF8EmailField(
        label=ugettext_lazy("E-mail"), required=False)
    quota = forms.IntegerField(
        label=ugettext_lazy("Quota"),
        required=False,
        help_text=_("Quota in MB for this mailbox. Define a custom value or "
                    "use domain's default one. Leave empty to define an "
                    "unlimited value (not allowed for domain "
                    "administrators)."),
        widget=forms.widgets.TextInput(attrs={"class": "form-control"})
    )
    quota_act = forms.BooleanField(required=False)
    aliases = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Alias(es)"),
        required=False,
        help_text=ugettext_lazy(
            "Alias(es) of this mailbox. Indicate only one address per input, "
            "press ENTER to add a new input. To create a catchall alias, just "
            "enter the domain name (@domain.tld)."
        )
    )
    senderaddress = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Sender addresses"),
        required=False,
        help_text=ugettext_lazy(
            "Additional sender address(es) for this account. The user will be "
            "allowed to send emails using this address, even if it "
            "does not exist locally. Indicate one address per input. Press "
            "ENTER to add a new input."
        )
    )

    def __init__(self, user, *args, **kwargs):
        self.mb = kwargs.pop("instance", None)
        self.user = user
        super(AccountFormMail, self).__init__(*args, **kwargs)
        self.field_widths = {
            "quota": 3
        }
        if self.mb is not None:
            self.fields["email"].required = True
            qset = self.mb.aliasrecipient_set.filter(alias__internal=False)
            for cpt, ralias in enumerate(qset):
                name = "aliases_{}".format(cpt + 1)
                self._create_field(
                    lib_fields.UTF8AndEmptyUserEmailField, name,
                    ralias.alias.address)
            for cpt, saddress in enumerate(self.mb.senderaddress_set.all()):
                name = "senderaddress_{}".format(cpt + 1)
                self._create_field(
                    lib_fields.UTF8AndEmptyUserEmailField, name,
                    saddress.address)
            self.fields["email"].initial = self.mb.full_address
            self.fields["quota_act"].initial = self.mb.use_domain_quota
            if not self.mb.use_domain_quota and self.mb.quota:
                self.fields["quota"].initial = self.mb.quota
        else:
            self.fields["quota_act"].initial = True

        if len(args) and isinstance(args[0], QueryDict):
            self._load_from_qdict(
                args[0], "aliases", lib_fields.UTF8AndEmptyUserEmailField)
            self._load_from_qdict(
                args[0], "senderaddress",
                lib_fields.UTF8AndEmptyUserEmailField)

    def clean_email(self):
        """Ensure lower case emails"""
        email = self.cleaned_data["email"].lower()
        self.locpart, domname = split_mailbox(email)
        if not domname:
            return email
        try:
            self.domain = models.Domain.objects.get(name=domname)
        except models.Domain.DoesNotExist:
            raise forms.ValidationError(_("Domain does not exist"))
        if not self.mb:
            try:
                core_signals.can_create_object.send(
                    sender=self.__class__, context=self.domain,
                    object_type="mailboxes")
            except lib_exceptions.ModoboaException as inst:
                raise forms.ValidationError(inst)
        return email

    def clean(self):
        """Custom fields validation.

        Check if quota is >= 0 only when the domain value is not used.
        """
        cleaned_data = super(AccountFormMail, self).clean()
        use_default_domain_quota = cleaned_data["quota_act"]
        condition = (
            not use_default_domain_quota and
            cleaned_data["quota"] is not None and
            cleaned_data["quota"] < 0)
        if condition:
            self.add_error("quota", _("Must be a positive integer"))
        self.aliases = []
        self.sender_addresses = []
        for name, value in list(cleaned_data.items()):
            if value == "":
                continue
            if name.startswith("aliases"):
                local_part, domname = split_mailbox(value)
                domain = models.Domain.objects.filter(name=domname).first()
                if not domain:
                    self.add_error(name, _("Local domain does not exist"))
                    continue
                if not self.user.can_access(domain):
                    self.add_error(
                        name, _("You don't have access to this domain"))
                    continue
                self.aliases.append(value.lower())
            elif name.startswith("senderaddress"):
                local_part, domname = split_mailbox(value)
                domain = models.Domain.objects.filter(name=domname).first()
                if domain and not self.user.can_access(domain):
                    self.add_error(
                        name, _("You don't have access to this domain"))
                    continue
                self.sender_addresses.append(value.lower())
        return cleaned_data

    def create_mailbox(self, user, account):
        """Create a mailbox associated to :kw:`account`."""
        if not user.can_access(self.domain):
            raise lib_exceptions.PermDeniedException
        core_signals.can_create_object.send(
            self.__class__, context=user, klass=models.Mailbox)
        self.mb = models.Mailbox(
            address=self.locpart, domain=self.domain, user=account,
            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(creator=user)

    def _update_aliases(self, user, account):
        """Update mailbox aliases."""
        qset = self.mb.aliasrecipient_set.select_related("alias").filter(
            alias__internal=False)
        for ralias in qset:
            if ralias.alias.address not in self.aliases:
                alias = ralias.alias
                ralias.delete()
                if alias.recipients_count > 0:
                    continue
                alias.delete()
            else:
                self.aliases.remove(ralias.alias.address)
        if not self.aliases:
            return
        core_signals.can_create_object.send(
            self.__class__, context=user, klass=models.Alias,
            count=len(self.aliases))
        core_signals.can_create_object.send(
            self.__class__, context=self.mb.domain,
            object_type="mailbox_aliases", count=len(self.aliases))
        for alias in self.aliases:
            if self.mb.aliasrecipient_set.select_related("alias").filter(
                    alias__address=alias).exists():
                continue
            local_part, domname = split_mailbox(alias)
            al = models.Alias(address=alias, enabled=account.is_active)
            al.domain = models.Domain.objects.get(name=domname)
            al.save()
            al.set_recipients([self.mb.full_address])
            al.post_create(user)

    def _update_sender_addresses(self):
        """Update mailbox sender addresses."""
        for saddress in self.mb.senderaddress_set.all():
            if saddress.address not in self.sender_addresses:
                saddress.delete()
            else:
                self.sender_addresses.remove(saddress.address)
        if not len(self.sender_addresses):
            return
        to_create = []
        for saddress in self.sender_addresses:
            to_create.append(
                models.SenderAddress(address=saddress, mailbox=self.mb))
        models.SenderAddress.objects.bulk_create(to_create)

    def save(self, user, account):
        """Save or update account mailbox."""
        if self.cleaned_data["email"] == "":
            return None

        if self.cleaned_data["quota_act"]:
            self.cleaned_data["quota"] = None

        if not hasattr(self, "mb") or self.mb is None:
            self.create_mailbox(user, account)
        else:
            self.cleaned_data["use_domain_quota"] = (
                self.cleaned_data["quota_act"])
            self.mb.update_from_dict(user, self.cleaned_data)

        account.email = self.cleaned_data["email"]
        account.save()

        self._update_aliases(user, account)
        self._update_sender_addresses()

        return self.mb
Exemple #4
0
class AliasForm(forms.ModelForm, DynamicForm):

    """A form to create/modify an alias."""

    address = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Email address"),
        help_text=ugettext_lazy(
            "The alias address. To create a catchall alias, just enter the "
            "domain name (@domain.tld)."
        ),
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    recipients = lib_fields.UTF8AndEmptyUserEmailField(
        label=ugettext_lazy("Recipients"), required=False,
        help_text=ugettext_lazy(
            "Addresses this alias will point to. Indicate only one address "
            "per input, press ENTER to add a new input."
        ),
        widget=forms.TextInput(attrs={"class": "form-control"})
    )

    class Meta:
        model = Alias
        fields = ("address", "enabled", )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(AliasForm, self).__init__(*args, **kwargs)
        self.fields = OrderedDict(
            (key, self.fields[key]) for key in
            ['address', 'recipients', 'enabled']
        )

        if len(args) and isinstance(args[0], QueryDict):
            if "instance" in kwargs:
                if not kwargs["instance"].domain.enabled:
                    del self.fields["enabled"]
            self._load_from_qdict(args[0], "recipients", forms.EmailField)
        elif "instance" in kwargs:
            alias = kwargs["instance"]
            if not alias.domain.enabled:
                self.fields["enabled"].widget.attrs["disabled"] = "disabled"
            cpt = 1
            for rcpt in alias.aliasrecipient_set.filter(alias__internal=False):
                name = "recipients_%d" % cpt
                self._create_field(forms.EmailField, name, rcpt.address, 2)
                cpt += 1

    def clean_address(self):
        """Check if address points to a local domain."""
        localpart, domname = split_mailbox(self.cleaned_data["address"])
        try:
            domain = Domain.objects.get(name=domname)
        except Domain.DoesNotExist:
            raise forms.ValidationError(_("Domain does not exist"))
        if not self.user.can_access(domain):
            raise forms.ValidationError(
                _("You don't have access to this domain")
            )
        return self.cleaned_data["address"].lower()

    def clean(self):
        """Check it there is at least one recipient."""
        super(AliasForm, self).clean()
        for field, value in self.cleaned_data.items():
            if field.startswith("recipients") and value:
                return self.cleaned_data
        self.add_error("recipients", _("No recipient defined"))
        return self.cleaned_data

    def save(self, commit=True):
        """Custom save method."""
        alias = super(AliasForm, self).save(commit=False)
        local_part, domname = split_mailbox(self.cleaned_data["address"])
        alias.domain = Domain.objects.get(name=domname)
        if commit:
            alias.save()
            address_list = [
                value for field, value in self.cleaned_data.items()
                if field.startswith("recipients") and value
            ]
            alias.set_recipients(address_list)
        return alias