mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
Remove sievefilters extension.
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
# coding: utf-8
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django import forms
|
||||
from sievelib.managesieve import SUPPORTED_AUTH_MECHS
|
||||
from modoboa.lib.parameters import AdminParametersForm, UserParametersForm
|
||||
from modoboa.lib.form_utils import SeparatorField, YesNoField, InlineRadioSelect
|
||||
|
||||
|
||||
def supported_auth_mechs():
|
||||
values = [('AUTO', 'auto')]
|
||||
for m in SUPPORTED_AUTH_MECHS:
|
||||
values += [(m, m.lower())]
|
||||
return values
|
||||
|
||||
|
||||
class ParametersForm(AdminParametersForm):
|
||||
app = "sievefilters"
|
||||
|
||||
sep1 = SeparatorField(label=_("ManageSieve settings"))
|
||||
|
||||
server = forms.CharField(
|
||||
label=_("Server address"),
|
||||
initial="127.0.0.1",
|
||||
help_text=_("Address of your MANAGESIEVE server"),
|
||||
widget=forms.TextInput(attrs={"class": "form-control"})
|
||||
)
|
||||
|
||||
port = forms.IntegerField(
|
||||
label=_("Server port"),
|
||||
initial=4190,
|
||||
help_text=_("Listening port of your MANAGESIEVE server"),
|
||||
widget=forms.TextInput(attrs={"class": "form-control"})
|
||||
)
|
||||
|
||||
starttls = YesNoField(
|
||||
label=_("Connect using STARTTLS"),
|
||||
initial="no",
|
||||
help_text=_("Use the STARTTLS extension")
|
||||
)
|
||||
|
||||
authentication_mech = forms.ChoiceField(
|
||||
label=_("Authentication mechanism"),
|
||||
choices=supported_auth_mechs(),
|
||||
initial="auto",
|
||||
help_text=_("Prefered authentication mechanism"),
|
||||
widget=forms.Select(attrs={"class": "form-control"})
|
||||
)
|
||||
|
||||
|
||||
class UserSettings(UserParametersForm):
|
||||
app = "sievefilters"
|
||||
|
||||
sep1 = SeparatorField(label=_("General"))
|
||||
|
||||
editor_mode = forms.ChoiceField(
|
||||
initial="gui",
|
||||
label=_("Editor mode"),
|
||||
choices=[("raw", "raw"), ("gui", "simplified")],
|
||||
help_text=_("Select the mode you want the editor to work in"),
|
||||
widget=InlineRadioSelect(attrs={"type": "checkbox"})
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def has_access(user):
|
||||
return user.mailbox_set.count() != 0
|
||||
@@ -1,322 +0,0 @@
|
||||
"""Custom forms."""
|
||||
|
||||
from django import forms
|
||||
from django.forms.widgets import RadioFieldRenderer, RadioSelect, RadioInput
|
||||
from django.http import QueryDict
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.html import conditional_escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from modoboa.extensions.admin.templatetags.admin_tags import gender
|
||||
|
||||
|
||||
class FiltersSetForm(forms.Form):
|
||||
name = forms.CharField(
|
||||
widget=forms.TextInput(attrs={"class": "form-control"})
|
||||
)
|
||||
active = forms.BooleanField(
|
||||
label=gender("Active", "m"), required=False,
|
||||
initial=False,
|
||||
help_text=ugettext_lazy("Check to activate this filters set")
|
||||
)
|
||||
|
||||
|
||||
class CustomRadioInput(RadioInput):
|
||||
|
||||
def __unicode__(self):
|
||||
return self.render()
|
||||
|
||||
def render(self, name=None, value=None, attrs=None, choices=()):
|
||||
name = name or self.name
|
||||
value = value or self.value
|
||||
attrs = attrs or self.attrs
|
||||
if 'id' in self.attrs:
|
||||
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
|
||||
else:
|
||||
label_for = ''
|
||||
choice_label = conditional_escape(force_unicode(self.choice_label))
|
||||
return mark_safe(
|
||||
u'<label%s class="radio-inline">%s %s</label>'
|
||||
% (label_for, self.tag(), choice_label)
|
||||
)
|
||||
|
||||
|
||||
class CustomRadioFieldRenderer(RadioFieldRenderer):
|
||||
|
||||
def __iter__(self):
|
||||
for i, choice in enumerate(self.choices):
|
||||
yield CustomRadioInput(
|
||||
self.name, self.value, self.attrs.copy(), choice, i)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
choice = self.choices[idx]
|
||||
return CustomRadioInput(
|
||||
self.name, self.value, self.attrs.copy(), choice, idx)
|
||||
|
||||
def render(self):
|
||||
return mark_safe(u'\n'.join([force_unicode(w) for w in self]))
|
||||
|
||||
|
||||
class CustomRadioSelect(RadioSelect):
|
||||
renderer = CustomRadioFieldRenderer
|
||||
|
||||
|
||||
class FilterForm(forms.Form):
|
||||
|
||||
def __init__(self, conditions, actions, request, *args, **kwargs):
|
||||
super(FilterForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.field_widths = {
|
||||
"match_type": 8
|
||||
}
|
||||
|
||||
self.fields["name"] = forms.CharField(label=_("Name"))
|
||||
self.fields["match_type"] = forms.ChoiceField(
|
||||
choices=[("allof", _("All of the following")),
|
||||
("anyof", _("Any of the following")),
|
||||
("all", _("All messages"))],
|
||||
initial="anyof",
|
||||
widget=CustomRadioSelect()
|
||||
)
|
||||
|
||||
self.header_operators = [
|
||||
("contains", _("contains"), "string"),
|
||||
("notcontains", _("does not contain"), "string"),
|
||||
("is", _("is"), "string"),
|
||||
("isnot", _("is not"), "string")
|
||||
]
|
||||
|
||||
self.cond_templates = [
|
||||
{"name": "Subject",
|
||||
"label": _("Subject"),
|
||||
"operators": self.header_operators},
|
||||
{"name": "From",
|
||||
"label": _("Sender"),
|
||||
"operators": self.header_operators},
|
||||
{"name": "To",
|
||||
"label": _("Recipient"),
|
||||
"operators": self.header_operators},
|
||||
{"name": "Cc",
|
||||
"label": _("Cc"),
|
||||
"operators": self.header_operators},
|
||||
{"name": "size", "label": _("Size"),
|
||||
"operators": [("over", _("is greater than"), "number"),
|
||||
("under", _("is less than"), "number")]},
|
||||
]
|
||||
|
||||
self.action_templates = [
|
||||
{"name": "fileinto", "label": _("Move message to"),
|
||||
"args": [{"type": "list", "vloader": "userfolders"}]},
|
||||
{"name": "redirect", "label": _("Redirect message to"),
|
||||
"args": [{"type": "string"}]},
|
||||
]
|
||||
|
||||
self.conds_cnt = 0
|
||||
for c in conditions:
|
||||
getattr(self, "_build_%s_field" % c[0])(c[1], c[2])
|
||||
self.actions_cnt = 0
|
||||
for a in actions:
|
||||
getattr(self, "_build_%s_field" % a[0])(request, a[1])
|
||||
|
||||
def clean_name(self):
|
||||
"""Check that name does not contain strange chars.
|
||||
"""
|
||||
if '#' in self.cleaned_data["name"]:
|
||||
raise forms.ValidationError(_("Wrong filter name"))
|
||||
return self.cleaned_data["name"]
|
||||
|
||||
def _build_header_field(self, name, op, value):
|
||||
targets = []
|
||||
ops = []
|
||||
vfield = None
|
||||
for tpl in self.cond_templates:
|
||||
targets += [(tpl["name"], tpl["label"]), ]
|
||||
if tpl["name"] != name:
|
||||
continue
|
||||
for opdef in tpl["operators"]:
|
||||
ops += [opdef[:2]]
|
||||
if op != opdef[0]:
|
||||
continue
|
||||
if opdef[2] in ["string", "number"]:
|
||||
vfield = forms.CharField(max_length=255, initial=value)
|
||||
|
||||
self.fields["cond_target_%d" % self.conds_cnt] = \
|
||||
forms.ChoiceField(initial=name, choices=targets)
|
||||
self.fields["cond_operator_%d" % self.conds_cnt] = \
|
||||
forms.ChoiceField(initial=op, choices=ops)
|
||||
self.fields["cond_value_%d" % self.conds_cnt] = vfield
|
||||
self.conds_cnt += 1
|
||||
|
||||
def _build_Subject_field(self, op, value):
|
||||
self._build_header_field("Subject", op, value)
|
||||
|
||||
def _build_To_field(self, op, value):
|
||||
self._build_header_field("To", op, value)
|
||||
|
||||
def _build_From_field(self, op, value):
|
||||
self._build_header_field("From", op, value)
|
||||
|
||||
def _build_Cc_field(self, op, value):
|
||||
self._build_header_field("Cc", op, value)
|
||||
|
||||
def _build_size_field(self, op, value):
|
||||
self._build_header_field("size", op, value)
|
||||
|
||||
def _build_action_field(self, request, name, value):
|
||||
actions = []
|
||||
args = None
|
||||
for tpl in self.action_templates:
|
||||
actions += [(tpl["name"], tpl["label"]), ]
|
||||
if name == tpl["name"]:
|
||||
args = tpl["args"]
|
||||
self.fields["action_name_%d" % self.actions_cnt] = \
|
||||
forms.ChoiceField(initial=name, choices=actions)
|
||||
for cnt in xrange(0, len(args)):
|
||||
arg = args[cnt]
|
||||
aname = "action_arg_%d_%d" % (self.actions_cnt, cnt)
|
||||
if arg["type"] == "string":
|
||||
self.fields[aname] = forms.CharField(
|
||||
max_length=255,
|
||||
initial=value)
|
||||
elif arg["type"] == "list":
|
||||
choices = getattr(self, arg["vloader"])(request)
|
||||
self.fields[aname] = forms.ChoiceField(
|
||||
initial=value,
|
||||
choices=choices)
|
||||
self.actions_cnt += 1
|
||||
|
||||
def _build_redirect_field(self, request, value):
|
||||
self._build_action_field(request, "redirect", value)
|
||||
|
||||
def _build_fileinto_field(self, request, value):
|
||||
self._build_action_field(request, "fileinto", value)
|
||||
|
||||
def __build_folders_list(self, folders, user, imapc, parentmb=None):
|
||||
ret = []
|
||||
for fd in folders:
|
||||
value = fd["path"] if "path" in fd else fd["name"]
|
||||
if parentmb:
|
||||
ret += [
|
||||
(value, fd["name"].replace(
|
||||
"%s%s" % (parentmb, imapc.hdelimiter), ""))
|
||||
]
|
||||
else:
|
||||
ret += [(value, fd["name"])]
|
||||
if "sub" in fd:
|
||||
submboxes = imapc.getmboxes(user, value, unseen_messages=False)
|
||||
ret += self.__build_folders_list(submboxes, user, imapc, value)
|
||||
return ret
|
||||
|
||||
def userfolders(self, request):
|
||||
from modoboa.extensions.webmail.lib import get_imapconnector
|
||||
|
||||
mbc = get_imapconnector(request)
|
||||
ret = mbc.getmboxes(request.user, unseen_messages=False)
|
||||
|
||||
folders = self.__build_folders_list(ret, request.user, mbc)
|
||||
return folders
|
||||
|
||||
def tofilter(self):
|
||||
conditions = []
|
||||
actions = []
|
||||
for cpt in xrange(0, self.conds_cnt):
|
||||
conditions += [(self.cleaned_data["cond_target_%d" % cpt],
|
||||
":" + self.cleaned_data["cond_operator_%d" % cpt],
|
||||
self.cleaned_data["cond_value_%d" % cpt])]
|
||||
for cpt in xrange(0, self.actions_cnt):
|
||||
naction = (self.cleaned_data["action_name_%d" % cpt],)
|
||||
argcpt = 0
|
||||
while True:
|
||||
try:
|
||||
naction += (
|
||||
self.cleaned_data[
|
||||
"action_arg_%d_%d" %
|
||||
(cpt, argcpt)],)
|
||||
except KeyError:
|
||||
break
|
||||
argcpt += 1
|
||||
actions += [naction]
|
||||
|
||||
return (conditions, actions)
|
||||
|
||||
|
||||
def build_filter_form_from_qdict(request):
|
||||
conditions = []
|
||||
actions = []
|
||||
qdict = QueryDict("", mutable=True)
|
||||
qdict["name"] = request.POST["name"]
|
||||
qdict["match_type"] = request.POST["match_type"]
|
||||
cpt = 0
|
||||
i = 0
|
||||
if qdict["match_type"] != "all":
|
||||
while True:
|
||||
if cpt == int(request.POST["conds"]):
|
||||
break
|
||||
if "cond_target_%d" % i in request.POST:
|
||||
qdict["cond_target_%d" % cpt] = (
|
||||
request.POST["cond_target_%d" % i]
|
||||
)
|
||||
qdict["cond_operator_%d" % cpt] = (
|
||||
request.POST["cond_operator_%d" % i]
|
||||
)
|
||||
qdict["cond_value_%d" % cpt] = request.POST["cond_value_%d" % i]
|
||||
condtarget = request.POST["cond_target_%d" % i]
|
||||
condop = request.POST["cond_operator_%d" % i]
|
||||
condvalue = request.POST["cond_value_%d" % i]
|
||||
conditions += [(condtarget, condop, condvalue)]
|
||||
cpt += 1
|
||||
i += 1
|
||||
cpt = 0
|
||||
i = 0
|
||||
while True:
|
||||
if cpt == int(request.POST["actions"]):
|
||||
break
|
||||
if "action_name_%d" % i in request.POST:
|
||||
qdict["action_name_%d" % cpt] = request.POST["action_name_%d" % i]
|
||||
action = request.POST["action_name_%d" % i]
|
||||
argcpt = 0
|
||||
args = []
|
||||
while True:
|
||||
try:
|
||||
qdict["action_arg_%d_%d" % (cpt, argcpt)] = \
|
||||
request.POST["action_arg_%d_%d" % (i, argcpt)]
|
||||
args += [request.POST["action_arg_%d_%d" % (i, argcpt)]]
|
||||
except KeyError:
|
||||
break
|
||||
argcpt += 1
|
||||
args = [action] + args
|
||||
actions += [args]
|
||||
cpt += 1
|
||||
i += 1
|
||||
|
||||
return FilterForm(conditions, actions, request, qdict)
|
||||
|
||||
|
||||
def build_filter_form_from_filter(request, name, fobj):
|
||||
from sievelib.commands import SizeCommand, TrueCommand
|
||||
|
||||
match_type = fobj["test"].name
|
||||
conditions = []
|
||||
for t in fobj["test"]["tests"]:
|
||||
if isinstance(t, TrueCommand):
|
||||
match_type = "all"
|
||||
conditions += [("Subject", "contains", "")]
|
||||
break
|
||||
elif isinstance(t, SizeCommand):
|
||||
conditions += [("size", t["comparator"][1:], t["limit"])]
|
||||
else:
|
||||
conditions += [(t["header-names"].strip('"'),
|
||||
t["match-type"][1:],
|
||||
t["key-list"].strip('"'))]
|
||||
actions = []
|
||||
for c in fobj.children:
|
||||
action = (c.name,)
|
||||
for arg in c.args_definition:
|
||||
action += (c[arg["name"]].strip('"'),)
|
||||
actions += [action]
|
||||
|
||||
form = FilterForm(conditions, actions, request)
|
||||
form.fields["name"].initial = name
|
||||
form.fields["match_type"].initial = match_type
|
||||
return form
|
||||
@@ -1,32 +0,0 @@
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events
|
||||
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
if target != "options_menu":
|
||||
return []
|
||||
if not user.mailbox_set.count():
|
||||
return []
|
||||
return [
|
||||
{"name": "sievefilters",
|
||||
"label": _("Message filters"),
|
||||
"url": reverse("sievefilters:index"),
|
||||
"img": "fa fa-filter"}
|
||||
]
|
||||
|
||||
|
||||
@events.observe("UserLogout")
|
||||
def userlogout(request):
|
||||
from .lib import SieveClient
|
||||
|
||||
if not request.user.mailbox_set.count():
|
||||
return
|
||||
try:
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
sc.logout()
|
||||
@@ -1,107 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""Internal tools."""
|
||||
|
||||
from sievelib.factory import FiltersSet
|
||||
from sievelib.managesieve import Client, Error
|
||||
from sievelib.parser import Parser
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.connections import ConnectionsManager, ConnectionError
|
||||
from modoboa.lib.exceptions import ModoboaException
|
||||
|
||||
|
||||
class SieveClientError(ModoboaException):
|
||||
http_code = 424
|
||||
|
||||
|
||||
class SieveClient(object):
|
||||
__metaclass__ = ConnectionsManager
|
||||
|
||||
def __init__(self, user=None, password=None):
|
||||
try:
|
||||
ret, msg = self.login(user, password)
|
||||
except Error as e:
|
||||
raise ConnectionError(str(e))
|
||||
if not ret:
|
||||
raise ConnectionError(msg)
|
||||
|
||||
def login(self, user, password):
|
||||
self.msc = Client(parameters.get_admin("SERVER"),
|
||||
int(parameters.get_admin("PORT")),
|
||||
debug=False)
|
||||
use_starttls = True if parameters.get_admin("STARTTLS") == "yes" \
|
||||
else False
|
||||
authmech = parameters.get_admin("AUTHENTICATION_MECH")
|
||||
if authmech == "AUTO":
|
||||
authmech = None
|
||||
try:
|
||||
ret = self.msc.connect(user, password, use_starttls, authmech)
|
||||
except Error:
|
||||
ret = False
|
||||
if not ret:
|
||||
return False, _(
|
||||
"Connection to MANAGESIEVE server failed, check your "
|
||||
"configuration"
|
||||
)
|
||||
return True, None
|
||||
|
||||
def logout(self):
|
||||
self.msc.logout()
|
||||
self.msc = None
|
||||
|
||||
def refresh(self, user, password):
|
||||
import ssl
|
||||
|
||||
if self.msc is not None:
|
||||
try:
|
||||
self.msc.capability()
|
||||
except Error as e:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
try:
|
||||
ret, msg = self.login(user, password)
|
||||
except (Error, ssl.SSLError) as e:
|
||||
raise ConnectionError(e)
|
||||
if not ret:
|
||||
raise ConnectionError(msg)
|
||||
|
||||
def listscripts(self):
|
||||
return self.msc.listscripts()
|
||||
|
||||
def getscript(self, name, format="raw"):
|
||||
content = self.msc.getscript(name)
|
||||
if content is None:
|
||||
raise SieveClientError(self.msc.errmsg)
|
||||
if format == "raw":
|
||||
return content
|
||||
p = Parser()
|
||||
if not p.parse(content):
|
||||
print "Parse error????"
|
||||
return None
|
||||
fs = FiltersSet(name)
|
||||
fs.from_parser_result(p)
|
||||
return fs
|
||||
|
||||
def pushscript(self, name, content, active=False):
|
||||
if isinstance(content, unicode):
|
||||
content = content.encode("utf-8")
|
||||
if not self.msc.havespace(name, len(content)):
|
||||
error = "%s (%s)" % (
|
||||
_("Not enough space on server"), self.msc.errmsg)
|
||||
raise SieveClientError(error)
|
||||
if not self.msc.putscript(name, content):
|
||||
raise SieveClientError(self.msc.errmsg)
|
||||
if active and not self.msc.setactive(name):
|
||||
raise SieveClientError(self.msc.errmsg)
|
||||
|
||||
def deletescript(self, name):
|
||||
if not self.msc.deletescript(name):
|
||||
raise SieveClientError(self.msc.errmsg)
|
||||
|
||||
def activatescript(self, name):
|
||||
if not self.msc.setactive(name):
|
||||
raise SieveClientError(self.msc.errmsg)
|
||||
@@ -1,24 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""Declare and register the sievefilters extension."""
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
class SieveFilters(ModoExtension):
|
||||
name = "sievefilters"
|
||||
label = "Sieve filters"
|
||||
version = "1.0"
|
||||
description = ugettext_lazy("Plugin to easily create server-side filters")
|
||||
url = "sfilters"
|
||||
available_for_topredirection = True
|
||||
|
||||
def load(self):
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
parameters.register(ParametersForm, ugettext_lazy("Sieve filters"))
|
||||
parameters.register(UserSettings, ugettext_lazy("Message filters"))
|
||||
from modoboa.extensions.sievefilters import general_callbacks
|
||||
|
||||
exts_pool.register_extension(SieveFilters)
|
||||
@@ -1,134 +0,0 @@
|
||||
.fset_container {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
#set_content textarea {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
#set_content label {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#filters_list {
|
||||
border-left: 1px solid #CCC;
|
||||
position: absolute;
|
||||
padding-left: 5px;
|
||||
left: 190px;
|
||||
right: 10px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
#id_content {
|
||||
width: 95% !important;
|
||||
height: 270px;
|
||||
}
|
||||
|
||||
/* Filter form */
|
||||
#filterform {
|
||||
margin: 7px;
|
||||
}
|
||||
|
||||
#filterform h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#submit_container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#error {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
#addfilterlist {
|
||||
background-color: #FAFAFA;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 26px 26px 26px 26px;
|
||||
padding: 14px 5px 5px;
|
||||
}
|
||||
|
||||
#matchtype {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
div.item {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
ul.errors {
|
||||
list-style: none;
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.errors li {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.leftbox {
|
||||
width: 155px;
|
||||
}
|
||||
|
||||
.leftbox h1 {
|
||||
float: none !important;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.leftbox ul {
|
||||
list-style: none;
|
||||
padding: 5px 0 0 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.leftbox li {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.leftbox a, .leftbox a:visited {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.leftbox a:hover {
|
||||
color: #6AB0C5;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.leftbox li.selected {
|
||||
background-color: #FFFF77;
|
||||
}
|
||||
|
||||
.leftbox img {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
a.green {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: green;
|
||||
}
|
||||
|
||||
a.red {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
(function($) {
|
||||
var DynamicCondition = function(element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.dyncondition.defaults, options);
|
||||
this.fields_cnt = 1;
|
||||
this.nextid = 1;
|
||||
|
||||
var $addlink = $('<a />', {
|
||||
href: '#',
|
||||
id: this.$element.attr("id") + '_rmbtn',
|
||||
html: '<i class="fa fa-plus"></i>'
|
||||
});
|
||||
$("select[name*=cond_target_]").change($.proxy(this.target_change, this));
|
||||
$addlink.click($.proxy(this.addfields, this));
|
||||
this.$element.append($addlink);
|
||||
|
||||
for (var cpt = 1; true; cpt++) {
|
||||
var $div = $("#condition_" + cpt);
|
||||
|
||||
if (!$div.length) {
|
||||
break;
|
||||
}
|
||||
$div.append(this.newrmlink());
|
||||
this.nextid++;
|
||||
this.fields_cnt++;
|
||||
}
|
||||
};
|
||||
|
||||
DynamicCondition.prototype = {
|
||||
constructor: DynamicCondition,
|
||||
|
||||
loadoperators: function($container, tpl) {
|
||||
$container.empty();
|
||||
for (var ocpt = 0; ocpt < tpl.operators.length; ocpt++) {
|
||||
var $opt = $("<option />", {
|
||||
value: tpl["operators"][ocpt][0],
|
||||
html: tpl["operators"][ocpt][1]
|
||||
});
|
||||
|
||||
$container.append($opt);
|
||||
}
|
||||
},
|
||||
|
||||
removefields: function(e) {
|
||||
var $link = $(e.target).parent();
|
||||
var id = $link.attr("id");
|
||||
|
||||
e.preventDefault();
|
||||
$("#" + id.replace("_rmbtn", "")).remove();
|
||||
this.fields_cnt--;
|
||||
},
|
||||
|
||||
newrmlink: function() {
|
||||
return $('<a />', {
|
||||
href: '#',
|
||||
id: 'condition_' + this.nextid + '_rmbtn',
|
||||
html: '<i class="fa fa-trash"></i>'
|
||||
}).click($.proxy(this.removefields, this));
|
||||
},
|
||||
|
||||
addfields: function(e) {
|
||||
e.preventDefault();
|
||||
var $div = $("<div />", {
|
||||
id: "condition_" + this.nextid, 'class': "item"
|
||||
});
|
||||
var $condtarget = $("<select />", {
|
||||
id: "id_cond_target_" + this.nextid,
|
||||
name: "cond_target_" + this.nextid,
|
||||
class: "form-control element-inline-block"
|
||||
}).change($.proxy(this.target_change, this));
|
||||
var $condoperator = $("<select />", {
|
||||
id: "id_cond_operator_" + this.nextid,
|
||||
name: "cond_operator_" + this.nextid,
|
||||
class: "form-control element-inline-block"
|
||||
});
|
||||
var $condvalue = $("<input />", {
|
||||
id: "id_cond_value_" + this.nextid,
|
||||
name: "cond_value_" + this.nextid,
|
||||
type: "text",
|
||||
class: "form-control element-inline-block"
|
||||
});
|
||||
var $rmlink = this.newrmlink();
|
||||
|
||||
for (var cpt = 0; cpt < this.options.templates.length; cpt++) {
|
||||
var tpl = this.options.templates[cpt];
|
||||
var $opt = $("<option />", {
|
||||
value: tpl.name,
|
||||
html: tpl.label
|
||||
});
|
||||
|
||||
$condtarget.append($opt);
|
||||
if (tpl.name != this.options.defaultcond) {
|
||||
continue;
|
||||
}
|
||||
this.loadoperators($condoperator, tpl);
|
||||
}
|
||||
|
||||
$div.append($condtarget, $condoperator, $condvalue, $rmlink);
|
||||
$condtarget.wrap('<div class="col-lg-3 col-md-3 col-sm-3"/>');
|
||||
$condoperator.wrap('<div class="col-lg-3 col-md-3 col-sm-3"/>');
|
||||
$condvalue.wrap('<div class="col-lg-4 col-md-4 col-sm-4"/>');
|
||||
this.$element.after($div);
|
||||
this.nextid++;
|
||||
this.fields_cnt++;
|
||||
},
|
||||
|
||||
target_change: function(e) {
|
||||
var $target = $(e.target);
|
||||
var parts = $target.attr("name").split("_");
|
||||
var $container = $("#id_cond_operator_" + parts[2]);
|
||||
|
||||
for (var cpt = 0; cpt < this.options.templates.length; cpt++) {
|
||||
var tpl = this.options.templates[cpt];
|
||||
|
||||
if (tpl.name != $target.val()) {
|
||||
continue;
|
||||
}
|
||||
this.loadoperators($container, tpl);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
counter: function() {
|
||||
return this.fields_cnt;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.dyncondition = function(method) {
|
||||
return this.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('dyncondition'),
|
||||
options = typeof method === "object" && method;
|
||||
|
||||
if (!data) {
|
||||
$this.data('dyncondition', new DynamicCondition(this, options));
|
||||
}
|
||||
if (typeof method === "string") {
|
||||
data[method]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.dyncondition.defaults = {
|
||||
defaultcond: "Subject",
|
||||
templates: []
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
/*
|
||||
* Dynamic actions class
|
||||
*/
|
||||
(function($) {
|
||||
var DynamicAction = function(element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.dynaction.defaults, options);
|
||||
this.nextid = 1;
|
||||
this.fields_cnt = 1;
|
||||
|
||||
var $addlink = $('<a />', {
|
||||
href: '#',
|
||||
id: this.$element.attr("id") + '_rmbtn',
|
||||
html: '<i class="fa fa-plus"></i>'
|
||||
});
|
||||
$("select[name*=action_name_]").change($.proxy(this.name_change, this));
|
||||
$addlink.click($.proxy(this.addfields, this));
|
||||
this.$element.append($addlink);
|
||||
|
||||
for (var cpt = 1; true; cpt++) {
|
||||
var $div = $("#action_" + cpt);
|
||||
|
||||
if (!$div.length) {
|
||||
break;
|
||||
}
|
||||
$div.append(this.newrmlink());
|
||||
this.nextid++;
|
||||
this.fields_cnt++;
|
||||
}
|
||||
|
||||
$("#id_action_arg_0_0").find("option").each(function() {
|
||||
var $this = $(this),
|
||||
cpt = 1,
|
||||
start = 0,
|
||||
value = $this.val();
|
||||
|
||||
while (true) {
|
||||
var id = value.indexOf(options.hdelimiter, start);
|
||||
if (id == -1) {
|
||||
break;
|
||||
}
|
||||
$this.css("margin-left", (cpt * 20) + "px");
|
||||
cpt++;
|
||||
start = id + 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.$fdoptions = $("#id_action_arg_0_0").find("option");
|
||||
};
|
||||
|
||||
DynamicAction.prototype = {
|
||||
constructor: DynamicAction,
|
||||
|
||||
loadargs: function(id, tpl) {
|
||||
var res = [];
|
||||
|
||||
for (var acpt = 0; acpt < tpl.args.length; acpt++) {
|
||||
var argname = "action_arg_" + id + "_" + acpt;
|
||||
var $child = null;
|
||||
|
||||
if (tpl.args[acpt].type == "list") {
|
||||
$child = $("<select />", {id: "id_" + argname, name: argname, class: "form-control"});
|
||||
if (tpl.args[acpt].vloader != undefined) {
|
||||
this[tpl.args[acpt].vloader]($child);
|
||||
}
|
||||
} else if (tpl.args[acpt].type == "string") {
|
||||
$child = $("<input />", {
|
||||
type: "text",
|
||||
id: "id_" + argname,
|
||||
name: argname,
|
||||
class: "form-control"
|
||||
});
|
||||
}
|
||||
res.push($child);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
||||
deletePrevArgs: function(id) {
|
||||
for (var cpt = 0; true; cpt++) {
|
||||
var $arg = $("#id_action_arg_" + id + "_" + cpt);
|
||||
if (!$arg.length) {
|
||||
break;
|
||||
}
|
||||
$arg.remove();
|
||||
}
|
||||
},
|
||||
|
||||
name_change: function(e) {
|
||||
var $target = $(e.target);
|
||||
var parts = $target.attr("name").split("_");
|
||||
var $pos = $("#action_" + parts[2] + "_rmbtn");
|
||||
|
||||
e.preventDefault();
|
||||
this.deletePrevArgs(parts[2]);
|
||||
for (var cpt = 0; cpt < this.options.templates.length; cpt++) {
|
||||
var tpl = this.options.templates[cpt];
|
||||
if (tpl.name != $target.val()) {
|
||||
continue;
|
||||
}
|
||||
$.each(this.loadargs(parts[2], tpl), function(idx, arg) {
|
||||
$pos.before(arg);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
newrmlink: function() {
|
||||
return $('<a />', {
|
||||
href: '#',
|
||||
id: 'action_' + this.nextid + '_rmbtn',
|
||||
html: '<i class="fa fa-trash"></i>'
|
||||
}).click($.proxy(this.removefields, this));
|
||||
},
|
||||
|
||||
addfields: function(e) {
|
||||
e.preventDefault();
|
||||
var $div = $("<div />", {id: "action_" + this.nextid, "class": "item"});
|
||||
var $actioname = $("<select />", {
|
||||
id: "id_action_name_" + this.nextid,
|
||||
name: "action_name_" + this.nextid,
|
||||
class: "form-control element-inline-block"
|
||||
});
|
||||
var $rmlink = this.newrmlink();
|
||||
var args = null;
|
||||
|
||||
for (var cpt = 0; cpt < this.options.templates.length; cpt++) {
|
||||
var tpl = this.options.templates[cpt];
|
||||
var $opt = $("<option />", {
|
||||
value: tpl.name,
|
||||
html: tpl.label
|
||||
});
|
||||
|
||||
$actioname.append($opt);
|
||||
if (tpl.name != this.options.defaultaction) {
|
||||
continue;
|
||||
}
|
||||
args = this.loadargs(this.nextid, tpl);
|
||||
}
|
||||
$div.append($actioname);
|
||||
$actioname.change($.proxy(this.name_change, this));
|
||||
$.each(args, function(idx, element) {
|
||||
$div.append(element);
|
||||
element.wrap('<div class="col-lg-5 col-md-5 col-sm-5"/>');
|
||||
});
|
||||
|
||||
$actioname.wrap('<div class="col-lg-5 col-md-5 col-sm-5"/>');
|
||||
$div.append($rmlink);
|
||||
this.$element.after($div);
|
||||
this.nextid++;
|
||||
this.fields_cnt++;
|
||||
},
|
||||
|
||||
removefields: function(e) {
|
||||
var $link = $(e.target).parent();
|
||||
var id = $link.attr("id");
|
||||
|
||||
e.preventDefault();
|
||||
$("#" + id.replace("_rmbtn", "")).remove();
|
||||
this.fields_cnt--;
|
||||
},
|
||||
|
||||
userfolders: function($container) {
|
||||
this.$fdoptions.each(function() {
|
||||
$container.append($(this).clone());
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.dynaction = function(method) {
|
||||
return this.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('dynaction'),
|
||||
options = typeof method === "object" && method;
|
||||
|
||||
if (!data) {
|
||||
$this.data('dynaction', new DynamicAction(this, options));
|
||||
}
|
||||
if (typeof method === "string") {
|
||||
data[method]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.dynaction.defaults = {
|
||||
defaultaction: "fileinto",
|
||||
hdelimiter: '.',
|
||||
templates: []
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Plugin : "Sieve filters"
|
||||
*
|
||||
* Javascript utilities
|
||||
*/
|
||||
var curscript = null;
|
||||
|
||||
/*
|
||||
* Remove a filter from a filters set.
|
||||
*
|
||||
*/
|
||||
function removefilter(evt) {
|
||||
evt.preventDefault();
|
||||
if (!confirm(gettext("Remove this filter?"))) {
|
||||
return;
|
||||
}
|
||||
var $this = $(this);
|
||||
|
||||
$.ajax({
|
||||
url: $this.attr("href"),
|
||||
dataType: 'json'
|
||||
}).done(function(response) {
|
||||
histomanager.update(true);
|
||||
$("body").notify('success', response, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler listening for the "change" event on the filters sets list.
|
||||
*/
|
||||
function changefs(evt) {
|
||||
evt.preventDefault();
|
||||
histomanager.baseurl($(this).val()).update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes buttons located inside the filters list
|
||||
*/
|
||||
function init_filters_list() {
|
||||
$("a[name=togglestate]").click(toggle_filter_state);
|
||||
$("a[name*=movefilter_]").click(move_filter);
|
||||
$("a[name=removefilter]").click(removefilter);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called just after a new filters set has been loaded.
|
||||
*
|
||||
* It updates the middle DIV and initializes the user interface.
|
||||
*/
|
||||
function loadfs(response) {
|
||||
curscript = histomanager.getbaseurl();
|
||||
$("#curfset").val(curscript);
|
||||
$("#set_content").html(response.content);
|
||||
|
||||
if ($("#filters_list") != undefined) {
|
||||
init_filters_list();
|
||||
}
|
||||
if ($("#fsetmenu").length) {
|
||||
$("#fsetmenu").remove();
|
||||
}
|
||||
$("#menu").after($(response.menu));
|
||||
$("a[name=activatefs]").click(activatefs);
|
||||
$("a[name=savefs]").click(savefs);
|
||||
$("a[name=removefs]").click(removefs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Common function to send a command that manipulates a filters set.
|
||||
*
|
||||
* (remove, activate)
|
||||
*/
|
||||
function send_command(cmd, extracb) {
|
||||
$.ajax({
|
||||
url: cmd,
|
||||
dataType: 'json'
|
||||
}).done(function(response) {
|
||||
if (extracb != undefined) {
|
||||
extracb(response);
|
||||
}
|
||||
if (!response.norefresh) {
|
||||
histomanager.update(true);
|
||||
}
|
||||
$("body").notify('success', response.respmsg, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Common utility used by filters set manipulation functions to
|
||||
* validate any new asked action. (activate, save, remove)
|
||||
*/
|
||||
function check_prereqs(evt, msg) {
|
||||
evt.preventDefault();
|
||||
if (!curscript) {
|
||||
return false;
|
||||
}
|
||||
if (msg != undefined && !confirm(msg)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the current filters set by applying the modifications to the
|
||||
* server.
|
||||
*/
|
||||
function savefs(evt) {
|
||||
if (!check_prereqs(evt, gettext("Save changes?"))) {
|
||||
return;
|
||||
}
|
||||
var $editor = $("#feditor");
|
||||
|
||||
$.ajax({
|
||||
url: $editor.attr("action"),
|
||||
type: $editor.attr("method"),
|
||||
dataType: 'json',
|
||||
data: $editor.serialize()
|
||||
}).done(function(response) {
|
||||
$("body").notify('success', response.respmsg, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the current filters set.
|
||||
*
|
||||
* On success, the user will be automatically redirected to the active
|
||||
* filters set.
|
||||
*/
|
||||
function removefs(evt) {
|
||||
if (!check_prereqs(evt, gettext("Remove filters set?"))) {
|
||||
return;
|
||||
}
|
||||
send_command($(this).attr("href"), function(response) {
|
||||
var $curfset = $("#curfset");
|
||||
|
||||
$curfset.find("option[value='" + curscript + "']").remove();
|
||||
histomanager.baseurl(response.newfs, 1);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate the current filters set.
|
||||
*/
|
||||
function activatefs(evt) {
|
||||
var $this = $(this);
|
||||
|
||||
if (!check_prereqs(evt, gettext("Activate this filters set?"))) {
|
||||
return;
|
||||
}
|
||||
send_command($this.attr("href"), function(response) {
|
||||
$("#curfset").find("option").each(function(index, element) {
|
||||
var $element = $(element);
|
||||
|
||||
($element.val() == curscript)
|
||||
? $element.html(curscript + " (" + gettext("active") + ")")
|
||||
: $element.html($element.val());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/Disable a specific filter
|
||||
*/
|
||||
function toggle_filter_state(event) {
|
||||
var $this = $(this);
|
||||
|
||||
event.preventDefault();
|
||||
$.ajax({
|
||||
url: $this.attr("href"),
|
||||
dataType: 'json'
|
||||
}).done(function(response) {
|
||||
$this.html(response.label);
|
||||
$this.attr("class", "");
|
||||
$this.addClass(response.color);
|
||||
});
|
||||
}
|
||||
|
||||
function move_filter(event) {
|
||||
var $this = $(this);
|
||||
|
||||
event.preventDefault();
|
||||
$.ajax({
|
||||
url: $this.attr('href'),
|
||||
dataType: 'json'
|
||||
}).done(function(response) {
|
||||
$("#set_content").html(response.content);
|
||||
init_filters_list();
|
||||
});
|
||||
}
|
||||
|
||||
function filterset_created(data) {
|
||||
var name = data.url;
|
||||
var option = $('<option value="' + name + '">' + name + '</option>');
|
||||
var curfset = $(parent.document).find("#curfset");
|
||||
|
||||
curfset.append(option);
|
||||
curfset.val(name);
|
||||
|
||||
if (data.active) {
|
||||
curfset.find("option").each(function(index, element) {
|
||||
var $element = $(element);
|
||||
|
||||
if ($element.val() == name) {
|
||||
$element.html(name + " (" + gettext("active") + ")");
|
||||
} else {
|
||||
$element.html($element.val());
|
||||
}
|
||||
});
|
||||
}
|
||||
histomanager.baseurl(data.url, 1).update(1);
|
||||
}
|
||||
|
||||
function filtersetform_cb() {
|
||||
$("#newfiltersset").find("input").keypress(function(e) {
|
||||
if (e.which == 13) e.preventDefault();
|
||||
});
|
||||
$(".submit").on('click', function(e) {
|
||||
simple_ajax_form_post(e, {
|
||||
formid: "newfiltersset",
|
||||
reload_on_success: false,
|
||||
success_cb: filterset_created
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* From here: specific functions used by the user-friendly form to
|
||||
* create/edit filters.
|
||||
*/
|
||||
function fetch_templates(url, container) {
|
||||
if (container) {
|
||||
return container;
|
||||
}
|
||||
var result;
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
async: false,
|
||||
dataType: 'json'
|
||||
}).done(function(data) {
|
||||
result = data;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{% extends "common/generic_modal_form.html" %}
|
||||
{% load i18n form_tags sfilters_tags %}
|
||||
|
||||
{% block modal_css_classes %}modal-lg{% endblock %}
|
||||
|
||||
{% block formbody %}
|
||||
{% if oldname %}<input type="hidden" name="oldname" value="{{ oldname }}" />{% endif %}
|
||||
{% render_field form.name %}
|
||||
<h6>{% trans "Conditions" %}</h6>
|
||||
<div id="addfilterlist">
|
||||
<div id="matchtype">
|
||||
{% render_field form.match_type %}
|
||||
</div>
|
||||
<div id="hide" style="display:{{ hidestyle }}">
|
||||
{% for ec in conds_nb %}
|
||||
{% display_condition form ec %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<h6>{% trans "Actions" %}</h6>
|
||||
<div id="addfilterlist">
|
||||
{% for ea in actions_nb %}
|
||||
{% display_action form ea %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,25 +0,0 @@
|
||||
{% load i18n sfilters_tags %}{% load url from future %}
|
||||
{% if fs.filters %}
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th width="10%">{% trans "Actions" %}</th>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th width="5%">{% trans "Active" %}</th>
|
||||
</tr>
|
||||
{% for filter in fs.filters %}
|
||||
<tr>
|
||||
<td>{% filter_actions fs.name filter forloop.counter forloop.last %}</td>
|
||||
<td>{{ filter.name }}</td>
|
||||
<td>
|
||||
<a name="togglestate"
|
||||
class={% if filter.enabled %}"green"{% else %}"red"{% endif %}
|
||||
href="{% url 'sievefilters:filter_toggle_state' fs.name filter.name %}">
|
||||
{{ filter.enabled|yesno }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="alert alert-info">{% trans "No filter defined yet" %}</div>
|
||||
{% endif %}
|
||||
@@ -1,104 +0,0 @@
|
||||
{% extends "twocols.html" %}{% load i18n sfilters_tags %}{% load url from future %}
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}{% trans "Message filters" %}{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'sievefilters/css/style.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script type="text/javascript" src="{% static 'js/history.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'sievefilters/js/lib.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/dynamic_input.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'sievefilters/js/jquery.dynfields.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
var histomanager = new History({
|
||||
deflocation: "{{ default_script }}",
|
||||
defcallback: loadfs
|
||||
});
|
||||
var cond_templates = null;
|
||||
var action_templates = null;
|
||||
|
||||
function display_filter_errors(data) {
|
||||
$("ul.errors").remove();
|
||||
$.each(data.form_errors, function(id, value) {
|
||||
if (id.indexOf('cond') && id.indexOf('action')) {
|
||||
return;
|
||||
}
|
||||
var fullid = "id_" + (data.prefix ? data.prefix + "-" : "") + id;
|
||||
var $widget = $("#" + fullid);
|
||||
var ulid = fullid + "-error";
|
||||
var $ul = $("<ul />", {
|
||||
"class": "errors",
|
||||
"id": ulid
|
||||
}).append($("<li />", {
|
||||
html: value[0]
|
||||
}));
|
||||
$widget.after($ul);
|
||||
});
|
||||
}
|
||||
|
||||
function filterform_cb() {
|
||||
cond_templates = fetch_templates("{% url 'sievefilters:templates_get' 'condition' %}", cond_templates);
|
||||
action_templates = fetch_templates("{% url 'sievefilters:templates_get' 'action' %}", action_templates);
|
||||
|
||||
var $dc = $("#condition_0").dyncondition({
|
||||
templates: cond_templates
|
||||
}).data('dyncondition');
|
||||
var $da = $("#action_0").dynaction({
|
||||
templates: action_templates,
|
||||
hdelimiter: '{{ hdelimiter }}'
|
||||
}).data('dynaction');
|
||||
|
||||
$("input[name=match_type]").click(function(e) {
|
||||
if ($(this).val() == "all") {
|
||||
$("div[id*=condition]").hide();
|
||||
} else {
|
||||
$("div[id*=condition]").show();
|
||||
}
|
||||
});
|
||||
|
||||
$(".submit").on('click', function(e) {
|
||||
var counters = "conds=" + $dc.fields_cnt + "&actions=" + $da.fields_cnt;
|
||||
|
||||
simple_ajax_form_post(e, {
|
||||
formid: 'filterform',
|
||||
reload_mode: 'history',
|
||||
extradata: counters,
|
||||
error_cb: display_filter_errors
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#curfset").change(changefs);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block leftcol %}
|
||||
<ul id="menu" class="nav nav-sidebar">
|
||||
<li class="nav-header">{% trans "Filter sets" %}</li>
|
||||
<li class="fset_container">
|
||||
<select id="curfset" class="form-control">
|
||||
{% if active_script %}
|
||||
<option value="{{ active_script }}">{{ active_script }} ({% trans "active" %})</option>
|
||||
{% endif %}
|
||||
{% for script in scripts %}
|
||||
<option value="{{ script }}">{{ script }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</li>
|
||||
{# It will add a li item : #}
|
||||
{% sfilters_menu user %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block apparea %}
|
||||
<div id="set_content">
|
||||
{% if not active_script and not scripts %}
|
||||
<div class="alert alert-info">{% trans "No filters set defined yet. You must create one in order to define filters." %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,6 +0,0 @@
|
||||
{% load url from future %}
|
||||
<form action="{% url 'sievefilters:fs_save' name %}"
|
||||
method="POST" id="feditor" name="feditor">{% csrf_token %}
|
||||
<textarea id="scriptcontent" name="scriptcontent">{{ scriptcontent }}</textarea>
|
||||
</form>
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
from django import template
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from modoboa.lib.web_utils import render_actions
|
||||
from modoboa.lib.templatetags.form_tags import configure_field_classes
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def sfilters_menu(user):
|
||||
entries = [
|
||||
{"name": "newfilterset",
|
||||
"img": "fa fa-plus",
|
||||
"label": _("New filters set"),
|
||||
"url": reverse("sievefilters:fs_add"),
|
||||
"modal": True,
|
||||
"modalcb": "filtersetform_cb"
|
||||
}
|
||||
]
|
||||
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries": entries, "user": user})
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def fset_menu(mode, setname):
|
||||
entries = []
|
||||
if mode == "gui":
|
||||
entries += [
|
||||
{"name": "newfilter",
|
||||
"img": "fa fa-plus",
|
||||
"label": _("New filter"),
|
||||
"url": reverse("sievefilters:filter_add",
|
||||
args=[setname]),
|
||||
"modal": True,
|
||||
"autowidth": True,
|
||||
"modalcb": "filterform_cb"}
|
||||
]
|
||||
if mode == "raw":
|
||||
entries += [
|
||||
{"name": "savefs",
|
||||
"img": "fa fa-download-alt",
|
||||
"label": _("Save filters set"),
|
||||
"url": reverse("sievefilters:fs_save",
|
||||
args=[setname])},
|
||||
]
|
||||
|
||||
entries += [
|
||||
{"name": "activatefs",
|
||||
"img": "fa fa-check",
|
||||
"label": _("Activate filters set"),
|
||||
"url": reverse("sievefilters:fs_activate",
|
||||
args=[setname])},
|
||||
{"name": "removefs",
|
||||
"img": "fa fa-trash",
|
||||
"label": _("Remove filters set"),
|
||||
"url": reverse("sievefilters:fs_delete", args=[setname])},
|
||||
{"name": "downloadfs",
|
||||
"img": "fa fa-download",
|
||||
"label": _("Download"),
|
||||
"url": reverse("sievefilters:fs_download", args=[setname])}
|
||||
]
|
||||
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries": entries})
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def filter_actions(setname, f, position, islast):
|
||||
actions = [
|
||||
{"name": "editfilter",
|
||||
"url": reverse(
|
||||
"sievefilters:filter_change", args=[setname, f["name"]]),
|
||||
"img": "fa fa-edit",
|
||||
"title": _("Edit filter"),
|
||||
"modal": True,
|
||||
"autowidth": True,
|
||||
"modalcb": "filterform_cb"},
|
||||
{"name": "removefilter",
|
||||
"url": reverse(
|
||||
"sievefilters:filter_delete", args=[setname, f["name"]]),
|
||||
"img": "fa fa-trash",
|
||||
"title": _("Remove this filter")}
|
||||
]
|
||||
if position != 1:
|
||||
actions += [
|
||||
{"name": "movefilter_up",
|
||||
"url": reverse(
|
||||
"sievefilters:filter_move_up", args=[setname, f["name"]]),
|
||||
"img": "fa fa-chevron-up",
|
||||
"title": _("Move this filter up")}
|
||||
]
|
||||
if not islast:
|
||||
actions += [
|
||||
{"name": "movefilter_down",
|
||||
"url": reverse(
|
||||
"sievefilters:filter_move_down", args=[setname, f["name"]]),
|
||||
"img": "fa fa-chevron-down",
|
||||
"title": _("Move this filter down")},
|
||||
]
|
||||
return render_actions(actions)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_errors(errors):
|
||||
if not len(errors):
|
||||
return ""
|
||||
t = template.Template("""
|
||||
<ul class="errors">
|
||||
{% for error in errors %}
|
||||
<li>{{ error|safe }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"errors": errors
|
||||
}))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_condition(form, cnt):
|
||||
target = form["cond_target_%d" % cnt]
|
||||
configure_field_classes(target)
|
||||
operator = form["cond_operator_%d" % cnt]
|
||||
configure_field_classes(operator)
|
||||
value = form["cond_value_%d" % cnt]
|
||||
configure_field_classes(value)
|
||||
t = template.Template("""
|
||||
<div id="condition_{{ idx }}" class="item">
|
||||
<div class="col-lg-3 col-md-3 col-sm-3">{{ tfield }}</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-3">{{ofield}}</div>
|
||||
<div class="col-lg-4 col-md-4 col-sm-4">{{ vfield }}</div>
|
||||
{{ verrors }}
|
||||
</div>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"idx": cnt,
|
||||
"tfield": target,
|
||||
"ofield": operator,
|
||||
"vfield": value,
|
||||
"verrors": display_errors(value.errors)
|
||||
}))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_action(form, cnt):
|
||||
action = form["action_name_%d" % cnt]
|
||||
configure_field_classes(action)
|
||||
values = []
|
||||
acnt = 0
|
||||
verrors = []
|
||||
while True:
|
||||
try:
|
||||
field = form["action_arg_%d_%d" % (cnt, acnt)]
|
||||
configure_field_classes(field)
|
||||
values += [field]
|
||||
if field.errors:
|
||||
verrors += field.errors
|
||||
acnt += 1
|
||||
except KeyError:
|
||||
break
|
||||
t = template.Template("""
|
||||
<div id="action_{{ idx }}" class="item">
|
||||
<div class="col-lg-5 col-md-5 col-sm-5">
|
||||
{{ afield }}
|
||||
</div>
|
||||
{% for v in values %}
|
||||
<div class="col-lg-5 col-md-5 col-sm-5">{{ v }}</div>
|
||||
{% endfor %}{{ verrors }}
|
||||
</div>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"idx": cnt,
|
||||
"afield": action, "values": values,
|
||||
"verrors": display_errors(verrors)
|
||||
}))
|
||||
@@ -1,42 +0,0 @@
|
||||
if __name__ == "__main__":
|
||||
clt = ManageSieveClient("mail.koalabs.org", 2000)
|
||||
if clt.connect("tonio@ngyn.org", "aka/12;c", starttls=True):
|
||||
print clt.get_sasl_mechanisms()
|
||||
print clt.get_sieve_capabilities()
|
||||
print clt.havespace("test", 45)
|
||||
|
||||
if not clt.putscript("myscript", """require ["fileinto", "envelope"];
|
||||
|
||||
if envelope :contains "to" "tmartin+sent" {
|
||||
fileinto "INBOX.sent";
|
||||
}
|
||||
"""):
|
||||
print clt.errmsg
|
||||
|
||||
if not clt.putscript("test", """#comment
|
||||
InvalidSieveCommand
|
||||
"""):
|
||||
print clt.errmsg
|
||||
|
||||
clt.deletescript("thescript")
|
||||
|
||||
if not clt.setactive("myscript"):
|
||||
print clt.errmsg
|
||||
print clt.listscripts()
|
||||
|
||||
sc = clt.getscript("myscript")
|
||||
if sc is None:
|
||||
print clt.errmsg
|
||||
else:
|
||||
print sc
|
||||
|
||||
if not clt.renamescript("myscript", "thescript"):
|
||||
print clt.errmsg
|
||||
|
||||
clt.setactive("")
|
||||
|
||||
if not clt.deletescript("thescript"):
|
||||
print clt.errmsg
|
||||
else:
|
||||
print clt.errmsg
|
||||
clt.logout()
|
||||
@@ -1,29 +0,0 @@
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
urlpatterns = patterns(
|
||||
'modoboa.extensions.sievefilters.views',
|
||||
|
||||
url(r'^$', 'index', name="index"),
|
||||
url(r'^savefs/(?P<name>.+)/$', 'savefs', name="fs_save"),
|
||||
url(r'^newfs/$', 'new_filters_set', name="fs_add"),
|
||||
url(r'^removefs/(?P<name>.+)/$', 'remove_filters_set', name="fs_delete"),
|
||||
url(r'^activatefs/(?P<name>.+)/$', 'activate_filters_set',
|
||||
name="fs_activate"),
|
||||
url(r'^downloadfs/(?P<name>.+)/$', 'download_filters_set',
|
||||
name="fs_download"),
|
||||
url(r'^templates/(?P<ftype>\w+)/$', 'get_templates',
|
||||
name="templates_get"),
|
||||
url(r'^(?P<setname>.+)/newfilter/$', 'newfilter',
|
||||
name="filter_add"),
|
||||
url(r'^(?P<setname>.+)/editfilter/(?P<fname>.+)/$', 'editfilter',
|
||||
name="filter_change"),
|
||||
url(r'^(?P<setname>.+)/removefilter/(?P<fname>.+)/$', 'removefilter',
|
||||
name="filter_delete"),
|
||||
url(r'^(?P<setname>.+)/togglestate/(?P<fname>.+)/$',
|
||||
'toggle_filter_state', name="filter_toggle_state"),
|
||||
url(r'^(?P<setname>.+)/moveup/(?P<fname>.+)/$',
|
||||
'move_filter_up', name="filter_move_up"),
|
||||
url(r'^(?P<setname>.+)/movedown/(?P<fname>.+)/$',
|
||||
'move_filter_down', name="filter_move_down"),
|
||||
url(r'^(?P<name>.+)/$', 'getfs', name="fs_get"),
|
||||
)
|
||||
@@ -1,337 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""Custom views."""
|
||||
|
||||
from rfc6266 import build_header
|
||||
from sievelib.commands import BadArgument, BadValue
|
||||
from sievelib.managesieve import Error
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .forms import (
|
||||
FilterForm, build_filter_form_from_qdict, build_filter_form_from_filter,
|
||||
FiltersSetForm
|
||||
)
|
||||
from .lib import SieveClient, SieveClientError
|
||||
from .templatetags.sfilters_tags import fset_menu
|
||||
from modoboa.extensions.admin.lib import needs_mailbox
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.connections import ConnectionError
|
||||
from modoboa.lib.exceptions import BadRequest
|
||||
from modoboa.lib.web_utils import (
|
||||
_render_error, ajax_response, render_to_json_response
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def index(request, tplname="sievefilters/index.html"):
|
||||
from modoboa.extensions.webmail.lib import get_imapconnector
|
||||
|
||||
try:
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
except ConnectionError as e:
|
||||
return _render_error(request, user_context={"error": e})
|
||||
|
||||
try:
|
||||
active_script, scripts = sc.listscripts()
|
||||
except Error as e:
|
||||
return _render_error(request, user_context={"error": e})
|
||||
|
||||
if active_script is None:
|
||||
active_script = ""
|
||||
default_script = "%s/" % scripts[0] if len(scripts) else ""
|
||||
else:
|
||||
default_script = "%s/" % active_script
|
||||
return render(request, tplname, {
|
||||
"selection": "user",
|
||||
"active_script": active_script,
|
||||
"default_script": default_script,
|
||||
"scripts": sorted(scripts),
|
||||
"hdelimiter": get_imapconnector(request).hdelimiter
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def get_templates(request, ftype):
|
||||
if ftype == "condition":
|
||||
return render_to_json_response(
|
||||
FilterForm([], [], request).cond_templates
|
||||
)
|
||||
return render_to_json_response(
|
||||
FilterForm([], [], request).action_templates
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def getfs(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
editormode = parameters.get_user(request.user, "EDITOR_MODE")
|
||||
error = None
|
||||
try:
|
||||
content = sc.getscript(name, format=editormode)
|
||||
except SieveClientError as e:
|
||||
error = str(e)
|
||||
else:
|
||||
if content is None:
|
||||
error = _("Failed to retrieve filters set")
|
||||
|
||||
if error is not None:
|
||||
return ajax_response(request, "ko", respmsg=error)
|
||||
|
||||
if editormode == "raw":
|
||||
htmlcontent = render_to_string("sievefilters/rawfilter.html", dict(
|
||||
name=name, scriptcontent=content
|
||||
))
|
||||
else:
|
||||
htmlcontent = render_to_string("sievefilters/guieditor.html", dict(
|
||||
fs=content
|
||||
))
|
||||
|
||||
menu = '<ul id="fsetmenu" class="nav nav-sidebar"><li class="nav-header">%s</li>%s</ul>' % \
|
||||
(_("Actions"), fset_menu(editormode, name))
|
||||
resp = dict(menu=menu, content=htmlcontent)
|
||||
return render_to_json_response(resp)
|
||||
|
||||
|
||||
def build_filter_ctx(ctx, form):
|
||||
ctx["form"] = form
|
||||
ctx["conds_nb"] = range(form.conds_cnt)
|
||||
ctx["actions_nb"] = range(form.actions_cnt)
|
||||
return ctx
|
||||
|
||||
|
||||
def submitfilter(
|
||||
request, setname, okmsg, tplname, tplctx, update=False, sc=None):
|
||||
form = build_filter_form_from_qdict(request)
|
||||
if form.is_valid():
|
||||
if sc is None:
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
conditions, actions = form.tofilter()
|
||||
match_type = form.cleaned_data["match_type"]
|
||||
if match_type == "all":
|
||||
match_type = "anyof"
|
||||
conditions = [("true",)]
|
||||
fltname = form.cleaned_data["name"].encode("utf-8")
|
||||
try:
|
||||
if not update:
|
||||
fset.addfilter(fltname, conditions, actions,
|
||||
match_type)
|
||||
else:
|
||||
oldname = request.POST["oldname"].encode("utf-8")
|
||||
fset.updatefilter(
|
||||
oldname, fltname, conditions, actions, match_type
|
||||
)
|
||||
except (BadArgument, BadValue) as inst:
|
||||
raise BadRequest(str(inst))
|
||||
sc.pushscript(fset.name, str(fset))
|
||||
return render_to_json_response(okmsg)
|
||||
|
||||
return render_to_json_response({'form_errors': form.errors}, status=400)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def newfilter(request, setname, tplname="sievefilters/filter.html"):
|
||||
ctx = dict(
|
||||
title=_("New filter"),
|
||||
formid="filterform",
|
||||
action=reverse("sievefilters:filter_add", args=[setname]),
|
||||
action_label=_("Create"),
|
||||
action_classes="submit"
|
||||
)
|
||||
if request.method == "POST":
|
||||
return submitfilter(
|
||||
request, setname, _("Filter created"), tplname, ctx
|
||||
)
|
||||
|
||||
conds = [("Subject", "contains", "")]
|
||||
actions = [("fileinto", "")]
|
||||
form = FilterForm(conds, actions, request)
|
||||
ctx = build_filter_ctx(ctx, form)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def editfilter(request, setname, fname, tplname="sievefilters/filter.html"):
|
||||
ctx = dict(
|
||||
title=_("Edit filter"),
|
||||
formid="filterform",
|
||||
action=reverse("sievefilters:filter_change", args=[setname, fname]),
|
||||
action_label=_("Update"),
|
||||
action_classes="submit"
|
||||
)
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
if request.method == "POST":
|
||||
return submitfilter(
|
||||
request, setname, _("Filter modified"), tplname, ctx,
|
||||
update=True, sc=sc
|
||||
)
|
||||
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
if isinstance(fname, unicode):
|
||||
fname = fname.encode("utf-8")
|
||||
f = fset.getfilter(fname)
|
||||
form = build_filter_form_from_filter(request, fname, f)
|
||||
ctx = build_filter_ctx(ctx, form)
|
||||
ctx["oldname"] = fname
|
||||
ctx["hidestyle"] = "none" \
|
||||
if form.fields["match_type"].initial == "all" else "block"
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def removefilter(request, setname, fname):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
if fset.removefilter(fname.encode("utf-8")):
|
||||
sc.pushscript(fset.name, str(fset))
|
||||
return render_to_json_response(_("Filter removed"))
|
||||
return render_to_json_response(_("Failed to remove filter"), status=500)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def savefs(request, name):
|
||||
if "scriptcontent" not in request.POST:
|
||||
return
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.pushscript(name, request.POST["scriptcontent"])
|
||||
except SieveClientError as e:
|
||||
error = str(e)
|
||||
return ajax_response(request, "ko", respmsg=error)
|
||||
return ajax_response(request, respmsg=_("Filters set saved"))
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def new_filters_set(request, tplname="common/generic_modal_form.html"):
|
||||
if request.method == "POST":
|
||||
form = FiltersSetForm(request.POST)
|
||||
if form.is_valid():
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
sc.pushscript(form.cleaned_data["name"], "# Empty script",
|
||||
form.cleaned_data["active"])
|
||||
return render_to_json_response({
|
||||
"url": form.cleaned_data["name"],
|
||||
"active": form.cleaned_data["active"],
|
||||
"respmsg": _("Filters set created")
|
||||
})
|
||||
return render_to_json_response({'form_errors': form.errors}, status=400)
|
||||
|
||||
ctx = {"title": _("Create a new filters set"),
|
||||
"formid": "newfiltersset",
|
||||
"action_label": _("Create"),
|
||||
"action_classes": "submit",
|
||||
"action": reverse("sievefilters:fs_add"),
|
||||
"withmenu": False,
|
||||
"withunseen": False,
|
||||
"form": FiltersSetForm()}
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def remove_filters_set(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
sc.deletescript(name)
|
||||
acs, scripts = sc.listscripts()
|
||||
return render_to_json_response(dict(
|
||||
respmsg=_("Filters set deleted"), newfs=acs
|
||||
))
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def activate_filters_set(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.activatescript(name)
|
||||
except SieveClientError as e:
|
||||
return ajax_response(request, "ko", respmsg=str(e))
|
||||
return ajax_response(request, respmsg=_("Filters set activated"))
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def download_filters_set(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
script = sc.getscript(name)
|
||||
except SieveClientError as e:
|
||||
return ajax_response(request, "ko", respmsg=str(e))
|
||||
|
||||
resp = HttpResponse(script)
|
||||
resp["Content-Type"] = "text/plain; charset=utf-8"
|
||||
resp["Content-Length"] = len(script)
|
||||
resp["Content-Disposition"] = build_header('%s.txt' % name)
|
||||
return resp
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def toggle_filter_state(request, setname, fname):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
if isinstance(fname, unicode):
|
||||
fname = fname.encode("utf-8")
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
if fset.is_filter_disabled(fname):
|
||||
ret = fset.enablefilter(fname)
|
||||
newstate = _("yes")
|
||||
color = "green"
|
||||
else:
|
||||
ret = fset.disablefilter(fname)
|
||||
newstate = _("no")
|
||||
color = "red"
|
||||
if not ret:
|
||||
pass
|
||||
sc.pushscript(setname, str(fset))
|
||||
return render_to_json_response({
|
||||
"label": newstate,
|
||||
"color": color
|
||||
})
|
||||
|
||||
|
||||
def move_filter(request, setname, fname, direction):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
fset.movefilter(fname.encode("utf-8"), direction)
|
||||
sc.pushscript(setname, str(fset))
|
||||
return ajax_response(
|
||||
request, template="sievefilters/guieditor.html", fs=fset
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def move_filter_up(request, setname, fname):
|
||||
return move_filter(request, setname, fname, "up")
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def move_filter_down(request, setname, fname):
|
||||
return move_filter(request, setname, fname, "down")
|
||||
Reference in New Issue
Block a user