mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: Quarantine 'self-service'
First commit.
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'),
|
||||
)
|
||||
|
||||
@@ -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,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" />
|
||||
|
||||
Reference in New Issue
Block a user