Commit da841bee authored by Arthur Lutz's avatar Arthur Lutz
Browse files

* webstats view with aggregation over a period

* action to access webstat view
* configurable separation of etypes in statperiod view
parent e1607e8295e6
......@@ -27,3 +27,14 @@ class AwstatsAccessAction(action.Action):
def url(self):
return self._cw.build_url('?vid=awstats')
class WebStatsAccessAction(action.Action):
__regid__ = 'webstats-action'
__select__ = match_user_groups('managers')
title = _('webstats statistics')
order = 12
category = 'manage'
def url(self):
return self._cw.build_url('?vid=webstats')
......@@ -21,15 +21,22 @@ from cubicweb.web.views import primary, navigation
from cubicweb.selectors import is_instance
class StatPeriodPrimaryView(primary.PrimaryView):
"""
`column_types_aggr` enables you to combine results by type
For example BlogEntry and MicroBlogEntries in one table and Cards in separate table :
column_types_aggr = (('MicroBlogEntry', 'BlogEntry'),
('Card'))
"""
__select__ = is_instance('StatPeriod')
column_types_aggr = None #tuple of tuples of types
def cell_call(self, row, col):
req = self._cw
self.w(u'<div id="statperiod"/>')
entity = self.cw_rset.get_entity(row, col)
self.w(u'<h1>%s %s - %s</h1>' % (_('Statistics for period :'), entity.start, entity.stop) )
# TODO - could loop over hit_type and make tabs
# TODO - facets ?
rset = self._cw.execute('Any C GROUPBY C WHERE X is Hits, X hit_type C')
self.w(u'<a href="%s">%s</a>' % (entity.absolute_url(showall=1),
_('show all results')))
......@@ -38,8 +45,18 @@ class StatPeriodPrimaryView(primary.PrimaryView):
rql = 'Any X, C ORDERBY C DESC %(limit)s WHERE H stats_about X, H hit_type "%(type)s",'\
'H count C, H period P, P eid %%(e)s' % {'type': hit_type[0],
'limit': req.form.get('showall') and ' ' or 'LIMIT 20' }
rset = self._cw.execute(rql, {'e':entity.eid})
self.w(self._cw.view('table', rset, 'null'))
if self.column_types_aggr:
self.w(u'<table><tr>')
for types in self.column_types_aggr:
self.w(u'<td>')
typedrql = rql + ', X is in (%s)' % ','.join(types)
rset = self._cw.execute(typedrql, {'e':entity.eid})
self.w(self._cw.view('table', rset, 'null'))
self.w(u'</td>')
self.w(u'</tr></table>')
else:
rset = self._cw.execute(rql, {'e':entity.eid})
self.w(self._cw.view('table', rset, 'null'))
self.w(u'</div>')
......@@ -63,8 +80,9 @@ class StatPeriodIPrevNextAdapter(navigation.IPrevNextAdapter):
return rset.get_entity(index+1, 0)
class StatGraph(primary.PrimaryView):
class StatGraph(EntityView):
__regid__ = 'webstatsgraph'
# select only instances with stats_about relation
def cell_call(self, row, col):
entity = self.cw_rset.get_entity(row, col)
......
......@@ -19,7 +19,7 @@
import os
import re
from datetime import datetime
from datetime import datetime, timedelta
import urllib
from logilab.mtconverter import xml_escape
......@@ -27,7 +27,7 @@ from logilab.common.textutils import BYTE_UNITS
from cubicweb.view import StartupView
from cubicweb.web.views import forms
from cubicweb.web.formfields import StringField
from cubicweb.web.formfields import StringField, DateField
from cubicweb.web import formwidgets as fwdgs
from cubes.awstats.utils import SECTIONSPEC, SECTIONLABELS, \
......@@ -201,3 +201,71 @@ class AwstatsView(StartupView):
for item in stats_dict[section_name].values()]
ordered_values.sort(reverse=reverse)
return ordered_values
class WebStatsRefreshForm(forms.FieldsForm):
"""Form to filter and select what stats are being displayed"""
__regid__ = 'select-webstats'
action = '/?vid=webstats'
start = DateField(label=_('Start:'),)
stop = DateField(label=_('Stop:'),)
limit = StringField(label=_('Number of results :'),
choices=[10,25,50,100,200,500])
form_buttons = [fwdgs.SubmitButton(label=_('Apply'))]
class StatPeriodsView(StartupView):
""" Web stats view - build from StatPeriods and Hits in cubicweb """
__regid__ = 'webstats'
column_types = None
def call(self):
req = self._cw
self.w(u'<div id="statperiod">')
form = self._cw.vreg['forms'].select('select-webstats', self._cw)
form.render(w=self.w)
start = req.form.get('start', '')
if not start:
start = (datetime.now() - timedelta(days=30)).strftime('%Y/%m/%d')
stop = req.form.get('stop', '')
if not stop:
stop = datetime.now().strftime('%Y/%m/%d')
limit = int(req.form.get('limit', 10))
self.w(u'<h1>%s</h1>' % _('Web stats'))
duration = datetime.strptime(stop, '%Y/%m/%d')-datetime.strptime(start, '%Y/%m/%d')
self.w(u'<h2>%s</h2>' % _('from %(start)s to %(stop)s (%(duration)s days)' % {'start':start,
'stop': stop,
'duration':duration.days}))
# TODO - slider FacetRangeWidget
rql = 'Any X,S WHERE X is StatPeriod, X start S'
self.wview('calendar', self._cw.execute(rql), 'null')
rset = self._cw.execute('Any C GROUPBY C WHERE X is Hits, X hit_type C')
for index, hit_type in enumerate(rset):
self.w(u'<h3>%s</h3>' % hit_type[0])
rql = 'Any X, SUM(C) GROUPBY X ORDERBY 2 DESC %(limit)s WHERE H stats_about X, ' \
'H hit_type "%(type)s", H count C, H period P, P start >= "%(start)s", P stop <= "%(stop)s" '\
'' % {'type': hit_type[0],
'limit': 'LIMIT %s' % limit,
'start': start,
'stop': stop,
}
if self.column_types:
self.w(u'<table><tr>')
for etype in self.column_types:
self.w(u'<td>')
typedrql = rql + ', X is %s' % etype
rset = self._cw.execute(typedrql)
self.w(self._cw.view('table', rset, 'null',
headers=(_(etype), 'hits')))
nolimit_rql = typedrql.replace('LIMIT %s' % limit, '')
self.w(u'<a href="%s">Export CSV</a>' % self._cw.build_url(rql=nolimit_rql,
vid='csvexport'))
self.w(u'</td>')
self.w(u'</tr></table>')
else:
rset = self._cw.execute(rql)
self.w(self._cw.view('table', rset, 'null'))
self.w(u'</div>')
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment