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 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 from_csv(self, user, row): """Create a new domain from a CSV entry. The expected fields order is the following:: "domain", name, quota, default_mailbox_quota, enabled :param ``core.User`` user: user creating the domain :param str row: a list containing domain's definition """ if len(row) < 5: raise BadRequest(_("Invalid line")) self.name = row[1].strip() if Domain.objects.filter(name=self.name).exists(): raise Conflict try: self.quota = int(row[2].strip()) except ValueError: raise BadRequest( _("Invalid quota value for domain '{}'") .format(self.name) ) try: self.default_mailbox_quota = int(row[3].strip()) except ValueError: raise BadRequest( _("Invalid default mailbox quota value for domain '{}'") .format(self.name) ) if self.quota != 0 and self.default_mailbox_quota > self.quota: raise BadRequest( _("Default mailbox quota cannot be greater than domain " "quota") ) self.enabled = (row[4].strip().lower() in ["true", "1", "yes", "y"]) core_signals.can_create_object.send( sender=self.__class__, context=user, klass=Domain, instance=self) self.save(creator=user)
def getmailcontent(request): mbox = request.GET.get("mbox", None) mailid = request.GET.get("mailid", None) if mbox is None or mailid is None: raise BadRequest(_("Invalid request")) email = ImapEmail(mbox, mailid, request, links=int(request.GET["links"])) return render( request, "common/viewmail.html", { "headers": email.render_headers(folder=mbox, mail_id=mailid), "folder": mbox, "imapid": mailid, "mailbody": email.body if email.body else "" })
def from_csv(self, user, row): """Create a new domain from a CSV entry. The expected fields order is the following:: "domain", name, quota, enabled :param ``core.User`` user: user creating the domain :param str row: a list containing domain's definition """ if len(row) < 4: raise BadRequest(_("Invalid line")) self.name = row[1].strip() if Domain.objects.filter(name=self.name).exists(): raise Conflict try: self.quota = int(row[2].strip()) except ValueError: raise BadRequest( _("Invalid quota value for domain '%s'") % self.name) self.enabled = (row[3].strip() in ["True", "1", "yes", "y"]) self.save(creator=user)
def getmailcontent(request): mbox = request.GET.get("mbox", None) mailid = request.GET.get("mailid", None) if mbox is None or mailid is None: raise BadRequest(_("Invalid request")) email = ImapEmail( request, "%s:%s" % (mbox, mailid), dformat="DISPLAYMODE", links=int(request.GET.get("links", "0")) ) return render(request, "common/viewmail.html", { "mailbody": email.body if email.body else "" })
def _listing(request): flt = None rcptfilter = None msgs = None if not request.user.is_superuser and request.user.group != 'SimpleUsers': if not Domain.objects.get_for_admin(request.user).count(): return empty_quarantine(request) navparams = QuarantineNavigationParameters(request) navparams.store() pattern = navparams.get('pattern', '') if pattern: criteria = navparams.get('criteria') if criteria == "both": criteria = "from_addr,subject,to" for c in criteria.split(","): if c == "from_addr": nfilter = Q(mail__from_addr__contains=pattern) elif c == "subject": nfilter = Q(mail__subject__contains=pattern) elif c == "to": rcptfilter = pattern continue else: raise BadRequest("unsupported search criteria %s" % c) flt = nfilter if flt is None else flt | nfilter msgtype = navparams.get('msgtype', None) if msgtype is not None: nfilter = Q(mail__msgrcpt__content=msgtype) flt = flt | nfilter if flt is not None else nfilter msgs = get_wrapper().get_mails(request, rcptfilter) page = navparams.get('page') lst = SQLlisting( request.user, msgs, flt, navparams=request.session["quarantine_navparams"], elems_per_page=int(parameters.get_user(request.user, "MESSAGES_PER_PAGE")) ) page = lst.paginator.getpage(page) if not page: return empty_quarantine(request) content = lst.fetch(request, page.id_start, page.id_stop) ctx = getctx( "ok", listing=content, paginbar=pagination_bar(page), page=page.number ) if request.session.get('location', 'listing') != 'listing': ctx['menu'] = quar_menu() request.session['location'] = 'listing' return render_to_json_response(ctx)
def validate_step(self): stepid = self.request.POST.get("stepid", None) if stepid is None: raise BadRequest(_("Invalid request")) stepid = int(stepid.replace("step", "")) if stepid < 0 or stepid > len(self.steps): raise BadRequest(_("Invalid request")) self.create_forms(self.request.POST) statuses = [] for cpt in xrange(0, stepid): statuses.append(self.steps[cpt].form.is_valid()) if False in statuses: return render_to_json_response( { 'stepid': stepid, 'form_errors': self.errors }, status=400) if stepid == len(self.steps): return self.done() return render_to_json_response({ 'title': self.steps[stepid].title, 'stepid': stepid })
def from_csv(self, user, row): """Create a domain alias from a CSV row Expected format: ["domainalias", domain alias name, targeted domain, enabled] :param user: a ``User`` object :param row: a list containing the alias definition """ if len(row) < 4: raise BadRequest(_("Invalid line")) self.name = row[1].strip() for model in [DomainAlias, Domain]: if model.objects.filter(name=self.name).exists(): raise Conflict domname = row[2].strip() try: self.target = Domain.objects.get(name=domname) except Domain.DoesNotExist: raise BadRequest(_("Unknown domain %s") % domname) core_signals.can_create_object.send( sender="import", context=self.target, object_type="domain_aliases") self.enabled = row[3].strip() in ["True", "1", "yes", "y"] self.save(creator=user)
def getmailsource(request): """Retrieve message source.""" mbox = request.GET.get("mbox", None) mailid = request.GET.get("mailid", None) if mbox is None or mailid is None: raise BadRequest(_("Invalid request")) email = ImapEmail(request, "%s:%s" % (mbox, mailid), dformat="DISPLAYMODE", links=request.GET.get("links", "0") == "1") return render(request, "modoboa_webmail/mail_source.html", { "title": _("Message source"), "source": email.source })
def delete(request): mbox = request.GET.get("mbox", None) selection = request.GET.getlist("selection[]", None) if mbox is None or selection is None: raise BadRequest(_("Invalid request")) selection = [item for item in selection if item.isdigit()] mbc = get_imapconnector(request) mbc.move(",".join(selection), mbox, request.user.parameters.get_value("trash_folder")) count = len(selection) message = ungettext("%(count)d message deleted", "%(count)d messages deleted", count) % {"count": count} return render_to_json_response(message)
def graphs(request): gset = request.GET.get("gset", None) searchq = request.GET.get("searchquery", None) graph_sets = {} for result in signals.get_graph_sets.send(sender="index", user=request.user): graph_sets.update(result[1]) if gset not in graph_sets: raise NotFound(_("Unknown graphic set")) period = request.GET.get("period", "day") tplvars = {"graphs": {}, "period": period} fname = graph_sets[gset].get_file_name(request.user, searchq) if fname is None: raise BadRequest(_("Unknown domain")) tplvars["fname"] = fname if period == "custom": if "start" not in request.GET or "end" not in request.GET: raise BadRequest(_("Bad custom period")) start = request.GET["start"] end = request.GET["end"] expr = re.compile(r'[:\- ]') period_name = "%s_%s" % (expr.sub('', start), expr.sub('', end)) start = date_to_timestamp(expr.split(start)) end = date_to_timestamp(expr.split(end)) else: end = int(time.mktime(time.localtime())) start = "-1%s" % period period_name = period tplvars["domain_selector"] = graph_sets[gset].domain_selector tplvars["graphs"] = graph_sets[gset].export(tplvars["fname"], start, end) tplvars["period_name"] = period_name tplvars["start"] = start tplvars["end"] = end return render_to_json_response(tplvars)
def list_quotas(request): from modoboa.lib.db_utils import db_type sort_order, sort_dir = get_sort_order(request.GET, "address") mboxes = Mailbox.objects.get_for_admin( request.user, request.GET.get("searchquery", None) ) mboxes = mboxes.exclude(quota=0) if sort_order in ["address", "quota", "quota_value__bytes"]: mboxes = mboxes.order_by("%s%s" % (sort_dir, sort_order)) elif sort_order == "quota_usage": where = "admin_mailbox.address||'@'||admin_domain.name" db_type = db_type() if db_type == "postgres": select = ( "(admin_quota.bytes::float / (CAST(admin_mailbox.quota " "AS BIGINT) * 1048576)) * 100" ) else: select = ( "admin_quota.bytes / (admin_mailbox.quota " "* 1048576) * 100" ) if db_type == "mysql": where = "CONCAT(admin_mailbox.address,'@',admin_domain.name)" mboxes = mboxes.extra( select={'quota_usage': select}, where=["admin_quota.username=%s" % where], tables=["admin_quota", "admin_domain"], order_by=["%s%s" % (sort_dir, sort_order)] ) else: raise BadRequest(_("Invalid request")) page = get_listing_page(mboxes, request.GET.get("page", 1)) context = { "headers": _render_to_string( request, "admin/quota_headers.html", {} ) } if page is None: context["length"] = 0 else: context["rows"] = _render_to_string( request, "admin/quotas.html", { "mboxes": page } ) context["pages"] = [page.number] return render_to_json_response(context)
def mark(request, name): status = request.GET.get("status", None) ids = request.GET.get("ids", None) if status is None or ids is None: raise BadRequest(_("Invalid request")) imapc = get_imapconnector(request) try: getattr(imapc, "mark_messages_%s" % status)(name, ids) except AttributeError: raise UnknownAction return render_to_json_response({ 'action': status, 'mbox': name, 'unseen': imapc.unseen_messages(name) })
def mark_as_junk(request): """Mark a message as SPAM.""" mbox = request.GET.get("mbox") selection = request.GET.getlist("selection[]") if mbox is None or selection is None: raise BadRequest(_("Invalid request")) selection = [item for item in selection if item.isdigit()] mbc = get_imapconnector(request) mbc.move(",".join(selection), mbox, request.user.parameters.get_value("junk_folder")) count = len(selection) message = ungettext("%(count)d message marked", "%(count)d messages marked", count) % {"count": count} return render_to_json_response(message)
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, internal=False).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 from_csv(self, user, row): """Import a relay domain from CSV. :param user: user importing the relay domain :param str row: relay domain definition """ if len(row) != 6: raise BadRequest(_("Invalid line")) self.name = row[1].strip() self.target_host = row[2].strip() self.service, created = Service.objects.get_or_create( name=row[3].strip()) self.enabled = (row[4].strip() == 'True') self.verify_recipients = (row[5].strip() == 'True') self.save(creator=user)
def set_quota(self, value=None, override_rules=False): """Set or update quota's value for this mailbox. A value equal to 0 means the mailbox won't have any quota. The following cases allow people to define such behaviour: * The domain has no quota * :keyword:`override_rules` is True :param integer value: the quota's value :param bool override_rules: allow to override defined quota rules """ if value is None: if self.use_domain_quota: self.quota = self.domain.quota else: self.quota = 0 elif int(value) > self.domain.quota and not override_rules: raise BadRequest( _("Quota is greater than the allowed domain's limit (%dM)" % self.domain.quota)) else: self.quota = value if not self.quota and self.domain.quota and not override_rules: raise BadRequest(_("A quota is required"))
def release_selfservice(request, mail_id): rcpt = request.GET.get("rcpt", None) secret_id = request.GET.get("secret_id", None) if rcpt is None or secret_id is None: raise BadRequest(_("Invalid request")) connector = get_connector() try: msgrcpt = connector.get_recipient_message(rcpt, mail_id) except Msgrcpt.DoesNotExist: raise BadRequest(_("Invalid request")) if secret_id != msgrcpt.mail.secret_id: raise BadRequest(_("Invalid request")) if parameters.get_admin("USER_CAN_RELEASE") == "no": connector.set_msgrcpt_status(rcpt, mail_id, 'p') msg = _("Request sent") else: amr = AMrelease() result = amr.sendreq(mail_id, secret_id, rcpt) if result: connector.set_msgrcpt_status(rcpt, mail_id, 'R') msg = _("Message released") else: raise BadRequest(result) return render_to_json_response(msg)
def viewmail(request, mail_id): rcpt = request.GET.get("rcpt", None) if rcpt is None: raise BadRequest(_("Invalid request")) if request.user.email == rcpt: SQLconnector().set_msgrcpt_status(rcpt, mail_id, "V") elif hasattr(request.user, "mailbox"): mb = request.user.mailbox if rcpt == mb.full_address or rcpt in mb.alias_addresses: SQLconnector().set_msgrcpt_status(rcpt, mail_id, "V") content = loader.get_template("modoboa_amavis/_email_display.html").render( {"mail_id": mail_id}) menu = viewm_menu(request.user, mail_id, rcpt) ctx = getctx("ok", menu=menu, listing=content) request.session["location"] = "viewmail" return render_to_json_response(ctx)
def from_csv(self, user, row): """Import a relay domain alias from CSV. :param user: user importing the relay domain alias :param str row: relay domain alias definition """ if len(row) != 4: raise BadRequest(_("Invalid line")) self.name = row[1].strip() try: self.target = RelayDomain.objects.get(name=row[2].strip()) except RelayDomain.DoesNotExist: raise NotFound(_("Relay domain %s does not exist" % row[2].strip())) self.enabled = (row[3].strip() == 'True') self.save(creator=user)
def compose_and_send(request, action, callback=None): mbox = request.GET.get("mbox", None) mailid = request.GET.get("mailid", None) if mbox is None or mailid is None: raise BadRequest(_("Invalid request")) url = "?action=%s&mbox=%s&mailid=%s" % (action, mbox, mailid) if request.method == "POST": status, resp = send_mail(request, url) if status and callback: callback(mbox, mailid) return resp form = ComposeMailForm() modclass = globals()["%sModifier" % action.capitalize()] email = modclass(mbox, mailid, request, form, addrfull=True, links="1") return render_compose(request, form, url, email)
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)
def graphs(request): gset = request.GET.get("gset", None) gsets = events.raiseDictEvent("GetGraphSets") if not gset in gsets: raise NotFound(_("Unknown graphic set")) searchq = request.GET.get("searchquery", None) period = request.GET.get("period", "day") tplvars = dict(graphs=[], period=period) if searchq in [None, "global"]: if not request.user.is_superuser: if not Domain.objects.get_for_admin(request.user).count(): return render_to_json_response({}) tplvars.update( domain=Domain.objects.get_for_admin(request.user)[0].name) else: tplvars.update(domain="global") else: domain = Domain.objects.filter(name__contains=searchq) if domain.count() != 1: return render_to_json_response({}) if not request.user.can_access(domain[0]): raise PermDeniedException tplvars.update(domain=domain[0].name) if period == "custom": if not "start" in request.GET or not "end" in request.GET: raise BadRequest(_("Bad custom period")) start = request.GET["start"] end = request.GET["end"] G = Grapher() expr = re.compile(r'[:\- ]') period_name = "%s_%s" % (expr.sub('', start), expr.sub('', end)) for tpl in gsets[gset].get_graphs(): tplvars['graphs'].append(tpl.display_name) G.process(tplvars["domain"], period_name, str2Time(*expr.split(start)), str2Time(*expr.split(end)), tpl) tplvars["period_name"] = period_name tplvars["start"] = start tplvars["end"] = end else: tplvars['graphs'] = gsets[gset].get_graph_names() return render_to_json_response( {'content': _render_to_string(request, "stats/graphs.html", tplvars)})
def from_csv(self, user, row): """Import a relay domain from CSV. :param user: user importing the relay domain :param str row: relay domain definition """ if len(row) != 6: raise BadRequest(_("Invalid line")) self.domain = admin_models.Domain( name=row[1].strip(), type="relaydomain", enabled=(row[4].strip() in ["True", "1", "yes", "y"])) self.domain.save(creator=user) self.target_host = row[2].strip() self.service, created = Service.objects.get_or_create( name=row[3].strip()) self.verify_recipients = (row[5].strip() in ["True", "1", "yes", "y"]) self.save(creator=user)
def parse_dest(self): self.dests = [] rawdata = self.cleaned_data["dest"].strip() if rawdata == "": return for d in rawdata.split(","): local_part, domname = split_mailbox(d) if not local_part or not domname or not len(domname): raise BadRequest("Invalid mailbox syntax for %s" % d) try: Domain.objects.get(name=domname) except Domain.DoesNotExist: self.dests += [d] else: raise PermDeniedException( _("You can't define a forward to a local destination. " "Please ask your administrator to create an alias " "instead."))
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 viewmail(request, mail_id): rcpt = request.GET.get("rcpt", None) if rcpt is None: raise BadRequest(_("Invalid request")) if request.user.email == rcpt: get_connector().set_msgrcpt_status(rcpt, mail_id, 'V') elif request.user.mailbox_set.count(): mb = Mailbox.objects.get(user=request.user) if rcpt == mb.full_address or rcpt in mb.alias_addresses: get_connector().set_msgrcpt_status(rcpt, mail_id, 'V') content = Template(""" <iframe src="{{ url }}" id="mailcontent"></iframe> """).render(Context({"url": reverse("amavis:mailcontent_get", args=[mail_id])})) menu = viewm_menu(request.user, mail_id, rcpt) ctx = getctx("ok", menu=menu, listing=content) request.session['location'] = 'viewmail' return render_to_json_response(ctx)
def graphs(request): gset = request.GET.get("gset", None) gsets = events.raiseDictEvent("GetGraphSets") if not gset in gsets: raise NotFound(_("Unknown graphic set")) searchq = request.GET.get("searchquery", None) period = request.GET.get("period", "day") tplvars = dict(graphs={}, period=period) if searchq in [None, "global"]: if not request.user.is_superuser: if not Domain.objects.get_for_admin(request.user).count(): return render_to_json_response({}) tplvars.update( domain=Domain.objects.get_for_admin(request.user)[0].name) else: tplvars.update(domain="global") else: domain = Domain.objects.filter(name__contains=searchq) if domain.count() != 1: return render_to_json_response({}) if not request.user.can_access(domain[0]): raise PermDeniedException tplvars.update(domain=domain[0].name) if period == "custom": if not "start" in request.GET or not "end" in request.GET: raise BadRequest(_("Bad custom period")) start = request.GET["start"] end = request.GET["end"] expr = re.compile(r'[:\- ]') period_name = "%s_%s" % (expr.sub('', start), expr.sub('', end)) start = date_to_timestamp(expr.split(start)) end = date_to_timestamp(expr.split(end)) else: end = int(time.mktime(time.localtime())) start = "-1%s" % period period_name = period tplvars['graphs'] = gsets[gset].export(tplvars["domain"], start, end) tplvars["period_name"] = period_name tplvars["start"] = start tplvars["end"] = end return render_to_json_response(tplvars)
def viewmail(request): mbox = request.GET.get("mbox", None) mailid = request.GET.get("mailid", None) if mbox is None or mailid is None: raise BadRequest(_("Invalid request")) links = request.GET.get("links", None) if links is None: links = 1 if parameters.get_user(request.user, "ENABLE_LINKS") == "yes" else 0 else: links = int(links) url = "{0}?mbox={1}&mailid={2}&links={3}".format( reverse("webmail:mailcontent_get"), mbox, mailid, links) content = Template(""" <iframe src="{{ url }}" id="mailcontent"></iframe> """).render(Context({"url": url})) return dict(listing=content, menuargs=dict(mail_id=mailid))
def get_recipients(self): recipients = [] rawdata = self.cleaned_data["dest"].strip() if not rawdata: return recipients for rcpt in rawdata.split(","): local_part, domname = split_mailbox(rcpt) if not local_part or not domname: raise BadRequest("Invalid mailbox syntax for %s" % rcpt) try: Domain.objects.get(name=domname) except Domain.DoesNotExist: recipients += [rcpt] else: raise PermDeniedException( _("You can't define a forward to a local destination. " "Please ask your administrator to create an alias " "instead.") ) return recipients