mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: big refactoring
* sieve extension still needs work * auth application removed
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
# coding: utf-8
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
username = forms.CharField(
|
||||
label=_("Username"),
|
||||
widget=forms.TextInput(attrs={"class": "input-block-level"})
|
||||
)
|
||||
password = forms.CharField(
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput(attrs={"class": "input-block-level"})
|
||||
)
|
||||
rememberme = forms.BooleanField(
|
||||
initial=False,
|
||||
required=False
|
||||
)
|
||||
@@ -1,41 +0,0 @@
|
||||
# coding: utf-8
|
||||
from Crypto.Cipher import AES
|
||||
import base64
|
||||
import random
|
||||
import string
|
||||
from modoboa.lib import parameters
|
||||
|
||||
|
||||
def random_key(l=16):
|
||||
"""Generate a random key
|
||||
|
||||
:param integer l: the key's length
|
||||
:return: a string
|
||||
"""
|
||||
char_set = string.digits + string.letters + string.punctuation
|
||||
return ''.join(random.sample(char_set * l, l))
|
||||
|
||||
|
||||
def encrypt(clear):
|
||||
key = parameters.get_admin("SECRET_KEY", app="admin")
|
||||
obj = AES.new(key, AES.MODE_ECB)
|
||||
if type(clear) is unicode:
|
||||
clear = clear.encode("utf-8")
|
||||
if len(clear) % AES.block_size:
|
||||
clear += " " * (AES.block_size - len(clear) % AES.block_size)
|
||||
ciph = obj.encrypt(clear)
|
||||
ciph = base64.b64encode(ciph)
|
||||
return ciph
|
||||
|
||||
|
||||
def decrypt(ciph):
|
||||
obj = AES.new(
|
||||
parameters.get_admin("SECRET_KEY", app="admin"), AES.MODE_ECB
|
||||
)
|
||||
ciph = base64.b64decode(ciph)
|
||||
clear = obj.decrypt(ciph)
|
||||
return clear.rstrip(' ')
|
||||
|
||||
|
||||
def get_password(request):
|
||||
return decrypt(request.session["password"])
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -1,23 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
This file demonstrates two different styles of tests (one doctest and one
|
||||
unittest). These will both pass when you run "manage.py test".
|
||||
|
||||
Replace these with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.failUnlessEqual(1 + 1, 2)
|
||||
|
||||
__test__ = {"doctest": """
|
||||
Another way to test that 1 + 1 is equal to 2.
|
||||
|
||||
>>> 1 + 1 == 2
|
||||
True
|
||||
"""}
|
||||
@@ -1,69 +0,0 @@
|
||||
# coding: utf-8
|
||||
import logging
|
||||
from django.views.decorators.cache import never_cache
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import _render_to_string
|
||||
from forms import LoginForm
|
||||
from modoboa.auth.lib import encrypt
|
||||
|
||||
|
||||
def dologin(request):
|
||||
error = None
|
||||
if request.method == "POST":
|
||||
form = LoginForm(request.POST)
|
||||
if form.is_valid():
|
||||
logger = logging.getLogger('modoboa.auth')
|
||||
user = authenticate(username=form.cleaned_data["username"],
|
||||
password=form.cleaned_data["password"])
|
||||
if user and user.is_active:
|
||||
login(request, user)
|
||||
if not form.cleaned_data["rememberme"]:
|
||||
request.session.set_expiry(0)
|
||||
if request.user.has_mailbox:
|
||||
request.session["password"] = encrypt(form.cleaned_data["password"])
|
||||
|
||||
request.session["django_language"] = \
|
||||
parameters.get_user(request.user, "LANG", app="general")
|
||||
|
||||
logger.info(_("User '%s' successfully logged in" % user.username))
|
||||
events.raiseEvent("UserLogin", request,
|
||||
form.cleaned_data["username"],
|
||||
form.cleaned_data["password"])
|
||||
|
||||
nextlocation = request.POST.get("next", None)
|
||||
if nextlocation is None or nextlocation == "None":
|
||||
if user.group == "SimpleUsers":
|
||||
nextlocation = reverse("modoboa.lib.webutils.topredirection")
|
||||
else:
|
||||
nextlocation = reverse("domains")
|
||||
return HttpResponseRedirect(nextlocation)
|
||||
error = _("Your username and password didn't match. Please try again.")
|
||||
logger.warning("Failed connection attempt from '%(addr)s' as user '%(user)s'" \
|
||||
% {"addr": request.META["REMOTE_ADDR"],
|
||||
"user": form.cleaned_data["username"]})
|
||||
|
||||
nextlocation = request.POST.get("next", None)
|
||||
httpcode = 401
|
||||
else:
|
||||
form = LoginForm()
|
||||
nextlocation = request.GET.get("next", None)
|
||||
httpcode = 200
|
||||
|
||||
return HttpResponse(_render_to_string(request, "registration/login.html", {
|
||||
"form": form, "error": error, "next": nextlocation,
|
||||
"annoucements": events.raiseQueryEvent("GetAnnouncement", "loginpage")
|
||||
}), status=httpcode)
|
||||
|
||||
dologin = never_cache(dologin)
|
||||
|
||||
|
||||
def dologout(request):
|
||||
events.raiseEvent("UserLogout", request)
|
||||
logger = logging.getLogger("modoboa.auth")
|
||||
logger.info(_("User '%s' logged out" % request.user.username))
|
||||
logout(request)
|
||||
return HttpResponseRedirect(reverse(dologin))
|
||||
@@ -4,8 +4,8 @@ from django.conf import settings
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from modoboa.lib.formutils import YesNoField, SeparatorField, InlineRadioSelect
|
||||
from modoboa.lib.sysutils import exec_cmd
|
||||
from modoboa.lib.cryptutils import random_key
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.auth.lib import random_key
|
||||
|
||||
|
||||
def enabled_applications():
|
||||
|
||||
@@ -7,8 +7,8 @@ from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.lib.webutils import _render_to_string
|
||||
from modoboa.lib.cryptutils import encrypt
|
||||
from modoboa.core.forms import LoginForm
|
||||
from modoboa.auth.lib import encrypt
|
||||
|
||||
|
||||
def dologin(request):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib import events, parameters
|
||||
from modoboa.extensions import ModoExtension, exts_pool
|
||||
from modoboa.core.extensions import ModoExtension, exts_pool
|
||||
|
||||
|
||||
class SieveFilters(ModoExtension):
|
||||
@@ -13,7 +13,7 @@ class SieveFilters(ModoExtension):
|
||||
url = "sfilters"
|
||||
|
||||
def load(self):
|
||||
from app_settings import ParametersForm, UserSettings
|
||||
from .app_settings import ParametersForm, UserSettings
|
||||
parameters.register(ParametersForm, ugettext_lazy("Sieve filters"))
|
||||
parameters.register(UserSettings, ugettext_lazy("Message filters"))
|
||||
|
||||
@@ -23,31 +23,31 @@ class SieveFilters(ModoExtension):
|
||||
|
||||
exts_pool.register_extension(SieveFilters)
|
||||
|
||||
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
import views
|
||||
|
||||
if target != "options_menu":
|
||||
return []
|
||||
if not user.has_mailbox:
|
||||
if not user.mailbox_set.count():
|
||||
return []
|
||||
return [
|
||||
{"name" : "sievefilters",
|
||||
"label" : _("Message filters"),
|
||||
"url" : reverse(views.index),
|
||||
"img" : "icon-check"}
|
||||
]
|
||||
{"name": "sievefilters",
|
||||
"label": _("Message filters"),
|
||||
"url": reverse("modobooa.extensions.sievefilters.views.index"),
|
||||
"img": "icon-check"}
|
||||
]
|
||||
|
||||
|
||||
@events.observe("UserLogout")
|
||||
def userlogout(request):
|
||||
from lib import SieveClient
|
||||
from .lib import SieveClient
|
||||
|
||||
if not request.user.has_mailbox:
|
||||
return
|
||||
try:
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
except Exception, e:
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
sc.logout()
|
||||
|
||||
@@ -29,7 +29,7 @@ class ParametersForm(AdminParametersForm):
|
||||
initial=4190,
|
||||
help_text=_("Listening port of your MANAGESIEVE server")
|
||||
)
|
||||
|
||||
|
||||
starttls = YesNoField(
|
||||
label=_("Connect using STARTTLS"),
|
||||
initial="no",
|
||||
@@ -59,4 +59,4 @@ class UserSettings(UserParametersForm):
|
||||
|
||||
@staticmethod
|
||||
def has_access(user):
|
||||
return user.has_mailbox
|
||||
return user.mailbox_set.count() != 0
|
||||
|
||||
@@ -7,11 +7,15 @@ from django.utils.html import conditional_escape
|
||||
from django.utils.encoding import force_unicode
|
||||
from modoboa.extensions.admin.templatetags.admin_tags import gender
|
||||
|
||||
|
||||
class FiltersSetForm(forms.Form):
|
||||
name = forms.CharField()
|
||||
active = forms.BooleanField(label=gender("Active", "m"), required=False,
|
||||
initial=False,
|
||||
help_text=ugettext_lazy("Check to activate this filters set"))
|
||||
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):
|
||||
@@ -27,15 +31,16 @@ class CustomRadioInput(RadioInput):
|
||||
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)
|
||||
)
|
||||
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)
|
||||
@@ -43,9 +48,11 @@ class CustomRadioFieldRenderer(RadioFieldRenderer):
|
||||
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)
|
||||
@@ -56,30 +63,32 @@ class FilterForm(forms.Form):
|
||||
("anyof", _("Any of the following")),
|
||||
("all", _("All messages"))],
|
||||
initial="anyof",
|
||||
widget=CustomRadioSelect(attrs={"class" : "radio inline"})
|
||||
)
|
||||
|
||||
self.header_operators = [("contains", _("contains"), "string"),
|
||||
("notcontains", _("does not contain"), "string"),
|
||||
("is", _("is"), "string"),
|
||||
("isnot", _("is not"), "string")]
|
||||
|
||||
widget=CustomRadioSelect(attrs={"class": "radio inline"})
|
||||
)
|
||||
|
||||
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")]},
|
||||
]
|
||||
|
||||
{"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"}]},
|
||||
]
|
||||
{"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:
|
||||
@@ -93,7 +102,7 @@ class FilterForm(forms.Form):
|
||||
ops = []
|
||||
vfield = None
|
||||
for tpl in self.cond_templates:
|
||||
targets += [(tpl["name"], tpl["label"]),]
|
||||
targets += [(tpl["name"], tpl["label"]), ]
|
||||
if tpl["name"] != name:
|
||||
continue
|
||||
for opdef in tpl["operators"]:
|
||||
@@ -109,7 +118,7 @@ class FilterForm(forms.Form):
|
||||
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)
|
||||
|
||||
@@ -129,7 +138,7 @@ class FilterForm(forms.Form):
|
||||
actions = []
|
||||
args = None
|
||||
for tpl in self.action_templates:
|
||||
actions += [(tpl["name"], tpl["label"]),]
|
||||
actions += [(tpl["name"], tpl["label"]), ]
|
||||
if name == tpl["name"]:
|
||||
args = tpl["args"]
|
||||
self.fields["action_name_%d" % self.actions_cnt] = \
|
||||
@@ -153,12 +162,12 @@ class FilterForm(forms.Form):
|
||||
def __build_folders_list(self, folders, user, imapc, parentmb=None):
|
||||
ret = []
|
||||
for fd in folders:
|
||||
value = fd["path"] if fd.has_key("path") else fd["name"]
|
||||
value = fd["path"] if "path" in fd else fd["name"]
|
||||
if parentmb:
|
||||
ret += [(value, fd["name"].replace("%s." % parentmb, ""))]
|
||||
else:
|
||||
ret += [(value, fd["name"])]
|
||||
if fd.has_key("sub"):
|
||||
if "sub" in fd:
|
||||
submboxes = imapc.getmboxes(user, value, unseen_messages=False)
|
||||
ret += self.__build_folders_list(submboxes, user, imapc, value)
|
||||
return ret
|
||||
@@ -191,7 +200,8 @@ class FilterForm(forms.Form):
|
||||
actions += [naction]
|
||||
|
||||
return (conditions, actions)
|
||||
|
||||
|
||||
|
||||
def build_filter_form_from_qdict(request):
|
||||
conditions = []
|
||||
actions = []
|
||||
@@ -204,7 +214,7 @@ def build_filter_form_from_qdict(request):
|
||||
while True:
|
||||
if cpt == int(request.POST["conds"]):
|
||||
break
|
||||
if request.POST.has_key("cond_target_%d" % i):
|
||||
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]
|
||||
@@ -219,7 +229,7 @@ def build_filter_form_from_qdict(request):
|
||||
while True:
|
||||
if cpt == int(request.POST["actions"]):
|
||||
break
|
||||
if request.POST.has_key("action_name_%d" % i):
|
||||
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
|
||||
@@ -239,6 +249,7 @@ 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, TrueCommand
|
||||
|
||||
@@ -252,8 +263,8 @@ def build_filter_form_from_filter(request, name, fobj):
|
||||
elif isinstance(t, SizeCommand):
|
||||
conditions += [("size", t["comparator"][1:], t["limit"])]
|
||||
else:
|
||||
conditions += [(t["header-names"].strip('"'),
|
||||
t["match-type"][1:],
|
||||
conditions += [(t["header-names"].strip('"'),
|
||||
t["match-type"][1:],
|
||||
t["key-list"].strip('"'))]
|
||||
actions = []
|
||||
for c in fobj.children:
|
||||
|
||||
@@ -7,9 +7,11 @@ from sievelib.factory import FiltersSet
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.connections import ConnectionsManager, ConnectionError
|
||||
|
||||
|
||||
class SieveClientError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class SieveClient(object):
|
||||
__metaclass__ = ConnectionsManager
|
||||
|
||||
@@ -22,7 +24,7 @@ class SieveClient(object):
|
||||
raise ConnectionError(msg)
|
||||
|
||||
def login(self, user, password):
|
||||
self.msc = Client(parameters.get_admin("SERVER"),
|
||||
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
|
||||
@@ -31,7 +33,7 @@ class SieveClient(object):
|
||||
authmech = None
|
||||
try:
|
||||
ret = self.msc.connect(user, password, use_starttls, authmech)
|
||||
except Error, e:
|
||||
except Error:
|
||||
ret = False
|
||||
if not ret:
|
||||
return False, _("Connection to MANAGESIEVE server failed, check your configuration")
|
||||
@@ -40,7 +42,7 @@ class SieveClient(object):
|
||||
def logout(self):
|
||||
self.msc.logout()
|
||||
self.msc = None
|
||||
|
||||
|
||||
def refresh(self, user, password):
|
||||
import ssl
|
||||
|
||||
@@ -85,7 +87,7 @@ class SieveClient(object):
|
||||
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)
|
||||
|
||||
@@ -2,106 +2,108 @@ from django import template
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from modoboa.lib.webutils import render_actions
|
||||
from modoboa.lib.webutils import render_actions, static_url
|
||||
|
||||
register = template.Library()
|
||||
|
||||
from modoboa.lib.webutils import static_url
|
||||
|
||||
@register.simple_tag
|
||||
def sfilters_menu(user):
|
||||
entries = [
|
||||
{"name" : "newfilterset",
|
||||
"img" : "icon-plus",
|
||||
"label" : _("New filters set"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.new_filters_set"),
|
||||
"modal" : True,
|
||||
"modalcb" : "filtersetform_cb"
|
||||
{"name": "newfilterset",
|
||||
"img": "icon-plus",
|
||||
"label": _("New filters set"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.new_filters_set"),
|
||||
"modal": True,
|
||||
"modalcb": "filtersetform_cb"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries": entries, "user": user})
|
||||
|
||||
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" : "icon-plus",
|
||||
"label" : _("New filter"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.newfilter",
|
||||
{"name": "newfilter",
|
||||
"img": "icon-plus",
|
||||
"label": _("New filter"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.newfilter",
|
||||
args=[setname]),
|
||||
"modal" : True,
|
||||
"autowidth" : True,
|
||||
"modalcb" : "filterform_cb"}
|
||||
]
|
||||
"modal": True,
|
||||
"autowidth": True,
|
||||
"modalcb": "filterform_cb"}
|
||||
]
|
||||
if mode == "raw":
|
||||
entries += [
|
||||
{"name" : "savefs",
|
||||
"img" : "icon-download-alt",
|
||||
"label" : _("Save filters set"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.savefs",
|
||||
{"name": "savefs",
|
||||
"img": "icon-download-alt",
|
||||
"label": _("Save filters set"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.savefs",
|
||||
args=[setname])},
|
||||
]
|
||||
|
||||
entries += [
|
||||
{"name" : "activatefs",
|
||||
"img" : "icon-ok",
|
||||
"label" : _("Activate filters set"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.activate_filters_set",
|
||||
args=[setname])},
|
||||
{"name" : "removefs",
|
||||
"img" : "icon-trash",
|
||||
"label" : _("Remove filters set"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.remove_filters_set",
|
||||
args=[setname])},
|
||||
{"name" : "downloadfs",
|
||||
"img" : "icon-download",
|
||||
"label" : _("Download"),
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.download_filters_set",
|
||||
args=[setname])}
|
||||
]
|
||||
|
||||
return render_to_string('common/menulist.html',
|
||||
{"entries" : entries})
|
||||
entries += [
|
||||
{"name": "activatefs",
|
||||
"img": "icon-ok",
|
||||
"label": _("Activate filters set"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.activate_filters_set",
|
||||
args=[setname])},
|
||||
{"name": "removefs",
|
||||
"img": "icon-trash",
|
||||
"label": _("Remove filters set"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.remove_filters_set",
|
||||
args=[setname])},
|
||||
{"name": "downloadfs",
|
||||
"img": "icon-download",
|
||||
"label": _("Download"),
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.download_filters_set",
|
||||
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("modoboa.extensions.sievefilters.views.editfilter",
|
||||
{"name": "editfilter",
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.editfilter",
|
||||
args=[setname, f["name"]]),
|
||||
"img" : "icon-edit",
|
||||
"title" : _("Edit filter"),
|
||||
"modal" : True,
|
||||
"autowidth" : True,
|
||||
"modalcb" : "filterform_cb"},
|
||||
{"name" : "removefilter",
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.removefilter",
|
||||
"img": "icon-edit",
|
||||
"title": _("Edit filter"),
|
||||
"modal": True,
|
||||
"autowidth": True,
|
||||
"modalcb": "filterform_cb"},
|
||||
{"name": "removefilter",
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.removefilter",
|
||||
args=[setname, f["name"]]),
|
||||
"img" : "icon-trash",
|
||||
"title" : _("Remove this filter")}
|
||||
]
|
||||
"img": "icon-trash",
|
||||
"title": _("Remove this filter")}
|
||||
]
|
||||
if position != 1:
|
||||
actions += [
|
||||
{"name" : "movefilter_up",
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.move_filter_up",
|
||||
{"name": "movefilter_up",
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.move_filter_up",
|
||||
args=[setname, f["name"]]),
|
||||
"img" : "icon-arrow-up",
|
||||
"title" : _("Move this filter up")}
|
||||
]
|
||||
"img": "icon-arrow-up",
|
||||
"title": _("Move this filter up")}
|
||||
]
|
||||
if not islast:
|
||||
actions += [
|
||||
{"name" : "movefilter_down",
|
||||
"url" : reverse("modoboa.extensions.sievefilters.views.move_filter_down",
|
||||
{"name": "movefilter_down",
|
||||
"url": reverse("modoboa.extensions.sievefilters.views.move_filter_down",
|
||||
args=[setname, f["name"]]),
|
||||
"img" : "icon-arrow-down",
|
||||
"title" : _("Move this filter down")},
|
||||
]
|
||||
"img": "icon-arrow-down",
|
||||
"title": _("Move this filter down")},
|
||||
]
|
||||
return render_actions(actions)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_errors(errors):
|
||||
if not len(errors):
|
||||
@@ -114,8 +116,9 @@ def display_errors(errors):
|
||||
</ul>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"errors" : errors
|
||||
}))
|
||||
"errors": errors
|
||||
}))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_condition(form, cnt):
|
||||
@@ -128,12 +131,13 @@ def display_condition(form, cnt):
|
||||
</div>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"idx" : cnt,
|
||||
"tfield" : target,
|
||||
"ofield" : operator,
|
||||
"vfield" : value,
|
||||
"verrors" : display_errors(value.errors)
|
||||
}))
|
||||
"idx": cnt,
|
||||
"tfield": target,
|
||||
"ofield": operator,
|
||||
"vfield": value,
|
||||
"verrors": display_errors(value.errors)
|
||||
}))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def display_action(form, cnt):
|
||||
@@ -155,7 +159,7 @@ def display_action(form, cnt):
|
||||
</div>
|
||||
""")
|
||||
return t.render(template.Context({
|
||||
"idx" : cnt,
|
||||
"afield" : action, "values" : values,
|
||||
"verrors" : display_errors(verrors)
|
||||
}))
|
||||
"idx": cnt,
|
||||
"afield": action, "values": values,
|
||||
"verrors": display_errors(verrors)
|
||||
}))
|
||||
|
||||
@@ -1,45 +1,51 @@
|
||||
# coding: utf-8
|
||||
from sievelib.managesieve import Error
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from django.template.loader import render_to_string
|
||||
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 parameters
|
||||
from modoboa.lib.webutils import _render, _render_to_string, _render_error, \
|
||||
from modoboa.lib.webutils import _render_to_string, _render_error, \
|
||||
ajax_response, ajax_simple_response
|
||||
from modoboa.lib.decorators import needs_mailbox
|
||||
from modoboa.lib.connections import ConnectionError
|
||||
from modoboa.auth.lib import get_password
|
||||
from lib import *
|
||||
from forms import *
|
||||
from modoboa.lib.cryptutils import get_password
|
||||
from modoboa.extensions.admin.lib import needs_mailbox
|
||||
from .lib import SieveClient, SieveClientError
|
||||
from .forms import (
|
||||
FilterForm, build_filter_form_from_qdict, build_filter_form_from_filter,
|
||||
FiltersSetForm
|
||||
)
|
||||
from templatetags.sfilters_tags import fset_menu
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def index(request, tplname="sievefilters/index.html"):
|
||||
try:
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
except ConnectionError, e:
|
||||
return _render_error(request, user_context={"error" : e})
|
||||
|
||||
return _render_error(request, user_context={"error": e})
|
||||
|
||||
try:
|
||||
active_script, scripts = sc.listscripts()
|
||||
except Error, e:
|
||||
return _render_error(request, user_context={"error" : 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),
|
||||
})
|
||||
return render(request, tplname, {
|
||||
"selection": "user",
|
||||
"active_script": active_script,
|
||||
"default_script": default_script,
|
||||
"scripts": sorted(scripts),
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
@@ -48,10 +54,11 @@ def get_templates(request, ftype):
|
||||
return ajax_simple_response(FilterForm([], [], request).cond_templates)
|
||||
return ajax_simple_response(FilterForm([], [], request).action_templates)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def getfs(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
editormode = parameters.get_user(request.user, "EDITOR_MODE")
|
||||
error = None
|
||||
@@ -67,30 +74,32 @@ def getfs(request, name):
|
||||
return ajax_response(request, "ko", respmsg=error)
|
||||
|
||||
if editormode == "raw":
|
||||
htmlcontent = render_to_string("sievefilters/rawfilter.html", dict(
|
||||
name=name, scriptcontent=content
|
||||
))
|
||||
htmlcontent = render_to_string("sievefilters/rawfilter.html", dict(
|
||||
name=name, scriptcontent=content
|
||||
))
|
||||
else:
|
||||
htmlcontent = render_to_string("sievefilters/guieditor.html", dict(
|
||||
fs=content
|
||||
))
|
||||
fs=content
|
||||
))
|
||||
|
||||
menu = '<ul id="fsetmenu" class="nav nav-list"><li class="nav-header">%s</li>%s</ul>' % \
|
||||
(_("Actions"), fset_menu(editormode, name))
|
||||
(_("Actions"), fset_menu(editormode, name))
|
||||
resp = dict(status="ok", menu=menu, content=htmlcontent)
|
||||
return ajax_simple_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,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
conditions, actions = form.tofilter()
|
||||
@@ -110,6 +119,7 @@ def submitfilter(request, setname, okmsg, tplname, tplctx, update=False, sc=None
|
||||
tplctx = build_filter_ctx(tplctx, form)
|
||||
return ajax_response(request, status="ko", template=tplname, **tplctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def newfilter(request, setname, tplname="sievefilters/filter.html"):
|
||||
@@ -119,15 +129,18 @@ def newfilter(request, setname, tplname="sievefilters/filter.html"):
|
||||
action=reverse(newfilter, args=[setname]),
|
||||
action_label=_("Create"),
|
||||
action_classes="submit"
|
||||
)
|
||||
)
|
||||
if request.method == "POST":
|
||||
return submitfilter(request, setname, _("Filter created"), tplname, ctx)
|
||||
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)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
@@ -138,13 +151,13 @@ def editfilter(request, setname, fname, tplname="sievefilters/filter.html"):
|
||||
action=reverse(editfilter, args=[setname, fname]),
|
||||
action_label=_("Update"),
|
||||
action_classes="submit"
|
||||
)
|
||||
sc = SieveClient(user=request.user.username,
|
||||
)
|
||||
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")
|
||||
f = fset.getfilter(fname)
|
||||
form = build_filter_form_from_filter(request, fname, f)
|
||||
@@ -152,12 +165,13 @@ def editfilter(request, setname, fname, tplname="sievefilters/filter.html"):
|
||||
ctx["oldname"] = fname
|
||||
ctx["hidestyle"] = "none" \
|
||||
if form.fields["match_type"].initial == "all" else "block"
|
||||
return _render(request, tplname, ctx)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def removefilter(request, setname, fname):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
if fset.removefilter(fname):
|
||||
@@ -165,12 +179,13 @@ def removefilter(request, setname, fname):
|
||||
return ajax_response(request, respmsg=_("Filter removed"))
|
||||
return ajax_response(request, "ko", respmsg=_("Failed to remove filter"))
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def savefs(request, name):
|
||||
if not request.POST.has_key("scriptcontent"):
|
||||
if not "scriptcontent" in request.POST:
|
||||
return
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.pushscript(name, request.POST["scriptcontent"])
|
||||
@@ -178,22 +193,23 @@ def savefs(request, name):
|
||||
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"):
|
||||
ctx = {"title" : _("Create a new filters set"),
|
||||
"formid" : "newfiltersset",
|
||||
"action_label" : _("Create"),
|
||||
"action_classes" : "submit",
|
||||
"action" : reverse(new_filters_set),
|
||||
"withmenu" : False,
|
||||
"withunseen" : False}
|
||||
ctx = {"title": _("Create a new filters set"),
|
||||
"formid": "newfiltersset",
|
||||
"action_label": _("Create"),
|
||||
"action_classes": "submit",
|
||||
"action": reverse(new_filters_set),
|
||||
"withmenu": False,
|
||||
"withunseen": False}
|
||||
if request.method == "POST":
|
||||
form = FiltersSetForm(request.POST)
|
||||
error = None
|
||||
if form.is_valid():
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.pushscript(form.cleaned_data["name"], "# Empty script",
|
||||
@@ -202,7 +218,7 @@ def new_filters_set(request, tplname="common/generic_modal_form.html"):
|
||||
error = str(e)
|
||||
else:
|
||||
return ajax_simple_response({
|
||||
"status": "ok",
|
||||
"status": "ok",
|
||||
"url": form.cleaned_data["name"],
|
||||
"active": form.cleaned_data["active"],
|
||||
"respmsg": _("Filters set created")
|
||||
@@ -213,12 +229,13 @@ def new_filters_set(request, tplname="common/generic_modal_form.html"):
|
||||
return ajax_response(request, status="ko", template=tplname, **ctx)
|
||||
|
||||
ctx["form"] = FiltersSetForm()
|
||||
return _render(request, tplname, ctx)
|
||||
return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def remove_filters_set(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.deletescript(name)
|
||||
@@ -226,13 +243,14 @@ def remove_filters_set(request, name):
|
||||
return ajax_simple_response(dict(status="ko", respmsg=str(e)))
|
||||
acs, scripts = sc.listscripts()
|
||||
return ajax_simple_response(dict(
|
||||
status="ok", respmsg=_("Filters set deleted"), newfs=acs
|
||||
))
|
||||
status="ok", respmsg=_("Filters set deleted"), newfs=acs
|
||||
))
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def activate_filters_set(request, name):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
sc.activatescript(name)
|
||||
@@ -240,10 +258,11 @@ def activate_filters_set(request, name):
|
||||
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,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
script = sc.getscript(name)
|
||||
@@ -256,10 +275,11 @@ def download_filters_set(request, name):
|
||||
resp["Content-Disposition"] = 'attachment; filename="%s.txt"' % name
|
||||
return resp
|
||||
|
||||
|
||||
@login_required
|
||||
@needs_mailbox()
|
||||
def toggle_filter_state(request, setname, fname):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
@@ -276,15 +296,16 @@ def toggle_filter_state(request, setname, fname):
|
||||
sc.pushscript(setname, str(fset))
|
||||
except SieveClientError, e:
|
||||
return ajax_response(request, "ko", respmsg=str(e))
|
||||
|
||||
|
||||
return ajax_simple_response({
|
||||
"status" : "ok",
|
||||
"label" : newstate,
|
||||
"color" : color
|
||||
})
|
||||
"status": "ok",
|
||||
"label": newstate,
|
||||
"color": color
|
||||
})
|
||||
|
||||
|
||||
def move_filter(request, setname, fname, direction):
|
||||
sc = SieveClient(user=request.user.username,
|
||||
sc = SieveClient(user=request.user.username,
|
||||
password=request.session["password"])
|
||||
try:
|
||||
fset = sc.getscript(setname, format="fset")
|
||||
@@ -292,13 +313,17 @@ def move_filter(request, setname, fname, direction):
|
||||
sc.pushscript(setname, str(fset))
|
||||
except (SieveClientError), e:
|
||||
return ajax_response(request, "ko", respmsg=str(e))
|
||||
return ajax_response(request, template="sievefilters/guieditor.html", fs=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):
|
||||
|
||||
@@ -644,7 +644,7 @@ def send_mail(request, posturl=None):
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from .forms import ComposeMailForm
|
||||
from modoboa.lib.webutils import _render_to_string
|
||||
from modoboa.auth.lib import get_password
|
||||
from modoboa.lib.cryptutils import get_password
|
||||
|
||||
form = ComposeMailForm(request.POST)
|
||||
editormode = parameters.get_user(request.user, "EDITOR")
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
from modoboa.auth.lib import decrypt
|
||||
from modoboa.lib.cryptutils import decrypt
|
||||
|
||||
|
||||
class ConnectionsManager(type):
|
||||
"""Singleton pattern implementation
|
||||
|
||||
This class is specialized in connection management.
|
||||
"""
|
||||
def __init__(cls, name, bases, dict):
|
||||
super(ConnectionsManager, cls).__init__(name, bases, dict)
|
||||
def __init__(cls, name, bases, ctx):
|
||||
super(ConnectionsManager, cls).__init__(name, bases, ctx)
|
||||
cls.instances = {}
|
||||
|
||||
def __call__(cls, **kwargs):
|
||||
key = None
|
||||
if kwargs.has_key("user"):
|
||||
if "user" in kwargs:
|
||||
key = kwargs["user"]
|
||||
else:
|
||||
return None
|
||||
if not cls.instances.has_key(key):
|
||||
if not key in cls.instances:
|
||||
cls.instances[key] = None
|
||||
if kwargs.has_key("password"):
|
||||
if "password" in kwargs:
|
||||
kwargs["password"] = decrypt(kwargs["password"])
|
||||
|
||||
if cls.instances[key] is None:
|
||||
@@ -27,5 +28,6 @@ class ConnectionsManager(type):
|
||||
cls.instances[key].refresh(key, kwargs["password"])
|
||||
return cls.instances[key]
|
||||
|
||||
|
||||
class ConnectionError(Exception):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user