Remove sievefilters extension.

This commit is contained in:
Antoine Nguyen
2015-02-11 13:59:49 +01:00
parent 704a046b5b
commit a434286e20
18 changed files with 0 additions and 2014 deletions
@@ -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
-322
View File
@@ -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()
-107
View File
@@ -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)
}))
-42
View File
@@ -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()
-29
View File
@@ -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"),
)
-337
View File
@@ -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")