Changes to support % of bounces from /
--- a/README.rst
+++ b/README.rst
@@ -33,6 +33,10 @@
googleanalytics.id = UA-1010101-1
googleanalytics.account = Account name (i.e. data.gov.uk, see top level item at https://www.google.com/analytics)
ga-report.period = monthly
+ ga-report.bounce_url = /data
+
+ The ga-report.bounce_url specifies the path to use when calculating bounces. For DGU this is /data
+ but you may want to set this to /.
Note that your credentials will be readable by system administrators on your server. Rather than use sensitive account details, it is suggested you give access to the GA account to a new Google account that you create just for this purpose.
--- a/ckanext/ga_report/controller.py
+++ b/ckanext/ga_report/controller.py
@@ -4,12 +4,12 @@
import logging
import operator
import collections
-from ckan.lib.base import BaseController, c, render, request, response, abort
+from ckan.lib.base import (BaseController, c, g, render, request, response, abort)
import sqlalchemy
from sqlalchemy import func, cast, Integer
import ckan.model as model
-from ga_model import GA_Url, GA_Stat
+from ga_model import GA_Url, GA_Stat, GA_ReferralStat
log = logging.getLogger('ckanext.ga-report')
@@ -58,7 +58,7 @@
c.months = _month_details(GA_Stat)
# Work out which month to show, based on query params of the first item
- c.month_desc = 'all time'
+ c.month_desc = 'all months'
c.month = request.params.get('month', '')
if c.month:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
@@ -70,14 +70,17 @@
entries = q.order_by('ga_stat.key').all()
def clean_key(key, val):
- if key in ['Average time on site', 'Pages per visit', 'Percent new visits']:
+ if key in ['Average time on site', 'Pages per visit', 'New visits', 'Bounces']:
val = "%.2f" % round(float(val), 2)
if key == 'Average time on site':
mins, secs = divmod(float(val), 60)
hours, mins = divmod(mins, 60)
val = '%02d:%02d:%02d (%s seconds) ' % (hours, mins, secs, val)
- if key in ['Bounces', 'Total pageviews']:
+ if key in ['New visits','Bounces']:
+ val = "%s%%" % val
+ if key in ['Total page views', 'Total visits']:
val = int(val)
+
return key, val
c.global_totals = []
@@ -90,21 +93,48 @@
for e in entries:
d[e.key].append(float(e.value))
for k, v in d.iteritems():
- if k in ['Bounces', 'Total pageviews']:
+ if k in ['Total page views', 'Total visits']:
v = sum(v)
else:
v = float(sum(v))/len(v)
key, val = clean_key(k,v)
+
c.global_totals.append((key, val))
c.global_totals = sorted(c.global_totals, key=operator.itemgetter(0))
keys = {
- 'Browser versions': 'browsers',
- 'Operating Systems versions': 'os',
+ 'Browser versions': 'browser_versions',
+ 'Browsers': 'browsers',
+ 'Operating Systems versions': 'os_versions',
+ 'Operating Systems': 'os',
'Social sources': 'social_networks',
'Languages': 'languages',
'Country': 'country'
}
+
+ def shorten_name(name, length=60):
+ return (name[:length] + '..') if len(name) > 60 else name
+
+ def fill_out_url(url):
+ import urlparse
+ return urlparse.urljoin(g.site_url, url)
+
+ c.social_referrer_totals, c.social_referrers = [], []
+ q = model.Session.query(GA_ReferralStat)
+ q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q
+ q = q.order_by('ga_referrer.count::int desc')
+ for entry in q.all():
+ c.social_referrers.append((shorten_name(entry.url), fill_out_url(entry.url),
+ entry.source,entry.count))
+
+ q = model.Session.query(GA_ReferralStat.url,
+ func.sum(GA_ReferralStat.count).label('count'))
+ 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)
+ for entry in q.all():
+ c.social_referrer_totals.append((shorten_name(entry[0]), fill_out_url(entry[0]),'',
+ entry[1]))
+
browser_version_re = re.compile("(.*)\((.*)\)")
for k, v in keys.iteritems():
@@ -143,9 +173,13 @@
entries.append((key,val,))
entries = sorted(entries, key=operator.itemgetter(1), reverse=True)
- setattr(c, v, [(k,v) for k,v in entries ])
-
-
+ # Get the total for each set of values and then set the value as
+ # a percentage of the total
+ if k == 'Social sources':
+ total = sum([x for n,x in c.global_totals if n == 'Total visits'])
+ else:
+ total = sum([num for _,num in entries])
+ setattr(c, v, [(k,_percent(v,total)) for k,v in entries ])
return render('ga_report/site/index.html')
@@ -164,7 +198,7 @@
writer = csv.writer(response)
writer.writerow(["Publisher", "Views", "Visits", "Period Name"])
- for publisher,view,visit in self._get_publishers(None):
+ for publisher,view,visit in _get_publishers(None):
writer.writerow([publisher.title.encode('utf-8'),
view,
visit,
@@ -203,42 +237,14 @@
# Work out which month to show, based on query params of the first item
c.month = request.params.get('month', '')
- c.month_desc = 'all time'
+ c.month_desc = 'all months'
if c.month:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
- c.top_publishers = self._get_publishers()
+ c.top_publishers = _get_publishers()
return render('ga_report/publisher/index.html')
- def _get_publishers(self, limit=20):
- connection = model.Session.connection()
- q = """
- select department_id, sum(pageviews::int) views, sum(visitors::int) visits
- from ga_url
- where department_id <> ''"""
- if c.month:
- q = q + """
- and period_name=%s
- """
- q = q + """
- group by department_id order by views desc
- """
- if limit:
- q = q + " limit %s;" % (limit)
-
- # Add this back (before and period_name =%s) if you want to ignore publisher
- # homepage views
- # and not url like '/publisher/%%'
-
- top_publishers = []
- res = connection.execute(q, c.month)
-
- for row in res:
- g = model.Group.get(row[0])
- if g:
- top_publishers.append((g, row[1], row[2]))
- return top_publishers
def _get_packages(self, publisher, count=-1):
if count == -1:
@@ -290,7 +296,7 @@
# Work out which month to show, based on query params of the first item
c.month = request.params.get('month', '')
if not c.month:
- c.month_desc = 'all time'
+ c.month_desc = 'all months'
else:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
@@ -308,3 +314,37 @@
return render('ga_report/publisher/read.html')
+def _get_publishers(limit=20):
+ connection = model.Session.connection()
+ q = """
+ select department_id, sum(pageviews::int) views, sum(visitors::int) visits
+ from ga_url
+ where department_id <> ''"""
+ if c.month:
+ q = q + """
+ and period_name=%s
+ """
+ q = q + """
+ group by department_id order by views desc
+ """
+ if limit:
+ q = q + " limit %s;" % (limit)
+
+ # Add this back (before and period_name =%s) if you want to ignore publisher
+ # homepage views
+ # and not url like '/publisher/%%'
+
+ top_publishers = []
+ res = connection.execute(q, c.month)
+
+ for row in res:
+ g = model.Group.get(row[0])
+ if g:
+ top_publishers.append((g, row[1], row[2]))
+ return top_publishers
+
+
+def _percent(num, total):
+ p = 100 * float(num)/float(total)
+ return "%.2f%%" % round(p, 2)
+
--- a/ckanext/ga_report/download_analytics.py
+++ b/ckanext/ga_report/download_analytics.py
@@ -1,7 +1,7 @@
import os
import logging
import datetime
-
+import collections
from pylons import config
import ga_model
@@ -108,6 +108,33 @@
ga_model.update_publisher_stats(period_name) # about 30 seconds.
self.sitewide_stats( period_name )
+ self.update_social_info(period_name, start_date, end_date)
+
+ def update_social_info(self, period_name, start_date, end_date):
+ start_date = start_date.strftime('%Y-%m-%d')
+ end_date = end_date.strftime('%Y-%m-%d')
+ query = 'ga:hasSocialSourceReferral=~Yes$'
+ metrics = 'ga:entrances'
+ sort = '-ga:entrances'
+
+ # Supported query params at
+ # https://developers.google.com/analytics/devguides/reporting/core/v3/reference
+ results = self.service.data().ga().get(
+ ids='ga:' + self.profile_id,
+ filters=query,
+ start_date=start_date,
+ metrics=metrics,
+ sort=sort,
+ dimensions="ga:landingPagePath,ga:socialNetwork",
+ max_results=10000,
+ end_date=end_date).execute()
+ data = collections.defaultdict(list)
+ rows = results.get('rows',[])
+ for row in rows:
+ from ga_model import _normalize_url
+ data[_normalize_url(row[0])].append( (row[1], int(row[2]),) )
+ ga_model.update_social(period_name, data)
+
def download(self, start_date, end_date, path='~/dataset/[a-z0-9-_]+'):
'''Get data from GA for a given time period'''
@@ -129,11 +156,6 @@
max_results=10000,
end_date=end_date).execute()
- if os.getenv('DEBUG'):
- import pprint
- pprint.pprint(results)
- print 'Total results: %s' % results.get('totalResults')
-
packages = []
for entry in results.get('rows'):
(loc,pageviews,visits) = entry
@@ -176,22 +198,42 @@
max_results=10000,
end_date=end_date).execute()
result_data = results.get('rows')
- ga_model.update_sitewide_stats(period_name, "Totals", {'Total pageviews': result_data[0][0]})
-
- results = self.service.data().ga().get(
- ids='ga:' + self.profile_id,
- start_date=start_date,
- metrics='ga:pageviewsPerVisit,ga:bounces,ga:avgTimeOnSite,ga:percentNewVisits',
+ ga_model.update_sitewide_stats(period_name, "Totals", {'Total page views': result_data[0][0]})
+
+ results = self.service.data().ga().get(
+ ids='ga:' + self.profile_id,
+ start_date=start_date,
+ metrics='ga:pageviewsPerVisit,ga:avgTimeOnSite,ga:percentNewVisits,ga:visitors',
max_results=10000,
end_date=end_date).execute()
result_data = results.get('rows')
data = {
'Pages per visit': result_data[0][0],
- 'Bounces': result_data[0][1],
- 'Average time on site': result_data[0][2],
- 'Percent new visits': result_data[0][3],
+ 'Average time on site': result_data[0][1],
+ 'New visits': result_data[0][2],
+ 'Total visits': result_data[0][3],
}
ga_model.update_sitewide_stats(period_name, "Totals", data)
+
+ # Bounces from /data. This url is specified in configuration because
+ # for DGU we don't want /.
+ path = config.get('ga-report.bounce_url','/')
+ print path
+ results = self.service.data().ga().get(
+ ids='ga:' + self.profile_id,
+ filters='ga:pagePath=~%s$' % (path,),
+ start_date=start_date,
+ metrics='ga:bounces,ga:uniquePageviews',
+ dimensions='ga:pagePath',
+ max_results=10000,
+ end_date=end_date).execute()
+ result_data = results.get('rows')
+ for results in result_data:
+ if results[0] == path:
+ bounce, total = [float(x) for x in results[1:]]
+ pct = 100 * bounce/total
+ print "%d bounces from %d total == %s" % (bounce, total, pct)
+ ga_model.update_sitewide_stats(period_name, "Totals", {'Bounces': pct})
def _locale_stats(self, start_date, end_date, period_name):
--- a/ckanext/ga_report/ga_model.py
+++ b/ckanext/ga_report/ga_model.py
@@ -13,6 +13,8 @@
def make_uuid():
return unicode(uuid.uuid4())
+metadata = MetaData()
+
class GA_Url(object):
@@ -21,20 +23,6 @@
for k,v in kwargs.items():
setattr(self, k, v)
-class GA_Stat(object):
-
- def __init__(self, **kwargs):
- for k,v in kwargs.items():
- setattr(self, k, v)
-
-class GA_Publisher(object):
-
- def __init__(self, **kwargs):
- for k,v in kwargs.items():
- setattr(self, k, v)
-
-
-metadata = MetaData()
url_table = Table('ga_url', metadata,
Column('id', types.UnicodeText, primary_key=True,
default=make_uuid),
@@ -47,6 +35,13 @@
)
mapper(GA_Url, url_table)
+
+class GA_Stat(object):
+
+ def __init__(self, **kwargs):
+ for k,v in kwargs.items():
+ setattr(self, k, v)
+
stat_table = Table('ga_stat', metadata,
Column('id', types.UnicodeText, primary_key=True,
default=make_uuid),
@@ -56,6 +51,12 @@
Column('value', types.UnicodeText), )
mapper(GA_Stat, stat_table)
+
+class GA_Publisher(object):
+
+ def __init__(self, **kwargs):
+ for k,v in kwargs.items():
+ setattr(self, k, v)
pub_table = Table('ga_publisher', metadata,
Column('id', types.UnicodeText, primary_key=True,
@@ -71,6 +72,24 @@
mapper(GA_Publisher, pub_table)
+class GA_ReferralStat(object):
+
+ def __init__(self, **kwargs):
+ for k,v in kwargs.items():
+ setattr(self, k, v)
+
+referrer_table = Table('ga_referrer', metadata,
+ Column('id', types.UnicodeText, primary_key=True,
+ default=make_uuid),
+ Column('period_name', types.UnicodeText),
+ Column('source', types.UnicodeText),
+ Column('url', types.UnicodeText),
+ Column('count', types.Integer),
+ )
+mapper(GA_ReferralStat, referrer_table)
+
+
+
def init_tables():
metadata.create_all(model.meta.engine)
@@ -93,8 +112,9 @@
>>> normalize_url('http://data.gov.uk/dataset/weekly_fuel_prices')
'/dataset/weekly_fuel_prices'
'''
- url = re.sub('https?://(www\.)?data.gov.uk', '', url)
- return url
+ # Deliberately leaving a /
+ url = url.replace('http:/','')
+ return '/' + '/'.join(url.split('/')[2:])
def _get_department_id_of_url(url):
@@ -167,6 +187,33 @@
model.Session.commit()
+def update_social(period_name, data):
+ # Clean up first.
+ model.Session.query(GA_ReferralStat).\
+ filter(GA_ReferralStat.period_name==period_name).delete()
+
+ for url,data in data.iteritems():
+ for entry in data:
+ source = entry[0]
+ count = entry[1]
+
+ item = model.Session.query(GA_ReferralStat).\
+ filter(GA_ReferralStat.period_name==period_name).\
+ filter(GA_ReferralStat.source==source).\
+ filter(GA_ReferralStat.url==url).first()
+ if item:
+ item.count = item.count + count
+ model.Session.add(item)
+ else:
+ # create the row
+ values = {'id': make_uuid(),
+ 'period_name': period_name,
+ 'source': source,
+ 'url': url,
+ 'count': count,
+ }
+ model.Session.add(GA_ReferralStat(**values))
+ model.Session.commit()
def update_publisher_stats(period_name):
"""
--- a/ckanext/ga_report/helpers.py
+++ b/ckanext/ga_report/helpers.py
@@ -3,15 +3,73 @@
import ckan.lib.base as base
import ckan.model as model
+from ckanext.ga_report.ga_model import GA_Url, GA_Publisher
+from ckanext.ga_report.controller import _get_publishers
_log = logging.getLogger(__name__)
+def popular_datasets(count=10):
+ import random
+
+ publisher = None
+ publishers = _get_publishers(30)
+ total = len(publishers)
+ while not publisher or not datasets:
+ rand = random.randrange(0, total)
+ publisher = publishers[rand][0]
+ if not publisher.state == 'active':
+ publisher = None
+ continue
+ datasets = _datasets_for_publisher(publisher, 10)[:count]
+
+ ctx = {
+ 'datasets': datasets,
+ 'publisher': publisher
+ }
+ return base.render_snippet('ga_report/ga_popular_datasets.html', **ctx)
+
+def single_popular_dataset(top=20):
+ import random
+
+ datasets = {}
+ rand = random.randrange(0, top)
+ entry = model.Session.query(GA_Url).\
+ filter(GA_Url.url.like('/dataset/%')).\
+ order_by('ga_url.pageviews::int desc')[rand]
+
+
+ dataset = None
+ while not dataset:
+ dataset = model.Package.get(entry.url[len('/dataset/'):])
+ if dataset and not dataset.state == 'active':
+ dataset = None
+ else:
+ publisher = model.Group.get(entry.department_id)
+
+ ctx = {
+ 'dataset': dataset,
+ 'publisher': publisher
+ }
+ return base.render_snippet('ga_report/ga_popular_single.html', **ctx)
+
+
def most_popular_datasets(publisher, count=20):
- from ckanext.ga_report.ga_model import GA_Url
if not publisher:
_log.error("No valid publisher passed to 'most_popular_datasets'")
return ""
+ results = _datasets_for_publisher(publisher, count)
+
+ ctx = {
+ 'dataset_count': len(datasets),
+ 'datasets': results,
+
+ 'publisher': publisher
+ }
+
+ return base.render_snippet('ga_report/publisher/popular.html', **ctx)
+
+def _datasets_for_publisher(publisher, count):
datasets = {}
entries = model.Session.query(GA_Url).\
filter(GA_Url.department_id==publisher.name).\
@@ -29,14 +87,5 @@
for k, v in datasets.iteritems():
results.append((k,v['views'],v['visits']))
- results = sorted(results, key=operator.itemgetter(1), reverse=True)
+ return sorted(results, key=operator.itemgetter(1), reverse=True)
- ctx = {
- 'dataset_count': len(datasets),
- 'datasets': results,
-
- 'publisher': publisher
- }
-
- return base.render_snippet('ga_report/publisher/popular.html', **ctx)
-
--- a/ckanext/ga_report/plugin.py
+++ b/ckanext/ga_report/plugin.py
@@ -2,6 +2,10 @@
import ckan.lib.helpers as h
import ckan.plugins as p
from ckan.plugins import implements, toolkit
+
+from ckanext.ga_report.helpers import (most_popular_datasets,
+ popular_datasets,
+ single_popular_dataset)
log = logging.getLogger('ckanext.ga-report')
@@ -19,10 +23,11 @@
A dictionary of extra helpers that will be available to provide
ga report info to templates.
"""
- from ckanext.ga_report.helpers import most_popular_datasets
return {
'ga_report_installed': lambda: True,
+ 'popular_datasets': popular_datasets,
'most_popular_datasets': most_popular_datasets,
+ 'single_popular_dataset': single_popular_dataset
}
def after_map(self, map):
--- a/ckanext/ga_report/report_model.py
+++ /dev/null
--- /dev/null
+++ b/ckanext/ga_report/templates/ga_report/ga_popular_datasets.html
@@ -1,1 +1,27 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+<div class="popular_datasets">
+ <div class="pull-right">
+ <a href="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='index')}" class="btn btn-primary">More popular datasets »</a>
+ </div>
+ <h2>Popular datasets</h2>
+ <h4>${publisher.title}</h4>
+ <ul>
+ <py:for each="dataset, _, _ in datasets">
+ <li>
+ <span>${h.link_to(dataset.title, h.url_for(controller='package', action='read', id=dataset.name))}</span>
+ <div>${h.truncate(dataset.notes, length=80, whole_word=True)}</div>
+ </li>
+ </py:for>
+ </ul>
+
+ </div>
+
+</html>
+
+
+
+
--- /dev/null
+++ b/ckanext/ga_report/templates/ga_report/ga_popular_single.html
@@ -1,1 +1,23 @@
+<html xmlns:py="http://genshi.edgewall.org/"
+ xmlns:i18n="http://genshi.edgewall.org/i18n"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+
+<div class="popular_datasets">
+ <h2>Featured dataset</h2>
+
+ <h3>${h.link_to(dataset.title, h.url_for(controller='package', action='read', id=dataset.name))}</h3> <div>${h.truncate(dataset.notes, length=200, whole_word=True)}</div>
+ <p></p>
+ <div>
+<a href="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='index')}" class="btn btn-primary">More popular datasets</a>
+<a href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" class="btn btn-primary">All usage data</a>
+ </div>
+ </div>
+
+
+</html>
+
+
+
+
--- a/ckanext/ga_report/templates/ga_report/ga_util.html
+++ b/ckanext/ga_report/templates/ga_report/ga_util.html
@@ -6,12 +6,33 @@
py:strip=""
>
- <table py:def="publisher_list(groups)" class="groups">
- <py:for each="group,title in groups">
- <tr>
- <td><a href="/publisher/${group.name}">${title}</a></td>
- </tr>
- </py:for>
+<table py:def="social_table(items, with_source=False)" class="table table-condensed table-bordered table-striped">
+ <tr>
+ <th>Name</th>
+ <th py:if="with_source">Source</th>
+ <th>Visits</th>
+ </tr>
+ <py:for each="name, url, source, count in items">
+ <tr>
+ <td><a href="${url}">${name}</a></td>
+ <td py:if="with_source">${source}</td>
+ <td>${count}</td>
+ </tr>
+ </py:for>
+ </table>
+
+
+<table py:def="stat_table(items, title='Views')" class="table table-condensed table-bordered table-striped">
+ <tr>
+ <th>Name</th>
+ <th>% ${title}</th>
+ </tr>
+ <py:for each="name, value in items">
+ <tr>
+ <td>${name}</td>
+ <td>${value}</td>
+ </tr>
+ </py:for>
</table>
@@ -19,12 +40,12 @@
<div id="minornavigation-bg-left">
<div id="minornavigation-bg-right">
<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_gear.png" height="16px" width="16px" alt="None" class="inline-icon "/> Site-wide</a></li>
+ <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>
<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:GaPublisherReport',action='index')}"><img src="/images/icons/page_white_gear.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:GaPublisherReport',action='index')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Publishers</a>
</li>
<li py:if="publisher" class="active">
- <a class="active" href="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='read', id=publisher.name)}"><img src="/images/icons/page_white_gear.png" height="16px" width="16px" alt="None" class="inline-icon "/>${publisher.title}</a>
+ <a class="active" href="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='read', id=publisher.name)}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/>${publisher.title}</a>
</li>
</ul>
--- a/ckanext/ga_report/templates/ga_report/publisher/index.html
+++ b/ckanext/ga_report/templates/ga_report/publisher/index.html
@@ -27,6 +27,7 @@
<div py:match="content">
+
<h1>Site Usage</h1>
${usage_nav('Publishers', None)}
@@ -35,7 +36,7 @@
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='index')}" method="get">
<div class="controls">
<select name="month">
- <option value='' py:attrs="{'selected': 'selected' if not c.month else None}">All time</option>
+ <option value='' py:attrs="{'selected': 'selected' if not c.month else None}">All months</option>
<py:for each="val,desc in c.months">
<option value='${val}' py:attrs="{'selected': 'selected' if c.month == val else None}">${desc}</option>
--- a/ckanext/ga_report/templates/ga_report/publisher/read.html
+++ b/ckanext/ga_report/templates/ga_report/publisher/read.html
@@ -11,7 +11,7 @@
<li class="widget-container boxed widget_text">
<h4>Publishers</h4>
<p>
- Dataset views records the number of times a specific dataset page has been viewed. Visits records the number of unique site visits.
+ Dataset views records the number of times a specific dataset page has been viewed for <a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a>. Visits records the number of unique site visits.
</p>
<p>
Note: this data does not include API calls.
@@ -35,7 +35,7 @@
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='read',id=c.publisher.name)}" method="get">
<div class="controls">
<select name="month">
- <option value='' py:attrs="{'selected': 'selected' if not c.month else None}">All time</option>
+ <option value='' py:attrs="{'selected': 'selected' if not c.month else None}">All months</option>
<py:for each="val,desc in c.months">