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 save(self, user, domain): if not self.fields: return if self.cleaned_data["create_dom_admin"] == "no": return username = "******" % (self.cleaned_data["dom_admin_username"], domain.name) try: da = User.objects.get(username=username) except User.DoesNotExist: pass else: raise Conflict(_("User '%s' already exists" % username)) events.raiseEvent("CanCreate", user, "mailboxes") 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(override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if self.cleaned_data["create_aliases"] == "yes": events.raiseEvent("CanCreate", user, "mailbox_aliases") alias = Alias(address="postmaster", domain=domain, enabled=True) alias.save(int_rcpts=[mb]) alias.post_create(user) domain.add_admin(da)
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: 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 core_signals.can_create_object.send(sender="import", context=user, object_type="mailboxes") core_signals.can_create_object.send(sender="import", context=domain, object_type="mailboxes") account.save() if Mailbox.objects.filter(address=mailbox, domain=domain).exists(): raise Conflict( _("Mailbox {} already exists").format(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.role == "DomainAdmins": for domname in row[2:]: try: dom = Domain.objects.get(name=domname.strip()) except Domain.DoesNotExist: continue dom.add_admin(account)
def importdata(request, formclass=ImportDataForm): """Generic import function As the process of importing data from a CSV file is the same whatever the type, we do a maximum of the work here. :param request: a ``Request`` instance :param typ: a string indicating the object type being imported :return: a ``Response`` instance """ error = None form = formclass(request.POST, request.FILES) if form.is_valid(): try: reader = csv.reader(request.FILES['sourcefile'], delimiter=form.cleaned_data['sepchar']) except csv.Error as inst: error = str(inst) if error is None: try: cpt = 0 for row in reader: if not row: continue try: fct = getattr(lib, "import_%s" % row[0].strip()) except AttributeError: fct = events.raiseQueryEvent('ImportObject', row[0].strip()) if not fct: continue fct = fct[0] with transaction.atomic(): try: fct(request.user, row, form.cleaned_data) except Conflict: if form.cleaned_data["continue_if_exists"]: continue raise Conflict( _("Object already exists: %s" % form.cleaned_data['sepchar'].join(row[:2]))) cpt += 1 msg = _("%d objects imported successfully" % cpt) return render(request, "admin/import_done.html", { "status": "ok", "msg": msg }) except (ModoboaException) as e: error = str(e) return render(request, "admin/import_done.html", { "status": "ko", "msg": error })
def save(self, *args, **kwargs): if not self.fields: return if not self.cleaned_data["create_dom_admin"]: return user = kwargs.pop("user") domain = kwargs.pop("domain") username = "******" % (self.cleaned_data["dom_admin_username"], domain.name) try: da = User.objects.get(username=username) except User.DoesNotExist: pass else: raise Conflict(_("User '%s' already exists") % username) core_signals.can_create_object.send(self.__class__, context=user, klass=Mailbox) da = User(username=username, email=username, is_active=True) if self.cleaned_data["random_password"]: password = lib.make_password() else: password = param_tools.get_global_parameter("default_password", app="core") da.set_password(password) da.save() da.role = "DomainAdmins" da.post_create(user) if self.cleaned_data["with_mailbox"]: dom_admin_username = self.cleaned_data["dom_admin_username"] mb = Mailbox(address=dom_admin_username, domain=domain, user=da, use_domain_quota=True) mb.set_quota(override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) condition = (domain.type == "domain" and self.cleaned_data["create_aliases"] and dom_admin_username != "postmaster") if condition: core_signals.can_create_object.send(self.__class__, context=user, klass=Alias) address = u"postmaster@{}".format(domain.name) alias = Alias.objects.create(address=address, domain=domain, enabled=True) alias.set_recipients([mb.full_address]) alias.post_create(user) domain.add_admin(da)
def importdata(request, formclass=ImportDataForm): """Generic import function As the process of importing data from a CSV file is the same whatever the type, we do a maximum of the work here. :param request: a ``Request`` instance :param typ: a string indicating the object type being imported :return: a ``Response`` instance """ error = None form = formclass(request.POST, request.FILES) if form.is_valid(): try: infile = io.TextIOWrapper(request.FILES['sourcefile'].file, encoding="utf8") reader = csv.reader(infile, delimiter=form.cleaned_data['sepchar']) except csv.Error as inst: error = smart_text(inst) else: try: cpt = 0 for row in reader: if not row: continue fct = signals.import_object.send(sender="importdata", objtype=row[0].strip()) fct = [func for x_, func in fct if func is not None] if not fct: continue fct = fct[0] with transaction.atomic(): try: fct(request.user, row, form.cleaned_data) except Conflict: if form.cleaned_data["continue_if_exists"]: continue raise Conflict( _("Object already exists: %s" % form.cleaned_data['sepchar'].join(row[:2]))) cpt += 1 msg = _("%d objects imported successfully" % cpt) return render(request, "admin/import_done.html", { "status": "ok", "msg": msg }) except (ModoboaException) as e: error = str(e) return render(request, "admin/import_done.html", { "status": "ko", "msg": error })
def _validate_alias(request, form, successmsg, callback=None): """Alias validation Common function shared between creation and modification actions. """ if form.is_valid(): try: alias = form.save() except IntegrityError: raise Conflict(_("Alias with this name already exists")) if callback: callback(request.user, alias) return render_to_json_response(successmsg) return render_to_json_response({'form_errors': form.errors}, status=400)
def save(self, *args, **kwargs): if not self.fields: return if self.cleaned_data["create_dom_admin"] == "no": return user = kwargs.pop("user") domain = kwargs.pop("domain") username = "******" % (self.cleaned_data["dom_admin_username"], domain.name) try: da = User.objects.get(username=username) except User.DoesNotExist: pass else: raise Conflict(_("User '%s' already exists") % username) core_signals.can_create_object.send(self.__class__, context=user, object_type="mailboxes") da = User(username=username, email=username, is_active=True) da.set_password("password") da.save() da.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(override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if domain.type == "domain" and \ self.cleaned_data["create_aliases"] == "yes": core_signals.can_create_object.send(self.__class__, context=user, object_type="mailbox_aliases") alias = Alias(address=u"postmaster@{}".format(domain.name), domain=domain, enabled=True) alias.save() alias.set_recipients([mb.full_address]) alias.post_create(user) domain.add_admin(da)
def import_data(user, file_object, options: dict): """Generic import function As the process of importing data from a CSV file is the same whatever the type, we do a maximum of the work here. """ try: infile = io.TextIOWrapper(file_object.file, encoding="utf8") reader = csv.reader(infile, delimiter=options["sepchar"]) except csv.Error as inst: error = str(inst) else: try: cpt = 0 for row in reader: if not row: continue fct = signals.import_object.send(sender="importdata", objtype=row[0].strip()) fct = [func for x_, func in fct if func is not None] if not fct: continue fct = fct[0] with transaction.atomic(): try: fct(user, row, options) except Conflict: if options["continue_if_exists"]: continue raise Conflict( _("Object already exists: %s") % options["sepchar"].join(row[:2])) cpt += 1 msg = _("%d objects imported successfully") % cpt return True, msg except (ModoboaException) as e: error = str(e) return False, error
def create_mailbox(self, user, account): """Create a mailbox associated to :kw:`account`.""" locpart, domname = split_mailbox(self.cleaned_data["email"]) try: domain = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise NotFound(_("Domain does not exist")) if not user.can_access(domain): raise PermDeniedException try: Mailbox.objects.get(address=locpart, domain=domain) except Mailbox.DoesNotExist: pass else: raise Conflict( _("Mailbox %s already exists" % self.cleaned_data["email"]) ) events.raiseEvent("CanCreate", user, "mailboxes") self.mb = Mailbox(address=locpart, domain=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 import_csv(filename, options): """Import objects from a CSV file.""" superadmin = User.objects.filter(is_superuser=True).first() if not os.path.exists(filename): print('File not found') sys.exit(1) num_lines = sum(1 for line in open(filename)) pbar = ProgressBar(widgets=[Percentage(), Bar(), ETA()], maxval=num_lines).start() with open(filename, 'r') as f: reader = csv.reader(f, delimiter=';') i = 0 for row in reader: i += 1 pbar.update(i) if not row: continue try: fct = getattr(lib, "import_%s" % row[0].strip()) except AttributeError: fct = events.raiseQueryEvent('ImportObject', row[0].strip()) if not fct: continue fct = fct[0] try: fct(superadmin, row, options) except Conflict: if options['continue_if_exists']: continue raise Conflict("Object already exists: %s" % options['sepchar'].join(row[:2])) pbar.finish()