mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-24 06:48:35 +02:00
@@ -35,13 +35,12 @@ def load():
|
||||
def destroy():
|
||||
events.unregister("AdminMenuDisplay", menu)
|
||||
|
||||
@events.observe("AdminMenuDisplay")
|
||||
@events.observe("UserMenuDisplay")
|
||||
def menu(target, user):
|
||||
if target == "admin_menu_box":
|
||||
if target == "top_menu":
|
||||
return [
|
||||
{"name" : "stats",
|
||||
"label" : ugettext("Statistics"),
|
||||
"url" : reverse('fullindex'),
|
||||
"img" : static_url("pics/graph.png")}
|
||||
"url" : reverse('fullindex')}
|
||||
]
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
var Stats = function(options) {
|
||||
this.initialize(options);
|
||||
};
|
||||
|
||||
Stats.prototype = {
|
||||
constructor: Stats,
|
||||
|
||||
defaults: {
|
||||
deflocation: "graphs/?view=global"
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.options.defcallback = $.proxy(this.graphs_cb, this);
|
||||
|
||||
var navobj = new History(this.options);
|
||||
this.navobj = navobj;
|
||||
|
||||
if (navobj.params.view != undefined) {
|
||||
$("#searchquery").attr("value", navobj.params.view);
|
||||
}
|
||||
$("#searchquery").focus(function() {
|
||||
$(this).attr("value", "");
|
||||
}).blur(function() {
|
||||
var $this = $(this);
|
||||
if ($this.attr("value") == "") {
|
||||
if (navobj.params["view"] == "global") {
|
||||
$this.attr("value", gettext("Search a domain"));
|
||||
} else {
|
||||
$this.attr("value", navobj.params.view);
|
||||
}
|
||||
}
|
||||
});
|
||||
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);
|
||||
}
|
||||
if (navobj.params.end) {
|
||||
$("#id_to").attr("value", navobj.params.end);
|
||||
}
|
||||
$("#custom-period input").datepicker({
|
||||
format: 'yyyy-mm-dd'
|
||||
});
|
||||
|
||||
this.register_nav_callbacks();
|
||||
this.listen();
|
||||
},
|
||||
|
||||
listen: function() {
|
||||
$("#searchform").on("keypress", $.proxy(this.search_domain, this));
|
||||
$(document).on("change", "input[name=period]",
|
||||
$.proxy(this.change_period, this));
|
||||
$("#customsend").on("click", $.proxy(this.customgraphs, this));
|
||||
},
|
||||
|
||||
register_nav_callbacks: function() {
|
||||
this.navobj.register_callback("graphs",
|
||||
$.proxy(this.graphs_cb, this));
|
||||
},
|
||||
|
||||
change_period: function(e) {
|
||||
var $input = $(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();
|
||||
}
|
||||
},
|
||||
|
||||
graphs_cb: function(data) {
|
||||
if (data.status == "ko") {
|
||||
$("body").notify("error", data.respmsg);
|
||||
return;
|
||||
}
|
||||
$("#graphs").html(data.content);
|
||||
},
|
||||
|
||||
search_domain: function(e) {
|
||||
var $input = $(e.target);
|
||||
|
||||
switch (e.which) {
|
||||
case 13:
|
||||
e.preventDefault();
|
||||
var domain = ($input.attr("value") == "") ? "global" : $input.attr("value");
|
||||
this.navobj.setparam("view", domain).update();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
customgraphs: function(e) {
|
||||
e.preventDefault();
|
||||
var $fromdate = $("#id_from");
|
||||
var $todate = $("#id_to");
|
||||
|
||||
if ($fromdate.attr("value") == "" || $todate.attr("value") == "") {
|
||||
return;
|
||||
}
|
||||
this.navobj.setparams({
|
||||
period: "custom",
|
||||
start: $fromdate.attr("value"),
|
||||
end: $todate.attr("value")
|
||||
}).update();
|
||||
}
|
||||
};
|
||||
@@ -1,115 +1,35 @@
|
||||
{% extends "admin/domains_header.html" %}
|
||||
{% extends "fixed.html" %}
|
||||
{% load i18n %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}css/calendar.css" />
|
||||
<style type="text/css">
|
||||
#selectors {
|
||||
}
|
||||
#periodbox, #domainbox {
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
}
|
||||
#graphs {
|
||||
margin-top: 15px;
|
||||
float: none;
|
||||
}
|
||||
#customperiod {
|
||||
display: none;
|
||||
border: 1px solid #dddddd;
|
||||
float: left;
|
||||
padding: 3px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/calendar.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}stats/css/stats.css" />
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}stats/js/stats.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.addEvent("domready", function() {
|
||||
var myCal = new Calendar({
|
||||
dateTravelStart: 'Y-m-d',
|
||||
dateTravelEnd : 'Y-m-d'
|
||||
}, {
|
||||
direction: 0, // -1 past, 0 past + future, 1 future
|
||||
pad: 1,
|
||||
offset: 1, // first day of the week: 0 = sunday, 1 = monday, etc..
|
||||
tweak: {x: -147, y: 18} // tweak calendar positioning
|
||||
});
|
||||
|
||||
getgraph_callback = function(resp) {
|
||||
if (resp.status == "ok") {
|
||||
$("graphs").set("html", resp.content);
|
||||
} else {
|
||||
infobox.error(resp.error);
|
||||
}
|
||||
};
|
||||
|
||||
get_period = function() {
|
||||
if ($("period").value != "custom") {
|
||||
$("customperiod").setStyle("display", "none");
|
||||
return "period=" + $("period").value;
|
||||
}
|
||||
$("customperiod").setStyle("display", "block");
|
||||
if ($("dateTravelStart").value == "" || $("dateTravelEnd").value == "") {
|
||||
return "";
|
||||
}
|
||||
return "period=custom"
|
||||
+ "&start=" + $("dateTravelStart").value
|
||||
+ "&end=" + $("dateTravelEnd").value;
|
||||
};
|
||||
|
||||
get_graph = function(evt) {
|
||||
var url = "{% url getgraph_root %}" + $("domain").value + "/";
|
||||
var p = get_period();
|
||||
|
||||
if (p == "") {
|
||||
return;
|
||||
}
|
||||
new Request.JSON.mdb({url : url + "?" + p, noCache: true,
|
||||
onSuccess : getgraph_callback}).get();
|
||||
};
|
||||
|
||||
$("domain").addEvent("change", get_graph);
|
||||
$("period").addEvent("change", get_graph);
|
||||
$("customsend").addEvent("click", get_graph);
|
||||
$(document).ready(function() {
|
||||
var stats = new Stats({
|
||||
graphurl: "{% url modoboa.extensions.stats.views.graphs %}"
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
{% block pagetitle %}{% trans "Statistics" %}{% endblock %}
|
||||
{% block subcontent %}
|
||||
<div id="selectors">
|
||||
<div id="domainbox">
|
||||
<label for="domain">{% trans "Domain:" %}</label>
|
||||
<select id="domain" name="domain">
|
||||
{% if user.is_superuser %}
|
||||
<option value="global" {% ifequal domain "global" %}selected{% endifequal %}>{% trans "Global" %}</option>
|
||||
{% endif %}
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}" {% ifequal d.name domain %}selected{% endifequal %}>{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="periodbox">
|
||||
<label for="period">{% trans "Period:" %}</label>
|
||||
<select id="period" name="period">
|
||||
{% for p in periods %}
|
||||
<option value="{{ p.name }}" {% ifequal p.name period %}selected{% endifequal %}>{% trans p.label %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div id="customperiod">
|
||||
{% trans "Start" %}: <input id="dateTravelStart" name="start"
|
||||
value="{{ start }}" type="text"/>
|
||||
{% trans "End" %}: <input id="dateTravelEnd" name="end"
|
||||
value="{{ end }}" type="text" />
|
||||
<input type="button" id="customsend" value="ok">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spacer"></div>
|
||||
<div id="graphs">
|
||||
{% include "stats/graphs.html" %}
|
||||
{% 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>
|
||||
{% 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>
|
||||
</div>
|
||||
<hr>
|
||||
<div id="graphs"></div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ from django.conf.urls.defaults import *
|
||||
|
||||
urlpatterns = patterns('modoboa.extensions.stats.views',
|
||||
url(r'^$', 'index', name='fullindex'),
|
||||
url(r'^graph/$', "getgraph", name="getgraph_root"),
|
||||
url(r'^graph/(?P<dom_id>\w+)/$', "getgraph", name="getgraph"),
|
||||
url(r'^graphs/$', "graphs"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
+33
-29
@@ -1,15 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# coding: utf-8
|
||||
from django.http import HttpResponse
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _, ugettext_noop
|
||||
from django.utils import simplejson
|
||||
from modoboa.lib.webutils import _render, _render_to_string, getctx
|
||||
from modoboa.lib.webutils import _render, _render_to_string, ajax_simple_response
|
||||
from modoboa.lib.permissions import check_domain_access
|
||||
from modoboa.admin.models import Domain, Mailbox
|
||||
from django.contrib.auth.decorators \
|
||||
import login_required, user_passes_test, permission_required
|
||||
from modoboa.extensions.stats.grapher import *
|
||||
from modoboa.lib.exceptions import *
|
||||
|
||||
graph_types = ['AVERAGE', 'MAX']
|
||||
graph_list = [{"name" : "traffic", "label" : ugettext_noop("Average normal traffic")},
|
||||
@@ -41,39 +41,43 @@ def index(request):
|
||||
})
|
||||
|
||||
@login_required
|
||||
@permission_required("admin.view_mailboxes")
|
||||
def getgraph(request, dom_id):
|
||||
@user_passes_test(lambda u: u.group != "SimpleUsers")
|
||||
def graphs(request):
|
||||
view = request.GET.get("view", None)
|
||||
if not view:
|
||||
raise ModoboaException(_("Invalid request"))
|
||||
period = request.GET.get("period", "day")
|
||||
if dom_id == "global":
|
||||
tplvars = dict(graphs=graph_list, period=period)
|
||||
if view == "global":
|
||||
if not request.user.is_superuser:
|
||||
raise PermDeniedError(_("you're not allowed to see those statistics"))
|
||||
domain = dom_id
|
||||
tplvars.update(domain=view)
|
||||
else:
|
||||
domain = Domain.objects.get(pk=dom_id)
|
||||
try:
|
||||
domain = Domain.objects.get(name=view)
|
||||
except Domain.DoesNotExist:
|
||||
raise ModoboaException(_("Domain not found. Please enter a full name"))
|
||||
if not request.user.can_access(domain):
|
||||
raise PermDeniedError(_("You don't have access to this domain"))
|
||||
tplvars.update(domain=domain.name)
|
||||
|
||||
ctx = None
|
||||
tplvars = {"graphs" : graph_list, "period" : period, "domain" : domain.name}
|
||||
if period == "custom":
|
||||
if not request.GET.has_key("start") or not request.GET.has_key("end"):
|
||||
ctx = getctx("ko", error=_("Bad custom period"))
|
||||
else:
|
||||
start = request.GET["start"]
|
||||
end = request.GET["end"]
|
||||
G = Grapher()
|
||||
period_name = "%s_%s" % (start.replace('-',''), end.replace('-',''))
|
||||
for tpl_name in graph_list:
|
||||
G.process(domain.name,
|
||||
period_name,
|
||||
str2Time(*start.split('-')),
|
||||
str2Time(*end.split('-')),
|
||||
tpl[tpl_name['name']])
|
||||
tplvars["period_name"] = period_name
|
||||
tplvars["start"] = start
|
||||
tplvars["end"] = end
|
||||
if ctx is None:
|
||||
content = _render_to_string(request, "stats/graphs.html", tplvars)
|
||||
ctx = getctx("ok", content=content)
|
||||
raise ModoboaException(_("Bad custom period"))
|
||||
start = request.GET["start"]
|
||||
end = request.GET["end"]
|
||||
G = Grapher()
|
||||
period_name = "%s_%s" % (start.replace('-',''), end.replace('-',''))
|
||||
for tpl_name in graph_list:
|
||||
G.process(tplvars["domain"],
|
||||
period_name,
|
||||
str2Time(*start.split('-')),
|
||||
str2Time(*end.split('-')),
|
||||
tpl[tpl_name['name']])
|
||||
tplvars["period_name"] = period_name
|
||||
tplvars["start"] = start
|
||||
tplvars["end"] = end
|
||||
|
||||
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
|
||||
return ajax_simple_response(dict(
|
||||
status="ok", content=_render_to_string(request, "stats/graphs.html", tplvars)
|
||||
))
|
||||
|
||||
+4
-10
@@ -31,7 +31,7 @@ History.prototype = {
|
||||
load_params: function() {
|
||||
var rawqs = window.location.hash.substr(1);
|
||||
|
||||
if (rawqs.indexOf('?')) {
|
||||
if (rawqs.indexOf('?') == -1) {
|
||||
this.params = {};
|
||||
return;
|
||||
}
|
||||
@@ -118,12 +118,6 @@ History.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
deleteParam: function(str) {
|
||||
if (this.params[str] != undefined) {
|
||||
delete this.params[str];
|
||||
}
|
||||
},
|
||||
|
||||
updateparams: function(str) {
|
||||
if (str.charAt(0) == '?') {
|
||||
str = str.substring(1);
|
||||
@@ -179,10 +173,10 @@ History.prototype = {
|
||||
},
|
||||
|
||||
delparam: function(name) {
|
||||
if (!this.params.has(name)) {
|
||||
return false;
|
||||
if (this.params[name] == undefined) {
|
||||
return this;
|
||||
}
|
||||
this.params.erase(name);
|
||||
delete(this.params[name]);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user