import re | import re |
import csv | import csv |
import sys | import sys |
import json | import json |
import logging | import logging |
import operator | import operator |
import collections | import collections |
from ckan.lib.base import (BaseController, c, g, render, request, response, abort) | from ckan.lib.base import (BaseController, c, g, render, request, response, abort) |
import sqlalchemy | import sqlalchemy |
from sqlalchemy import func, cast, Integer | from sqlalchemy import func, cast, Integer |
import ckan.model as model | import ckan.model as model |
from ga_model import GA_Url, GA_Stat, GA_ReferralStat, GA_Publisher | from ga_model import GA_Url, GA_Stat, GA_ReferralStat, GA_Publisher |
log = logging.getLogger('ckanext.ga-report') | log = logging.getLogger('ckanext.ga-report') |
DOWNLOADS_AVAILABLE_FROM = '2012-12' | DOWNLOADS_AVAILABLE_FROM = '2012-12' |
def _get_month_name(strdate): | def _get_month_name(strdate): |
import calendar | import calendar |
from time import strptime | from time import strptime |
d = strptime(strdate, '%Y-%m') | d = strptime(strdate, '%Y-%m') |
return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year) | return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year) |
def _get_unix_epoch(strdate): | def _get_unix_epoch(strdate): |
from time import strptime,mktime | from time import strptime,mktime |
d = strptime(strdate, '%Y-%m') | d = strptime(strdate, '%Y-%m') |
return int(mktime(d)) | return int(mktime(d)) |
def _month_details(cls, stat_key=None): | def _month_details(cls, stat_key=None): |
''' | ''' |
Returns a list of all the periods for which we have data, unfortunately | Returns a list of all the periods for which we have data, unfortunately |
knows too much about the type of the cls being passed as GA_Url has a | knows too much about the type of the cls being passed as GA_Url has a |
more complex query | more complex query |
This may need extending if we add a period_name to the stats | This may need extending if we add a period_name to the stats |
''' | ''' |
months = [] | months = [] |
day = None | day = None |
q = model.Session.query(cls.period_name,cls.period_complete_day)\ | q = model.Session.query(cls.period_name,cls.period_complete_day)\ |
.filter(cls.period_name!='All').distinct(cls.period_name) | .filter(cls.period_name!='All').distinct(cls.period_name) |
if stat_key: | if stat_key: |
q= q.filter(cls.stat_name==stat_key) | q= q.filter(cls.stat_name==stat_key) |
vals = q.order_by("period_name desc").all() | vals = q.order_by("period_name desc").all() |
if vals and vals[0][1]: | if vals and vals[0][1]: |
day = int(vals[0][1]) | day = int(vals[0][1]) |
ordinal = 'th' if 11 <= day <= 13 \ | ordinal = 'th' if 11 <= day <= 13 \ |
else {1:'st',2:'nd',3:'rd'}.get(day % 10, 'th') | else {1:'st',2:'nd',3:'rd'}.get(day % 10, 'th') |
day = "{day}{ordinal}".format(day=day, ordinal=ordinal) | day = "{day}{ordinal}".format(day=day, ordinal=ordinal) |
for m in vals: | for m in vals: |
months.append( (m[0], _get_month_name(m[0]))) | months.append( (m[0], _get_month_name(m[0]))) |
return months, day | return months, day |
class GaReport(BaseController): | class GaReport(BaseController): |
def csv(self, month): | def csv(self, month): |
import csv | import csv |
q = model.Session.query(GA_Stat).filter(GA_Stat.stat_name!='Downloads') | q = model.Session.query(GA_Stat).filter(GA_Stat.stat_name!='Downloads') |
if month != 'all': | if month != 'all': |
q = q.filter(GA_Stat.period_name==month) | q = q.filter(GA_Stat.period_name==month) |
entries = q.order_by('GA_Stat.period_name, GA_Stat.stat_name, GA_Stat.key').all() | entries = q.order_by('GA_Stat.period_name, GA_Stat.stat_name, GA_Stat.key').all() |
response.headers['Content-Type'] = "text/csv; charset=utf-8" | response.headers['Content-Type'] = "text/csv; charset=utf-8" |
response.headers['Content-Disposition'] = str('attachment; filename=stats_%s.csv' % (month,)) | response.headers['Content-Disposition'] = str('attachment; filename=stats_%s.csv' % (month,)) |
writer = csv.writer(response) | writer = csv.writer(response) |
writer.writerow(["Period", "Statistic", "Key", "Value"]) | writer.writerow(["Period", "Statistic", "Key", "Value"]) |
for entry in entries: | for entry in entries: |
writer.writerow([entry.period_name.encode('utf-8'), | writer.writerow([entry.period_name.encode('utf-8'), |
entry.stat_name.encode('utf-8'), | entry.stat_name.encode('utf-8'), |
entry.key.encode('utf-8'), | entry.key.encode('utf-8'), |
entry.value.encode('utf-8')]) | entry.value.encode('utf-8')]) |
def index(self): | def index(self): |
# Get the month details by fetching distinct values and determining the | # Get the month details by fetching distinct values and determining the |
# month names from the values. | # month names from the values. |
c.months, c.day = _month_details(GA_Stat) | c.months, c.day = _month_details(GA_Stat) |
# Work out which month to show, based on query params of the first item | # Work out which month to show, based on query params of the first item |
c.month_desc = 'all months' | c.month_desc = 'all months' |
c.month = request.params.get('month', '') | c.month = request.params.get('month', '') |
if c.month: | if c.month: |
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) | c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) |
q = model.Session.query(GA_Stat).\ | q = model.Session.query(GA_Stat).\ |
filter(GA_Stat.stat_name=='Totals') | filter(GA_Stat.stat_name=='Totals') |
if c.month: | if c.month: |
q = q.filter(GA_Stat.period_name==c.month) | q = q.filter(GA_Stat.period_name==c.month) |
entries = q.order_by('ga_stat.key').all() | entries = q.order_by('ga_stat.key').all() |
def clean_key(key, val): | def clean_key(key, val): |
if key in ['Average time on site', 'Pages per visit', 'New visits', 'Bounce rate (home page)']: | if key in ['Average time on site', 'Pages per visit', 'New visits', 'Bounce rate (home page)']: |
val = "%.2f" % round(float(val), 2) | val = "%.2f" % round(float(val), 2) |
if key == 'Average time on site': | if key == 'Average time on site': |
mins, secs = divmod(float(val), 60) | mins, secs = divmod(float(val), 60) |
hours, mins = divmod(mins, 60) | hours, mins = divmod(mins, 60) |
val = '%02d:%02d:%02d (%s seconds) ' % (hours, mins, secs, val) | val = '%02d:%02d:%02d (%s seconds) ' % (hours, mins, secs, val) |
if key in ['New visits','Bounce rate (home page)']: | if key in ['New visits','Bounce rate (home page)']: |
val = "%s%%" % val | val = "%s%%" % val |
if key in ['Total page views', 'Total visits']: | if key in ['Total page views', 'Total visits']: |
val = int(val) | val = int(val) |
return key, val | return key, val |
# Query historic values for sparkline rendering | # Query historic values for sparkline rendering |
sparkline_query = model.Session.query(GA_Stat)\ | sparkline_query = model.Session.query(GA_Stat)\ |
.filter(GA_Stat.stat_name=='Totals')\ | .filter(GA_Stat.stat_name=='Totals')\ |
.order_by(GA_Stat.period_name) | .order_by(GA_Stat.period_name) |
sparkline_data = {} | sparkline_data = {} |
for x in sparkline_query: | for x in sparkline_query: |
sparkline_data[x.key] = sparkline_data.get(x.key,[]) | sparkline_data[x.key] = sparkline_data.get(x.key,[]) |
key, val = clean_key(x.key,float(x.value)) | key, val = clean_key(x.key,float(x.value)) |
tooltip = '%s: %s' % (_get_month_name(x.period_name), val) | tooltip = '%s: %s' % (_get_month_name(x.period_name), val) |
sparkline_data[x.key].append( (tooltip,x.value) ) | sparkline_data[x.key].append( (tooltip,x.value) ) |
# Trim the latest month, as it looks like a huge dropoff | # Trim the latest month, as it looks like a huge dropoff |
for key in sparkline_data: | for key in sparkline_data: |
sparkline_data[key] = sparkline_data[key][:-1] | sparkline_data[key] = sparkline_data[key][:-1] |
c.global_totals = [] | c.global_totals = [] |
if c.month: | if c.month: |
for e in entries: | for e in entries: |
key, val = clean_key(e.key, e.value) | key, val = clean_key(e.key, e.value) |
sparkline = sparkline_data[e.key] | sparkline = sparkline_data[e.key] |
c.global_totals.append((key, val, sparkline)) | c.global_totals.append((key, val, sparkline)) |
else: | else: |
d = collections.defaultdict(list) | d = collections.defaultdict(list) |
for e in entries: | for e in entries: |
d[e.key].append(float(e.value)) | d[e.key].append(float(e.value)) |
for k, v in d.iteritems(): | for k, v in d.iteritems(): |
if k in ['Total page views', 'Total visits']: | if k in ['Total page views', 'Total visits']: |
v = sum(v) | v = sum(v) |
else: | else: |
v = float(sum(v))/float(len(v)) | v = float(sum(v))/float(len(v)) |
sparkline = sparkline_data[k] | sparkline = sparkline_data[k] |
key, val = clean_key(k,v) | key, val = clean_key(k,v) |
c.global_totals.append((key, val, sparkline)) | c.global_totals.append((key, val, sparkline)) |
# Sort the global totals into a more pleasant order | # Sort the global totals into a more pleasant order |
def sort_func(x): | def sort_func(x): |
key = x[0] | key = x[0] |
total_order = ['Total page views','Total visits','Pages per visit'] | total_order = ['Total page views','Total visits','Pages per visit'] |
if key in total_order: | if key in total_order: |
return total_order.index(key) | return total_order.index(key) |
return 999 | return 999 |
c.global_totals = sorted(c.global_totals, key=sort_func) | c.global_totals = sorted(c.global_totals, key=sort_func) |
keys = { | keys = { |
'Browser versions': 'browser_versions', | 'Browser versions': 'browser_versions', |
'Browsers': 'browsers', | 'Browsers': 'browsers', |
'Operating Systems versions': 'os_versions', | 'Operating Systems versions': 'os_versions', |
'Operating Systems': 'os', | 'Operating Systems': 'os', |
'Social sources': 'social_networks', | 'Social sources': 'social_networks', |
'Languages': 'languages', | 'Languages': 'languages', |
'Country': 'country' | 'Country': 'country' |
} | } |
def shorten_name(name, length=60): | def shorten_name(name, length=60): |
return (name[:length] + '..') if len(name) > 60 else name | return (name[:length] + '..') if len(name) > 60 else name |
def fill_out_url(url): | def fill_out_url(url): |
import urlparse | import urlparse |
return urlparse.urljoin(g.site_url, url) | return urlparse.urljoin(g.site_url, url) |
c.social_referrer_totals, c.social_referrers = [], [] | c.social_referrer_totals, c.social_referrers = [], [] |
q = model.Session.query(GA_ReferralStat) | q = model.Session.query(GA_ReferralStat) |
q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q | q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q |
q = q.order_by('ga_referrer.count::int desc') | q = q.order_by('ga_referrer.count::int desc') |
for entry in q.all(): | for entry in q.all(): |
c.social_referrers.append((shorten_name(entry.url), fill_out_url(entry.url), | c.social_referrers.append((shorten_name(entry.url), fill_out_url(entry.url), |
entry.source,entry.count)) | entry.source,entry.count)) |
q = model.Session.query(GA_ReferralStat.url, | q = model.Session.query(GA_ReferralStat.url, |
func.sum(GA_ReferralStat.count).label('count')) | func.sum(GA_ReferralStat.count).label('count')) |
q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q | q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q |
q = q.order_by('count desc').group_by(GA_ReferralStat.url) | q = q.order_by('count desc').group_by(GA_ReferralStat.url) |
for entry in q.all(): | for entry in q.all(): |
c.social_referrer_totals.append((shorten_name(entry[0]), fill_out_url(entry[0]),'', | c.social_referrer_totals.append((shorten_name(entry[0]), fill_out_url(entry[0]),'', |
entry[1])) | entry[1])) |
for k, v in keys.iteritems(): | for k, v in keys.iteritems(): |
q = model.Session.query(GA_Stat).\ | q = model.Session.query(GA_Stat).\ |
filter(GA_Stat.stat_name==k).\ | filter(GA_Stat.stat_name==k).\ |
order_by(GA_Stat.period_name) | order_by(GA_Stat.period_name) |
# Buffer the tabular data | # Buffer the tabular data |
if c.month: | if c.month: |
entries = [] | entries = [] |
q = q.filter(GA_Stat.period_name==c.month).\ | q = q.filter(GA_Stat.period_name==c.month).\ |
order_by('ga_stat.value::int desc') | order_by('ga_stat.value::int desc') |
d = collections.defaultdict(int) | d = collections.defaultdict(int) |
for e in q.all(): | for e in q.all(): |
d[e.key] += int(e.value) | d[e.key] += int(e.value) |
entries = [] | entries = [] |
for key, val in d.iteritems(): | for key, val in d.iteritems(): |
entries.append((key,val,)) | entries.append((key,val,)) |
entries = sorted(entries, key=operator.itemgetter(1), reverse=True) | entries = sorted(entries, key=operator.itemgetter(1), reverse=True) |
# Run a query on all months to gather graph data | # Run a query on all months to gather graph data |
graph_query = model.Session.query(GA_Stat).\ | graph_query = model.Session.query(GA_Stat).\ |
filter(GA_Stat.stat_name==k).\ | filter(GA_Stat.stat_name==k).\ |
order_by(GA_Stat.period_name) | order_by(GA_Stat.period_name) |
graph_dict = {} | graph_dict = {} |
for stat in graph_query: | for stat in graph_query: |
graph_dict[ stat.key ] = graph_dict.get(stat.key,{ | graph_dict[ stat.key ] = graph_dict.get(stat.key,{ |
'name':stat.key, | 'name':stat.key, |
'data': [] | 'data': [] |
}) | }) |
graph_dict[ stat.key ]['data'].append({ | graph_dict[ stat.key ]['data'].append({ |
'x':_get_unix_epoch(stat.period_name), | 'x':_get_unix_epoch(stat.period_name), |
'y':float(stat.value) | 'y':float(stat.value) |
}) | }) |
graph = [ graph_dict[x[0]] for x in entries ] | graph = [ graph_dict[x[0]] for x in entries ] |
setattr(c, v+'_graph', json.dumps( _to_rickshaw(graph,percentageMode=True) )) | setattr(c, v+'_graph', json.dumps( _to_rickshaw(graph,percentageMode=True) )) |
# Get the total for each set of values and then set the value as | # Get the total for each set of values and then set the value as |
# a percentage of the total | # a percentage of the total |
if k == 'Social sources': | if k == 'Social sources': |
total = sum([x for n,x,graph in c.global_totals if n == 'Total visits']) | total = sum([x for n,x,graph in c.global_totals if n == 'Total visits']) |
else: | else: |
total = sum([num for _,num in entries]) | total = sum([num for _,num in entries]) |
setattr(c, v, [(k,_percent(v,total)) for k,v in entries ]) | setattr(c, v, [(k,_percent(v,total)) for k,v in entries ]) |
return render('ga_report/site/index.html') | return render('ga_report/site/index.html') |
class GaDatasetReport(BaseController): | class GaDatasetReport(BaseController): |
""" | """ |
Displays the pageview and visit count for datasets | Displays the pageview and visit count for datasets |
with options to filter by publisher and time period. | with options to filter by publisher and time period. |
""" | """ |
def publisher_csv(self, month): | def publisher_csv(self, month): |
''' | ''' |
Returns a CSV of each publisher with the total number of dataset | Returns a CSV of each publisher with the total number of dataset |
views & visits. | views & visits. |
''' | ''' |
c.month = month if not month == 'all' else '' | c.month = month if not month == 'all' else '' |
response.headers['Content-Type'] = "text/csv; charset=utf-8" | response.headers['Content-Type'] = "text/csv; charset=utf-8" |
response.headers['Content-Disposition'] = str('attachment; filename=publishers_%s.csv' % (month,)) | response.headers['Content-Disposition'] = str('attachment; filename=publishers_%s.csv' % (month,)) |
writer = csv.writer(response) | writer = csv.writer(response) |
writer.writerow(["Publisher Title", "Publisher Name", "Views", "Visits", "Period Name"]) | writer.writerow(["Publisher Title", "Publisher Name", "Views", "Visits", "Period Name"]) |
top_publishers, top_publishers_graph = _get_top_publishers(None) | top_publishers, top_publishers_graph = _get_top_publishers(None) |
for publisher,view,visit in top_publishers: | for publisher,view,visit in top_publishers: |
writer.writerow([publisher.title.encode('utf-8'), | writer.writerow([publisher.title.encode('utf-8'), |
publisher.name.encode('utf-8'), | publisher.name.encode('utf-8'), |
view, | view, |
visit, | visit, |
month]) | month]) |
def dataset_csv(self, id='all', month='all'): | def dataset_csv(self, id='all', month='all'): |
''' | ''' |
Returns a CSV with the number of views & visits for each dataset. | Returns a CSV with the number of views & visits for each dataset. |
:param id: A Publisher ID or None if you want for all | :param id: A Publisher ID or None if you want for all |
:param month: The time period, or 'all' | :param month: The time period, or 'all' |
''' | ''' |
c.month = month if not month == 'all' else '' | c.month = month if not month == 'all' else '' |
if id != 'all': | if id != 'all': |
c.publisher = model.Group.get(id) | c.publisher = model.Group.get(id) |
if not c.publisher: | if not c.publisher: |
abort(404, 'A publisher with that name could not be found') | abort(404, 'A publisher with that name could not be found') |
packages = self._get_packages(c.publisher) | packages = self._get_packages(c.publisher) |
response.headers['Content-Type'] = "text/csv; charset=utf-8" | response.headers['Content-Type'] = "text/csv; charset=utf-8" |
response.headers['Content-Disposition'] = \ | response.headers['Content-Disposition'] = \ |
str('attachment; filename=datasets_%s_%s.csv' % (c.publisher_name, month,)) | str('attachment; filename=datasets_%s_%s.csv' % (c.publisher_name, month,)) |
writer = csv.writer(response) | writer = csv.writer(response) |
writer.writerow(["Dataset Title", "Dataset Name", "Views", "Visits", "Resource downloads", "Period Name"]) | writer.writerow(["Dataset Title", "Dataset Name", "Views", "Visits", "Resource downloads", "Period Name"]) |
for package,view,visit,downloads in packages: | for package,view,visit,downloads in packages: |
writer.writerow([package.title.encode('utf-8'), | writer.writerow([package.title.encode('utf-8'), |
package.name.encode('utf-8'), | package.name.encode('utf-8'), |
view, | view, |
visit, | visit, |
downloads, | downloads, |
month]) | month]) |
def publishers(self): | def publishers(self): |
'''A list of publishers and the number of views/visits for each''' | '''A list of publishers and the number of views/visits for each''' |
# Get the month details by fetching distinct values and determining the | # Get the month details by fetching distinct values and determining the |
# month names from the values. | # month names from the values. |
c.months, c.day = _month_details(GA_Url) | c.months, c.day = _month_details(GA_Url) |
# Work out which month to show, based on query params of the first item | # Work out which month to show, based on query params of the first item |
c.month = request.params.get('month', '') | c.month = request.params.get('month', '') |
c.month_desc = 'all months' | c.month_desc = 'all months' |
if c.month: | if c.month: |
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) | c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) |
c.top_publishers, graph_data = _get_top_publishers() | c.top_publishers, graph_data = _get_top_publishers() |
c.top_publishers_graph = json.dumps( _to_rickshaw(graph_data) ) | c.top_publishers_graph = json.dumps( _to_rickshaw(graph_data) ) |
return render('ga_report/publisher/index.html') | return render('ga_report/publisher/index.html') |
def _get_packages(self, publisher=None, count=-1): | def _get_packages(self, publisher=None, count=-1): |
'''Returns the datasets in order of views''' | '''Returns the datasets in order of views''' |
have_download_data = True | have_download_data = True |
month = c.month or 'All' | month = c.month or 'All' |
if month != 'All': | if month != 'All': |
have_download_data = month >= DOWNLOADS_AVAILABLE_FROM | have_download_data = month >= DOWNLOADS_AVAILABLE_FROM |
q = model.Session.query(GA_Url,model.Package)\ | q = model.Session.query(GA_Url,model.Package)\ |
.filter(model.Package.name==GA_Url.package_id)\ | .filter(model.Package.name==GA_Url.package_id)\ |
.filter(GA_Url.url.like('/dataset/%')) | .filter(GA_Url.url.like('/dataset/%')) |
if publisher: | if publisher: |
q = q.filter(GA_Url.department_id==publisher.name) | q = q.filter(GA_Url.department_id==publisher.name) |
q = q.filter(GA_Url.period_name==month) | q = q.filter(GA_Url.period_name==month) |
q = q.order_by('ga_url.pageviews::int desc') | q = q.order_by('ga_url.pageviews::int desc') |
top_packages = [] | top_packages = [] |
if count == -1: | if count == -1: |
entries = q.all() | entries = q.all() |
else: | else: |
entries = q.limit(count) | entries = q.limit(count) |
for entry,package in entries: | for entry,package in entries: |
if package: | if package: |
# Downloads .... | # Downloads .... |
if have_download_data: | if have_download_data: |
dls = model.Session.query(GA_Stat).\ | dls = model.Session.query(GA_Stat).\ |
filter(GA_Stat.stat_name=='Downloads').\ | filter(GA_Stat.stat_name=='Downloads').\ |
filter(GA_Stat.key==package.name) | filter(GA_Stat.key==package.name) |
if month != 'All': # Fetch everything unless the month is specific | if month != 'All': # Fetch everything unless the month is specific |
dls = dls.filter(GA_Stat.period_name==month) | dls = dls.filter(GA_Stat.period_name==month) |
downloads = 0 | downloads = 0 |
for x in dls: | for x in dls: |
downloads += int(x.value) | downloads += int(x.value) |
else: | else: |
downloads = 'No data' | downloads = 'No data' |
top_packages.append((package, entry.pageviews, entry.visits, downloads)) | top_packages.append((package, entry.pageviews, entry.visits, downloads)) |
else: | else: |
log.warning('Could not find package associated package') | log.warning('Could not find package associated package') |
return top_packages | return top_packages |
def read(self): | def read(self): |
''' | ''' |
Lists the most popular datasets across all publishers | Lists the most popular datasets across all publishers |
''' | ''' |
return self.read_publisher(None) | return self.read_publisher(None) |
def read_publisher(self, id): | def read_publisher(self, id): |
''' | ''' |
Lists the most popular datasets for a publisher (or across all publishers) | Lists the most popular datasets for a publisher (or across all publishers) |
''' | ''' |
count = 20 | count = 20 |
c.publishers = _get_publishers() | c.publishers = _get_publishers() |
id = request.params.get('publisher', id) | id = request.params.get('publisher', id) |
if id and id != 'all': | if id and id != 'all': |
c.publisher = model.Group.get(id) | c.publisher = model.Group.get(id) |
if not c.publisher: | if not c.publisher: |
abort(404, 'A publisher with that name could not be found') | abort(404, 'A publisher with that name could not be found') |
c.publisher_name = c.publisher.name | c.publisher_name = c.publisher.name |
c.top_packages = [] # package, dataset_views in c.top_packages | c.top_packages = [] # package, dataset_views in c.top_packages |
# Get the month details by fetching distinct values and determining the | # Get the month details by fetching distinct values and determining the |
# month names from the values. | # month names from the values. |
c.months, c.day = _month_details(GA_Url) | c.months, c.day = _month_details(GA_Url) |
# Work out which month to show, based on query params of the first item | # Work out which month to show, based on query params of the first item |
c.month = request.params.get('month', '') | c.month = request.params.get('month', '') |
if not c.month: | if not c.month: |
c.month_desc = 'all months' | c.month_desc = 'all months' |
else: | else: |
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) | c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) |
month = c.month or 'All' | month = c.month or 'All' |
c.publisher_page_views = 0 | c.publisher_page_views = 0 |
q = model.Session.query(GA_Url).\ | q = model.Session.query(GA_Url).\ |
filter(GA_Url.url=='/publisher/%s' % c.publisher_name) | filter(GA_Url.url=='/publisher/%s' % c.publisher_name) |
entry = q.filter(GA_Url.period_name==c.month).first() | entry = q.filter(GA_Url.period_name==c.month).first() |
c.publisher_page_views = entry.pageviews if entry else 0 | c.publisher_page_views = entry.pageviews if entry else 0 |
c.top_packages = self._get_packages(c.publisher, 20) | c.top_packages = self._get_packages(c.publisher, 20) |
# Graph query | # Graph query |
top_package_names = [ x[0].name for x in c.top_packages ] | top_package_names = [ x[0].name for x in c.top_packages ] |
graph_query = model.Session.query(GA_Url,model.Package)\ | graph_query = model.Session.query(GA_Url,model.Package)\ |
.filter(model.Package.name==GA_Url.package_id)\ | .filter(model.Package.name==GA_Url.package_id)\ |
.filter(GA_Url.url.like('/dataset/%'))\ | .filter(GA_Url.url.like('/dataset/%'))\ |
.filter(GA_Url.package_id.in_(top_package_names)) | .filter(GA_Url.package_id.in_(top_package_names)) |
graph_dict = {} | graph_dict = {} |
for entry,package in graph_query: | for entry,package in graph_query: |
if not package: continue | if not package: continue |
if entry.period_name=='All': continue | if entry.period_name=='All': continue |
graph_dict[package.name] = graph_dict.get(package.name,{ | graph_dict[package.name] = graph_dict.get(package.name,{ |
'name':package.title, | 'name':package.title, |
'data':[] | 'data':[] |
}) | }) |
graph_dict[package.name]['data'].append({ | graph_dict[package.name]['data'].append({ |
'x':_get_unix_epoch(entry.period_name), | 'x':_get_unix_epoch(entry.period_name), |
'y':int(entry.pageviews), | 'y':int(entry.pageviews), |
}) | }) |
graph = [ graph_dict[x] for x in top_package_names ] | graph = [ graph_dict[x] for x in top_package_names ] |
c.graph_data = json.dumps( _to_rickshaw(graph) ) | c.graph_data = json.dumps( _to_rickshaw(graph) ) |
return render('ga_report/publisher/read.html') | return render('ga_report/publisher/read.html') |
def _to_rickshaw(data, percentageMode=False): | def _to_rickshaw(data, percentageMode=False): |
if data==[]: | if data==[]: |
return data | return data |
# Create a consistent x-axis between all series | # Create a consistent x-axis between all series |
num_points = [ len(series['data']) for series in data ] | num_points = [ len(series['data']) for series in data ] |
ideal_index = num_points.index( max(num_points) ) | ideal_index = num_points.index( max(num_points) ) |
x_axis = [ point['x'] for point in data[ideal_index]['data'] ] | x_axis = [] |
for series in data: | |
for point in series['data']: | |
x_axis.append(point['x']) | |
x_axis = sorted( list( set(x_axis) ) ) | |
# Zero pad any missing values | |
for series in data: | for series in data: |
xs = [ point['x'] for point in series['data'] ] | xs = [ point['x'] for point in series['data'] ] |
assert set(xs).issubset( set(x_axis) ), (xs, x_axis) | |
# Zero pad any missing values | |
for x in set(x_axis).difference(set(xs)): | for x in set(x_axis).difference(set(xs)): |
series['data'].append( {'x':x, 'y':0} ) | series['data'].append( {'x':x, 'y':0} ) |
if percentageMode: | if percentageMode: |
def get_totals(series_list): | def get_totals(series_list): |
totals = {} | totals = {} |
for series in series_list: | for series in series_list: |
for point in series['data']: | for point in series['data']: |
totals[point['x']] = totals.get(point['x'],0) + point['y'] | totals[point['x']] = totals.get(point['x'],0) + point['y'] |
lengths = [ len(series['data']) for series in series_list ] | |
assert len(set(lengths))==1 | |
assert lengths[0] == len(totals) | |
return totals | return totals |
# Transform data into percentage stacks | # Transform data into percentage stacks |
totals = get_totals(data) | totals = get_totals(data) |
# Roll insignificant series into a catch-all | # Roll insignificant series into a catch-all |
THRESHOLD = 0.01 | THRESHOLD = 0.01 |
raw_data = data | raw_data = data |
data = [] | data = [] |
for series in raw_data: | for series in raw_data: |
for point in series['data']: | for point in series['data']: |
fraction = float(point['y']) / totals[point['x']] | fraction = float(point['y']) / totals[point['x']] |
if not (series in data) and fraction>THRESHOLD: | if not (series in data) and fraction>THRESHOLD: |
data.append(series) | data.append(series) |
# Overwrite data with a set of intereting series | # Overwrite data with a set of intereting series |
others = [ x for x in raw_data if not (x in data) ] | others = [ x for x in raw_data if not (x in data) ] |
data.append({ | data.append({ |
'name':'Other', | 'name':'Other', |
'data': [ {'x':x,'y':y} for x,y in get_totals(others).items() ] | 'data': [ {'x':x,'y':y} for x,y in get_totals(others).items() ] |
}) | }) |
# Turn each point into a percentage | # Turn each point into a percentage |
for series in data: | for series in data: |
for point in series['data']: | for point in series['data']: |
point['y'] = (point['y']*100) / totals[point['x']] | point['y'] = (point['y']*100) / totals[point['x']] |
# Sort the points | # Sort the points |
for series in data: | for series in data: |
series['data'] = sorted( series['data'], key=lambda x:x['x'] ) | series['data'] = sorted( series['data'], key=lambda x:x['x'] ) |
# Strip the latest month's incomplete analytics | # Strip the latest month's incomplete analytics |
series['data'] = series['data'][:-1] | series['data'] = series['data'][:-1] |
return data | return data |
def _get_top_publishers(limit=20): | def _get_top_publishers(limit=20): |
''' | ''' |
Returns a list of the top 20 publishers by dataset visits. | Returns a list of the top 20 publishers by dataset visits. |
(The number to show can be varied with 'limit') | (The number to show can be varied with 'limit') |
''' | ''' |
month = c.month or 'All' | month = c.month or 'All' |
connection = model.Session.connection() | connection = model.Session.connection() |
q = """ | q = """ |
select department_id, sum(pageviews::int) views, sum(visits::int) visits | select department_id, sum(pageviews::int) views, sum(visits::int) visits |
from ga_url | from ga_url |
where department_id <> '' | where department_id <> '' |
and package_id <> '' | and package_id <> '' |
and url like '/dataset/%%' | and url like '/dataset/%%' |
and period_name=%s | and period_name=%s |
group by department_id order by views desc | group by department_id order by views desc |
""" | """ |
if limit: | if limit: |
q = q + " limit %s;" % (limit) | q = q + " limit %s;" % (limit) |
top_publishers = [] | top_publishers = [] |
res = connection.execute(q, month) | res = connection.execute(q, month) |
department_ids = [] | department_ids = [] |
for row in res: | for row in res: |
g = model.Group.get(row[0]) | g = model.Group.get(row[0]) |
if g: | if g: |
department_ids.append(row[0]) | department_ids.append(row[0]) |
top_publishers.append((g, row[1], row[2])) | top_publishers.append((g, row[1], row[2])) |
graph = [] | graph = [] |
if limit is not None: | if limit is not None: |
# Query for a history graph of these publishers | # Query for a history graph of these publishers |
q = model.Session.query( | q = model.Session.query( |
GA_Url.department_id, | GA_Url.department_id, |
GA_Url.period_name, | GA_Url.period_name, |
func.sum(cast(GA_Url.pageviews,sqlalchemy.types.INT)))\ | func.sum(cast(GA_Url.pageviews,sqlalchemy.types.INT)))\ |
.filter( GA_Url.department_id.in_(department_ids) )\ | .filter( GA_Url.department_id.in_(department_ids) )\ |
.filter( GA_Url.period_name!='All' )\ | .filter( GA_Url.period_name!='All' )\ |
.filter( GA_Url.url.like('/dataset/%') )\ | .filter( GA_Url.url.like('/dataset/%') )\ |
.filter( GA_Url.package_id!='' )\ | .filter( GA_Url.package_id!='' )\ |
.group_by( GA_Url.department_id, GA_Url.period_name ) | .group_by( GA_Url.department_id, GA_Url.period_name ) |
graph_dict = {} | graph_dict = {} |
for dept_id,period_name,views in q: | for dept_id,period_name,views in q: |
graph_dict[dept_id] = graph_dict.get( dept_id, { | graph_dict[dept_id] = graph_dict.get( dept_id, { |
'name' : model.Group.get(dept_id).title, | 'name' : model.Group.get(dept_id).title, |
'data' : [] | 'data' : [] |
}) | }) |
graph_dict[dept_id]['data'].append({ | graph_dict[dept_id]['data'].append({ |
'x': _get_unix_epoch(period_name), | 'x': _get_unix_epoch(period_name), |
'y': views | 'y': views |
}) | }) |
# Sort dict into ordered list | # Sort dict into ordered list |
for id in department_ids: | for id in department_ids: |
graph.append( graph_dict[id] ) | graph.append( graph_dict[id] ) |
return top_publishers, graph | return top_publishers, graph |
def _get_publishers(): | def _get_publishers(): |
''' | ''' |
Returns a list of all publishers. Each item is a tuple: | Returns a list of all publishers. Each item is a tuple: |
(name, title) | (name, title) |
''' | ''' |
publishers = [] | publishers = [] |
for pub in model.Session.query(model.Group).\ | for pub in model.Session.query(model.Group).\ |
filter(model.Group.type=='publisher').\ | filter(model.Group.type=='publisher').\ |
filter(model.Group.state=='active').\ | filter(model.Group.state=='active').\ |
order_by(model.Group.name): | order_by(model.Group.name): |
publishers.append((pub.name, pub.title)) | publishers.append((pub.name, pub.title)) |
return publishers | return publishers |
def _percent(num, total): | def _percent(num, total): |
p = 100 * float(num)/float(total) | p = 100 * float(num)/float(total) |
return "%.2f%%" % round(p, 2) | return "%.2f%%" % round(p, 2) |
.table-condensed td.sparkline-cell { | .table-condensed td.sparkline-cell { |
padding: 1px 0 0 0; | padding: 1px 0 0 0; |
width: 108px; | width: 108px; |
text-align: center; | text-align: center; |
} | } |
.rickshaw_chart_container { | .rickshaw_chart_container { |
position: relative; | position: relative; |
height: 350px; | height: 350px; |
margin: 0 auto 20px auto; | margin: 0 auto 20px auto; |
} | } |
.rickshaw_chart { | .rickshaw_chart { |
position: absolute; | position: absolute; |
left: 40px; | left: 40px; |
width: 500px; | width: 500px; |
top: 0; | top: 0; |
bottom: 0; | bottom: 0; |
} | } |
.rickshaw_legend { | .rickshaw_legend { |
background: transparent; | background: transparent; |
width: 100%; | width: 100%; |
padding-top: 4px; | |
} | } |
.rickshaw_y_axis { | .rickshaw_y_axis { |
position: absolute; | position: absolute; |
top: 0; | top: 0; |
bottom: 0; | bottom: 0; |
width: 40px; | width: 40px; |
} | } |
.rickshaw_legend .label { | .rickshaw_legend .label { |
background: transparent !important; | background: transparent !important; |
color: #000000 !important; | color: #000000 !important; |
font-weight: normal !important; | font-weight: normal !important; |
} | |
.rickshaw_legend .instructions { | |
color: #000; | |
margin-bottom: 6px; | |
} | } |
.rickshaw_legend .line .action { | .rickshaw_legend .line .action { |
display: none; | display: none; |
} | } |
.rickshaw_legend .line .swatch { | .rickshaw_legend .line .swatch { |
display: block; | display: block; |
float: left; | float: left; |
} | } |
.rickshaw_legend .line .label { | .rickshaw_legend .line .label { |
display: block; | display: block; |
white-space: normal; | white-space: normal; |
float: left; | float: left; |
width: 200px; | width: 200px; |
} | } |
.rickshaw_legend .line .label:hover { | |
text-decoration: underline; | |
} | |
.ga-reports-table .td-numeric { | |
text-align: center; | |
} | |
var CKAN = CKAN || {}; | var CKAN = CKAN || {}; |
CKAN.GA_Reports = {}; | CKAN.GA_Reports = {}; |
CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) { | CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) { |
var graphLegends = $('#graph-legend-container'); | var graphLegends = $('#graph-legend-container'); |
if (!Modernizr.svg) { | if (!Modernizr.svg) { |
$("#chart_"+css_name) | $("#chart_"+css_name) |
.html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>') | .html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>') |
.closest('.rickshaw_chart_container').css('height',50); | .closest('.rickshaw_chart_container').css('height',50); |
var myLegend = $('<div id="legend_'+css_name+'"/>') | var myLegend = $('<div id="legend_'+css_name+'"/>') |
.html('(Graph cannot be rendered)') | .html('(Graph cannot be rendered)') |
.appendTo(graphLegends); | .appendTo(graphLegends); |
return; | return; |
} | } |
var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends); | var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends); |
var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } ); | var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } ); |
$.each(data, function(i, object) { | $.each(data, function(i, object) { |
object['color'] = palette.color(); | object['color'] = palette.color(); |
}); | }); |
// Rickshaw renders the legend in reverse order... | // Rickshaw renders the legend in reverse order... |
data.reverse(); | data.reverse(); |
var graphElement = document.querySelector("#chart_"+css_name); | var graphElement = document.querySelector("#chart_"+css_name); |
var graph = new Rickshaw.Graph( { | var graph = new Rickshaw.Graph( { |
element: document.querySelector("#chart_"+css_name), | element: document.querySelector("#chart_"+css_name), |
renderer: mode, | renderer: mode, |
series: data , | series: data , |
height: 328 | height: 328 |
}); | }); |
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } ); | var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } ); |
var y_axis = new Rickshaw.Graph.Axis.Y( { | var y_axis = new Rickshaw.Graph.Axis.Y( { |
graph: graph, | graph: graph, |
orientation: 'left', | orientation: 'left', |
tickFormat: Rickshaw.Fixtures.Number.formatKMBT, | tickFormat: Rickshaw.Fixtures.Number.formatKMBT, |
element: document.getElementById('y_axis_'+css_name) | element: document.getElementById('y_axis_'+css_name) |
} ); | } ); |
var legend = new Rickshaw.Graph.Legend( { | var legend = new Rickshaw.Graph.Legend( { |
element: document.querySelector('#legend_'+css_name), | element: document.querySelector('#legend_'+css_name), |
graph: graph | graph: graph |
} ); | } ); |
var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( { | var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( { |
graph: graph, | graph: graph, |
legend: legend | legend: legend |
} ); | } ); |
myLegend.prepend('<div class="instructions">Click on a series below to isolate its graph:</div>'); | |
graph.render(); | graph.render(); |
}; | }; |
CKAN.GA_Reports.bind_sparklines = function() { | CKAN.GA_Reports.bind_sparklines = function() { |
/* | /* |
* Bind to the 'totals' tab being on screen, when the | * Bind to the 'totals' tab being on screen, when the |
* Sparkline graphs should be drawn. | * Sparkline graphs should be drawn. |
* Note that they cannot be drawn sooner. | * Note that they cannot be drawn sooner. |
*/ | */ |
var created = false; | |
$('a[href="#totals"]').on( | $('a[href="#totals"]').on( |
'shown', | 'shown', |
function() { | function() { |
var sparkOptions = { | if (!created) { |
enableTagOptions: true, | var sparkOptions = { |
type: 'line', | enableTagOptions: true, |
width: 100, | type: 'line', |
height: 26, | width: 100, |
chartRangeMin: 0, | height: 26, |
spotColor: '', | chartRangeMin: 0, |
maxSpotColor: '', | spotColor: '', |
minSpotColor: '', | maxSpotColor: '', |
highlightSpotColor: '000000', | minSpotColor: '', |
lineColor: '3F8E6D', | highlightSpotColor: '#000000', |
fillColor: 'B7E66B' | lineColor: '#3F8E6D', |
}; | fillColor: '#B7E66B' |
$('.sparkline').sparkline('html',sparkOptions); | }; |
} | $('.sparkline').sparkline('html',sparkOptions); |
created = true; | |
} | |
$.sparkline_display_visible(); | |
} | |
); | ); |
}; | }; |
CKAN.GA_Reports.bind_sidebar = function() { | CKAN.GA_Reports.bind_sidebar = function() { |
/* | /* |
* Bind to changes in the tab behaviour: | * Bind to changes in the tab behaviour: |
* Show the correct rickshaw graph in the sidebar. | * Show the correct rickshaw graph in the sidebar. |
* Not to be called before all graphs load. | * Not to be called before all graphs load. |
*/ | */ |
$('a[data-toggle="hashchange"]').on( | $('a[data-toggle="hashchange"]').on( |
'shown', | 'shown', |
function(e) { | function(e) { |
var href = $(e.target).attr('href'); | var href = $(e.target).attr('href'); |
var pane = $(href); | var pane = $(href); |
if (!pane.length) { console.err('bad href',href); return; } | if (!pane.length) { console.err('bad href',href); return; } |
var legend_name = "none"; | var legend_name = "none"; |
var graph = pane.find('.rickshaw_chart'); | var graph = pane.find('.rickshaw_chart'); |
if (graph.length) { | if (graph.length) { |
legend_name = graph.attr('id').replace('chart_',''); | legend_name = graph.attr('id').replace('chart_',''); |
} | } |
legend_name = '#legend_'+legend_name; | legend_name = '#legend_'+legend_name; |
$('#graph-legend-container > *').hide(); | $('#graph-legend-container > *').hide(); |
$('#graph-legend-container .instructions').show(); | |
$(legend_name).show(); | $(legend_name).show(); |
} | } |
); | ); |
}; | }; |
CKAN.GA_Reports.bind_month_selector = function() { | CKAN.GA_Reports.bind_month_selector = function() { |
var handler = function(e) { | var handler = function(e) { |
var target = $(e.delegateTarget); | var target = $(e.delegateTarget); |
var form = target.closest('form'); | var form = target.closest('form'); |
var url = form.attr('action')+'?month='+target.val()+window.location.hash; | var url = form.attr('action')+'?month='+target.val()+window.location.hash; |
window.location = url; | window.location = url; |
}; | }; |
var selectors = $('select[name="month"]'); | var selectors = $('select[name="month"]'); |
assert(selectors.length>0); | assert(selectors.length>0); |
selectors.bind('change', handler); | selectors.bind('change', handler); |
}; | }; |
/* | /* |
* Custom bootstrap plugin for handling data-toggle="hashchange". | * Custom bootstrap plugin for handling data-toggle="hashchange". |
* Behaves like data-toggle="tab" but I respond to the hashchange. | * Behaves like data-toggle="tab" but I respond to the hashchange. |
* Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this? | * Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this? |
*/ | */ |
$(function() { | $(function() { |
var mapping = {}; | var mapping = {}; |
$('a[data-toggle="hashchange"]').each( | $('a[data-toggle="hashchange"]').each( |
function(i,link) { | function(i,link) { |
link = $(link); | link = $(link); |
mapping[link.attr('href')] = link; | mapping[link.attr('href')] = link; |
} | } |
); | ); |
$(window).hashchange(function() { | $(window).hashchange(function() { |
var link = mapping[window.location.hash]; | var link = mapping[window.location.hash]; |
if (link) { link.tab('show'); } | if (link) { link.tab('show'); } |
}); | }); |
}); | }); |
<html | <html |
xmlns="http://www.w3.org/1999/xhtml" | xmlns="http://www.w3.org/1999/xhtml" |
xmlns:i18n="http://genshi.edgewall.org/i18n" | xmlns:i18n="http://genshi.edgewall.org/i18n" |
xmlns:py="http://genshi.edgewall.org/" | xmlns:py="http://genshi.edgewall.org/" |
xmlns:xi="http://www.w3.org/2001/XInclude" | xmlns:xi="http://www.w3.org/2001/XInclude" |
py:strip="" | py:strip="" |
> | > |
<select name="month" py:def="month_selector(current_month, months, day)"> | <select name="month" py:def="month_selector(current_month, months, day)"> |
<option value='' py:attrs="{'selected': 'selected' if not current_month else None}">All months</option> | <option value='' py:attrs="{'selected': 'selected' if not current_month else None}">All months</option> |
<py:for each="i, (val,desc) in enumerate(months)"> | <py:for each="i, (val,desc) in enumerate(months)"> |
<option value='${val}' py:attrs="{'selected': 'selected' if current_month == val else None}">${desc}<py:if test="i == 0 and day"> (up to ${day})</py:if></option> | <option value='${val}' py:attrs="{'selected': 'selected' if current_month == val else None}">${desc}<py:if test="i == 0 and day"> (up to ${day})</py:if></option> |
</py:for> | </py:for> |
</select> | </select> |
<table py:def="social_table(items, with_source=False)" class="table table-condensed table-bordered table-striped"> | <table py:def="social_table(items, with_source=False)" class="ga-reports-table table table-condensed table-bordered table-striped"> |
<tr> | <tr> |
<th>Name</th> | <th>Name</th> |
<th py:if="with_source">Source</th> | <th py:if="with_source">Source</th> |
<th>Visits</th> | <th>Visits</th> |
</tr> | </tr> |
<py:for each="name, url, source, count in items"> | <py:for each="name, url, source, count in items"> |
<tr> | <tr> |
<td><a href="${url}">${name}</a></td> | <td><a href="${url}">${name}</a></td> |
<td py:if="with_source">${source}</td> | <td py:if="with_source">${source}</td> |
<td>${count}</td> | <td class="td-numeric">${count}</td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
<div py:def="rickshaw_graph(items_json,id,mode='line',colorscheme='munin')"> | <div py:def="rickshaw_graph(items_json,id,mode='line',colorscheme='munin')"> |
<div id="chart_container_$id" class="rickshaw_chart_container"> | <div id="chart_container_$id" class="rickshaw_chart_container"> |
<div id="y_axis_$id" class="rickshaw_y_axis"></div> | <div id="y_axis_$id" class="rickshaw_y_axis"></div> |
<div id="chart_$id" class="rickshaw_chart"></div> | <div id="chart_$id" class="rickshaw_chart"></div> |
<script type="text/javascript"> | <script type="text/javascript"> |
$(function() { | $(function() { |
var items = $items_json; | var items = $items_json; |
if (items.length==0) { return; } | if (items.length==0) { return; } |
CKAN.GA_Reports.render_rickshaw('$id', items, '$mode', '$colorscheme'); | CKAN.GA_Reports.render_rickshaw('$id', items, '$mode', '$colorscheme'); |
}); | }); |
</script> | </script> |
</div> | </div> |
</div> | </div> |
<table py:def="stat_table(items, title='Views')" class="table table-condensed table-bordered table-striped"> | <table py:def="stat_table(items, title='Views')" class="ga-reports-table table table-condensed table-bordered table-striped"> |
<tr> | <tr> |
<th>Name</th> | <th>Name</th> |
<th>% ${title}</th> | <th class="td-numeric">% ${title}</th> |
</tr> | </tr> |
<py:for each="name, value in items"> | <py:for each="name, value in items"> |
<tr> | <tr> |
<td>${name}</td> | <td>${name}</td> |
<td>${value}</td> | <td class="td-numeric">${value}</td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
<div py:def="usage_nav(active_name)" id="minornavigation"> | <div py:def="usage_nav(active_name)" id="minornavigation"> |
<div id="minornavigation-bg-left"> | <div id="minornavigation-bg-left"> |
<div id="minornavigation-bg-right"> | <div id="minornavigation-bg-right"> |
<ul class="nav nav-pills"> | <ul class="nav nav-pills"> |
<li py:attrs="{'class': 'active' if active_name=='Site-wide' else None}"><a py:attrs="{'class': 'active' if active_name=='Site-wide' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Site-wide</a></li> | <?python querystring='?month='+c.month if c.month else '' ?> |
<li py:attrs="{'class': 'active' if active_name=='Site-wide' else None}"><a py:attrs="{'class': 'active' if active_name=='Site-wide' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}${querystring}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Site-wide</a></li> | |
<li py:attrs="{'class': 'active' if active_name=='Publishers' else None}"> | <li py:attrs="{'class': 'active' if active_name=='Publishers' else None}"> |
<a py:attrs="{'class': 'active' if active_name=='Publishers' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Publishers</a> | <a py:attrs="{'class': 'active' if active_name=='Publishers' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}${querystring}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Publishers</a> |
</li> | </li> |
<li py:attrs="{'class': 'active' if active_name=='Datasets' else None}"> | <li py:attrs="{'class': 'active' if active_name=='Datasets' else None}"> |
<a py:attrs="{'class': 'active' if active_name=='Datasets' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Datasets</a> | <a py:attrs="{'class': 'active' if active_name=='Datasets' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}${querystring}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Datasets</a> |
</li> | </li> |
</ul> | </ul> |
</div> | </div> |
</div> | </div> |
</div> | </div> |
</html> | </html> |
<html xmlns:py="http://genshi.edgewall.org/" | <html xmlns:py="http://genshi.edgewall.org/" |
xmlns:i18n="http://genshi.edgewall.org/i18n" | xmlns:i18n="http://genshi.edgewall.org/i18n" |
xmlns:xi="http://www.w3.org/2001/XInclude" | xmlns:xi="http://www.w3.org/2001/XInclude" |
py:strip=""> | py:strip=""> |
<xi:include href="../ga_util.html" /> | <xi:include href="../ga_util.html" /> |
<py:def function="page_title">Usage by Publisher</py:def> | <py:def function="page_title">Usage by Publisher</py:def> |
<py:match path="primarysidebar"> | <py:match path="primarysidebar"> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Download</h4> | <h4>Download</h4> |
<p><center> | <p><center> |
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center> | <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center> |
</p> | </p> |
</li> | </li> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Graph Legend</h4> | <h4>Graph Legend</h4> |
<div id="graph-legend-container"> | <div id="graph-legend-container"> |
</div> | </div> |
</li> | </li> |
<xi:include href="../notes.html" /> | <xi:include href="../notes.html" /> |
</py:match> | </py:match> |
<py:def function="optional_head"> | <py:def function="optional_head"> |
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> | <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> |
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> | <link rel="stylesheet" type="text/css" href="/css/ga_report.css?1"/> |
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> | <script type="text/javascript" src="/scripts/ckanext_ga_reports.js?1"></script> |
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> | <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> |
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> | <script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> |
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> |
</py:def> | </py:def> |
<div py:match="content"> | <div py:match="content"> |
<h1>Site Usage</h1> | <h1>Site Usage</h1> |
${usage_nav('Publishers')} | ${usage_nav('Publishers')} |
${rickshaw_graph(c.top_publishers_graph,'publishers')} | ${rickshaw_graph(c.top_publishers_graph,'publishers')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get"> |
<div class="controls"> | <div class="controls"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</div> | </div> |
</form> | </form> |
<table class="table table-condensed table-bordered table-striped"> | <table class="ga-reports-table table table-condensed table-bordered table-striped"> |
<tr> | <tr> |
<th>Publisher</th> | <th>Publisher</th> |
<th>Dataset Views</th> | <th class="td-numeric">Dataset Views</th> |
</tr> | </tr> |
<py:for each="publisher, views, visits in c.top_publishers"> | <py:for each="publisher, views, visits in c.top_publishers"> |
<tr> | <tr> |
<td> | <td> |
${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))} | ${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))} |
</td> | </td> |
<td>${views}</td> | <td class="td-numeric">${views}</td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
</div> | </div> |
<py:def function="optional_footer"> | <py:def function="optional_footer"> |
<script type="text/javascript"> | <script type="text/javascript"> |
$(function() { | $(function() { |
CKAN.GA_Reports.bind_month_selector(); | CKAN.GA_Reports.bind_month_selector(); |
}); | }); |
</script> | </script> |
</py:def> | </py:def> |
<xi:include href="../../layout.html" /> | <xi:include href="../../layout.html" /> |
</html> | </html> |
<html xmlns:py="http://genshi.edgewall.org/" | <html xmlns:py="http://genshi.edgewall.org/" |
xmlns:i18n="http://genshi.edgewall.org/i18n" | xmlns:i18n="http://genshi.edgewall.org/i18n" |
xmlns:xi="http://www.w3.org/2001/XInclude" | xmlns:xi="http://www.w3.org/2001/XInclude" |
py:strip=""> | py:strip=""> |
<xi:include href="../ga_util.html" /> | <xi:include href="../ga_util.html" /> |
<py:def function="page_title">Usage by Dataset</py:def> | <py:def function="page_title">Usage by Dataset</py:def> |
<py:def function="optional_head"> | <py:def function="optional_head"> |
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> | <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> |
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> | <link rel="stylesheet" type="text/css" href="/css/ga_report.css?1"/> |
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> | <script type="text/javascript" src="/scripts/ckanext_ga_reports.js?1"></script> |
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> | <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> |
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> | <script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> |
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> |
</py:def> | </py:def> |
<py:match path="primarysidebar"> | <py:match path="primarysidebar"> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Download</h4> | <h4>Download</h4> |
<p><center> | <p><center> |
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center> | <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center> |
</p> | </p> |
</li> | </li> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Graph Legend</h4> | <h4>Graph Legend</h4> |
<div id="graph-legend-container"> | <div id="graph-legend-container"> |
</div> | </div> |
</li> | </li> |
<xi:include href="../notes.html" /> | <xi:include href="../notes.html" /> |
</py:match> | </py:match> |
<div py:match="content"> | <div py:match="content"> |
<h1>Site Usage</h1> | <h1>Site Usage</h1> |
${usage_nav('Datasets')} | ${usage_nav('Datasets')} |
<h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3> | <h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3> |
<p py:if="not c.top_packages">No page views in this period</p> | <p py:if="not c.top_packages">No page views in this period</p> |
<py:if test="c.top_packages"> | <py:if test="c.top_packages"> |
${rickshaw_graph(c.graph_data,'dataset-downloads',debug=True)} | ${rickshaw_graph(c.graph_data,'dataset-downloads',debug=True)} |
</py:if> | </py:if> |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}" method="get"> |
<div class="controls"> | <div class="controls"> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
<select name="publisher"> | <select name="publisher"> |
<option value='' py:attrs="{'selected': 'selected' if not c.publisher else None}">All publishers</option> | <option value='' py:attrs="{'selected': 'selected' if not c.publisher else None}">All publishers</option> |
<py:for each="val,desc in c.publishers"> | <py:for each="val,desc in c.publishers"> |
<option value='${val}' py:attrs="{'selected': 'selected' if c.publisher_name == val else None}">${desc}</option> | <option value='${val}' py:attrs="{'selected': 'selected' if c.publisher_name == val else None}">${desc}</option> |
</py:for> | </py:for> |
</select> | </select> |
<input class="btn button btn-primary" type='submit' value="Update"/> | <input class="btn button btn-primary" type='submit' value="Update"/> |
</div> | </div> |
</form> | </form> |
<py:if test="c.top_packages"> | <py:if test="c.top_packages"> |
<table class="table table-condensed table-bordered table-striped"> | <table class="ga-reports-table table table-condensed table-bordered table-striped"> |
<tr> | <tr> |
<th>Dataset</th> | <th>Dataset</th> |
<th>Views</th> | <th>Views</th> |
<th>Downloads</th> | <th>Downloads</th> |
</tr> | </tr> |
<py:for each="package, views, visits,downloads in c.top_packages"> | <py:for each="package, views, visits,downloads in c.top_packages"> |
<tr> | <tr> |
<td> | <td> |
${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))} | ${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))} |
</td> | </td> |
<td>${views}</td> | <td class="td-numeric">${views}</td> |
<td>${downloads}</td> | <td class="td-numeric">${downloads}</td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
</py:if> | </py:if> |
</div> | </div> |
<xi:include href="../../layout.html" /> | <xi:include href="../../layout.html" /> |
</html> | </html> |
<html xmlns:py="http://genshi.edgewall.org/" | <html xmlns:py="http://genshi.edgewall.org/" |
xmlns:i18n="http://genshi.edgewall.org/i18n" | xmlns:i18n="http://genshi.edgewall.org/i18n" |
xmlns:xi="http://www.w3.org/2001/XInclude" | xmlns:xi="http://www.w3.org/2001/XInclude" |
py:strip=""> | py:strip=""> |
<xi:include href="../ga_util.html" /> | <xi:include href="../ga_util.html" /> |
<py:def function="page_title">Site usage</py:def> | <py:def function="page_title">Site usage</py:def> |
<py:def function="optional_head"> | <py:def function="optional_head"> |
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> | <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> |
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> | <link rel="stylesheet" type="text/css" href="/css/ga_report.css?1"/> |
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> | <script type="text/javascript" src="/scripts/ckanext_ga_reports.js?1"></script> |
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> | <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> |
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> | <script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> |
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> |
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> | <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> |
</py:def> | </py:def> |
<py:match path="primarysidebar"> | <py:match path="primarysidebar"> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Download</h4> | <h4>Download</h4> |
<p><center> | <p><center> |
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center> | <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center> |
</p> | </p> |
</li> | </li> |
<li class="widget-container boxed widget_text"> | <li class="widget-container boxed widget_text"> |
<h4>Graph Legend</h4> | <h4>Graph Legend</h4> |
<div id="graph-legend-container"> | <div id="graph-legend-container"> |
<div id="legend_none">(No graph loaded)</div> | <div id="legend_none">(No graph loaded)</div> |
</div> | </div> |
</li> | </li> |
<xi:include href="../notes.html" /> | <xi:include href="../notes.html" /> |
</py:match> | </py:match> |
<div py:match="content"> | <div py:match="content"> |
<h1>Site Usage</h1> | <h1>Site Usage</h1> |
${usage_nav('Site-wide')} | ${usage_nav('Site-wide')} |
<div class="tabbable"> | <div class="tabbable"> |
<ul class="nav nav-tabs"> | <ul class="nav nav-tabs"> |
<li><a href="#totals" data-toggle="hashchange">Totals</a></li> | <li><a href="#totals" data-toggle="hashchange">Totals</a></li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li> | <li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li> |
<li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li> | <li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li> |
</ul> | </ul> |
</li> | </li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#os" data-toggle="hashchange">Operating Systems</a></li> | <li><a href="#os" data-toggle="hashchange">Operating Systems</a></li> |
<li><a href="#os_versions" data-toggle="hashchange">Versions</a></li> | <li><a href="#os_versions" data-toggle="hashchange">Versions</a></li> |
</ul> | </ul> |
</li> | </li> |
<li class="dropdown"> | <li class="dropdown"> |
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Social | <a href="#" class="dropdown-toggle" data-toggle="dropdown">Social |
<b class="caret"></b></a> | <b class="caret"></b></a> |
<ul class="dropdown-menu"> | <ul class="dropdown-menu"> |
<li><a href="#social_networks" data-toggle="hashchange">All networks</a></li> | <li><a href="#social_networks" data-toggle="hashchange">All networks</a></li> |
<li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li> | <li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li> |
</ul> | </ul> |
</li> | </li> |
<li><a href="#languages" data-toggle="hashchange">Languages</a></li> | <li><a href="#languages" data-toggle="hashchange">Languages</a></li> |
<li><a href="#country" data-toggle="hashchange">Country</a></li> | <li><a href="#country" data-toggle="hashchange">Country</a></li> |
</ul> | </ul> |
<div class="tab-content"> | <div class="tab-content"> |
<div class="tab-pane" id="totals"> | <div class="tab-pane" id="totals"> |
<table class="table table-condensed table-bordered table-striped"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | |
${month_selector(c.month, c.months, c.day)} | |
</form> | |
<table class="ga-reports-table table table-condensed table-bordered table-striped"> | |
<tr> | <tr> |
<th>Name</th> | <th>Name</th> |
<th>Value</th> | <th class="td-numeric">Value</th> |
<th>History</th> | <th>History</th> |
</tr> | </tr> |
<py:for each="name, value, graph in c.global_totals"> | <py:for each="name, value, graph in c.global_totals"> |
<tr> | <tr> |
<td>${name}</td> | <td>${name}</td> |
<td>${value}</td> | <td class="td-numeric">${value}</td> |
<td class="sparkline-cell"> | <td class="sparkline-cell"> |
<span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}"> | <span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}"> |
${','.join([y for x,y in graph])} | ${','.join([y for x,y in graph])} |
</span> | </span> |
</td> | </td> |
</tr> | </tr> |
</py:for> | </py:for> |
</table> | </table> |
</div> | </div> |
<div class="tab-pane" id="browsers_versions"> | <div class="tab-pane" id="browsers_versions"> |
${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')} | ${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')} |
<p>Note: Where a browser has a large number of versions, these have been grouped together.</p> | <p>Note: Where a browser has a large number of versions, these have been grouped together.</p> |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.browser_versions)} | ${stat_table(c.browser_versions)} |
</div> | </div> |
<div class="tab-pane" id="browsers_names"> | <div class="tab-pane" id="browsers_names"> |
${rickshaw_graph(c.browsers_graph,'browsers',mode='stack')} | ${rickshaw_graph(c.browsers_graph,'browsers',mode='stack')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.browsers)} | ${stat_table(c.browsers)} |
</div> | </div> |
<div class="tab-pane" id="os"> | <div class="tab-pane" id="os"> |
${rickshaw_graph(c.os_graph,'os',mode='stack')} | ${rickshaw_graph(c.os_graph,'os',mode='stack')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.os)} | ${stat_table(c.os)} |
</div> | </div> |
<div class="tab-pane" id="os_versions"> | <div class="tab-pane" id="os_versions"> |
${rickshaw_graph(c.os_versions_graph,'os_versions',mode='stack')} | ${rickshaw_graph(c.os_versions_graph,'os_versions',mode='stack')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.os_versions)} | ${stat_table(c.os_versions)} |
</div> | </div> |
<div class="tab-pane" id="social_referrals_totals"> | <div class="tab-pane" id="social_referrals_totals"> |
<p>Number of visits that were referred from social networks</p> | <p>Number of visits that were referred from social networks</p> |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${social_table(c.social_referrer_totals)} | ${social_table(c.social_referrer_totals)} |
</div> | </div> |
<div class="tab-pane" id="social_networks"> | <div class="tab-pane" id="social_networks"> |
${rickshaw_graph(c.social_networks_graph, 'social_networks',mode='stack')} | ${rickshaw_graph(c.social_networks_graph, 'social_networks',mode='stack')} |
<p>Percentage of visits that were referred from these social networks</p> | <p>Percentage of visits that were referred from these social networks</p> |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.social_networks, 'Visits')} | ${stat_table(c.social_networks, 'Visits')} |
</div> | </div> |
<div class="tab-pane" id="languages"> | <div class="tab-pane" id="languages"> |
${rickshaw_graph(c.languages_graph,'languages',mode='stack')} | ${rickshaw_graph(c.languages_graph,'languages',mode='stack')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.languages)} | ${stat_table(c.languages)} |
</div> | </div> |
<div class="tab-pane" id="country"> | <div class="tab-pane" id="country"> |
${rickshaw_graph(c.country_graph,'country',mode='stack')} | ${rickshaw_graph(c.country_graph,'country',mode='stack')} |
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> | <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> |
<label>Show stats table for:</label> | <label>Show stats table for:</label> |
${month_selector(c.month, c.months, c.day)} | ${month_selector(c.month, c.months, c.day)} |
</form> | </form> |
${stat_table(c.country)} | ${stat_table(c.country)} |
</div> | </div> |
</div> | </div> |
</div> | </div> |
</div> | </div> |
<py:def function="optional_footer"> | <py:def function="optional_footer"> |
<script type="text/javascript"> | <script type="text/javascript"> |
$(function() { | $(function() { |
CKAN.GA_Reports.bind_sparklines(); | CKAN.GA_Reports.bind_sparklines(); |
CKAN.GA_Reports.bind_sidebar(); | CKAN.GA_Reports.bind_sidebar(); |
CKAN.GA_Reports.bind_month_selector(); | CKAN.GA_Reports.bind_month_selector(); |
if (!window.location.hash) { | if (!window.location.hash) { |
window.location.hash='totals'; | window.location.hash='totals'; |
} | } |
else { | else { |
$(window).trigger('hashchange'); | $(window).trigger('hashchange'); |
} | } |
}); | }); |
</script> | </script> |
</py:def> | </py:def> |
<xi:include href="../../layout.html" /> | <xi:include href="../../layout.html" /> |
</html> | </html> |