mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Statistics plugin almost done. Needs more testing.
This commit is contained in:
@@ -39,7 +39,8 @@ def domain_menu(domain_id, selection, perms):
|
||||
"class" : "boxed",
|
||||
"rel" : "{handler:'iframe',size:{x:300,y:180}}"}
|
||||
]
|
||||
entries += events.raiseQueryEvent("AdminMenuDisplay", target="admin_menu_bar" , domain=domain_id)
|
||||
entries += events.raiseQueryEvent("AdminMenuDisplay", target="admin_menu_bar",
|
||||
perms=perms, domain=domain_id)
|
||||
return render_to_string('main/menu.html',
|
||||
{"selection" : selection, "entries" : entries,
|
||||
"perms" : perms})
|
||||
@@ -49,6 +50,13 @@ def settings_menu(selection):
|
||||
return render_to_string('admin/settings_menu.html',
|
||||
{"selection" : selection})
|
||||
|
||||
@register.simple_tag
|
||||
def loadadminextmenu(perms):
|
||||
menu = events.raiseQueryEvent("AdminMenuDisplay", target="admin_menu_box",
|
||||
perms=perms)
|
||||
return render_to_string('main/menulist.html',
|
||||
{"menu" : menu, "perms" : perms})
|
||||
|
||||
@register.filter
|
||||
def gender(value, target):
|
||||
if genders.has_key(value):
|
||||
|
||||
+5
-3
@@ -16,6 +16,7 @@ from forms import MailboxForm, DomainForm, AliasForm, PermissionForm
|
||||
from mailng.lib.authbackends import crypt_password
|
||||
from mailng.lib import _render, _ctx_ok, _ctx_ko
|
||||
from mailng.lib import events
|
||||
import string
|
||||
import copy
|
||||
|
||||
def is_superuser(user):
|
||||
@@ -29,9 +30,10 @@ def good_domain(f):
|
||||
if request.user.is_superuser:
|
||||
return f(request, dom_id, **kwargs)
|
||||
mb = Mailbox.objects.get(user=request.user.id)
|
||||
domid = isinstance(dom_id, str) and "%d" % dom_id or dom_id
|
||||
if domid == mb.domain.id:
|
||||
return f(request, domid, **kwargs)
|
||||
if isinstance(dom_id, str) or isinstance(dom_id, unicode):
|
||||
dom_id = string.atoi(dom_id)
|
||||
if dom_id == mb.domain.id:
|
||||
return f(request, dom_id, **kwargs)
|
||||
|
||||
from django.conf import settings
|
||||
path = urlquote(request.get_full_path())
|
||||
|
||||
@@ -43,13 +43,13 @@ def urls():
|
||||
include('mailng.extensions.amavis_quarantine.urls'))
|
||||
|
||||
def menu(**kwargs):
|
||||
if kwargs["target"] != "user_menu_box":
|
||||
return []
|
||||
return [
|
||||
{"name" : _("Quarantine"),
|
||||
"url" : reverse(index),
|
||||
"img" : "/static/pics/quarantine.png"}
|
||||
]
|
||||
if kwargs["target"] == "user_menu_box":
|
||||
return [
|
||||
{"name" : _("Quarantine"),
|
||||
"url" : reverse(index),
|
||||
"img" : "/static/pics/quarantine.png"}
|
||||
]
|
||||
return []
|
||||
|
||||
def lookup(*args):
|
||||
filter = ""
|
||||
|
||||
+46
-29
@@ -4,19 +4,48 @@ import os
|
||||
import time
|
||||
import datetime
|
||||
import rrdtool
|
||||
from django.utils.translation import ugettext as _
|
||||
from mailng.lib import getoption
|
||||
|
||||
default_avg_template = {
|
||||
traffic_avg_template = {
|
||||
'name' : 'traffic',
|
||||
'width' : '540',
|
||||
'height' : '100',
|
||||
'title' : 'average message flow per minute',
|
||||
'vertlabel' : 'msgs/min',
|
||||
'cf' : 'AVERAGE',
|
||||
'vars' : {
|
||||
'sent' : { "type" : "AREA", "color" : "#00FF00", "legend" : "sent messages" },
|
||||
'recv' : { "type" : "AREA", "color" : "#0000FF", "legend" : "received messages" },
|
||||
# 'bounced' : { "color" : "#FFFF00", "legend" : "bounced messages" },
|
||||
# 'reject' : { "color" : "#FF0000", "legend" : "rejected messages" },
|
||||
'sent' : { "type" : "AREA", "color" : "#00FF00",
|
||||
"legend" : _("sent messages") },
|
||||
'recv' : { "type" : "AREA", "color" : "#0000FF",
|
||||
"legend" : _("received messages") },
|
||||
}
|
||||
}
|
||||
|
||||
badtraffic_avg_template = {
|
||||
'name' : 'badtraffic',
|
||||
'width' : '540',
|
||||
'height' : '100',
|
||||
'vertlabel' : _('msgs/min'),
|
||||
'cf' : 'AVERAGE',
|
||||
'vars' : {
|
||||
'bounced' : { "type" : "AREA", "color" : "#FFFF00",
|
||||
"legend" : _("bounced messages") },
|
||||
'reject' : { "type" : "AREA", "color" : "#FF0000",
|
||||
"legend" : _("rejected messages") },
|
||||
}
|
||||
}
|
||||
|
||||
size_avg_template = {
|
||||
'name' : 'size',
|
||||
'width' : '540',
|
||||
'height' : '100',
|
||||
'vertlabel' : _('bytes/min'),
|
||||
'cf' : 'AVERAGE',
|
||||
'vars' : {
|
||||
'size_recv' : { "type" : "AREA", "color" : "#FF9900",
|
||||
"legend" : _("received size") },
|
||||
'size_sent' : { "type" : "AREA", "color" : "#339999",
|
||||
"legend" : _("sent size") },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +54,13 @@ class Grapher(object):
|
||||
self.rrd_rootdir = getoption("RRD_ROOTDIR", "/tmp")
|
||||
self.img_rootdir = getoption("IMG_ROOTDIR", "/tmp")
|
||||
|
||||
def process(self, target, suffix, start, end, tpl=default_avg_template):
|
||||
def process(self, target, suffix, start, end, tpl=traffic_avg_template):
|
||||
rrdfile = "%s/%s.rrd" % (self.rrd_rootdir, target)
|
||||
if not os.path.exists(rrdfile):
|
||||
return
|
||||
ext = "png"
|
||||
path = "%s/%s_%s_%s.%s" % (self.img_rootdir, target, tpl['cf'], suffix, ext)
|
||||
path = "%s/%s_%s_%s_%s.%s" % (self.img_rootdir, tpl['name'],
|
||||
target, tpl['cf'], suffix, ext)
|
||||
start = str(start)
|
||||
end = str(end)
|
||||
defs = []
|
||||
@@ -39,7 +69,8 @@ class Grapher(object):
|
||||
defs += ['DEF:%s=%s:%s:%s' % (v, rrdfile, v, tpl['cf']),
|
||||
'CDEF:%spm=%s,60,*' % (v, v)]
|
||||
type = d.has_key("type") and d["type"] or "LINE"
|
||||
lines += ["%s:%spm%s:%s" % (type, v, d["color"], d["legend"])]
|
||||
lines += ["%s:%spm%s:%s" % (type, v, d["color"],
|
||||
d["legend"].encode("utf-8"))]
|
||||
params = defs + lines
|
||||
rrdtool.graph(path,
|
||||
"--imgformat", "PNG",
|
||||
@@ -47,30 +78,16 @@ class Grapher(object):
|
||||
"--height", tpl["height"],
|
||||
"--start", start,
|
||||
"--end", end,
|
||||
"--vertical-label", tpl["vertlabel"],
|
||||
"--title", tpl["title"],
|
||||
"--vertical-label", tpl["vertlabel"].encode("utf-8"),
|
||||
"--lower-limit", "0",
|
||||
"--slope-mode",
|
||||
*params)
|
||||
|
||||
def make_defaults(self, target):
|
||||
#now = int(time.time())
|
||||
#start = now - (now % 86400)
|
||||
#end = start + 86400
|
||||
def make_defaults(self, target, tpl=traffic_avg_template):
|
||||
end = "now"
|
||||
self.process(target, "day", "-1day", end)
|
||||
|
||||
#today = datetime.date.today()
|
||||
#day = today.day - today.weekday()
|
||||
#weekbegin = datetime.date(today.year, today.month, day)
|
||||
#start = weekbegin.strftime("%Y%m%d")
|
||||
#end = "+1week"
|
||||
self.process(target, "week", "-1week", end)
|
||||
|
||||
# monthbegin = datetime.date(today.year, today.month, 1)
|
||||
# start = monthbegin.strftime("%Y%m%d")
|
||||
# end = "+1month"
|
||||
self.process(target, "month", "-1month", end)
|
||||
self.process(target, "year", "-1year", end)
|
||||
self.process(target, "day", "-1day", end, tpl)
|
||||
self.process(target, "week", "-1week", end, tpl)
|
||||
self.process(target, "month", "-1month", end, tpl)
|
||||
self.process(target, "year", "-1year", end, tpl)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import sys
|
||||
import os
|
||||
import re
|
||||
import rrdtool
|
||||
import string
|
||||
from optparse import OptionParser
|
||||
from mailng.lib import getoption
|
||||
from mailng.admin.models import Domain
|
||||
@@ -19,6 +20,8 @@ Postfix log parser.
|
||||
rrdstep = 60
|
||||
xpoints = 540
|
||||
points_per_sample = 3
|
||||
variables = ["sent", "recv", "bounced", "reject", "spam", "virus",
|
||||
"size_sent", "size_recv"]
|
||||
|
||||
class LogParser(object):
|
||||
def __init__(self, logfile, workdir,
|
||||
@@ -86,7 +89,7 @@ class LogParser(object):
|
||||
|
||||
# Set up data sources for our RRD
|
||||
params = []
|
||||
for v in ["sent", "recv", "bounced", "reject"]:
|
||||
for v in variables:
|
||||
params += ['DS:%s:%s:%s:0:U' % (v, ds_type, rrdstep * 2)]
|
||||
|
||||
# Set up RRD to archive data
|
||||
@@ -125,39 +128,54 @@ class LogParser(object):
|
||||
print "[rrd] VERBOSE events at %s already recorded in RRD" %m
|
||||
return False
|
||||
|
||||
tpl = ""
|
||||
for v in variables:
|
||||
if tpl != "":
|
||||
tpl += ":"
|
||||
tpl += v
|
||||
# Missing some RRD steps
|
||||
# Est ce vraiment nécessaire... ?
|
||||
if m > self.lupdates[fname] + rrdstep:
|
||||
values = ""
|
||||
for v in variables:
|
||||
if values != "": values += ":"
|
||||
values += "0"
|
||||
for p in range(self.lupdates[fname] + rrdstep, m, rrdstep):
|
||||
if self.verbose:
|
||||
print "[rrd] VERBOSE update %s:%s:%s:%s:%s (SKIP)" \
|
||||
%(p,'0','0','0','0')
|
||||
rrdtool.update(fname, "%s:%s:%s:%s:%s" \
|
||||
% (p, '0', '0', '0', '0'))
|
||||
rrdtool.update(fname, "-t", tpl, "%s:%s" % (p, values))
|
||||
|
||||
if self.verbose:
|
||||
print "[rrd] VERBOSE update %s:%s:%s:%s:%s" \
|
||||
%(m, self.data[dom][m]['sent'], self.data[dom][m]['recv'],\
|
||||
self.data[dom][m]['bounced'], self.data[dom][m]['reject'])
|
||||
|
||||
rrdtool.update(fname, "%s:%s:%s:%s:%s" \
|
||||
% (m, self.data[dom][m]['sent'],
|
||||
self.data[dom][m]['recv'],
|
||||
self.data[dom][m]['bounced'],
|
||||
self.data[dom][m]['reject']))
|
||||
values = "%s" % m
|
||||
tpl = ""
|
||||
for v in variables:
|
||||
values += ":"
|
||||
values += str(self.data[dom][m][v])
|
||||
if tpl != "":
|
||||
tpl += ":"
|
||||
tpl += v
|
||||
rrdtool.update(fname, "-t", tpl, values)
|
||||
self.lupdates[fname] = m
|
||||
return True
|
||||
|
||||
def inc_counter(self, dom, cur_t, counter):
|
||||
def initcounters(self, dom, cur_t):
|
||||
init = {}
|
||||
for v in variables: init[v] = 0
|
||||
self.data[dom][cur_t] = init
|
||||
|
||||
def inc_counter(self, dom, cur_t, counter, val=1):
|
||||
if not self.data[dom].has_key(cur_t):
|
||||
self.data[dom][cur_t] = \
|
||||
{'sent' : 0, 'recv' : 0, 'bounced' : 0, 'reject' : 0}
|
||||
self.data[dom][cur_t][counter] += 1
|
||||
self.initcounters(dom, cur_t)
|
||||
self.data[dom][cur_t][counter] += val
|
||||
|
||||
if not self.data["global"].has_key(cur_t):
|
||||
self.data["global"][cur_t] = \
|
||||
{'sent' : 0, 'recv' : 0, 'bounced' : 0, 'reject' : 0}
|
||||
self.data["global"][cur_t][counter] += 1
|
||||
self.initcounters("global", cur_t)
|
||||
self.data["global"][cur_t][counter] += val
|
||||
|
||||
def process(self):
|
||||
for line in self.f.readlines():
|
||||
@@ -170,9 +188,10 @@ class LogParser(object):
|
||||
cur_t = self.str2Time(self.year, mo, da, ho, mi, se)
|
||||
cur_t = cur_t - cur_t % rrdstep
|
||||
|
||||
m = re.search("(\w{10}): from=<(.*)>", log)
|
||||
m = re.search("(\w{10}): from=<(.*)>, size=(\d+)", log)
|
||||
if m:
|
||||
self.workdict[m.group(1)] = {'from' : m.group(2)}
|
||||
self.workdict[m.group(1)] = {'from' : m.group(2),
|
||||
'size' : string.atoi(m.group(3))}
|
||||
continue
|
||||
|
||||
m = re.search("(\w{10}): to=<(.*)>.*status=(\S+)", log)
|
||||
@@ -183,10 +202,14 @@ class LogParser(object):
|
||||
addrfrom = re.match("([^@]+)@(.+)", self.workdict[m.group(1)]['from'])
|
||||
if addrfrom and addrfrom.group(2) in self.domains:
|
||||
self.inc_counter(addrfrom.group(2), cur_t, 'sent')
|
||||
self.inc_counter(addrfrom.group(2), cur_t, 'size_sent',
|
||||
self.workdict[m.group(1)]['size'])
|
||||
addrto = re.match("([^@]+)@(.+)", m.group(2))
|
||||
if addrto.group(2) in self.domains:
|
||||
if m.group(3) == "sent":
|
||||
self.inc_counter(addrto.group(2), cur_t, 'recv')
|
||||
self.inc_counter(addrto.group(2), cur_t, 'size_recv',
|
||||
self.workdict[m.group(1)]['size'])
|
||||
else:
|
||||
self.inc_counter(addrto.group(2), cur_t, m.group(3))
|
||||
continue
|
||||
@@ -205,7 +228,10 @@ class LogParser(object):
|
||||
sortedData = [ (i, data[i]) for i in sorted(data.keys()) ]
|
||||
for t, dict in sortedData:
|
||||
self.update_rrd(dom, t)
|
||||
G.make_defaults(dom)
|
||||
|
||||
G.make_defaults(dom, tpl=grapher.traffic_avg_template)
|
||||
G.make_defaults(dom, tpl=grapher.badtraffic_avg_template)
|
||||
G.make_defaults(dom, tpl=grapher.size_avg_template)
|
||||
|
||||
if __name__ == "__main__":
|
||||
log_file = getoption("LOGFILE", "/var/log/maillog")
|
||||
|
||||
+41
-31
@@ -11,38 +11,36 @@ from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf.urls.defaults import *
|
||||
from mailng.lib import events, _render
|
||||
from mailng.admin.views import is_superuser
|
||||
from mailng.admin.views import good_domain
|
||||
from mailng.admin.models import Domain, Mailbox
|
||||
#from mailng.extensions.stats.mailrrd import parser
|
||||
from django.contrib.auth.decorators \
|
||||
import login_required
|
||||
import pdb
|
||||
import login_required, user_passes_test, permission_required
|
||||
|
||||
graph_nature = ["sent_recv","boun_reje"]
|
||||
graph_types = ["AVERAGE","MAX"]
|
||||
tmp_path = "static/tmp"
|
||||
graph_types = ['AVERAGE', 'MAX']
|
||||
|
||||
def init():
|
||||
events.register("AdminMenuDisplay", menu)
|
||||
events.register("AdminMenuDisplay", menu)
|
||||
|
||||
def urls():
|
||||
return (r'^mailng/stats/',
|
||||
include('mailng.extensions.stats.urls'))
|
||||
|
||||
|
||||
def menu(**kwargs):
|
||||
print kwargs
|
||||
domain_id = kwargs['domain']
|
||||
if kwargs["target"] == "admin_menu_bar":
|
||||
domain_id = kwargs['domain']
|
||||
return [
|
||||
{"label" : _("Statistics"),
|
||||
"name" : "stats",
|
||||
"url" : reverse('domindex', args=[domain_id]),
|
||||
"img" : "/static/pics/graph.png"}
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
if kwargs["target"] == "admin_menu_box":
|
||||
return [
|
||||
{"name" : _("Statistics"),
|
||||
"url" : reverse('fullindex'),
|
||||
"img" : "/static/pics/graph.png"}
|
||||
]
|
||||
return []
|
||||
|
||||
@login_required
|
||||
def domain(request,dom_id):
|
||||
@@ -82,26 +80,38 @@ def graph_display(request,dom_id,graph_t=graph_types):
|
||||
"domain":domain,"domains" : domains, "messages" : errors ,
|
||||
"types" : graph_type, "tmp_path" : tmp_path})
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def adminindex(request):
|
||||
period = request.GET.has_key("period") and request.GET["period"] or "day"
|
||||
domain = request.GET.has_key("domain") and request.GET["domain"] or "global"
|
||||
if domain != "global":
|
||||
domain = Domain.objects.get(pk=domain)
|
||||
domain = domain.name
|
||||
domains = Domain.objects.all()
|
||||
return _render(request, 'stats/adminindex.html', {
|
||||
"domains" : domains, "domain" : domain,
|
||||
"graphs" : {"traffic" : _("Average normal traffic"),
|
||||
"badtraffic" : _("Average bad traffic"),
|
||||
"size" : _("Average normal traffic size")},
|
||||
"periods" : ["day", "week", "month", "year"],
|
||||
"period" : period
|
||||
})
|
||||
|
||||
@login_required
|
||||
@good_domain
|
||||
@permission_required("admin.view_mailboxes")
|
||||
def index(request, dom_id=None):
|
||||
domains = []
|
||||
errors = []
|
||||
domain = None
|
||||
if dom_id:
|
||||
if request.user.has_perm("admin.view_mailboxes"):
|
||||
domain = Domain.objects.get(pk=dom_id)
|
||||
if domain:
|
||||
domains.append(domain)
|
||||
else:
|
||||
print "pas de dom"
|
||||
else:
|
||||
domains = Domain.objects.all()
|
||||
period = request.GET.has_key("period") and request.GET["period"] or "day"
|
||||
if request.user.has_perm("admin.view_mailboxes"):
|
||||
domain = Domain.objects.get(pk=dom_id)
|
||||
|
||||
if domains == []:
|
||||
errors.append(_("No Domain defined"))
|
||||
return _render(request, 'stats/index.html', {
|
||||
"page" : "Statistics",
|
||||
"domain" : domain, "domains": domains, "messages" : errors ,
|
||||
"periods" : ["day", "week", "month", "year"]
|
||||
})
|
||||
"domain" : domain,
|
||||
"graphs" : {"traffic" : _("Average normal traffic"),
|
||||
"badtraffic" : _("Average bad traffic"),
|
||||
"size" : _("Average normal traffic size")},
|
||||
"periods" : ["day", "week", "month", "year"],
|
||||
"period" : period
|
||||
})
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{% extends "layout.html" %}
|
||||
{% load i18n %}
|
||||
{% load stats_extra %}
|
||||
{% block html_head %}
|
||||
<script src="/static/js/mootools-more.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/stylesheets/box.css" />
|
||||
<style type="text/css">
|
||||
#graphcontent {
|
||||
margin: 25px auto 10px;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
#selectors {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.addEvent("domready", function() {
|
||||
$("period").addEvent("change", function(event) {
|
||||
{% url extensions.stats.main.adminindex as stats_url %}
|
||||
location.href = "{{ stats_url }}" + "?period=" + $("period").value;
|
||||
});
|
||||
$("domain").addEvent("change", function(event) {
|
||||
{% url extensions.stats.main.adminindex as stats_url %}
|
||||
location.href = "{{ stats_url }}" + "?domain=" + $("domain").value;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block middletitle %}{% trans "Global statistics" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div id="graphcontent">
|
||||
<div id="selectors">
|
||||
<label for="domain">{% trans "Domain:" %}</label>
|
||||
<select id="domain" name="domain">
|
||||
<option value="global" {% ifequal domain "global" %}selected{% endifequal %}>{% trans "Global" %}</option>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}" {% ifequal d.name domain %}selected{% endifequal %}>{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="period">{% trans "Period:" %}</label>
|
||||
<select id="period" name="period">
|
||||
{% for p in periods %}
|
||||
<option value="{{ p }}" {% ifequal p period %}selected{% endifequal %}>{% getLabel p %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% include "stats/graphs.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% load i18n %}
|
||||
{% for g, title in graphs.items %}
|
||||
<h3>{{ title }}</h3>
|
||||
<p><img src="/static/graphs/{{ g }}_{{ domain }}_AVERAGE_{{ period }}.png"
|
||||
alt="{% trans 'No statistics available' %}" /></p>
|
||||
{% endfor %}
|
||||
@@ -1,34 +1,21 @@
|
||||
{% extends "layout.html" %}
|
||||
{% extends "admin/domain_header.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<script src="/static/js/mootools-more.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/stylesheets/box.css" />
|
||||
<style type="text/css">
|
||||
form {
|
||||
margin: 0 auto;
|
||||
width: 98%;
|
||||
#selectors {
|
||||
float: right;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: smaller;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
errors {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin: 20px 20px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
#graphcontent {
|
||||
margin:60px auto 10px;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.addEvent("domready", function() {
|
||||
$("period").addEvent("change", function(event) {
|
||||
{% url extensions.stats.main.index domain.id as stats_url %}
|
||||
location.href = "{{ stats_url }}" + "?period=" + $("period").value;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -38,45 +25,15 @@
|
||||
{% domain_menu domain.id "stats" perms %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block middletitle %}
|
||||
{% if domain %}
|
||||
{% trans "Statistics for" %} {{ domain.name }}
|
||||
{% else %}
|
||||
{% trans "Global statistics" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div id="graphcontent">
|
||||
<table>
|
||||
{% if domain %}
|
||||
{% for p in periods %}
|
||||
<tr>
|
||||
<td>
|
||||
<img src="/static/graphs/{{ domain.name }}_AVERAGE_{{ p }}.png" alt="No statistics available" />
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% if domains %}
|
||||
<tr>
|
||||
<th width="50px">{% trans "Graph type" %}</th>
|
||||
<th width="80px">{% trans "Domain name" %}</th>
|
||||
</tr>
|
||||
|
||||
{% for dom in domains %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<td>
|
||||
{% for t in types %}
|
||||
{% url extensions.stats.main.graph_display dom.id,t as graphurl %}
|
||||
<a name="loadGraph" href="{{ graphurl }}">{{ t|lower }} </a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% url extensions.stats.main.domain dom.id as domurl %}
|
||||
<td><a name="loadDom" href="{{ domurl }}">{{ dom.name }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</table>
|
||||
{% block domcontent %}
|
||||
<div id="selectors">
|
||||
<label for="period">{% trans "Period:" %}</label>
|
||||
<select id="period" name="period">
|
||||
{% for p in periods %}
|
||||
<option value="{{ p }}" {% ifequal p period %}selected{% endifequal %}>{{ p }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% include "stats/graphs.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
from django import template
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def getLabel(var):
|
||||
labels = {
|
||||
"day" : _("Day"),
|
||||
"week" : _("Week"),
|
||||
"month" : _("Month"),
|
||||
"year" : _("Year")
|
||||
}
|
||||
return labels.has_key(var) and labels[var] or var
|
||||
@@ -1,7 +1,7 @@
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('mailng.extensions.stats.main',
|
||||
url(r'^$', 'index', name='fullindex'),
|
||||
url(r'^$', 'adminindex', name='fullindex'),
|
||||
url(r'^(?P<dom_id>\d+)/$', 'index', name='domindex'),
|
||||
(r'^display/(?P<dom_id>\d+)/(?P<graph_t>\w+)/$', 'graph_display'),
|
||||
(r'^domain/(?P<dom_id>\d+)/$', 'domain'),
|
||||
|
||||
+149
-81
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-10-30 11:19+0100\n"
|
||||
"POT-Creation-Date: 2009-11-03 15:22+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -17,64 +17,69 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin/forms.py:16 templates/admin/domains.html:17
|
||||
#: templates/admin/mailboxes.html:18
|
||||
#: templates/admin/mailboxes.html:17
|
||||
msgid "Quota"
|
||||
msgstr ""
|
||||
|
||||
#: admin/forms.py:17
|
||||
msgid "Mailbox quota in MB (default to domain quota if blank)"
|
||||
msgstr ""
|
||||
"Quota en Mo de la boite aux lettres (par défaut celui du domaine si vide)"
|
||||
|
||||
#: admin/forms.py:18
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: admin/forms.py:18
|
||||
#: admin/forms.py:19
|
||||
msgid "Password used to log in"
|
||||
msgstr "Mot de passe utilisé pour se connecter"
|
||||
|
||||
#: admin/forms.py:19 main/forms.py:21
|
||||
#: admin/forms.py:20 main/forms.py:21
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
#: admin/forms.py:20
|
||||
#: admin/forms.py:21
|
||||
msgid "Password confirmation"
|
||||
msgstr "Confirmation du mot de passe"
|
||||
|
||||
#: admin/forms.py:23
|
||||
#: admin/forms.py:24
|
||||
msgid "Check to activate this mailbox"
|
||||
msgstr "Cocher pour activer cette boite aux lettres"
|
||||
|
||||
#: admin/forms.py:36 main/forms.py:36
|
||||
#: admin/forms.py:37 main/forms.py:36
|
||||
msgid "Passwords mismatch"
|
||||
msgstr "Les mots de passe diffèrent"
|
||||
|
||||
#: admin/forms.py:55 templates/admin/domain_header.html:7
|
||||
#: admin/forms.py:56 templates/admin/domain_header.html:6
|
||||
#: templates/admin/editdomain.html:7 templates/admin/permissions.html:42
|
||||
msgid "Domain"
|
||||
msgstr "Domaine"
|
||||
|
||||
#: admin/forms.py:57
|
||||
#: admin/forms.py:58
|
||||
msgid "Select a domain in the list"
|
||||
msgstr "Sélectionner un domaine dans la liste"
|
||||
|
||||
#: admin/forms.py:58
|
||||
#: admin/forms.py:59
|
||||
msgid "User"
|
||||
msgstr "Utilisateur"
|
||||
|
||||
#: admin/forms.py:59
|
||||
#: admin/forms.py:60
|
||||
msgid "Select a user in the list"
|
||||
msgstr "Sélectionner un utilisateur dans la liste"
|
||||
|
||||
#: admin/forms.py:60
|
||||
#: admin/forms.py:61
|
||||
msgid "Role"
|
||||
msgstr "Rôle"
|
||||
|
||||
#: admin/forms.py:61
|
||||
#: admin/forms.py:62
|
||||
msgid "Super administrator"
|
||||
msgstr "Super administrateur"
|
||||
|
||||
#: admin/forms.py:62
|
||||
#: admin/forms.py:63
|
||||
msgid "Domain administrator"
|
||||
msgstr "Admin. de domaine"
|
||||
|
||||
#: admin/forms.py:63
|
||||
#: admin/forms.py:64
|
||||
msgid "Select the role you want this user to have"
|
||||
msgstr "Sélectionner le rôle souhaité pour cet utilisateur"
|
||||
|
||||
@@ -114,11 +119,6 @@ msgstr "Adresse de la boite aux lettres (sans la partie @domain.tld)"
|
||||
msgid "password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: admin/models.py:44
|
||||
msgid "Mailbox quota in MB (default to domain quota if blank)"
|
||||
msgstr ""
|
||||
"Quota en Mo de la boite aux lettres (par défaut celui du domaine si vide)"
|
||||
|
||||
#: admin/models.py:107
|
||||
msgid "The alias address (without the domain part)"
|
||||
msgstr "L'adresse de l'alias (sans la partie domaine)"
|
||||
@@ -135,44 +135,44 @@ msgstr "La boite aux lettres sur laquelle pointe cet alias"
|
||||
msgid "Check to activate this alias"
|
||||
msgstr "Cocher pour activer cet alias"
|
||||
|
||||
#: admin/views.py:23
|
||||
#: admin/views.py:24
|
||||
msgid "Permission denied."
|
||||
msgstr "Permission refusée."
|
||||
|
||||
#: admin/views.py:67 admin/views.py:97
|
||||
#: admin/views.py:69 admin/views.py:99
|
||||
msgid "Domain with this name already defined"
|
||||
msgstr "Un domaine avec ce nom existe déjà"
|
||||
|
||||
#: admin/views.py:76
|
||||
#: admin/views.py:78
|
||||
msgid "Failed to initialise domain, check permissions"
|
||||
msgstr "Impossible d'initialiser le domaine, vérifier les permissions"
|
||||
|
||||
#: admin/views.py:100
|
||||
#: admin/views.py:102
|
||||
msgid "Failed to rename domain, check permissions"
|
||||
msgstr "Impossible de renommer le domaine, vérifier les permissions"
|
||||
|
||||
#: admin/views.py:154 admin/views.py:213
|
||||
#: admin/views.py:156 admin/views.py:215
|
||||
msgid "Mailbox with this address already exists"
|
||||
msgstr "Une boite aux lettres pour cette adresse existe déjà"
|
||||
|
||||
#: admin/views.py:185
|
||||
#: admin/views.py:187
|
||||
msgid "Mailbox created."
|
||||
msgstr "Boite aux lettres créé."
|
||||
|
||||
#: admin/views.py:189
|
||||
#: admin/views.py:191
|
||||
msgid "Failed to initialise mailbox, check permissions"
|
||||
msgstr ""
|
||||
"Impossible d'initialiser la boite aux lettres, vérifier les permissions"
|
||||
|
||||
#: admin/views.py:216
|
||||
#: admin/views.py:218
|
||||
msgid "Failed to rename mailbox, check permissions"
|
||||
msgstr "Impossible de renommer la boite aux lettres, vérifier les permissions."
|
||||
|
||||
#: admin/views.py:292 admin/views.py:322
|
||||
#: admin/views.py:294 admin/views.py:324
|
||||
msgid "Alias with this address already exists"
|
||||
msgstr "Un alias avec cette adresse existe déjà"
|
||||
|
||||
#: admin/views.py:395
|
||||
#: admin/views.py:397
|
||||
msgid "admin is intouchable!!"
|
||||
msgstr "admin est intouchable!!"
|
||||
|
||||
@@ -200,8 +200,8 @@ msgstr "Alias"
|
||||
msgid "Properties"
|
||||
msgstr "Propriétés"
|
||||
|
||||
#: extensions/amavis_quarantine/main.py:49
|
||||
#: extensions/amavis_quarantine/templates/index.html:153
|
||||
#: extensions/amavis_quarantine/main.py:48
|
||||
#: extensions/amavis_quarantine/templates/index.html:152
|
||||
msgid "Quarantine"
|
||||
msgstr "Quarantaine"
|
||||
|
||||
@@ -215,29 +215,29 @@ msgstr "%(count)d message%(plural)s supprimé correctement"
|
||||
msgid "%(count)d message%(plural)s released successfully"
|
||||
msgstr "%(count)d messages relâché correctement"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:95
|
||||
#: extensions/amavis_quarantine/templates/index.html:94
|
||||
msgid "Delete this selection?"
|
||||
msgstr "Supprimer cette sélection?"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:102
|
||||
#: extensions/amavis_quarantine/templates/index.html:101
|
||||
msgid "Release this selection?"
|
||||
msgstr "Relâcher cette sélection?"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:136
|
||||
#: extensions/amavis_quarantine/templates/index.html:158
|
||||
#: extensions/amavis_quarantine/templates/index.html:135
|
||||
#: extensions/amavis_quarantine/templates/index.html:157
|
||||
msgid "Search..."
|
||||
msgstr "Chercher..."
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:160
|
||||
#: extensions/amavis_quarantine/templates/index.html:159
|
||||
msgid "From address"
|
||||
msgstr "Emetteur"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:161
|
||||
#: extensions/amavis_quarantine/templates/index.html:160
|
||||
#: extensions/amavis_quarantine/templates/listing.html:35
|
||||
msgid "Subject"
|
||||
msgstr "Sujet"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/index.html:162
|
||||
#: extensions/amavis_quarantine/templates/index.html:161
|
||||
msgid "Both"
|
||||
msgstr "Tous"
|
||||
|
||||
@@ -277,11 +277,11 @@ msgstr ""
|
||||
msgid "Message headers"
|
||||
msgstr "Entêtes du message"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/viewmail.html:32
|
||||
#: extensions/amavis_quarantine/templates/viewmail.html:22
|
||||
msgid "Mail content"
|
||||
msgstr "Contenu du message"
|
||||
|
||||
#: extensions/amavis_quarantine/templates/viewmail.html:41
|
||||
#: extensions/amavis_quarantine/templates/viewmail.html:31
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
@@ -327,29 +327,98 @@ msgstr "Supprimer ce message?"
|
||||
msgid "Options"
|
||||
msgstr ""
|
||||
|
||||
#: extensions/dummy_plugin/main.py:17
|
||||
msgid "Dummy"
|
||||
msgstr ""
|
||||
|
||||
#: extensions/postfix_autoreply/main.py:35
|
||||
msgid "Auto-reply message"
|
||||
msgstr "Message de réponse automatique"
|
||||
|
||||
#: extensions/stats/main.py:39
|
||||
#: extensions/stats/grapher.py:18
|
||||
msgid "sent messages"
|
||||
msgstr "messages envoyés"
|
||||
|
||||
#: extensions/stats/grapher.py:20
|
||||
msgid "received messages"
|
||||
msgstr "messages reçus"
|
||||
|
||||
#: extensions/stats/grapher.py:28
|
||||
msgid "msgs/min"
|
||||
msgstr ""
|
||||
|
||||
#: extensions/stats/grapher.py:32
|
||||
msgid "bounced messages"
|
||||
msgstr "messages ?"
|
||||
|
||||
#: extensions/stats/grapher.py:34
|
||||
msgid "rejected messages"
|
||||
msgstr "messages rejetés"
|
||||
|
||||
#: extensions/stats/grapher.py:42
|
||||
msgid "bytes/min"
|
||||
msgstr "octes/min"
|
||||
|
||||
#: extensions/stats/grapher.py:46
|
||||
msgid "received size"
|
||||
msgstr "taille reçue"
|
||||
|
||||
#: extensions/stats/grapher.py:48
|
||||
msgid "sent size"
|
||||
msgstr "taille envoyée"
|
||||
|
||||
#: extensions/stats/main.py:32 extensions/stats/main.py:39
|
||||
msgid "Statistics"
|
||||
msgstr "Statistiques"
|
||||
|
||||
#: extensions/stats/main.py:66 extensions/stats/main.py:95
|
||||
#: extensions/stats/main.py:68
|
||||
msgid "No Domain defined"
|
||||
msgstr "Aucun domaine défini."
|
||||
|
||||
#: extensions/stats/templates/index.html:62
|
||||
msgid "Graph type"
|
||||
#: extensions/stats/main.py:94 extensions/stats/main.py:112
|
||||
msgid "Average normal traffic"
|
||||
msgstr "Trafic normal moyen"
|
||||
|
||||
#: extensions/stats/main.py:95 extensions/stats/main.py:113
|
||||
msgid "Average bad traffic"
|
||||
msgstr "Mauvais trafic moyen"
|
||||
|
||||
#: extensions/stats/main.py:96 extensions/stats/main.py:114
|
||||
msgid "Average normal traffic size"
|
||||
msgstr "Taille moyenne du trafic moyen"
|
||||
|
||||
#: extensions/stats/templates/adminindex.html:31
|
||||
msgid "Global statistics"
|
||||
msgstr "Statistiques globales"
|
||||
|
||||
#: extensions/stats/templates/adminindex.html:35
|
||||
msgid "Domain:"
|
||||
msgstr "Domaine :"
|
||||
|
||||
#: extensions/stats/templates/adminindex.html:37
|
||||
msgid "Global"
|
||||
msgstr ""
|
||||
|
||||
#: extensions/stats/templates/index.html:63
|
||||
msgid "Domain name"
|
||||
msgstr "Nom du domaine"
|
||||
#: extensions/stats/templates/adminindex.html:43
|
||||
#: extensions/stats/templates/index.html:30
|
||||
msgid "Period:"
|
||||
msgstr "Période :"
|
||||
|
||||
#: extensions/stats/templates/graphs.html:5
|
||||
msgid "No statistics available"
|
||||
msgstr "Aucune statistique disponible"
|
||||
|
||||
#: extensions/stats/templatetags/stats_extra.py:9
|
||||
msgid "Day"
|
||||
msgstr "Jour"
|
||||
|
||||
#: extensions/stats/templatetags/stats_extra.py:10
|
||||
msgid "Week"
|
||||
msgstr "Semaine"
|
||||
|
||||
#: extensions/stats/templatetags/stats_extra.py:11
|
||||
msgid "Month"
|
||||
msgstr "Mois"
|
||||
|
||||
#: extensions/stats/templatetags/stats_extra.py:12
|
||||
msgid "Year"
|
||||
msgstr "Année"
|
||||
|
||||
#: main/forms.py:17
|
||||
msgid "Old password"
|
||||
@@ -371,10 +440,6 @@ msgstr "sujet"
|
||||
msgid "content"
|
||||
msgstr "contenu"
|
||||
|
||||
#: main/models.py:10
|
||||
msgid "until"
|
||||
msgstr ""
|
||||
|
||||
#: main/views.py:45
|
||||
msgid "Auto reply message updated successfully."
|
||||
msgstr "Message de réponse auto. mis à jour."
|
||||
@@ -383,27 +448,27 @@ msgstr "Message de réponse auto. mis à jour."
|
||||
msgid "Change password"
|
||||
msgstr "Changer de mot de passe"
|
||||
|
||||
#: templates/layout.html:42
|
||||
#: templates/layout.html:44
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: templates/layout.html:49
|
||||
#: templates/layout.html:51
|
||||
msgid "Preferences"
|
||||
msgstr "Préférences"
|
||||
|
||||
#: templates/layout.html:56
|
||||
#: templates/layout.html:58
|
||||
msgid "Logout"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: templates/layout.html:69 templates/admin/newdomain.html:7
|
||||
#: templates/layout.html:72 templates/admin/newdomain.html:7
|
||||
msgid "New domain"
|
||||
msgstr "Nouveau domaine"
|
||||
|
||||
#: templates/layout.html:76
|
||||
#: templates/layout.html:79
|
||||
msgid "Domains"
|
||||
msgstr "Domaines"
|
||||
|
||||
#: templates/layout.html:83 templates/admin/settings_header.html:6
|
||||
#: templates/layout.html:86 templates/admin/settings_header.html:6
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
@@ -416,34 +481,34 @@ msgstr "Ajouter une permission"
|
||||
msgid "Create"
|
||||
msgstr "Créer"
|
||||
|
||||
#: templates/admin/aliases.html:10
|
||||
#: templates/admin/aliases.html:9
|
||||
msgid "No alias defined."
|
||||
msgstr "Aucun alias défini."
|
||||
|
||||
#: templates/admin/aliases.html:14 templates/admin/domains.html:14
|
||||
#: templates/admin/mailboxes.html:15 templates/admin/permissions.html:14
|
||||
#: templates/admin/aliases.html:13 templates/admin/domains.html:14
|
||||
#: templates/admin/mailboxes.html:14 templates/admin/permissions.html:14
|
||||
#: templates/admin/permissions.html:41
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/admin/aliases.html:15 templates/admin/mailboxes.html:17
|
||||
#: templates/admin/aliases.html:14 templates/admin/mailboxes.html:16
|
||||
msgid "Address"
|
||||
msgstr "Adresse"
|
||||
|
||||
#: templates/admin/aliases.html:16 templates/admin/editmailbox.html:7
|
||||
#: templates/admin/aliases.html:15 templates/admin/editmailbox.html:7
|
||||
msgid "Mailbox"
|
||||
msgstr "Boite aux lettres"
|
||||
|
||||
#: templates/admin/aliases.html:17 templates/admin/domains.html:18
|
||||
#: templates/admin/aliases.html:16 templates/admin/domains.html:18
|
||||
#: templates/admin/permissions.html:17 templates/admin/permissions.html:44
|
||||
msgid "Enabled"
|
||||
msgstr "Activé"
|
||||
|
||||
#: templates/admin/aliases.html:25
|
||||
#: templates/admin/aliases.html:24
|
||||
msgid "Edit alias"
|
||||
msgstr "Editer cet alias"
|
||||
|
||||
#: templates/admin/aliases.html:29
|
||||
#: templates/admin/aliases.html:28
|
||||
msgid "Delete alias"
|
||||
msgstr "Supprimer cet alias"
|
||||
|
||||
@@ -455,7 +520,7 @@ msgstr "Domaines disponibles"
|
||||
msgid "No domain defined."
|
||||
msgstr "Aucun domaine défini."
|
||||
|
||||
#: templates/admin/domains.html:15 templates/admin/mailboxes.html:16
|
||||
#: templates/admin/domains.html:15 templates/admin/mailboxes.html:15
|
||||
#: templates/admin/permissions.html:43
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
@@ -468,37 +533,37 @@ msgstr "Editer le domaine"
|
||||
msgid "Delete domain"
|
||||
msgstr "Supprimer le domaine"
|
||||
|
||||
#: templates/admin/domains.html:36 templates/admin/mailboxes.html:46
|
||||
#: templates/admin/domains.html:36 templates/admin/mailboxes.html:45
|
||||
msgid "MB"
|
||||
msgstr "Mo"
|
||||
|
||||
#: templates/admin/domains.html:37 templates/admin/mailboxes.html:47
|
||||
#: templates/admin/domains.html:37 templates/admin/mailboxes.html:46
|
||||
msgid "yes,no"
|
||||
msgstr "oui,non"
|
||||
|
||||
#: templates/admin/editalias.html:14 templates/admin/editdomain.html:15
|
||||
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:19
|
||||
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:17
|
||||
#: templates/main/chpassword.html:15
|
||||
msgid "Update"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
#: templates/admin/mailboxes.html:11
|
||||
#: templates/admin/mailboxes.html:10
|
||||
msgid "No mailbox defined."
|
||||
msgstr "Aucune boite aux lettres définie."
|
||||
|
||||
#: templates/admin/mailboxes.html:27
|
||||
#: templates/admin/mailboxes.html:26
|
||||
msgid "Edit mailbox"
|
||||
msgstr "Editer la boite aux lettres"
|
||||
|
||||
#: templates/admin/mailboxes.html:32
|
||||
#: templates/admin/mailboxes.html:31
|
||||
msgid "Delete mailbox"
|
||||
msgstr "Supprimer la boite aux lettres"
|
||||
|
||||
#: templates/admin/mailboxes.html:37
|
||||
#: templates/admin/mailboxes.html:36
|
||||
msgid "Add new alias"
|
||||
msgstr "Ajouter un alias"
|
||||
|
||||
#: templates/admin/mailboxes.html:41
|
||||
#: templates/admin/mailboxes.html:40
|
||||
msgid "Mailbox aliases"
|
||||
msgstr "Alias de cette boite aux lettres"
|
||||
|
||||
@@ -538,11 +603,11 @@ msgstr "Aucun admin de domaine défini."
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/main/confirm.html:26
|
||||
#: templates/main/confirm.html:25
|
||||
msgid "Do not delete mailbox directory"
|
||||
msgstr "Ne pas supprimer le répertoire de la boite aux lettres"
|
||||
|
||||
#: templates/main/header.html:8
|
||||
#: templates/main/header.html:6
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
@@ -563,3 +628,6 @@ msgid "Your username and password didn't match. Please try again."
|
||||
msgstr ""
|
||||
"Votre nom d'utilisateur et mot de passe ne correspondent pas. Veuillez "
|
||||
"réessayer."
|
||||
|
||||
#~ msgid "Domain name"
|
||||
#~ msgstr "Nom du domaine"
|
||||
|
||||
@@ -25,6 +25,7 @@ def menu(selection, perms):
|
||||
|
||||
@register.simple_tag
|
||||
def loadextmenu(perms):
|
||||
menu = events.raiseQueryEvent("UserMenuDisplay", target="user_menu_box")
|
||||
menu = events.raiseQueryEvent("UserMenuDisplay", target="user_menu_box",
|
||||
perms=perms)
|
||||
return render_to_string('main/menulist.html',
|
||||
{"menu" : menu, "perms" : perms})
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
</div>
|
||||
<br/>
|
||||
{% if user.is_superuser %}
|
||||
{% load admin_extras %}
|
||||
<div id="menubox" class="leftbox">
|
||||
<ul>
|
||||
<li>
|
||||
@@ -85,6 +86,7 @@
|
||||
{% trans "Settings" %}
|
||||
</a>
|
||||
</li>
|
||||
{% loadadminextmenu perms %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user