diff --git a/extensions/stats/__init__.py b/extensions/stats/__init__.py
index a19a796f1..e833c252e 100644
--- a/extensions/stats/__init__.py
+++ b/extensions/stats/__init__.py
@@ -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 []
diff --git a/extensions/stats/static/css/stats.css b/extensions/stats/static/css/stats.css
new file mode 100644
index 000000000..71e70d3e6
--- /dev/null
+++ b/extensions/stats/static/css/stats.css
@@ -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;
+}
\ No newline at end of file
diff --git a/extensions/stats/static/js/stats.js b/extensions/stats/static/js/stats.js
new file mode 100644
index 000000000..1460b5fc1
--- /dev/null
+++ b/extensions/stats/static/js/stats.js
@@ -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();
+ }
+};
diff --git a/extensions/stats/templates/stats/index.html b/extensions/stats/templates/stats/index.html
index 83e9ac203..80a8c24e9 100644
--- a/extensions/stats/templates/stats/index.html
+++ b/extensions/stats/templates/stats/index.html
@@ -1,115 +1,35 @@
-{% extends "admin/domains_header.html" %}
+{% extends "fixed.html" %}
{% load i18n %}
{% block html_head %}
-
-
-
-
+
+
+
-
{% endblock %}
-{% block pagetitle %}{% trans "Statistics" %}{% endblock %}
-{% block subcontent %}
-
-
-
-
- {% include "stats/graphs.html" %}
+{% block fixed_content %}
+
+
+
{% endblock %}
diff --git a/extensions/stats/urls.py b/extensions/stats/urls.py
index 2850ff4bd..2d5a460c0 100644
--- a/extensions/stats/urls.py
+++ b/extensions/stats/urls.py
@@ -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
\w+)/$', "getgraph", name="getgraph"),
+ url(r'^graphs/$', "graphs"),
)
diff --git a/extensions/stats/views.py b/extensions/stats/views.py
index 67c31f2e2..fc7d28a97 100644
--- a/extensions/stats/views.py
+++ b/extensions/stats/views.py
@@ -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)
+ ))
diff --git a/static/js/history.js b/static/js/history.js
index bcf2e3aea..76a788379 100644
--- a/static/js/history.js
+++ b/static/js/history.js
@@ -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;
},