Last functionalities of the "sievefilters" plugin.

fixed #139
This commit is contained in:
Antoine Nguyen
2011-06-30 21:59:18 +02:00
parent 0ab1823d3a
commit 0add00f333
10 changed files with 124 additions and 40 deletions
+23 -18
View File
@@ -16,9 +16,9 @@ header_operators = [("contains", _("contains"), "string"),
class FilterForm(forms.Form):
name = forms.CharField(label=_("Name"))
match_type = forms.ChoiceField(choices=[("allof", _("Match all of the following")),
("anyof", _("Match any of the following")),
("all", _("Match all messages"))],
match_type = forms.ChoiceField(choices=[("allof", _("All of the following")),
("anyof", _("Any of the following")),
("all", _("All messages"))],
initial="anyof",
widget=forms.RadioSelect)
@@ -158,19 +158,20 @@ def build_filter_form_from_qdict(request):
qdict["match_type"] = request.POST["match_type"]
cpt = 0
i = 0
while True:
if cpt == int(request.POST["conds"]):
break
if request.POST.has_key("cond_target_%d" % i):
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
if qdict["match_type"] != "all":
while True:
if cpt == int(request.POST["conds"]):
break
if request.POST.has_key("cond_target_%d" % i):
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:
@@ -197,12 +198,16 @@ def build_filter_form_from_qdict(request):
return FilterForm(conditions, actions, request, qdict)
def build_filter_form_from_filter(request, name, fobj):
from sievelib.commands import SizeCommand
from sievelib.commands import SizeCommand, TrueCommand
match_type = fobj["test"].name
conditions = []
for t in fobj["test"]["tests"]:
if isinstance(t, SizeCommand):
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('"'),
+8 -2
View File
@@ -26,7 +26,9 @@ class SieveClient(object):
authmech = parameters.get_admin("AUTHENTICATION_MECH")
if authmech == "AUTO":
authmech = None
if not self.msc.connect(user, password, use_starttls, authmech):
try:
ret = self.msc.connect(user, password, use_starttls, authmech)
except Error, e:
return False, _("Connection to MANAGESIEVE server failed, check your configuration")
return True, None
@@ -37,7 +39,10 @@ class SieveClient(object):
pass
else:
return
ret, msg = self.login(user, password)
try:
ret, msg = self.login(user, password)
except Error, e:
raise ConnectionError(e)
if not ret:
raise ConnectionError(msg)
@@ -52,6 +57,7 @@ class SieveClient(object):
return content
p = Parser()
if not p.parse(content):
print "Parse error????"
return None
fs = FiltersSet(name)
fs.from_parser_result(p)
+23 -2
View File
@@ -102,7 +102,8 @@
#actionlist {
border: 1px solid #CCC;
padding-top: 10px;
padding: 5px;
padding-top: 15px;
}
#condlist ul {
@@ -120,6 +121,8 @@
#matchtype {
margin-bottom: 10px;
margin-left: 7px;
font-size: 0.9em;
}
#submit {
@@ -129,6 +132,11 @@
div.item {
margin-bottom: 10px;
margin-left: 5px;
overflow: auto;
}
div.item input[type=text], div.item select {
width: 190px;
}
div.item input, div.item select {
@@ -149,7 +157,8 @@ ul.errors {
.errors li {
color: red;
font-style: bold;
font-weight: bold;
font-size: 0.9em;
display: inline;
}
@@ -191,4 +200,16 @@ ul.errors {
.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;
}
+3 -1
View File
@@ -181,7 +181,9 @@ function toggle_filter_state(event) {
url: this.get("href"),
onSuccess: function(response) {
if (response.status == "ok") {
this.set("html", response.respmsg);
this.set("html", response.label);
this.set("class", "");
this.addClass(response.color);
} else {
infobox.error(respmsg.respmsg);
}
@@ -13,12 +13,22 @@ var action_templates = null;
var da = null;
var dc = null;
function matchtype_cb(event) {
if (this.get("value") == "all") {
$$("#condlist div[class=item]").slide("out");
} else {
$("hide").setStyle("display", "block");
$$("#condlist div[class=item]").slide("in");
}
}
function initform() {
var clist = $$("select[name*=cond_target_]");
var alist = $$("select[name*=action_name_]");
dc = new DynamicCondition(clist, {
templates: cond_templates
templates: cond_templates,
parentContainer: $("condlist")
});
da = new DynamicAction(alist, {
templates: action_templates,
@@ -27,6 +37,8 @@ function initform() {
clist.addEvent("change", dc.onTargetChange.bind(dc));
alist.addEvent("change", da.onNameChange.bind(da));
$$("input[name=match_type]").addEvent("click", matchtype_cb);
}
$(document).addEvent("domready", function() {
@@ -60,13 +72,16 @@ $(document).addEvent("domready", function() {
<h2>{% trans "Conditions" %}</h2>
<div id="condlist">
<div id="matchtype">
<label>{% trans "Match type" %}:</label>
{{ form.match_type }}{% display_errors form.match_type.errors %}
<div class="spacer"></div>
</div>
<div class="spacer"></div>
{% if hideconds %}<div id="hide" style="display:none">{% endif %}
{% for ec in conds_nb %}
{% display_condition form ec %}
{% endfor %}
{% if hideconds %}</div>{% endif %}
</div>
<h2>{% trans "Actions" %}</h2>
<div id="actionlist">
@@ -14,6 +14,7 @@
<td>{{ filter.name }}</td>
<td>
<a name="togglestate"
class={% if filter.enabled %}"green"{% else %}"red"{% endif %}
href="{% url extensions.sievefilters.views.toggle_filter_state fs.name filter.name %}">
{{ filter.enabled|yesno }}
</a>
@@ -5,7 +5,7 @@
<script type="text/javascript" src="{{ MEDIA_URL }}sievefilters/js/lib.js"></script>
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}sievefilters/css/style.css" />
<script type="text/javascript">
var current_anchor = new AnchorNavigation("{{ active_script }}", {
var current_anchor = new AnchorNavigation("{{ default_script }}", {
defcallback: loadfs
});
@@ -20,7 +20,7 @@ $(document).addEvent("domready", function() {
<label>{% trans "Filters sets" %}</label>
<select id="curfset">
{% if active_script %}
<option value="{{ active_script }}">{{ active_script }} (active)</option>
<option value="{{ active_script }}">{{ active_script }} ({% trans "active" %})</option>
{% endif %}
{% for script in scripts %}
<option value="{{ script }}">{{ script }}</option>
@@ -34,7 +34,7 @@ def fset_menu(mode, setname):
"label" : _("New filter"),
"url" : reverse(views.newfilter, args=[setname]),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:650,y:400}}"},
"rel" : "{handler:'iframe',size:{x:700,y:400}}"},
]
if mode == "raw":
@@ -130,18 +130,21 @@ def display_action(form, cnt):
action = form["action_name_%d" % cnt]
values = []
acnt = 0
verrors = []
while True:
try:
values += [form["action_arg_%d_%d" % (cnt, acnt)]]
print display_errors(form["action_arg_%d_%d" % (cnt, acnt)].errors)
if len(form["action_arg_%d_%d" % (cnt, acnt)].errors):
verrors += form["action_arg_%d_%d" % (cnt, acnt)].errors
acnt += 1
except KeyError:
break
t = template.Template("""
<div class="item">
{{ afield }}{% for v in values %}{{ v }}{% endfor %}
{{ afield }}{% for v in values %}{{ v }}{% endfor %}{{ verrors }}
</div>
""")
return t.render(template.Context({
"afield" : action, "values" : values
"afield" : action, "values" : values,
"verrors" : display_errors(verrors)
}))
+35 -7
View File
@@ -4,21 +4,30 @@ from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from modoboa.lib import _render, _render_to_string, \
from modoboa.lib import _render, _render_to_string, _render_error, \
ajax_response, ajax_simple_response, parameters
from modoboa.lib.connections import ConnectionError
from modoboa.auth.lib import get_password
from lib import *
from forms import *
@login_required
def index(request, tplname="sievefilters/index.html"):
sc = SieveClient(user=request.user.username,
password=request.session["password"])
try:
sc = SieveClient(user=request.user.username,
password=request.session["password"])
except ConnectionError, e:
return _render_error(request, user_context={"error" : e})
active_script, scripts = sc.listscripts()
if active_script is None:
active_script = ""
default_script = scripts[0] if len(scripts) else ""
else:
default_script = active_script
return _render(request, tplname, {
"active_script" : active_script,
"default_script" : default_script,
"scripts" : sorted(scripts),
})
@@ -42,10 +51,17 @@ 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, e:
return ajax_response(request, "ko", respmsg=str(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":
return ajax_response(request, template="sievefilters/rawfilter.html",
@@ -67,13 +83,17 @@ def submitfilter(request, setname, okmsg, tplname, tplctx, update=False, sc=None
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",)]
if not update:
fset.addfilter(form.cleaned_data["name"], conditions, actions,
form.cleaned_data["match_type"])
match_type)
else:
fset.updatefilter(request.POST["oldname"],
form.cleaned_data["name"], conditions, actions,
form.cleaned_data["match_type"])
match_type)
sc.pushscript(fset.name, str(fset))
return ajax_response(request, respmsg=okmsg, ajaxnav=True)
tplctx = build_filter_ctx(tplctx, form)
@@ -107,6 +127,8 @@ def editfilter(request, setname, fname, tplname="sievefilters/filter.html"):
form = build_filter_form_from_filter(request, fname, f)
ctx = build_filter_ctx(ctx, form)
ctx["oldname"] = fname
if form.fields["match_type"].initial == "all":
ctx["hideconds"] = True
return _render(request, tplname, ctx)
@login_required
@@ -206,16 +228,22 @@ def toggle_filter_state(request, setname, fname):
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))
except SieveClientError, e:
return ajax_response(request, "ko", respmsg=str(e))
return ajax_response(request, respmsg=newstate)
return ajax_simple_response({
"status" : "ok",
"label" : newstate,
"color" : color
})
def move_filter(request, setname, fname, direction):
sc = SieveClient(user=request.user.username,
+6 -3
View File
@@ -3,7 +3,7 @@ var DynamicTextInput = new Class({
Implements: [Options],
options: {
parentContainer: null
},
initialize: function(targets, options) {
@@ -62,13 +62,16 @@ var DynamicTextInput = new Class({
id: "delbtn_" + this.nextid,
src: parent.static_url("pics/remove.png")
});
this.nextid += 1;
delbtn.setStyles({
"float" : "right",
"margin-top": "2px"
});
field[0].inject(this.target.getParent(), "after");
if (!this.options.parentContainer) {
field[0].inject(this.target.getParent(), "after");
} else {
field[0].inject(this.options.parentContainer);
}
delbtn.inject(field[1], "after");
delbtn.addEvent("click", this.removeelement.bind(this));
this.target.set("value", "");