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 edit(request, rdom_id, tplname='common/tabforms.html'): rdom = RelayDomain.objects.get(pk=rdom_id) if not request.user.can_access(rdom): raise PermDeniedException instances = {'general': rdom} events.raiseEvent("FillRelayDomainInstances", request.user, rdom, instances) if request.method == 'POST': rdom.oldname = rdom.name form = RelayDomainForm(request.user, request.POST, instances=instances) if form.is_valid(): form.save(request.user) events.raiseEvent('RelayDomainModified', rdom) return render_to_json_response(_('Relay domain modified')) return render_to_json_response({'form_errors': form.errors}, status=400) ctx = { 'action': reverse(edit, args=[rdom.id]), 'formid': 'rdomform', 'title': rdom.name, 'action_label': _("Update"), 'action_classes': "submit", 'tabs': RelayDomainForm(request.user, instances=instances) } return render(request, tplname, ctx)
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 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) self._update_sender_addresses() return self.mb
def delete(self, fromuser, *args, **kwargs): """Custom delete method To check permissions properly, we need to make a distinction between 2 cases: * If the user owns a mailbox, the check is made on that object (useful for domain admins) * Otherwise, the check is made on the user """ from modoboa.lib.permissions import \ get_object_owner, grant_access_to_object, ungrant_access_to_object if fromuser == self: raise PermDeniedException(_("You can't delete your own account")) if not fromuser.can_access(self): raise PermDeniedException owner = get_object_owner(self) for ooentry in self.objectaccess_set.filter(is_owner=True): if ooentry.content_object is not None: grant_access_to_object(owner, ooentry.content_object, True) ungrant_access_to_object(ooentry.content_object, self) events.raiseEvent("AccountDeleted", self, fromuser, **kwargs) ungrant_access_to_object(self) super(User, self).delete()
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) for alias in self.mb.alias_set.all(): if not alias.full_address 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 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 _new_alias(request, title, action, successmsg, tplname="common/generic_modal_form.html"): events.raiseEvent("CanCreate", request.user, "mailbox_aliases") ctx = { "title": title, "action": action, "formid": "aliasform", "action_label": _("Create"), "action_classes": "submit" } if request.method == "POST": def callback(user, alias): alias.post_create(user) form = AliasForm(request.user, request.POST) return _validate_alias(request, form, successmsg, tplname, ctx, callback) form = AliasForm(request.user) ctx["form"] = form return render(request, tplname, ctx)
def delete(self, fromuser, *args, **kwargs): """Custom delete method To check permissions properly, we need to make a distinction between 2 cases: * If the user owns a mailbox, the check is made on that object (useful for domain admins) * Otherwise, the check is made on the user """ from modoboa.lib.permissions import \ get_object_owner, grant_access_to_object, ungrant_access_to_object if fromuser == self: raise PermDeniedException( _("You can't delete your own account") ) if not fromuser.can_access(self): raise PermDeniedException owner = get_object_owner(self) for ooentry in self.objectaccess_set.filter(is_owner=True): if ooentry.content_object is not None: grant_access_to_object(owner, ooentry.content_object, True) events.raiseEvent("AccountDeleted", self, fromuser, **kwargs) ungrant_access_to_object(self) super(User, self).delete()
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 handle(self, *args, **options): """Command entry point.""" load_core_settings() if not User.objects.filter(is_superuser=True).count(): admin = User(username="******", is_superuser=True) admin.set_password("password") admin.save() ObjectAccess.objects.create( user=admin, content_object=admin, is_owner=True) exts_pool.load_all() superadmin = User.objects.filter(is_superuser=True).first() groups = PERMISSIONS.keys() + [ role[0] for role in events.raiseQueryEvent("GetExtraRoles", superadmin, None) ] for groupname in groups: group, created = Group.objects.get_or_create(name=groupname) permissions = ( PERMISSIONS.get(groupname, []) + events.raiseQueryEvent("GetExtraRolePermissions", groupname) ) if not permissions: continue add_permissions_to_group(group, permissions) for extname in exts_pool.extensions.keys(): extension = exts_pool.get_extension(extname) extension.load_initial_data() events.raiseEvent("InitialDataLoaded", extname)
def save(self, user, commit=True, rdomalias_post_create=False): """Custom save method. As relay domain aliases are defined using the same form as relay domains, we need to save them manually. :param ``User`` user: connected user """ rd = super(RelayDomainFormGeneral, self).save(commit=False) if commit: rd.save() aliases = [] for k, v in self.cleaned_data.iteritems(): if not k.startswith("aliases"): continue if v in ["", None]: continue aliases.append(v) for rdalias in rd.relaydomainalias_set.all(): if not rdalias.name in aliases: rdalias.delete() else: aliases.remove(rdalias.name) if aliases: events.raiseEvent("CanCreate", user, "relay_domain_aliases", len(aliases)) for alias in aliases: try: rd.relaydomainalias_set.get(name=alias) except RelayDomainAlias.DoesNotExist: pass else: continue al = RelayDomainAlias(name=alias, target=rd, enabled=rd.enabled) al.save(creator=user) if rdomalias_post_create else al.save() return rd
def editdomain(request, dom_id, tplname="admin/editdomainform.html"): domain = Domain.objects.get(pk=dom_id) if not request.user.can_access(domain): raise PermDeniedException instances = dict(general=domain) events.raiseEvent("FillDomainInstances", request.user, domain, instances) if request.method == "POST": domain.oldname = domain.name form = DomainForm(request.user, request.POST, instances=instances) if form.is_valid(): form.save(request.user) events.raiseEvent("DomainModified", domain) return render_to_json_response(_("Domain modified")) return render_to_json_response({ 'form_errors': form.errors }, status=400) domadmins = [u for u in domain.admins if request.user.can_access(u) and not u.is_superuser] if not request.user.is_superuser: domadmins = [u for u in domadmins if u.group == "DomainAdmins"] ctx = {"title": domain.name, "action_label": _("Update"), "action_classes": "submit", "action": reverse(editdomain, args=[dom_id]), "formid": "domform", "domain": domain, "tabs": DomainForm(request.user, instances=instances), "domadmins": domadmins} return render(request, tplname, ctx)
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 _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 edit(request, rdom_id, tplname='common/tabforms.html'): rdom = RelayDomain.objects.get(pk=rdom_id) if not request.user.can_access(rdom): raise PermDeniedException instances = {'general': rdom} events.raiseEvent("FillRelayDomainInstances", request.user, rdom, instances) return RelayDomainForm(request, instances=instances).process()
def edit(request, rdom_id, tplname='common/tabforms.html'): rdom = RelayDomain.objects.get(pk=rdom_id) if not request.user.can_access(rdom): raise PermDeniedException instances = {'general': rdom} events.raiseEvent("FillRelayDomainInstances", request.user, rdom, instances) if request.method == 'POST': rdom.oldname = rdom.name form = RelayDomainForm(request.user, request.POST, instances=instances) if form.is_valid(): form.save(request.user) events.raiseEvent('RelayDomainModified', rdom) return render_to_json_response(_('Relay domain modified')) return render_to_json_response( {'form_errors': form.errors}, status=400 ) ctx = { 'action': reverse(edit, args=[rdom.id]), 'formid': 'rdomform', 'title': rdom.name, 'action_label': _("Update"), 'action_classes': "submit", 'tabs': RelayDomainForm(request.user, instances=instances) } return render(request, tplname, ctx)
def handle(self, *args, **options): """Command entry point.""" load_core_settings() if not User.objects.filter(is_superuser=True).count(): admin = User(username="******", is_superuser=True) admin.set_password("password") admin.save() ObjectAccess.objects.create(user=admin, content_object=admin, is_owner=True) exts_pool.load_all() superadmin = User.objects.filter(is_superuser=True).first() groups = PERMISSIONS.keys() + [ role[0] for role in events.raiseQueryEvent("GetExtraRoles", superadmin, None) ] for groupname in groups: group, created = Group.objects.get_or_create(name=groupname) permissions = ( PERMISSIONS.get(groupname, []) + events.raiseQueryEvent("GetExtraRolePermissions", groupname)) if not permissions: continue add_permissions_to_group(group, permissions) for extname in exts_pool.extensions.keys(): extension = exts_pool.get_extension(extname) extension.load_initial_data() events.raiseEvent("InitialDataLoaded", extname)
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("modoboa_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 _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 save(self, user, commit=True): d = super(DomainFormGeneral, self).save(commit=False) if commit: old_mail_homes = None hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm == "yes": if self.oldname is not None and d.name != self.oldname: for q in Quota.objects.filter(username__contains="@%s" % self.oldname): q.username = q.username.replace("@%s" % self.oldname, "@%s" % d.name) q.save() old_mail_homes = dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all()) d.save() Mailbox.objects.filter(domain=d, use_domain_quota=True).update(quota=d.quota) if old_mail_homes is not None: for mb in d.mailbox_set.all(): mb.rename_dir(old_mail_homes[mb.id]) for k, v in self.cleaned_data.iteritems(): if not k.startswith("aliases"): continue if v in ["", None]: continue try: d.domainalias_set.get(name=v) except DomainAlias.DoesNotExist: pass else: continue events.raiseEvent("CanCreate", user, "domain_aliases") al = DomainAlias(name=v, target=d, enabled=d.enabled) al.save(creator=user) for dalias in d.domainalias_set.all(): if not len(filter(lambda name: self.cleaned_data[name] == dalias.name, self.cleaned_data.keys())): dalias.delete() return d
def editdomain(request, dom_id, tplname="admin/editdomainform.html"): domain = Domain.objects.get(pk=dom_id) if not request.user.can_access(domain): raise PermDeniedException instances = dict(general=domain) events.raiseEvent("FillDomainInstances", request.user, domain, instances) return DomainForm(request, instances=instances).process()
def from_csv(self, user, row, crypt_password=True): """Create a new account from a CSV file entry. The expected order is the following:: "account", loginname, password, first name, last name, enabled, group Additional fields can be added using the *AccountImported* event. :param user: a ``core.User`` instance :param row: a list containing the expected information :param crypt_password: """ from modoboa.lib.permissions import get_account_roles if len(row) < 7: raise BadRequest(_("Invalid line")) desired_role = row[6].strip() if not user.is_superuser: allowed_roles = get_account_roles(user) allowed_roles = [role[0] for role in allowed_roles] if desired_role not in allowed_roles: raise PermDeniedException( _("You can't import an account with a role greater than " "yours")) self.username = row[1].strip() try: User.objects.get(username=self.username) except User.DoesNotExist: pass else: raise Conflict if desired_role == "SimpleUsers": if len(row) < 8 or not row[7].strip(): raise BadRequest( _("The simple user '%s' must have a valid email address" % self.username)) if self.username != row[7].strip(): raise BadRequest( _("username and email fields must not differ for '%s'" % self.username)) if crypt_password: self.set_password(row[2].strip()) else: self.password = row[2].strip() self.first_name = row[3].strip() self.last_name = row[4].strip() self.is_active = (row[5].strip() in ["True", "1", "yes", "y"]) self.save() self.set_role(desired_role) self.post_create(user) if len(row) < 8: return events.raiseEvent("AccountImported", user, self, row[7:])
def editaccount(request, pk): account = User.objects.get(pk=pk) if not request.user.can_access(account): raise PermDeniedException mb = account.mailbox if hasattr(account, "mailbox") else None instances = dict(general=account, mail=mb, perms=account) events.raiseEvent("FillAccountInstances", request.user, account, instances) return AccountForm(request, instances=instances).process()
def dologout(request): """Logout the current user. """ if not request.user.is_anonymous(): events.raiseEvent("UserLogout", request) logger = logging.getLogger("modoboa.auth") logger.info(_("User '%s' logged out" % request.user.username)) logout(request) return HttpResponseRedirect(reverse("core:login"))
def editdomain(request, dom_id): """Edit domain view.""" domain = Domain.objects.get(pk=dom_id) if not request.user.can_access(domain): raise PermDeniedException instances = dict(general=domain) events.raiseEvent("FillDomainInstances", request.user, domain, instances) return DomainForm(request, instances=instances).process()
def dologout(request): """Logout the current user. """ if not request.user.is_anonymous(): events.raiseEvent("UserLogout", request) logger = logging.getLogger("modoboa.auth") logger.info(_("User '%s' logged out" % request.user.username)) logout(request) return HttpResponseRedirect(reverse(dologin))
def editaccount(request, accountid, tplname="common/tabforms.html"): account = User.objects.get(pk=accountid) if not request.user.can_access(account): raise PermDeniedException mb = account.mailbox if hasattr(account, "mailbox") else None instances = dict(general=account, mail=mb, perms=account) events.raiseEvent("FillAccountInstances", request.user, account, instances) return AccountForm(request, instances=instances).process()
def dologin(request): """Try to authenticate.""" error = None if request.method == "POST": form = LoginForm(request.POST) if form.is_valid(): logger = logging.getLogger('modoboa.auth') user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"]) if user and user.is_active: login(request, user) if not form.cleaned_data["rememberme"]: request.session.set_expiry(0) request.session["django_language"] = \ parameters.get_user(request.user, "LANG") logger.info( _("User '%s' successfully logged in" % user.username)) events.raiseEvent("UserLogin", request, form.cleaned_data["username"], form.cleaned_data["password"]) nextlocation = request.POST.get("next", None) if nextlocation is None or nextlocation == "None": if user.group == "SimpleUsers": nextlocation = reverse("topredirection") else: # FIXME nextlocation = reverse("modoboa_admin:domain_list") return HttpResponseRedirect(nextlocation) error = _( "Your username and password didn't match. Please try again.") logger.warning( "Failed connection attempt from '%(addr)s' as user '%(user)s'" % { "addr": request.META["REMOTE_ADDR"], "user": form.cleaned_data["username"] }) nextlocation = request.POST.get("next", None) httpcode = 401 else: form = LoginForm() nextlocation = request.GET.get("next", None) httpcode = 200 return HttpResponse(_render_to_string( request, "registration/login.html", { "form": form, "error": error, "next": nextlocation, "annoucements": events.raiseQueryEvent("GetAnnouncement", "loginpage") }), status=httpcode)
def dologin(request): """Try to authenticate.""" error = None if request.method == "POST": form = LoginForm(request.POST) if form.is_valid(): logger = logging.getLogger('modoboa.auth') user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"]) if user and user.is_active: nextlocation = None if not user.last_login: # Redirect to profile on first login nextlocation = reverse("core:user_index") login(request, user) if not form.cleaned_data["rememberme"]: request.session.set_expiry(0) translation.activate(request.user.language) request.session[translation.LANGUAGE_SESSION_KEY] = ( request.user.language) logger.info( _("User '%s' successfully logged in" % user.username) ) events.raiseEvent("UserLogin", request, form.cleaned_data["username"], form.cleaned_data["password"]) if nextlocation is None: nextlocation = request.POST.get("next", None) if nextlocation is None or nextlocation == "None": if user.group == "SimpleUsers": nextlocation = reverse("topredirection") else: nextlocation = reverse("admin:domain_list") return HttpResponseRedirect(nextlocation) error = _( "Your username and password didn't match. Please try again.") logger.warning( "Failed connection attempt from '%(addr)s' as user '%(user)s'" % {"addr": request.META["REMOTE_ADDR"], "user": form.cleaned_data["username"]} ) nextlocation = request.POST.get("next", None) httpcode = 401 else: form = LoginForm() nextlocation = request.GET.get("next", None) httpcode = 200 return HttpResponse(_render_to_string(request, "registration/login.html", { "form": form, "error": error, "next": nextlocation, "annoucements": events.raiseQueryEvent("GetAnnouncement", "loginpage") }), status=httpcode)
def from_csv(self, user, row, crypt_password=True): """Create a new account from a CSV file entry. The expected order is the following:: "account", loginname, password, first name, last name, enabled, group Additional fields can be added using the *AccountImported* event. :param user: a ``core.User`` instance :param row: a list containing the expected information :param crypt_password: """ from modoboa.lib.permissions import get_account_roles if len(row) < 7: raise BadRequest(_("Invalid line")) allowed_roles = get_account_roles(user) allowed_roles = [role[0] for role in allowed_roles] role = row[6].strip() if role not in allowed_roles: raise PermDeniedException( _("You can't import an account with a role greater than yours") ) self.username = row[1].strip() try: User.objects.get(username=self.username) except User.DoesNotExist: pass else: raise Conflict if role == "SimpleUsers": if len(row) < 8 or not row[7].strip(): raise BadRequest( _("The simple user '%s' must have a valid email address" % self.username) ) if self.username != row[7].strip(): raise BadRequest( _("username and email fields must not differ for '%s'" % self.username) ) if crypt_password: self.set_password(row[2].strip()) else: self.password = row[2].strip() self.first_name = row[3].strip() self.last_name = row[4].strip() self.is_active = (row[5].strip() in ["True", "1", "yes", "y"]) self.save(creator=user) self.set_role(role) if len(row) < 8: return events.raiseEvent("AccountImported", user, self, row[7:])
def create_mailbox(self, user, account): """Create a mailbox associated to :kw:`account`.""" if not user.can_access(self.domain): raise PermDeniedException events.raiseEvent("CanCreate", user, "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 editaccount(request, accountid, tplname="common/tabforms.html"): account = User.objects.get(pk=accountid) if not request.user.can_access(account): raise PermDeniedException mb = None if account.mailbox_set.count(): mb = account.mailbox_set.all()[0] instances = dict(general=account, mail=mb, perms=account) events.raiseEvent("FillAccountInstances", request.user, account, instances) return AccountForm(request, instances=instances).process()
def newdomain(request, tplname="common/wizard_forms.html"): events.raiseEvent("CanCreate", request.user, "domains") 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": 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)
def dologin(request): error = None if request.method == "POST": form = LoginForm(request.POST) if form.is_valid(): logger = logging.getLogger("modoboa.auth") user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"]) if user and user.is_active: login(request, user) if not form.cleaned_data["rememberme"]: request.session.set_expiry(0) if request.user.has_mailbox: request.session["password"] = encrypt(form.cleaned_data["password"]) request.session["django_language"] = parameters.get_user(request.user, "LANG", app="general") logger.info(_("User '%s' successfully logged in" % user.username)) events.raiseEvent("UserLogin", request, form.cleaned_data["username"], form.cleaned_data["password"]) nextlocation = request.POST.get("next", None) if nextlocation is None or nextlocation == "None": if user.group == "SimpleUsers": nextlocation = reverse("modoboa.lib.webutils.topredirection") else: nextlocation = reverse("domains") return HttpResponseRedirect(nextlocation) error = _("Your username and password didn't match. Please try again.") logger.warning( "Failed connection attempt from '%(addr)s' as user '%(user)s'" % {"addr": request.META["REMOTE_ADDR"], "user": form.cleaned_data["username"]} ) nextlocation = request.POST.get("next", None) httpcode = 401 else: form = LoginForm() nextlocation = request.GET.get("next", None) httpcode = 200 return HttpResponse( _render_to_string( request, "registration/login.html", { "form": form, "error": error, "next": nextlocation, "annoucements": events.raiseQueryEvent("GetAnnouncement", "loginpage"), }, ), status=httpcode, )
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): """Custom save method As forms interact with each other, it is simpler to make custom code to save them. """ events.raiseEvent("AccountModified", self.instances["general"], self.account) self.forms[1]["instance"].save(self.user, self.account) if len(self.forms) <= 2: return for f in self.forms[2:]: f["instance"].save()
def on(self): self.enabled = True self.save() self.__get_ext_instance() self.instance.load() self.instance.init() if self.instance.needs_media: path = os.path.join(settings.MEDIA_ROOT, self.name) exec_cmd("mkdir %s" % path) events.raiseEvent("ExtEnabled", self)
def save(self, user, commit=True, domalias_post_create=False): """Custom save method Updating a domain may have consequences on other objects (domain alias, mailbox, quota). The most tricky part concerns quotas update. """ d = super(DomainFormGeneral, self).save(commit=False) if commit: old_mail_homes = None if self.oldname is not None and d.name != self.oldname: d.name = self.oldname old_mail_homes = \ dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all()) d.name = self.cleaned_data['name'] d.save() Mailbox.objects.filter(domain=d, use_domain_quota=True) \ .update(quota=d.quota) aliases = [] for k, v in self.cleaned_data.iteritems(): if not k.startswith("aliases"): continue if v in ["", None]: continue aliases.append(v) for dalias in d.domainalias_set.all(): if dalias.name not in aliases: dalias.delete() else: aliases.remove(dalias.name) if aliases: events.raiseEvent("CanCreate", user, "domain_aliases", len(aliases)) for alias in aliases: try: d.domainalias_set.get(name=alias) except DomainAlias.DoesNotExist: pass else: continue al = DomainAlias(name=alias, target=d, enabled=d.enabled) al.save( creator=user) if domalias_post_create else al.save() if old_mail_homes is not None: self.update_mailbox_quotas(d) for mb in d.mailbox_set.all(): mb.rename_dir(old_mail_homes[mb.id]) return d
def delete(self, fromuser, keepdir=False): from modoboa.lib.permissions import \ ungrant_access_to_object, ungrant_access_to_objects if self.domainalias_set.count(): events.raiseEvent("DomainAliasDeleted", self.domainalias_set.all()) ungrant_access_to_objects(self.domainalias_set.all()) if self.mailbox_set.count(): Quota.objects.filter(username__contains='@%s' % self.name).delete() events.raiseEvent("DeleteMailbox", self.mailbox_set.all()) ungrant_access_to_objects(self.mailbox_set.all()) hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm == "yes" and not keepdir: for mb in self.mailbox_set.all(): mb.delete_dir() if self.alias_set.count(): events.raiseEvent("MailboxAliasDelete", self.alias_set.all()) ungrant_access_to_objects(self.alias_set.all()) if parameters.get_admin("AUTO_ACCOUNT_REMOVAL") == "yes": for account in User.objects.filter( mailbox__domain__name=self.name): account.delete(fromuser, keepdir) events.raiseEvent("DeleteDomain", self) ungrant_access_to_object(self) super(Domain, self).delete()
def save(self): """Custom save method As forms interact with each other, it is simpler to make custom code to save them. """ events.raiseEvent( "AccountModified", self.instances["general"], self.account ) self.forms[1]["instance"].save(self.user, self.account) if len(self.forms) <= 2: return for f in self.forms[2:]: f["instance"].save()
def delete(self, fromuser, keepdir=False): from modoboa.lib.permissions import \ ungrant_access_to_object, ungrant_access_to_objects if self.domainalias_set.count(): events.raiseEvent("DomainAliasDeleted", self.domainalias_set.all()) ungrant_access_to_objects(self.domainalias_set.all()) if self.mailbox_set.count(): Quota.objects.filter(username__contains='@%s' % self.name).delete() events.raiseEvent("DeleteMailbox", self.mailbox_set.all()) ungrant_access_to_objects(self.mailbox_set.all()) hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False) if hm == "yes" and not keepdir: for mb in self.mailbox_set.all(): MailboxOperation.objects.create( type='delete', argument=mb.mail_home ) if self.alias_set.count(): events.raiseEvent("MailboxAliasDelete", self.alias_set.all()) ungrant_access_to_objects(self.alias_set.all()) if parameters.get_admin("AUTO_ACCOUNT_REMOVAL") == "yes": for account in User.objects.filter(mailbox__domain__name=self.name): account.delete(fromuser, keepdir) events.raiseEvent("DeleteDomain", self) ungrant_access_to_object(self) super(Domain, self).delete()
def off(self): self.__get_ext_instance() if self.instance is None: return self.instance.destroy() self.enabled = False self.save() if self.instance.needs_media: path = os.path.join(settings.MEDIA_ROOT, self.name) exec_cmd("rm -r %s" % path) events.raiseEvent("ExtDisabled", self)
def save(self, user, commit=True, domalias_post_create=False): """Custom save method Updating a domain may have consequences on other objects (domain alias, mailbox, quota). The most tricky part concerns quotas update. """ d = super(DomainFormGeneral, self).save(commit=False) if commit: old_mail_homes = None if self.oldname is not None and d.name != self.oldname: d.name = self.oldname old_mail_homes = \ dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all()) d.name = self.cleaned_data['name'] d.save() Mailbox.objects.filter(domain=d, use_domain_quota=True) \ .update(quota=d.quota) aliases = [] for k, v in self.cleaned_data.iteritems(): if not k.startswith("aliases"): continue if v in ["", None]: continue aliases.append(v) for dalias in d.domainalias_set.all(): if dalias.name not in aliases: dalias.delete() else: aliases.remove(dalias.name) if aliases: events.raiseEvent( "CanCreate", user, "domain_aliases", len(aliases)) for alias in aliases: try: d.domainalias_set.get(name=alias) except DomainAlias.DoesNotExist: pass else: continue al = DomainAlias(name=alias, target=d, enabled=d.enabled) al.save(creator=user) if domalias_post_create else al.save() if old_mail_homes is not None: self.update_mailbox_quotas(d) for mb in d.mailbox_set.all(): mb.rename_dir(old_mail_homes[mb.id]) return d
def save(self, user, account): 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.update_mailbox(user, account) events.raiseEvent( 'SaveExtraFormFields', 'mailform', self.mb, self.cleaned_data ) account.email = self.cleaned_data["email"] account.save() aliases = [] for name, value in self.cleaned_data.iteritems(): if not name.startswith("aliases"): continue if value == "": continue aliases.append(value) for alias in self.mb.alias_set.all(): if not alias.full_address in aliases: if len(alias.get_recipients()) >= 2: continue alias.delete() else: aliases.remove(alias.full_address) if aliases: 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], creator=user) return self.mb
def dologin(request): """Try to authenticate.""" error = None if request.method == "POST": form = LoginForm(request.POST) if form.is_valid(): logger = logging.getLogger('modoboa.auth') user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"]) if user and user.is_active: login(request, user) if not form.cleaned_data["rememberme"]: request.session.set_expiry(0) translation.activate(request.user.language) request.session[translation.LANGUAGE_SESSION_KEY] = ( request.user.language) logger.info( _("User '%s' successfully logged in" % user.username)) events.raiseEvent("UserLogin", request, form.cleaned_data["username"], form.cleaned_data["password"]) return HttpResponseRedirect(find_nextlocation(request, user)) error = _( "Your username and password didn't match. Please try again.") logger.warning( "Failed connection attempt from '%(addr)s' as user '%(user)s'" % { "addr": request.META["REMOTE_ADDR"], "user": form.cleaned_data["username"] }) nextlocation = request.POST.get("next", None) httpcode = 401 else: form = LoginForm() nextlocation = request.GET.get("next", None) httpcode = 200 return HttpResponse(_render_to_string( request, "registration/login.html", { "form": form, "error": error, "next": nextlocation, "annoucements": events.raiseQueryEvent("GetAnnouncement", "loginpage") }), status=httpcode)
def save(self, user, account): 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.update_mailbox(user, account) events.raiseEvent('SaveExtraFormFields', 'mailform', self.mb, self.cleaned_data) account.email = self.cleaned_data["email"] account.save() aliases = [] for name, value in self.cleaned_data.iteritems(): if not name.startswith("aliases"): continue if value == "": continue aliases.append(value) for alias in self.mb.alias_set.all(): if not alias.full_address in aliases: if len(alias.get_recipients()) >= 2: continue alias.delete() else: aliases.remove(alias.full_address) if aliases: 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], creator=user) return self.mb
def on(self, update_db=True): """Activate this extension.""" if update_db: self.enabled = True self.save() self.__get_ext_instance() self.instance.load() self.instance.init() if self.instance.needs_media: path = os.path.join(settings.MEDIA_ROOT, self.name) exec_cmd("mkdir %s" % path) events.raiseEvent("ExtEnabled", self)
def newdomain(request, tplname="common/wizard_forms.html"): events.raiseEvent("CanCreate", request.user, "domains") 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": 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)
def newdomain(request, tplname="common/wizard_forms.html"): events.raiseEvent("CanCreate", request.user, "domains") cwizard = CreationWizard() 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", new_args=[request.user] ) if request.method == "POST": retcode, data = cwizard.validate_step(request) if retcode == -1: raise BadRequest(data) if retcode == 1: return render_to_json_response( {'title': cwizard.get_title(data + 1), 'stepid': data} ) if retcode == 2: genform = cwizard.steps[0]["form"] domain = genform.save(request.user) domain.post_create(request.user) try: cwizard.steps[1]["form"].save(request.user, domain) except ModoboaException as e: transaction.rollback() raise return render_to_json_response(_("Domain created")) return render_to_json_response({ 'stepid': data, 'form_errors': cwizard.errors }, status=400) ctx = {"title": _("New domain"), "action_label": _("Create"), "action_classes": "submit", "action": reverse(newdomain), "formid": "domform"} cwizard.create_forms() ctx.update(steps=cwizard.steps) ctx.update(subtitle="1. %s" % cwizard.steps[0]['title']) return render(request, tplname, ctx)