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 %} -
-
- - -
- -
- - -
-
- {% trans "Start" %}: - {% trans "End" %}: - -
-
- -
-
- {% 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; },