def from_csv(self, user, row, expected_elements=5): """Create a new alias from a CSV file entry """ if len(row) < expected_elements: raise BadRequest(_("Invalid line: %s" % row)) localpart, domname = split_mailbox(row[1].strip()) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest(_("Domain '%s' does not exist" % domname)) if not user.can_access(domain): raise PermDeniedException try: Alias.objects.get(address=localpart, domain__name=domain) except Alias.DoesNotExist: pass else: raise Conflict self.address = localpart self.domain = domain self.enabled = (row[2].strip() in ["True", "1", "yes", "y"]) int_rcpts = [] ext_rcpts = [] for rcpt in row[3:]: rcpt = rcpt.strip() if not rcpt: continue localpart, domname = split_mailbox(rcpt) try: Domain.objects.get(name=domname) except Domain.DoesNotExist: ext_rcpts += [rcpt] continue try: target = Alias.objects.get( domain__name=domname, address=localpart ) if target.full_address == self.full_address: target = None except Alias.DoesNotExist: target = None if target is None: try: target = Mailbox.objects.get(address=localpart, domain__name=domname) except Mailbox.DoesNotExist: raise BadRequest(_("Local recipient %s not found" % rcpt)) int_rcpts += [target] self.save(int_rcpts=int_rcpts, ext_rcpts=ext_rcpts) self.post_create(user)
def get_or_build_user(self, username, ldap_user): """ This must return a (User, created) 2-tuple for the given LDAP user. username is the Django-friendly username of the user. ldap_user.dn is the user's DN and ldap_user.attrs contains all of their LDAP attributes. """ group = "SimpleUsers" admin_groups = self.global_params["ldap_admin_groups"].split(";") for grp in admin_groups: if grp.strip() in ldap_user.group_names: group = "DomainAdmins" break if group == "SimpleUsers": lpart, domain = split_mailbox(username) if domain is None: return None user, created = User.objects.get_or_create( username__iexact=username, defaults={ "username": username.lower(), "is_local": False, "language": settings.LANGUAGE_CODE } ) if created: populate_callback(user, group) return user, created
def _update_aliases(self, user, account): """Update mailbox aliases.""" aliases = [] for name, value in self.cleaned_data.iteritems(): if not name.startswith("aliases"): continue if value == "": continue aliases.append(value.lower()) qset = self.mb.aliasrecipient_set.select_related("alias").filter( alias__internal=False) for ralias in qset: if ralias.alias.address not in aliases: alias = ralias.alias ralias.delete() if alias.recipients_count >= 2: continue alias.delete() else: aliases.remove(ralias.alias.address) if not aliases: return events.raiseEvent("CanCreate", user, "mailbox_aliases", len(aliases)) for alias in 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 update_from_dict(self, user, values): """Update mailbox from a dictionary.""" newaddress = None if values["email"] != self.full_address: newaddress = values["email"] elif (self.user.role == "SimpleUsers" and self.user.username != self.full_address): newaddress = self.user.username if newaddress is not None: local_part, domname = split_mailbox(newaddress) domain = Domain.objects.filter(name=domname).first() if domain is None: raise lib_exceptions.NotFound(_("Domain does not exist")) if not user.can_access(domain): raise lib_exceptions.PermDeniedException if "use_domain_quota" in values: self.use_domain_quota = values["use_domain_quota"] override_rules = True \ if not self.quota or user.has_perm("admin.add_domain") \ else False self.set_quota(values["quota"], override_rules) if newaddress: self.rename(local_part, domain) self.save() events.raiseEvent("MailboxModified", self)
def get_or_create_user(self, username, ldap_user): """ This must return a (User, created) 2-tuple for the given LDAP user. username is the Django-friendly username of the user. ldap_user.dn is the user's DN and ldap_user.attrs contains all of their LDAP attributes. """ group = "SimpleUsers" admin_groups = self.global_params["ldap_admin_groups"].split(";") for grp in admin_groups: if grp.strip() in ldap_user.group_names: group = "DomainAdmins" break if group == 'SimpleUsers': lpart, domain = split_mailbox(username) if domain is None: return None user, created = User.objects.get_or_create( username__iexact=username, defaults={ 'username': username.lower(), 'is_local': False }) if created: populate_callback(user, group) return user, created
def use_external_recipients_cb(sender, **kwargs): localpart, domname = split_mailbox(kwargs['recipients']) return ( AliasPipe.objects.filter( address=localpart, domain__name=domname ).first() is not None )
def update_from_dict(self, user, values): """Update mailbox from a dictionary.""" newaddress = None if values["email"] != self.full_address: newaddress = values["email"] elif (self.user.group == "SimpleUsers" and self.user.username != self.full_address): newaddress = self.user.username if newaddress is not None: local_part, domname = split_mailbox(newaddress) domain = Domain.objects.filter(name=domname).first() if domain is None: raise lib_exceptions.NotFound(_("Domain does not exist")) if not user.can_access(domain): raise lib_exceptions.PermDeniedException if "use_domain_quota" in values: self.use_domain_quota = values["use_domain_quota"] override_rules = True \ if not self.quota or user.has_perm("admin.add_domain") \ else False self.set_quota(values["quota"], override_rules) if newaddress: self.rename(local_part, domain) self.save() events.raiseEvent("MailboxModified", self)
def _migrate_mailboxes(self, domain, options, creator): """Migrate mailboxes of a single domain.""" print "\tMigrating mailboxes" old_mboxes = pf_models.Mailbox.objects \ .using(options["_from"]).filter(domain=domain.name) for old_mb in old_mboxes: new_user = core_models.User() new_user.username = old_mb.username new_user.first_name = old_mb.name.partition(' ')[0] new_user.last_name = old_mb.name.partition(' ')[2] new_user.email = old_mb.username new_user.is_active = old_mb.active if old_mb.created: new_user.date_joined = old_mb.created set_account_password( new_user, old_mb.password, options["passwords_scheme"]) new_user.save(creator=creator, using=options["_to"]) new_user.role = "SimpleUsers" local_part = split_mailbox(old_mb.username)[0] new_mb = admin_models.Mailbox( user=new_user, address=local_part, domain=domain) self._migrate_dates(new_mb, old_mb) new_mb.set_quota(old_mb.quota / 1024000, override_rules=True) new_mb.save(creator=creator, using=options["_to"])
def _create_mailbox(self, creator, account, data): """Create a new Mailbox instance.""" full_address = data.pop("full_address") address, domain_name = email_utils.split_mailbox(full_address) domain = get_object_or_404( admin_models.Domain, name=domain_name) if not creator.can_access(domain): raise serializers.ValidationError({ "domain": _("Permission denied.")}) try: core_signals.can_create_object.send( sender=self.__class__, context=creator, klass=admin_models.Mailbox) core_signals.can_create_object.send( sender=self.__class__, context=domain, object_type="mailboxes") except lib_exceptions.ModoboaException as inst: raise serializers.ValidationError({ "domain": force_text(inst)}) quota = data.pop("quota", None) mb = admin_models.Mailbox( user=account, address=address, domain=domain, **data) mb.set_quota(quota, creator.has_perm("admin.add_domain")) mb.save(creator=creator) account.email = full_address return mb
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 update_mailbox(self, user, account): newaddress = None if self.cleaned_data["email"] != self.mb.full_address: newaddress = self.cleaned_data["email"] elif (account.group == "SimpleUsers" and account.username != self.mb.full_address): newaddress = account.username if newaddress is not None: self.mb.old_full_address = self.mb.full_address local_part, domname = split_mailbox(newaddress) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise NotFound(_("Domain does not exist")) if not user.can_access(domain): raise PermDeniedException self.mb.rename(local_part, domain) self.mb.use_domain_quota = self.cleaned_data["quota_act"] override_rules = True \ if not self.mb.quota or user.has_perm("admin.add_domain") \ else False self.mb.set_quota(self.cleaned_data["quota"], override_rules) self.mb.save() events.raiseEvent('MailboxModified', self.mb)
def from_csv(self, user, row, expected_elements=5): """Create a new alias from a CSV file entry.""" if len(row) < expected_elements: raise BadRequest(_("Invalid line: %s" % row)) address = row[1].strip() localpart, domname = split_mailbox(address) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest(_("Domain '%s' does not exist" % domname)) if not user.can_access(domain): raise PermDeniedException core_signals.can_create_object.send(sender="import", context=user, klass=Alias) core_signals.can_create_object.send(sender="import", context=domain, object_type="mailbox_aliases") if Alias.objects.filter(address=address).exists(): raise Conflict self.address = address self.domain = domain self.enabled = (row[2].strip().lower() in ["true", "1", "yes", "y"]) self.save() self.set_recipients([raddress.strip() for raddress in row[3:]]) self.post_create(user)
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() condition = (not cleaned_data["quota_act"] 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) if not models.Domain.objects.filter(name=domname).exists(): self.add_error(name, _("Local domain does not exist")) continue self.aliases.append(value.lower()) elif name.startswith("senderaddress"): self.sender_addresses.append(value.lower()) return cleaned_data
def account_auto_created(user): from modoboa.core.models import User from modoboa.lib.permissions import grant_access_to_object from .lib import check_if_domain_exists if parameters.get_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX") == "no": return localpart, domname = split_mailbox(user.username) if user.group != 'SimpleUsers' and domname is None: return sadmins = User.objects.filter(is_superuser=True) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: label = check_if_domain_exists( domname, [(DomainAlias, _('domain alias'))]) if label is not None: return domain = Domain(name=domname, enabled=True, quota=0) domain.save(creator=sadmins[0]) for su in sadmins[1:]: grant_access_to_object(su, domain) try: mb = Mailbox.objects.get(domain=domain, address=localpart) except Mailbox.DoesNotExist: mb = Mailbox( address=localpart, domain=domain, user=user, use_domain_quota=True ) mb.set_quota(override_rules=True) mb.save(creator=sadmins[0]) for su in sadmins[1:]: grant_access_to_object(su, mb)
def _update_aliases(self, user, account): """Update mailbox aliases.""" aliases = [] for name, value in self.cleaned_data.iteritems(): if not name.startswith("aliases"): continue if value == "": continue aliases.append(value.lower()) for alias in self.mb.alias_set.all(): if alias.full_address not in aliases: if len(alias.get_recipients()) >= 2: continue alias.delete() else: aliases.remove(alias.full_address) if not aliases: return events.raiseEvent( "CanCreate", user, "mailbox_aliases", len(aliases) ) for alias in aliases: local_part, domname = split_mailbox(alias) try: self.mb.alias_set.get(address=local_part, domain__name=domname) except Alias.DoesNotExist: pass else: continue al = Alias(address=local_part, enabled=account.is_active) al.domain = Domain.objects.get(name=domname) al.save(int_rcpts=[self.mb]) al.post_create(user)
def _get_domain_from_rcpt(self, rcpt): """Retrieve a domain from a recipient address.""" local_part, domname = split_mailbox(rcpt) domain = admin_models.Domain.objects.filter(name=domname).first() if not domain: raise InternalError(_("Local domain not found")) return domain
def update_from_dict(self, user, values): """Update mailbox from a dictionary.""" newaddress = None if values["email"] != self.full_address: newaddress = values["email"] elif (self.user.role == "SimpleUsers" and self.user.username != self.full_address): newaddress = self.user.username if newaddress is not None: local_part, domname = split_mailbox(newaddress) domain = Domain.objects.filter(name=domname).first() if domain is None: raise lib_exceptions.NotFound(_("Domain does not exist")) if not user.can_access(domain): raise lib_exceptions.PermDeniedException if "use_domain_quota" in values: self.use_domain_quota = values["use_domain_quota"] if "use_domain_quota" in values or "quota" in values: override_rules = ( not self.quota or user.is_superuser or user.has_perm("admin.add_domain") and not user.userobjectlimit_set.get(name="quota").max_value) self.set_quota(values["quota"], override_rules) self.message_limit = values.get("message_limit") if newaddress: self.rename(local_part, domain) self.save()
def from_csv(self, user, row, expected_elements=5): """Create a new alias from a CSV file entry """ if len(row) < expected_elements: raise BadRequest(_("Invalid line: %s" % row)) address = row[1].strip() localpart, domname = split_mailbox(address) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest(_("Domain '%s' does not exist" % domname)) if not user.can_access(domain): raise PermDeniedException core_signals.can_create_object.send( sender="import", context=user, object_type="mailbox_aliases") core_signals.can_create_object.send( sender="import", context=domain, object_type="mailbox_aliases") if Alias.objects.filter(address=address).exists(): raise Conflict self.address = address self.domain = domain self.enabled = (row[2].strip() in ["True", "1", "yes", "y"]) self.save() self.set_recipients([raddress.strip() for raddress in row[3:]]) self.post_create(user)
def account_auto_created(sender, user, **kwargs): """New account has been auto-created, build the rest.""" if not param_tools.get_global_parameter("auto_create_domain_and_mailbox"): return localpart, domname = split_mailbox(user.username) if user.role != "SimpleUsers" and domname is None: return sadmins = core_models.User.objects.filter(is_superuser=True) try: domain = models.Domain.objects.get(name=domname) except models.Domain.DoesNotExist: label = lib.check_if_domain_exists( domname, [(models.DomainAlias, _("domain alias"))]) if label is not None: return domain = models.Domain(name=domname, enabled=True, default_mailbox_quota=0) domain.save(creator=sadmins[0]) for su in sadmins[1:]: permissions.grant_access_to_object(su, domain) qset = models.Mailbox.objects.filter(domain=domain, address=localpart) if not qset.exists(): mb = models.Mailbox(address=localpart, domain=domain, user=user, use_domain_quota=True) mb.set_quota(override_rules=True) mb.save(creator=sadmins[0]) user.email = mb.full_address user.save(update_fields=["email"]) for su in sadmins[1:]: permissions.grant_access_to_object(su, mb)
def filter_mbox(self, queryset, name, value): address, domain = split_mailbox(value) if address: queryset = queryset.filter(mbox__address__icontains=address) if domain: queryset = queryset.filter(mbox__domain__name__icontains=domain) return queryset
def _update_aliases(self, user, account): """Update mailbox aliases.""" aliases = [] for name, value in self.cleaned_data.iteritems(): if not name.startswith("aliases"): continue if value == "": continue aliases.append(value.lower()) for alias in self.mb.alias_set.all(): if alias.full_address not in aliases: if len(alias.get_recipients()) >= 2: continue alias.delete() else: aliases.remove(alias.full_address) if not aliases: return events.raiseEvent("CanCreate", user, "mailbox_aliases", len(aliases)) for alias in aliases: local_part, domname = split_mailbox(alias) try: self.mb.alias_set.get(address=local_part, domain__name=domname) except Alias.DoesNotExist: pass else: continue al = Alias(address=local_part, enabled=account.is_active) al.domain = Domain.objects.get(name=domname) al.save(int_rcpts=[self.mb]) al.post_create(user)
def account_auto_created(user): from modoboa.core.models import User from modoboa.lib.permissions import grant_access_to_object from .lib import check_if_domain_exists if parameters.get_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX") == "no": return localpart, domname = split_mailbox(user.username) if user.group != 'SimpleUsers' and domname is None: return sadmins = User.objects.filter(is_superuser=True) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: label = check_if_domain_exists(domname, [(DomainAlias, _('domain alias'))]) if label is not None: return domain = Domain(name=domname, enabled=True, quota=0) domain.save(creator=sadmins[0]) for su in sadmins[1:]: grant_access_to_object(su, domain) try: mb = Mailbox.objects.get(domain=domain, address=localpart) except Mailbox.DoesNotExist: mb = Mailbox(address=localpart, domain=domain, user=user, use_domain_quota=True) mb.set_quota(override_rules=True) mb.save(creator=sadmins[0]) for su in sadmins[1:]: grant_access_to_object(su, mb)
def account_auto_created(sender, user, **kwargs): """New account has been auto-created, build the rest.""" if not param_tools.get_global_parameter("auto_create_domain_and_mailbox"): return localpart, domname = split_mailbox(user.username) if user.role != 'SimpleUsers' and domname is None: return sadmins = core_models.User.objects.filter(is_superuser=True) try: domain = models.Domain.objects.get(name=domname) except models.Domain.DoesNotExist: label = lib.check_if_domain_exists( domname, [(models.DomainAlias, _("domain alias"))]) if label is not None: return domain = models.Domain( name=domname, enabled=True, default_mailbox_quota=0) domain.save(creator=sadmins[0]) for su in sadmins[1:]: permissions.grant_access_to_object(su, domain) qset = models.Mailbox.objects.filter(domain=domain, address=localpart) if not qset.exists(): mb = models.Mailbox( address=localpart, domain=domain, user=user, use_domain_quota=True ) mb.set_quota(override_rules=True) mb.save(creator=sadmins[0]) for su in sadmins[1:]: permissions.grant_access_to_object(su, mb)
def update_from_dict(self, user, values): """Update mailbox from a dictionary.""" newaddress = None if values["email"] != self.full_address: newaddress = values["email"] elif (self.user.role == "SimpleUsers" and self.user.username != self.full_address): newaddress = self.user.username if newaddress is not None: local_part, domname = split_mailbox(newaddress) domain = Domain.objects.filter(name=domname).first() if domain is None: raise lib_exceptions.NotFound(_("Domain does not exist")) if not user.can_access(domain): raise lib_exceptions.PermDeniedException if "use_domain_quota" in values: self.use_domain_quota = values["use_domain_quota"] if "use_domain_quota" in values or "quota" in values: override_rules = ( not self.quota or user.is_superuser or user.has_perm("admin.add_domain") and not user.userobjectlimit_set.get(name="quota").max_value ) self.set_quota(values["quota"], override_rules) if newaddress: self.rename(local_part, domain) self.save()
async def apply_policies(attributes): """Apply defined policies to received request.""" sasl_username = attributes.get("sasl_username") if not sasl_username: return SUCCESS_ACTION rclient = await aioredis.create_redis_pool(settings.REDIS_URL) decr_domain = False decr_user = False localpart, domain = split_mailbox(sasl_username) if await rclient.hexists(constants.REDIS_HASHNAME, domain): counter = await rclient.hget(constants.REDIS_HASHNAME, domain) logger.info("Domain {} current counter: {}".format(domain, counter)) if int(counter) <= 0: return FAILURE_ACTION decr_domain = True if await rclient.hexists(constants.REDIS_HASHNAME, sasl_username): counter = await rclient.hget(constants.REDIS_HASHNAME, sasl_username) logger.info("Account {} current counter: {}".format( sasl_username, counter)) if int(counter) <= 0: return FAILURE_ACTION decr_user = True if decr_domain: await decrement_limit(rclient, "domain", domain) if decr_user: await decrement_limit(rclient, "account", sasl_username) return SUCCESS_ACTION
def save(self): """Custom save method.""" usernames = {} for name, value in self.cleaned_data.iteritems(): if not name.startswith("username") or not value: continue res = re.match(r"[^_]+_(\d+)$", name) pos = int(res.group(1)) if res else None usernames[value] = pos for rule in self.calendar.rules.select_related().all(): if rule.mailbox.full_address not in usernames: rule.delete() for username, pos in usernames.iteritems(): local_part, domname = split_mailbox(username) try: mbox = Mailbox.objects.get(address=local_part, domain__name=domname) except Mailbox.DoesNotExist: raise BadRequest(_("Mailbox %s does not exist")) if pos: raccess = self.cleaned_data.get("read_access_%d" % pos, False) waccess = self.cleaned_data.get("write_access_%d" % pos, False) else: raccess = self.cleaned_data.get("read_access", False) waccess = self.cleaned_data.get("write_access", False) acr, created = AccessRule.objects.get_or_create( mailbox=mbox, calendar=self.calendar) acr.read = raccess acr.write = waccess acr.save()
def save(self): """Custom save method.""" usernames = {} for name, value in self.cleaned_data.iteritems(): if not name.startswith("username") or not value: continue res = re.match(r"[^_]+_(\d+)$", name) pos = int(res.group(1)) if res else None usernames[value] = pos for rule in self.calendar.rules.select_related().all(): if rule.mailbox.full_address not in usernames: rule.delete() for username, pos in usernames.iteritems(): local_part, domname = split_mailbox(username) try: mbox = Mailbox.objects.get( address=local_part, domain__name=domname ) except Mailbox.DoesNotExist: raise BadRequest(_("Mailbox %s does not exist")) if pos: raccess = self.cleaned_data.get("read_access_%d" % pos, False) waccess = self.cleaned_data.get("write_access_%d" % pos, False) else: raccess = self.cleaned_data.get("read_access", False) waccess = self.cleaned_data.get("write_access", False) acr, created = AccessRule.objects.get_or_create( mailbox=mbox, calendar=self.calendar ) acr.read = raccess acr.write = waccess acr.save()
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() condition = ( not cleaned_data["quota_act"] 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) if not models.Domain.objects.filter(name=domname).exists(): self.add_error(name, _("Local domain does not exist")) continue self.aliases.append(value.lower()) elif name.startswith("senderaddress"): self.sender_addresses.append(value.lower()) return cleaned_data
def _create_mailbox(self, creator, account, data): """Create a new Mailbox instance.""" full_address = data.pop("full_address") address, domain_name = email_utils.split_mailbox(full_address) domain = get_object_or_404(admin_models.Domain, name=domain_name) if not creator.can_access(domain): raise serializers.ValidationError( {"domain": _("Permission denied.")}) try: core_signals.can_create_object.send(sender=self.__class__, context=creator, klass=admin_models.Mailbox) core_signals.can_create_object.send(sender=self.__class__, context=domain, object_type="mailboxes") except lib_exceptions.ModoboaException as inst: raise serializers.ValidationError({"domain": force_text(inst)}) quota = data.pop("quota", None) mb = admin_models.Mailbox(user=account, address=address, domain=domain, **data) mb.set_quota(quota, creator.has_perm("admin.add_domain")) mb.save(creator=creator) account.email = full_address return mb
def _migrate_mailboxes(self, domain, options, creator): """Migrate mailboxes of a single domain.""" print "\tMigrating mailboxes" old_mboxes = pf_models.Mailbox.objects \ .using(options["_from"]).filter(domain=domain.name) for old_mb in old_mboxes: new_user = core_models.User() new_user.username = old_mb.username new_user.first_name = old_mb.name.partition(' ')[0] new_user.last_name = old_mb.name.partition(' ')[2] new_user.email = old_mb.username new_user.is_active = old_mb.active if old_mb.created: new_user.date_joined = old_mb.created set_account_password(new_user, old_mb.password, options["passwords_scheme"]) new_user.save(creator=creator, using=options["_to"]) new_user.role = "SimpleUsers" local_part = split_mailbox(old_mb.username)[0] new_mb = admin_models.Mailbox(user=new_user, address=local_part, domain=domain) self._migrate_dates(new_mb, old_mb) new_mb.set_quota(old_mb.quota / 1024000, override_rules=True) new_mb.save(creator=creator, using=options["_to"])
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 get_or_create_user(self, username, ldap_user): """ This must return a (User, created) 2-tuple for the given LDAP user. username is the Django-friendly username of the user. ldap_user.dn is the user's DN and ldap_user.attrs contains all of their LDAP attributes. """ group = 'SimpleUsers' admin_groups = parameters \ .get_admin('LDAP_ADMIN_GROUPS', app='core').split(';') for grp in admin_groups: if grp.strip() in ldap_user.group_names: group = 'DomainAdmins' break if group == 'SimpleUsers': lpart, domain = split_mailbox(username) if domain is None: return None user, created = User.objects.get_or_create( username__iexact=username, defaults={'username': username.lower(), 'is_local': False} ) if created: populate_callback(user, group) return user, created
def validate_address(self, value): """Check domain.""" local_part, domain = email_utils.split_mailbox(value) domain = admin_models.Domain.objects.filter(name=domain).first() user = self.context["request"].user if domain and not user.can_access(domain): raise serializers.ValidationError( _("You don't have access to this domain.")) return value
def validate_address(self, value): """Check domain.""" local_part, domain = email_utils.split_mailbox(value) self.domain = admin_models.Domain.objects.filter(name=domain).first() if self.domain is None: raise serializers.ValidationError(_("Domain not found.")) if not self.context["request"].user.can_access(self.domain): raise serializers.ValidationError(_("Permission denied.")) return value
def save(self, commit=True): alias = super(AliasForm, self).save(commit=False) localpart, domname = split_mailbox(self.cleaned_data["email"]) alias.address = localpart alias.domain = Domain.objects.get(name=domname) if commit: alias.save(int_rcpts=self.int_rcpts, ext_rcpts=self.ext_rcpts) self.save_m2m() return alias
def import_account_mailbox(sender, user, account, row, **kwargs): """Handle extra fields when an account is imported. Expected fields: email address; quota; [domain; ...] :param User user: user importing the account :param User account: account being imported :param list rom: list of fields (strings) """ account.email = row[0].strip().lower() if account.email: mailbox, domname = split_mailbox(account.email) domain = models.Domain.objects.filter(name=domname).first() if not domain: raise exceptions.BadRequest( _("Account import failed (%s): domain does not exist") % account.username ) if not user.can_access(domain): raise exceptions.PermDeniedException core_signals.can_create_object.send( sender="import", context=user, klass=models.Mailbox) core_signals.can_create_object.send( sender="import", context=domain, object_type="mailboxes") account.save() qset = models.Mailbox.objects.filter(address=mailbox, domain=domain) if qset.exists(): raise exceptions.Conflict( _("Mailbox {} already exists").format(account.email)) if len(row) == 1: quota = None else: try: quota = int(row[1].strip()) except ValueError: raise exceptions.BadRequest( _("Account import failed (%s): wrong quota value") % account.username ) use_domain_quota = True if not quota else False mb = models.Mailbox( address=mailbox, domain=domain, user=account, use_domain_quota=use_domain_quota) mb.set_quota( quota, override_rules=user.has_perm("admin.change_domain") ) mb.save(creator=user) if account.role == "DomainAdmins": for domname in row[2:]: try: dom = models.Domain.objects.get(name=domname.strip()) except models.Domain.DoesNotExist: continue dom.add_admin(account)
def import_account_mailbox(sender, user, account, row, **kwargs): """Handle extra fields when an account is imported. Expected fields: email address; quota; [domain; ...] :param User user: user importing the account :param User account: account being imported :param list rom: list of fields (strings) """ account.email = row[0].strip().lower() if account.email: mailbox, domname = split_mailbox(account.email) domain = models.Domain.objects.filter(name=domname).first() if not domain: raise exceptions.BadRequest( _("Account import failed (%s): domain does not exist") % account.username) if not user.can_access(domain): raise exceptions.PermDeniedException core_signals.can_create_object.send(sender="import", context=user, klass=models.Mailbox) core_signals.can_create_object.send(sender="import", context=domain, object_type="mailboxes") account.save() qset = models.Mailbox.objects.filter(address=mailbox, domain=domain) if qset.exists(): raise exceptions.Conflict( _("Mailbox {} already exists").format(account.email)) if len(row) == 1: quota = None else: try: quota = int(row[1].strip()) except ValueError: raise exceptions.BadRequest( _("Account import failed (%s): wrong quota value") % account.username) use_domain_quota = True if not quota else False mb = models.Mailbox(address=mailbox, domain=domain, user=account, use_domain_quota=use_domain_quota) mb.set_quota(quota, override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if account.role == "DomainAdmins": for domname in row[2:]: try: dom = models.Domain.objects.get(name=domname.strip()) except models.Domain.DoesNotExist: continue dom.add_admin(account)
def set_recipients(self): """Recipients dispatching We make a difference between 'local' recipients (the ones hosted by Modoboa) and 'external' recipients. """ self.ext_rcpts = [] self.int_rcpts = [] total = 0 for k, v in self.cleaned_data.items(): if not k.startswith("recipients"): continue if v == "": continue local_part, domname = split_mailbox(v) if domname is None: raise BadRequest( u"%s %s" % (_("Invalid mailbox"), v) ) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: domain = None if domain is not None: try: rcpt = Alias.objects.get(domain=domain, address=local_part) if rcpt.full_address == self.cleaned_data["email"]: rcpt = None except Alias.DoesNotExist: rcpt = None if rcpt is None: try: rcpt = Mailbox.objects.get( domain=domain, address=local_part) except Mailbox.DoesNotExist: raise NotFound( _("Local recipient %s not found" % v) ) if rcpt in self.int_rcpts: raise Conflict( _("Recipient %s already present" % v) ) self.int_rcpts += [rcpt] total += 1 continue if v in self.ext_rcpts: raise Conflict( _("Recipient %s already present" % v) ) self.ext_rcpts += [v] total += 1 if total == 0: raise BadRequest(_("No recipient defined"))
def clean_email(self): localpart, domname = split_mailbox(self.cleaned_data["email"]) 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["email"]
def check_relaydomain_alias(sender, **kwargs): """Allow the creation of an alias on a relaydomain.""" recipient = kwargs.get("recipients") if not recipient: return localpart, domain = split_mailbox(recipient) if not (models.RelayDomain.objects.select_related().filter(domain__name=domain).exists()): return False if admin_models.Mailbox.objects.select_related("domain").filter(domain__name=domain, address=localpart).exists(): return False return True
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")) return email
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 check_relaydomain_alias(sender, recipients, **kwargs): """Allow the creation of an alias on a relaydomain.""" localpart, domain = split_mailbox(recipients) qset = admin_models.Domain.objects.filter(name=domain, type="relaydomain") if not qset.exists(): return False qset = admin_models.Mailbox.objects.select_related("domain").filter( domain__name=domain, address=localpart) if qset.exists(): return False return True
def clean_email(self): localpart, domname = split_mailbox(self.cleaned_data["email"]) 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["email"].lower()
def set_recipients(self, address_list): """Set recipients for this alias. Special recipients: * local mailbox + extension: r_mailbox will be set to local mailbox * alias address == recipient address: valid only to keep local copies (when a forward is defined) and to create exceptions when a catchall is defined on the associated domain """ to_create = [] for address in set(address_list): if not address: continue if self.aliasrecipient_set.filter(address=address).exists(): continue local_part, domname, extension = ( split_mailbox(address, return_extension=True)) if domname is None: raise BadRequest( u"%s %s" % (_("Invalid address"), address) ) domain = Domain.objects.filter(name=domname).first() kwargs = {"address": address, "alias": self} if ( (domain is not None) and ( any( r[1] for r in signals.use_external_recipients.send( self, recipients=address) ) is False ) ): rcpt = Mailbox.objects.filter( domain=domain, address=local_part).first() if rcpt is None: rcpt = Alias.objects.filter( address='%s@%s' % (local_part, domname) ).first() if rcpt is None: raise NotFound( _("Local recipient {}@{} not found") .format(local_part, domname) ) if rcpt.address == self.address: raise Conflict kwargs["r_alias"] = rcpt else: kwargs["r_mailbox"] = rcpt AliasRecipient(**kwargs).save() # Remove old recipients self.aliasrecipient_set.exclude( address__in=address_list).delete()
def set_recipients(self, address_list): """Set recipients for this alias. Special recipients: * local mailbox + extension: r_mailbox will be set to local mailbox * alias address == recipient address: valid only to keep local copies (when a forward is defined) and to create exceptions when a catchall is defined on the associated domain """ to_create = [] for address in set(address_list): if not address: continue if self.aliasrecipient_set.filter(address=address).exists(): continue local_part, domname, extension = ( split_mailbox(address, return_extension=True)) if domname is None: raise BadRequest( u"%s %s" % (_("Invalid address"), address) ) domain = Domain.objects.filter(name=domname).first() kwargs = {"address": address, "alias": self} if ( (domain is not None) and ( any( r[1] for r in signals.use_external_recipients.send( self, recipients=address) ) is False ) ): rcpt = Mailbox.objects.filter( domain=domain, address=local_part).first() if rcpt is None: rcpt = Alias.objects.filter( address='%s@%s' % (local_part, domname) ).first() if rcpt is None: raise NotFound( _("Local recipient {}@{} not found") .format(local_part, domname) ) if rcpt.address == self.address: raise Conflict kwargs["r_alias"] = rcpt else: kwargs["r_mailbox"] = rcpt to_create.append(AliasRecipient(**kwargs)) AliasRecipient.objects.bulk_create(to_create) # Remove old recipients self.aliasrecipient_set.exclude( address__in=address_list).delete()
def import_account_mailbox(user, account, row): """Handle extra fields when an account is imported. Expected fields: email address; quota; [domain; ...] :param User user: user importing the account :param User account: account being imported :param list rom: list of fields (strings) """ account.email = row[0].strip() if account.email: account.save() mailbox, domname = split_mailbox(account.email) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest( _("Account import failed (%s): domain does not exist" % account.username) ) if not user.can_access(domain): raise PermDeniedException try: mb = Mailbox.objects.get(address=mailbox, domain=domain) except Mailbox.DoesNotExist: pass else: raise Conflict(_("Mailbox %s already exists" % account.email)) if len(row) == 1: quota = None else: try: quota = int(row[1].strip()) except ValueError: raise BadRequest( _("Account import failed (%s): wrong quota value" % account.username) ) use_domain_quota = True if not quota else False mb = Mailbox(address=mailbox, domain=domain, user=account, use_domain_quota=use_domain_quota) mb.set_quota( quota, override_rules=user.has_perm("admin.change_domain") ) mb.save(creator=user) if account.group == "DomainAdmins": for domname in row[2:]: try: dom = Domain.objects.get(name=domname.strip()) except Domain.DoesNotExist: continue dom.add_admin(account)
def import_account_mailbox(user, account, row): """Handle extra fields when an account is imported. Expected fields: email address; quota; [domain; ...] :param User user: user importing the account :param User account: account being imported :param list rom: list of fields (strings) """ account.email = row[0].strip() if account.email: account.save() mailbox, domname = split_mailbox(account.email) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest( _("Account import failed (%s): domain does not exist" % account.username)) if not user.can_access(domain): raise PermDeniedException try: mb = Mailbox.objects.get(address=mailbox, domain=domain) except Mailbox.DoesNotExist: pass else: raise Conflict(_("Mailbox %s already exists" % account.email)) if len(row) == 1: quota = None else: try: quota = int(row[1].strip()) except ValueError: raise BadRequest( _("Account import failed (%s): wrong quota value" % account.username)) use_domain_quota = True if not quota else False mb = Mailbox(address=mailbox, domain=domain, user=account, use_domain_quota=use_domain_quota) mb.set_quota(quota, override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if account.group == "DomainAdmins": for domname in row[2:]: try: dom = Domain.objects.get(name=domname.strip()) except Domain.DoesNotExist: continue dom.add_admin(account)
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
def check_relaydomain_alias(sender, **kwargs): """Allow the creation of an alias on a relaydomain.""" recipient = kwargs.get("recipients") if not recipient: return localpart, domain = split_mailbox(recipient) if not (models.RelayDomain.objects.select_related().filter( domain__name=domain).exists()): return False if (admin_models.Mailbox.objects.select_related("domain").filter( domain__name=domain, address=localpart).exists()): return False return True
def create_alarm(ltype, name): """Create a new alarm.""" title = _("Daily sending limit reached") internal_name = "sending_limit" if ltype == "domain": domain = admin_models.Domain.objects.get(name=name) domain.alarms.create(title=title, internal_name=internal_name) else: localpart, domain = split_mailbox(name) mailbox = admin_models.Mailbox.objects.get( address=localpart, domain__name=domain) mailbox.alarms.create( domain=mailbox.domain, title=title, internal_name=internal_name)
def _get_mailbox_from_rcpt(self, rcpt): """Retrieve a mailbox from a recipient address.""" local_part, domname = split_mailbox(rcpt) try: mailbox = Mailbox.objects.select_related("domain").get( address=local_part, domain__name=domname) except Mailbox.DoesNotExist: try: alias = Alias.objects.select_related("domain").get( address=local_part, domain__name=domname) except Alias.DoesNotExist: raise InternalError(_("No recipient found")) if alias.type != "alias": return None mailbox = alias.mboxes.all()[0] return mailbox
def get_identities(user, searchquery=None, idtfilter=None, grpfilter=None): """Return all the identities owned by a user. :param user: the desired user :param str searchquery: search pattern :param list idtfilter: identity type filters :param list grpfilter: group names filters :return: a queryset """ accounts = [] if idtfilter is None or not idtfilter or idtfilter == "account": ids = user.objectaccess_set \ .filter(content_type=ContentType.objects.get_for_model(user)) \ .values_list('object_id', flat=True) q = Q(pk__in=ids) if searchquery is not None: q &= Q(username__icontains=searchquery) \ | Q(email__icontains=searchquery) if grpfilter is not None and grpfilter: if grpfilter == "SuperAdmins": q &= Q(is_superuser=True) else: q &= Q(groups__name=grpfilter) accounts = User.objects.select_related().filter(q) aliases = [] if idtfilter is None or not idtfilter \ or (idtfilter in ["alias", "forward", "dlist"]): alct = ContentType.objects.get_for_model(Alias) ids = user.objectaccess_set.filter(content_type=alct) \ .values_list('object_id', flat=True) q = Q(pk__in=ids) if searchquery is not None: if '@' in searchquery: local_part, domname = split_mailbox(searchquery) if local_part: q &= Q(address__icontains=local_part) if domname: q &= Q(domain__name__icontains=domname) else: q &= Q(address__icontains=searchquery) | \ Q(domain__name__icontains=searchquery) aliases = Alias.objects.select_related().filter(q) if idtfilter is not None and idtfilter: aliases = [al for al in aliases if al.type == idtfilter] return chain(accounts, aliases)