Debugging
Debugging

file:a/.gitignore -> file:b/.gitignore
*.py[co] *.py[co]
*.py~ *.py~
.gitignore .gitignore
   
# Packages # Packages
*.egg *.egg
*.egg-info *.egg-info
dist dist
build build
eggs eggs
parts parts
bin bin
var var
sdist sdist
develop-eggs develop-eggs
.installed.cfg .installed.cfg
   
  # Private info
  credentials.json
  token.dat
   
# Installer logs # Installer logs
pip-log.txt pip-log.txt
   
# Unit test / coverage reports # Unit test / coverage reports
.coverage .coverage
.tox .tox
   
#Translations #Translations
*.mo *.mo
   
#Mr Developer #Mr Developer
.mr.developer.cfg .mr.developer.cfg
   
file:a/README.rst -> file:b/README.rst
ckanext-ga-report ckanext-ga-report
================= =================
   
**Status:** Development **Status:** Development
   
**CKAN Version:** 1.7.1+ **CKAN Version:** 1.7.1+
   
   
Overview Overview
-------- --------
   
For creating detailed reports of CKAN analytics, including totals per group. For creating detailed reports of CKAN analytics, including totals per group.
   
Whereas ckanext-googleanalytics focusses on providing page view stats a recent period and for all time (aimed at end users), ckanext-ga-report is more interested in building regular periodic reports (more for site managers to monitor). Whereas ckanext-googleanalytics focusses on providing page view stats a recent period and for all time (aimed at end users), ckanext-ga-report is more interested in building regular periodic reports (more for site managers to monitor).
   
Contents of this extension: Contents of this extension:
   
* Use the CLI tool to download Google Analytics data for each time period into this extension's database tables * Use the CLI tool to download Google Analytics data for each time period into this extension's database tables
   
* Users can view the data as web page reports * Users can view the data as web page reports
   
   
Installation Installation
------------ ------------
   
1. Activate you CKAN python environment and install this extension's software:: 1. Activate you CKAN python environment and install this extension's software::
   
$ pyenv/bin/activate $ pyenv/bin/activate
$ pip install -e git+https://github.com/okfn/ckanext-ga-report.git#egg=ckanext-ga-report $ pip install -e git+https://github.com/datagovuk/ckanext-ga-report.git#egg=ckanext-ga-report
   
2. Ensure you development.ini (or similar) contains the info about your Google Analytics account and configuration:: 2. Ensure you development.ini (or similar) contains the info about your Google Analytics account and configuration::
   
googleanalytics.id = UA-1010101-1 googleanalytics.id = UA-1010101-1
googleanalytics.username = googleaccount@gmail.com googleanalytics.account = Account name (i.e. data.gov.uk, see top level item at https://www.google.com/analytics)
googleanalytics.password = googlepassword  
ga-report.period = monthly ga-report.period = monthly
   
Note that your password 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. 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.
   
3. Set up this extension's database tables using a paster command. (Ensure your CKAN pyenv is still activated, run the command from ``src/ckanext-ga-report``, alter the ``--config`` option to point to your site config file):: 3. Set up this extension's database tables using a paster command. (Ensure your CKAN pyenv is still activated, run the command from ``src/ckanext-ga-report``, alter the ``--config`` option to point to your site config file)::
   
$ paster initdb --config=../ckan/development.ini $ paster initdb --config=../ckan/development.ini
   
4. Enable the extension in your CKAN config file by adding it to ``ckan.plugins``:: 4. Enable the extension in your CKAN config file by adding it to ``ckan.plugins``::
   
ckan.plugins = ga-report ckan.plugins = ga-report
   
   
  Authorization
  --------------
   
  Before you can access the data, you need to set up the OAUTH details which you can do by following the `instructions <https://developers.google.com/analytics/resources/tutorials/hello-analytics-api>`_ the outcome of which will be a file called credentials.json which should look like credentials.json.template with the relevant fields completed. These steps are below for convenience:
   
  1. Visit the `Google APIs Console <https://code.google.com/apis/console>`_
   
  2. Sign-in and create a project or use an existing project.
   
  3. In the `Services pane <https://code.google.com/apis/console#:services>`_ , activate Analytics API for your project. If prompted, read and accept the terms of service.
   
  4. Go to the `API Access pane <https://code.google.com/apis/console/#:access>`_
   
  5. Click Create an OAuth 2.0 client ID....
   
  6. Fill out the Branding Information fields and click Next.
   
  7. In Client ID Settings, set Application type to Installed application.
   
  8. Click Create client ID
   
  9. The details you need below are Client ID, Client secret, and Redirect URIs
   
   
  Once you have set up your credentials.json file you can generate an oauth token file by using the
  following command, which will store your oauth token in a file called token.dat once you have finished
  giving permission in the browser::
   
  $ paster getauthtoken --config=../ckan/development.ini
   
   
Tutorial Tutorial
-------- --------
   
Download some GA data and store it in CKAN's db. (Ensure your CKAN pyenv is still activated, run the command from ``src/ckanext-ga-report``, alter the ``--config`` option to point to your site config file):: Download some GA data and store it in CKAN's db. (Ensure your CKAN pyenv is still activated, run the command from ``src/ckanext-ga-report``, alter the ``--config`` option to point to your site config file) and specifying the name of your auth file (token.dat by default) from the previous step::
   
$ paster loadanalytics latest --config=../ckan/development.ini $ paster loadanalytics token.dat latest --config=../ckan/development.ini
   
  The value after the token file is how much data you want to retrieve, this can be
   
  * **all** - data for all time (since 2010)
   
  * **latest** - (default) just the 'latest' data
   
  * **YYYY-MM-DD** - just data for all time periods going back to (and including) this date
   
   
   
Software Licence Software Licence
================ ================
   
This software is developed by Cabinet Office. It is Crown Copyright and opened up under the Open Government Licence (OGL) (which is compatible with Creative Commons Attibution License). This software is developed by Cabinet Office. It is Crown Copyright and opened up under the Open Government Licence (OGL) (which is compatible with Creative Commons Attibution License).
   
OGL terms: http://www.nationalarchives.gov.uk/doc/open-government-licence/ OGL terms: http://www.nationalarchives.gov.uk/doc/open-government-licence/
   
import logging import logging
  import datetime
   
from ckan.lib.cli import CkanCommand from ckan.lib.cli import CkanCommand
# No other CKAN imports allowed until _load_config is run, or logging is disabled # No other CKAN imports allowed until _load_config is run,
  # or logging is disabled
   
   
class InitDB(CkanCommand): class InitDB(CkanCommand):
"""Initialise the extension's database tables """Initialise the extension's database tables
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 0 max_args = 0
min_args = 0 min_args = 0
   
def command(self): def command(self):
self._load_config() self._load_config()
   
import ckan.model as model import ckan.model as model
model.Session.remove() model.Session.remove()
model.Session.configure(bind=model.meta.engine) model.Session.configure(bind=model.meta.engine)
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
import ga_model import ga_model
ga_model.init_tables() ga_model.init_tables()
log.info("DB tables are setup") log.info("DB tables are setup")
   
   
  class GetAuthToken(CkanCommand):
  """ Get's the Google auth token
   
  Usage: paster getauthtoken <credentials_file>
   
  Where <credentials_file> is the file name containing the details
  for the service (obtained from https://code.google.com/apis/console).
  By default this is set to credentials.json
  """
  summary = __doc__.split('\n')[0]
  usage = __doc__
  max_args = 0
  min_args = 0
   
  def command(self):
  """
  In this case we don't want a valid service, but rather just to
  force the user through the auth flow. We allow this to complete to
  act as a form of verification instead of just getting the token and
  assuming it is correct.
  """
  from ga_auth import init_service
  init_service('token.dat',
  self.args[0] if self.args
  else 'credentials.json')
   
   
class LoadAnalytics(CkanCommand): class LoadAnalytics(CkanCommand):
"""Get data from Google Analytics API and save it """Get data from Google Analytics API and save it
in the ga_model in the ga_model
   
Usage: paster loadanalytics <time-period> Usage: paster loadanalytics <tokenfile> <time-period>
   
Where <time-period> is: Where <tokenfile> is the name of the auth token file from
  the getauthtoken step.
   
  And where <time-period> is:
all - data for all time all - data for all time
latest - (default) just the 'latest' data latest - (default) just the 'latest' data
YYYY-MM-DD - just data for all time periods going YYYY-MM - just data for the specific month
back to (and including) this date  
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 1 max_args = 2
min_args = 0 min_args = 1
   
def command(self): def command(self):
self._load_config() self._load_config()
   
from download_analytics import DownloadAnalytics from download_analytics import DownloadAnalytics
downloader = DownloadAnalytics() from ga_auth import (init_service, get_profile_id)
   
time_period = self.args[0] if self.args else 'latest' try:
  svc = init_service(self.args[0], None)
  except TypeError:
  print ('Have you correctly run the getauthtoken task and '
  'specified the correct file here')
  return
   
  downloader = DownloadAnalytics(svc, profile_id=get_profile_id(svc))
   
  time_period = self.args[1] if self.args and len(self.args) > 1 \
  else 'latest'
if time_period == 'all': if time_period == 'all':
downloader.all_() downloader.all_()
elif time_period == 'latest': elif time_period == 'latest':
downloader.latest() downloader.latest()
else: else:
since_date = datetime.datetime.strptime(time_period, '%Y-%m-%d') # The month to use
downloader.since_date(since_date) for_date = datetime.datetime.strptime(time_period, '%Y-%m')
  downloader.specific_month(for_date)
   
   
import logging import logging
from ckan.lib.base import BaseController, c, render import operator
import report_model from ckan.lib.base import BaseController, c, render, request, response
   
  import sqlalchemy
  from sqlalchemy import func, cast, Integer
  import ckan.model as model
  from ga_model import GA_Url, GA_Stat
   
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
   
  def _get_month_name(strdate):
  import calendar
  from time import strptime
  d = strptime(strdate, '%Y-%m')
  return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year)
   
   
  def _month_details(cls):
  months = []
  vals = model.Session.query(cls.period_name).distinct().all()
  for m in vals:
  months.append( (m[0], _get_month_name(m[0])))
  return sorted(months, key=operator.itemgetter(0), reverse=True)
   
   
class GaReport(BaseController): class GaReport(BaseController):
   
  def csv(self, month):
  import csv
   
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.period_name==month).\
  order_by('GA_Stat.stat_name, GA_Stat.key').all()
   
  response.headers['Content-disposition'] = 'attachment; filename=dgu_analytics_%s.csv' % (month)
  response.headers['Content-Type'] = "text/csv; charset=utf-8"
   
  writer = csv.writer(response)
  writer.writerow(["Period", "Statistic", "Key", "Value"])
   
  for entry in entries:
  writer.writerow([entry.period_name.encode('utf-8'),
  entry.stat_name.encode('utf-8'),
  entry.key.encode('utf-8'),
  entry.value.encode('utf-8')])
   
def index(self): def index(self):
return render('index.html')  
   
  # Get the month details by fetching distinct values and determining the
  # month names from the values.
  c.months = _month_details(GA_Stat)
   
  # Work out which month to show, based on query params of the first item
  c.month = request.params.get('month', c.months[0][0] if c.months else '')
  c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.stat_name=='Totals').\
  filter(GA_Stat.period_name==c.month).\
  order_by('ga_stat.key').all()
  c.global_totals = [(s.key, s.value) for s in entries ]
   
  keys = {
  'Browser versions': 'browsers',
  'Operating Systems versions': 'os',
  'Social sources': 'social_networks',
  'Languages': 'languages',
  'Country': 'country'
  }
   
  for k, v in keys.iteritems():
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.stat_name==k).\
  filter(GA_Stat.period_name==c.month).\
  order_by('ga_stat.value::int desc').all()
  setattr(c, v, [(s.key, s.value) for s in entries ])
   
   
  return render('ga_report/site/index.html')
   
   
  class GaPublisherReport(BaseController):
  """
  Displays the pageview and visit count for specific publishers based on
  the datasets associated with the publisher.
  """
   
  def index(self):
  try:
  # Get the month details by fetching distinct values and determining the
  # month names from the values.
  c.months = _month_details(GA_Url)
   
  # Work out which month to show, based on query params of the first item
  c.month = request.params.get('month', c.months[0][0] if c.months else '')
  c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])