wip: Quarantine 'self-service'

First commit.
This commit is contained in:
Antoine Nguyen
2012-04-04 16:18:22 +02:00
parent 311f95f912
commit ccf24f4905
9 changed files with 215 additions and 12 deletions
+11
View File
@@ -43,6 +43,8 @@ def load():
help=_("Path to the PDP server socket (if unix mode)"))
parameters.register_admin("USER_CAN_RELEASE", type="list_yesno", deflt="no",
help=_("Allow users to directly release their messages"))
parameters.register_admin("SELF_SERVICE", type="list_yesno", deflt="no",
help=_("Activate the 'self-service' mode"))
parameters.register_user(
"MESSAGES_PER_PAGE", type="int", deflt=40,
@@ -67,3 +69,12 @@ def menu(target, user):
]
return []
@events.observe("CreateMailbox")
def create_user_record(user, mailbox):
from models import Users
u = Users()
u.email = mailbox.full_address
u.fullname = mailbox.user.fullname
u.local = "1"
u.save()
+24
View File
@@ -2,8 +2,32 @@ import socket
import re
import struct
import string
from functools import wraps
from modoboa.lib import parameters
def selfservice(ssfunc=None):
"""Decorator used to expose views to the 'self-service' feature
The 'self-service' feature allows users to act on quarantined
messages without beeing authenticated.
This decorator only acts as a 'router'.
:param ssfunc: the function to call if the 'self-service'
pre-requisites are satisfied
"""
def decorator(f):
@wraps(f)
def wrapped_f(request, *args, **kwargs):
if request.user.is_authenticated():
return f(request, *args, **kwargs)
if parameters.get_admin("SELF_SERVICE") == "no":
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(reverse(f, args=args))
return ssfunc(request, *args, **kwargs)
return wrapped_f
return decorator
class AMrelease(object):
def __init__(self):
mode = parameters.get_admin("AM_PDP_MODE")
@@ -0,0 +1,20 @@
#menubar {
padding-left: 15px;
}
#listing {
position: absolute;
padding: 0px;
right: 0;
left: 0;
bottom: 0;
overflow: hidden;
}
#mailcontent {
border: 0;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
@@ -0,0 +1,35 @@
function send_action(e, message) {
var $link = $(e.target);
e.preventDefault();
if (!confirm(message)) {
return;
}
$.ajax({
url: $link.attr("href"),
dataType: 'json',
success: function(data) {
if (data.status == "ok") {
$("body").notify("success", data.respmsg, 2000);
} else {
$("body").notify("error", data.respmsg);
}
}
});
}
function release(e) {
send_action(e, gettext("Release this message?"));
}
function remove(e) {
send_action(e, gettext("Delete this message?"));
}
$(document).ready(function() {
$("#listing").css({
top: $("#menubar").outerHeight() + 10
});
$(document).on("click", "a[name=release]", release);
$(document).on("click", "a[name=delete]", remove);
});
@@ -0,0 +1,30 @@
<!DOCTYPE html>
{% load i18n libextras amextras %}
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Modoboa</title>
<link rel="icon" type="image/png" href="{{ MEDIA_URL }}css/logo-icon.png" />
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/bootstrap-responsive.css" />
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}amavis_quarantine/css/selfservice.css" />
<script src="{{ MEDIA_URL }}js/jquery.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/bootstrap.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/utils.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/common.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/notify.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}amavis_quarantine/js/selfservice.js" type="text/javascript"></script>
{% url django.views.i18n.javascript_catalog as catalog_url %}
<script type="text/javascript" src="{{ catalog_url }}"></script>
<script type="text/javascript">
set_media_url("{{ MEDIA_URL }}");
</script>
</head>
<body>
<div id="fixed_content">
<div id="menubar">{% viewm_menu_simple user mail_id rcpt secret_id %}</div>
<div id="listing">{{ content }}</div>
</div>
</body>
</html>
@@ -52,6 +52,26 @@ def viewm_menu(user, mail_id, rcpt):
return render_to_string('common/buttons_list.html',
{"entries" : entries})
@register.simple_tag
def viewm_menu_simple(user, mail_id, rcpt, secret_id=""):
entries = [
{"name" : "release",
"img" : "icon-ok",
"url" : reverse(amavis_quarantine.views.release, args=[mail_id]) \
+ ("?rcpt=%s" % rcpt \
+ (("&secret_id=%s" % secret_id) if secret_id != "" else "")),
"label" : _("Release")},
{"name" : "delete",
"img" : "icon-remove",
"url" : reverse(amavis_quarantine.views.delete, args=[mail_id]) \
+ "?rcpt=%s" % rcpt \
+ ("&secret_id=%s" % secret_id if secret_id != "" else ""),
"label" : _("Delete")},
]
return render_to_string('common/buttons_list.html',
{"entries" : entries})
@register.simple_tag
def quar_menu(user, nbrequests):
entries = [
@@ -94,7 +114,7 @@ def quar_menu(user, nbrequests):
"extraopts" : extraopts
})
if nbrequests != -1:
if nbrequests > 0:
tpl = Template('<div class="btn-group"><a name="viewrequests" href="#" class="btn btn-danger">{{ label }}</a></div>')
extracontent += tpl.render(Context(dict(
label=_("%d pending requests" % nbrequests)
+1 -1
View File
@@ -5,9 +5,9 @@ urlpatterns = patterns(
(r'^$', 'index'),
(r'^listing/$', '_listing'),
(r'^getmailcontent/(?P<mail_id>[\w\-\+]+)/$', 'getmailcontent'),
(r'^(?P<mail_id>[\w\-\+]+)/headers/$', 'viewheaders'),
(r'^process/$', 'process'),
(r'^delete/(?P<mail_id>[\w\-\+]+)/$', 'delete'),
(r'^release/(?P<mail_id>[\w\-\+]+)/$', 'release'),
(r'^(?P<mail_id>[\w\-\+]+)/$', 'viewmail'),
(r'^(?P<mail_id>[\w\-\+]+)/headers/$', 'viewheaders'),
)
+73 -9
View File
@@ -1,6 +1,6 @@
# coding: utf-8
import email
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.template import Template, Context
from django.utils import simplejson
from django.utils.translation import ugettext as _, ungettext
@@ -9,9 +9,10 @@ from django.contrib.auth.decorators \
import login_required
from django.db.models import Q
from modoboa.lib import parameters
from modoboa.lib.webutils import _render, getctx, ajax_response
from modoboa.lib.exceptions import ModoboaException
from modoboa.lib.webutils import _render, getctx, ajax_response, ajax_simple_response
from modoboa.admin.models import Mailbox
from lib import AMrelease
from lib import AMrelease, selfservice
from templatetags.amextras import *
from modoboa.lib.email_listing import parse_search_parameters
from sql_listing import *
@@ -116,7 +117,21 @@ def index(request):
deflocation="listing/", defcallback="listing_cb", selection="quarantine"
))
@login_required
def getmailcontent_selfservice(request, mail_id):
from sql_listing import SQLemail
qmails = Quarantine.objects.filter(mail=mail_id)
content = ""
for qm in qmails:
content += qm.mail_text
msg = email.message_from_string(content)
mail = SQLemail(msg, mformat="plain", links="0")
return _render(request, "common/viewmail.html", {
"headers" : mail.render_headers(),
"mailbody" : mail.body
})
@selfservice(getmailcontent_selfservice)
def getmailcontent(request, mail_id):
from sql_listing import SQLemail
@@ -133,7 +148,21 @@ def getmailcontent(request, mail_id):
"mailbody" : mail.body
})
@login_required
def viewmail_selfservice(request, mail_id,
tplname="amavis_quarantine/viewmail_selfservice.html"):
rcpt = request.GET.get("rcpt", None)
secret_id = request.GET.get("secret_id", "")
if rcpt is None:
raise Http404
content = Template("""
<iframe src="{% url modoboa.extensions.amavis_quarantine.views.getmailcontent mail_id %}" id="mailcontent"></iframe>
""").render(Context(dict(mail_id=mail_id)))
return _render(request, tplname, dict(
mail_id=mail_id, rcpt=rcpt, secret_id=secret_id, content=content
))
@selfservice(viewmail_selfservice)
def viewmail(request, mail_id):
if request.user.group != 'SimpleUsers':
rcpt = request.GET["rcpt"]
@@ -175,7 +204,19 @@ def check_mail_id(request, mail_id):
mail_id = [mail_id]
return mail_id
@login_required
def delete_selfservice(request, mail_id):
rcpt = request.GET.get("rcpt", None)
if rcpt is None:
raise ModoboaException(_("Invalid request"))
try:
msgrcpt = Msgrcpt.objects.get(mail=mail_id, rid__email=rcpt)
msgrcpt.rs = 'D'
msgrcpt.save()
except Msgrcpt.DoesNotExist:
raise ModoboaException(_("Invalid request"))
return ajax_simple_response(dict(status="ok", respmsg=_("Message deleted")))
@selfservice(delete_selfservice)
def delete(request, mail_id):
mail_id = check_mail_id(request, mail_id)
if request.user.group == 'SimpleUsers':
@@ -195,15 +236,38 @@ def delete(request, mail_id):
return ajax_response(request, respmsg=message,
url=__get_current_url(request))
@login_required
def release_selfservice(request, mail_id):
rcpt = request.GET.get("rcpt", None)
secret_id = request.GET.get("secret_id", None)
if rcpt is None or secret_id is None:
raise ModoboaException(_("Invalid request"))
try:
msgrcpt = Msgrcpt.objects.get(mail=mail_id, rid__email=rcpt)
except Msgrcpt.DoesNotExist:
raise ModoboaException(_("Invalid request"))
if secret_id != msgrcpt.mail.secret_id:
raise ModoboaException(_("Invalid request"))
if parameters.get_admin("USER_CAN_RELEASE") == "no":
msgrcpt.rs = 'p'
msg = _("Request sent")
else:
amr = AMrelease()
result = amr.sendreq(mail_id, secret_id, rcpt)
if result:
rcpt.rs = 'R'
msg = _("Message released")
else:
raise ModoboaException(result)
msgrcpt.save()
return ajax_simple_response(dict(status="ok", respmsg=msg))
@selfservice(release_selfservice)
def release(request, mail_id):
mail_id = check_mail_id(request, mail_id)
if request.user.group == 'SimpleUsers':
mb = Mailbox.objects.get(user=request.user)
print mail_id
msgrcpts = Msgrcpt.objects.filter(mail__in=mail_id, rid__email=mb.full_address)
if parameters.get_admin("USER_CAN_RELEASE") == "no":
print msgrcpts
msgrcpts.update(rs='p')
message = ungettext("%(count)d request sent",
"%(count)d requests sent",
-1
View File
@@ -1,6 +1,5 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
{% load i18n %}
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://www.w3.org/2005/10/profile">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />