wip: stats extension layout

New layout is done. Now it's time to open this extension to the others.

see #333
This commit is contained in:
Antoine Nguyen
2012-10-28 18:30:25 +01:00
parent 68af0db6f2
commit b969575bdf
7 changed files with 115 additions and 130 deletions
@@ -0,0 +1,51 @@
# coding: utf-8
from django.utils.translation import ugettext_lazy
class MailTrafic(object):
pass
traffic_avg_template = {
'name' : 'traffic',
'title' : ugettext_lazy("Average normal traffic"),
'width' : '540',
'height' : '120',
'vertlabel' : ugettext_lazy('msgs/min'),
'cf' : 'AVERAGE',
'vars' : {
'sent' : { "type" : "AREA", "color" : "#00FF00",
"legend" : ugettext_lazy("sent messages") },
'recv' : { "type" : "AREA", "color" : "#0000FF",
"legend" : ugettext_lazy("received messages") },
}
}
badtraffic_avg_template = {
'name' : 'badtraffic',
'title' : ugettext_lazy("Average bad traffic"),
'width' : '540',
'height' : '120',
'vertlabel' : ugettext_lazy('msgs/min'),
'cf' : 'AVERAGE',
'vars' : {
'bounced' : { "type" : "AREA", "color" : "#FFFF00",
"legend" : ugettext_lazy("bounced messages") },
'reject' : { "type" : "AREA", "color" : "#FF0000",
"legend" : ugettext_lazy("rejected messages") },
}
}
size_avg_template = {
'name' : 'size',
'title' : ugettext_lazy("Average normal traffic size"),
'width' : '540',
'height' : '120',
'vertlabel' : ugettext_lazy('bytes/min'),
'cf' : 'AVERAGE',
'vars' : {
'size_recv' : { "type" : "AREA", "color" : "#FF9900",
"legend" : ugettext_lazy("received size") },
'size_sent' : { "type" : "AREA", "color" : "#339999",
"legend" : ugettext_lazy("sent size") },
}
}
+13 -53
View File
@@ -1,57 +1,11 @@
# -*- coding: utf-8 -*-
# coding: utf-8
import sys, os
import time
import datetime
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.lib import parameters
traffic_avg_template = {
'name' : 'traffic',
'width' : '540',
'height' : '100',
'vertlabel' : 'msgs/min',
'cf' : 'AVERAGE',
'vars' : {
'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") },
}
}
tpl = {'traffic':traffic_avg_template,
'badtraffic':badtraffic_avg_template,
'size':size_avg_template}
def str2Time(y, M, d, h="0", m="0", s="0"):
"""Date conversion
@@ -77,7 +31,7 @@ class Grapher(object):
self.rrd_rootdir = parameters.get_admin("RRD_ROOTDIR")
self.img_rootdir = parameters.get_admin("IMG_ROOTDIR")
def process(self, target, suffix, start, end, tpl=traffic_avg_template):
def process(self, target, suffix, start, end, tpl):
import rrdtool
rrdfile = "%s/%s.rrd" % (self.rrd_rootdir, target)
@@ -90,12 +44,17 @@ class Grapher(object):
end = str(end)
defs = []
lines = []
defs.append('COMMENT: %s %s %s %s\\c' % ("From", start, "to", end))
defs.append('COMMENT:\\s')
for v, d in tpl["vars"].iteritems():
defs += [str('DEF:%s=%s:%s:%s' % (v, rrdfile, v, tpl['cf'])),
str('CDEF:%spm=%s,60,*' % (v, v))]
str('CDEF:%spm=%s,60,*' % (v, v)),
str('VDEF:%s_total=%s,TOTAL' % (v, v))]
type = d.has_key("type") and d["type"] or "LINE"
lines += [str("%s:%spm%s:%s" % (type, v, d["color"],
d["legend"].encode("utf-8")))]
lines += [str("%s:%spm%s:%s:STACK" % (type, v, d["color"],
(d["legend"].encode("utf8")).ljust(20)))]
lines.append('GPRINT:%s_total:%s%%7.0lf%%s\\l' % (v, _("Total").encode('utf-8')))
params = defs + lines
rrdtool.graph(str(path),
"--imgformat", "PNG",
@@ -107,12 +66,13 @@ class Grapher(object):
"--lower-limit", "0",
"--slope-mode",
"--units-exponent", "0",
"--title", tpl["title"].encode("utf-8"),
*params)
if not os.path.exists(path):
print "[graph] Impossible to create %s graph" %path
def make_defaults(self, target, tpl=traffic_avg_template):
def make_defaults(self, target, tpl):
end = "%d" % int(time.mktime(time.localtime()))
self.process(target, "day", "-1day", end, tpl)
self.process(target, "week", "-1week", end, tpl)
@@ -1,24 +0,0 @@
#fixed_content {
padding: 0 15px;
}
#searchform {
float: left;
margin-right: 10px;
margin-bottom: 0px;
}
#menubar {
clear: both;
}
#graphs {
margin-top: 15px;
}
#period {
}
#custom-period {
margin-left: 10px;
}
@@ -31,14 +31,6 @@ Stats.prototype = {
}
}
});
if (navobj.params.period) {
$("input[value=" + navobj.params.period + "]").attr("checked", "checked");
if (navobj.params.period != "custom") {
$("#custom-period").hide();
}
} else {
$("#custom-period").hide();
}
if (navobj.params.start) {
$("#id_from").attr("value", navobj.params.start);
}
@@ -55,8 +47,7 @@ Stats.prototype = {
listen: function() {
$("#searchform").on("keypress", $.proxy(this.search_domain, this));
$(document).on("change", "input[name=period]",
$.proxy(this.change_period, this));
$(".period_selector").click($.proxy(this.change_period, this));
$("#customsend").on("click", $.proxy(this.customgraphs, this));
},
@@ -66,15 +57,11 @@ Stats.prototype = {
},
change_period: function(e) {
var $input = $(e.target);
e.preventDefault();
var $link = $(e.target);
if ($input.attr("value") == "custom") {
$("#custom-period").show();
} else {
$("#custom-period").hide();
this.navobj.delparam("start").delparam("end");
this.navobj.setparam("period", $input.attr("value")).update();
}
this.navobj.delparam("start").delparam("end");
this.navobj.setparam("period", $link.attr("data-period")).update();
},
graphs_cb: function(data) {
@@ -82,7 +69,7 @@ Stats.prototype = {
$("body").notify("error", data.respmsg);
return;
}
$("#graphs").html(data.content);
$("#graphs_mailstats").html(data.content);
},
search_domain: function(e) {
@@ -1,9 +1,5 @@
{% load i18n %}
{% if start or end %}
<h2>{% trans "Custom period : from" %} {{ start }} {% trans "to" %} {{ end }}</h2>
{% endif %}
{% for elems in graphs %}
<h3>{% trans elems.label %}</h3>
<p><img src="{{ MEDIA_URL }}stats/{{ elems.name }}_{{ domain }}_AVERAGE_{% ifequal period 'custom' %}{{ period_name }}{% else %}{{ period }}{% endifequal %}.png"
{% for name in graphs %}
<p><img src="{{ MEDIA_URL }}stats/{{ name }}_{{ domain }}_AVERAGE_{% ifequal period 'custom' %}{{ period_name }}{% else %}{{ period }}{% endifequal %}.png"
alt="{% trans 'No statistics available' %}" /></p>
{% endfor %}
@@ -1,4 +1,4 @@
{% extends "fixed.html" %}{% load i18n %}
{% extends "twocols.html" %}{% load i18n %}
{% block pagetitle %}{% trans "Graphical statistics" %}{% endblock %}
{% block html_head %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}stats/css/stats.css" />
@@ -13,24 +13,43 @@ $(document).ready(function() {
});
</script>
{% endblock %}
{% block fixed_content %}
<div id="menubar">
<form id="searchform" class="form-search">
<input class="input-medium search-query" type="text"
value={% if squery %}"{{ squery }}"{% else %}"{% trans 'Search a domain' %}"{% endif %}
id="searchquery" name="searchquery" />
</form>
<form id="period" class="form-inline">
{% for p in periods %}<label class="radio"><input name="period" type="radio" value="{{ p.name }}"{% if p.name == period %}checked{% endif %} />{% trans p.label %}</label>
{% block leftcol %}
<div id="periods" class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">
{% trans "Predefined time ranges" %}
</li>
{% for p in periods %}<li class="period">
<a href="#" class="period_selector" data-period="{{ p.name }}">{% trans p.label %}</a>
</li>
{% endfor %}
<span id="custom-period">
<input id="id_from" class="input-small" name="date_from" value="{{ start }}" type="text" />
<input id="id_to" class="input-small" name="date_to" value="{{ end }}" type="text" />
<button class="btn" id="customsend">{% trans "Apply" %}</button>
</span>
</form>
<li class="nav-header">
{% trans "Custom time range" %}
</li>
<li>
<form class="form-inline">
<span id="custom-period">
<div class="input-prepend">
<span class="add-on"><i class="icon-indent-left"></i></span><input id="id_from" class="input-medium" name="date_from" value="{{ start }}" type="text" />
</div>
<div class="input-prepend">
<span class="add-on"><i class="icon-indent-right"></i></span><input id="id_to" class="input-medium" name="date_to" value="{{ end }}" type="text" />
</div>
<button class="btn" id="customsend">{% trans "Apply" %}</button>
</span>
</form>
</li>
</ul>
</div>
{% endblock %}
{% block apparea %}
<div id="graphs" class="tabbable">
<ul class="nav nav-tabs">
<li class="active"><a href="#graphs_mailstats" data-toggle="tab">{% trans "Mail trafic" %}</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="graphs_mailstats"></div>
</div>
</div>
<hr>
<div id="graphs"></div>
{% endblock %}
+6 -10
View File
@@ -6,16 +6,12 @@ from django.contrib.auth.decorators \
import login_required, user_passes_test, permission_required
from modoboa.extensions.stats.grapher import *
from modoboa.lib.exceptions import *
from graph_templates import *
graph_types = ['AVERAGE', 'MAX']
graph_list = [{"name" : "traffic", "label" : ugettext_lazy("Average normal traffic")},
{"name" : "badtraffic", "label" : ugettext_lazy("Average bad traffic")},
{"name" : "size", "label" : ugettext_lazy("Average normal traffic size")}]
periods = [{"name" : "day", "label" : ugettext_lazy("Day")},
{"name" : "week", "label" : ugettext_lazy("Week")},
{"name" : "month", "label" : ugettext_lazy("Month")},
{"name" : "year", "label" : ugettext_lazy("Year")},
{"name" : "custom", "label" : ugettext_lazy("Custom")}]
{"name" : "year", "label" : ugettext_lazy("Year")}]
@login_required
@permission_required("admin.view_mailboxes")
@@ -31,7 +27,6 @@ def index(request):
period = request.GET.get("period", "day")
return _render(request, 'stats/index.html', {
"graphs" : graph_list,
"periods" : periods,
"period" : period,
"selection" : "stats",
@@ -45,7 +40,7 @@ def graphs(request):
if not view:
raise ModoboaException(_("Invalid request"))
period = request.GET.get("period", "day")
tplvars = dict(graphs=graph_list, period=period)
tplvars = dict(graphs=[], period=period)
if view == "global":
if not request.user.is_superuser:
raise PermDeniedException
@@ -66,12 +61,13 @@ def graphs(request):
end = request.GET["end"]
G = Grapher()
period_name = "%s_%s" % (start.replace('-',''), end.replace('-',''))
for tpl_name in graph_list:
for tpl in [traffic_avg_template, badtraffic_avg_template, size_avg_template]:
tplvars['graphs'].append(tpl['name'])
G.process(tplvars["domain"],
period_name,
str2Time(*start.split('-')),
str2Time(*end.split('-')),
tpl[tpl_name['name']])
tpl)
tplvars["period_name"] = period_name
tplvars["start"] = start
tplvars["end"] = end