fix copy pasta error master
fix copy pasta error

import ckan.plugins as p import ckan.plugins as p
from ckan.lib.base import BaseController, config from ckan.lib.base import BaseController, config
import stats as stats_lib import stats as stats_lib
import ckan.lib.helpers as h import ckan.lib.helpers as h
   
class StatsController(BaseController): class StatsController(BaseController):
   
def index(self): def index(self):
c = p.toolkit.c c = p.toolkit.c
stats = stats_lib.Stats() stats = stats_lib.Stats()
rev_stats = stats_lib.RevisionStats() rev_stats = stats_lib.RevisionStats()
c.top_rated_packages = stats.top_rated_packages() c.top_rated_packages = stats.top_rated_packages()
c.most_edited_packages = stats.most_edited_packages() c.most_edited_packages = stats.most_edited_packages()
c.largest_groups = stats.largest_groups() c.largest_groups = stats.largest_groups()
c.top_tags = stats.top_tags()  
c.top_package_owners = stats.top_package_owners() c.top_package_owners = stats.top_package_owners()
c.summary_stats = stats.summary_stats() c.summary_stats = stats.summary_stats()
c.activity_counts = stats.activity_counts() c.activity_counts = stats.activity_counts()
c.by_org = stats.by_org() c.by_org = stats.by_org()
  c.res_by_org = stats.res_by_org()
  c.top_active_orgs = stats.top_active_orgs()
c.user_access_list = stats.user_access_list() c.user_access_list = stats.user_access_list()
c.recent_datasets = stats.recent_datasets() c.recent_datasets = stats.recent_datasets()
c.new_packages_by_week = rev_stats.get_by_week('new_packages') c.new_packages_by_week = rev_stats.get_by_week('new_packages')
c.deleted_packages_by_week = rev_stats.get_by_week('deleted_packages') c.deleted_packages_by_week = rev_stats.get_by_week('deleted_packages')
c.num_packages_by_week = rev_stats.get_num_packages_by_week() c.num_packages_by_week = rev_stats.get_num_packages_by_week()
c.package_revisions_by_week = rev_stats.get_by_week('package_revisions') c.package_revisions_by_week = rev_stats.get_by_week('package_revisions')
   
# Used in the legacy CKAN templates. # Used in the legacy CKAN templates.
c.packages_by_week = [] c.packages_by_week = []
   
# Used in new CKAN templates gives more control to the templates for formatting. # Used in new CKAN templates gives more control to the templates for formatting.
c.raw_packages_by_week = [] c.raw_packages_by_week = []
for week_date, num_packages, cumulative_num_packages in c.num_packages_by_week: for week_date, num_packages, cumulative_num_packages in c.num_packages_by_week:
c.packages_by_week.append('[new Date(%s), %s]' % (week_date.replace('-', ','), cumulative_num_packages)) c.packages_by_week.append('[new Date(%s), %s]' % (week_date.replace('-', ','), cumulative_num_packages))
c.raw_packages_by_week.append({'date': h.date_str_to_datetime(week_date), 'total_packages': cumulative_num_packages}) c.raw_packages_by_week.append({'date': h.date_str_to_datetime(week_date), 'total_packages': cumulative_num_packages})
   
c.all_package_revisions = [] c.all_package_revisions = []
c.raw_all_package_revisions = [] c.raw_all_package_revisions = []
for week_date, revs, num_revisions, cumulative_num_revisions in c.package_revisions_by_week: for week_date, revs, num_revisions, cumulative_num_revisions in c.package_revisions_by_week:
c.all_package_revisions.append('[new Date(%s), %s]' % (week_date.replace('-', ','), num_revisions)) c.all_package_revisions.append('[new Date(%s), %s]' % (week_date.replace('-', ','), num_revisions))
c.raw_all_package_revisions.append({'date': h.date_str_to_datetime(week_date), 'total_revisions': num_revisions}) c.raw_all_package_revisions.append({'date': h.date_str_to_datetime(week_date), 'total_revisions': num_revisions})
   
c.new_datasets = [] c.new_datasets = []
c.raw_new_datasets = [] c.raw_new_datasets = []
for week_date, pkgs, num_packages, cumulative_num_packages in c.new_packages_by_week: for week_date, pkgs, num_packages, cumulative_num_packages in c.new_packages_by_week:
c.new_datasets.append('[new Date(%s), %s]' % (week_date.replace('-', ','), num_packages)) c.new_datasets.append('[new Date(%s), %s]' % (week_date.replace('-', ','), num_packages))
c.raw_new_datasets.append({'date': h.date_str_to_datetime(week_date), 'new_packages': num_packages}) c.raw_new_datasets.append({'date': h.date_str_to_datetime(week_date), 'new_packages': num_packages})
   
return p.toolkit.render('ckanext/stats/index.html') return p.toolkit.render('ckanext/stats/index.html')
   
def leaderboard(self, id=None): def leaderboard(self, id=None):
c = p.toolkit.c c = p.toolkit.c
c.solr_core_url = config.get('ckanext.stats.solr_core_url', c.solr_core_url = config.get('ckanext.stats.solr_core_url',
'http://solr.okfn.org/solr/ckan') 'http://solr.okfn.org/solr/ckan')
return p.toolkit.render('ckanext/stats/leaderboard.html') return p.toolkit.render('ckanext/stats/leaderboard.html')
   
   
import datetime import datetime
   
from pylons import config from pylons import config
from sqlalchemy import Table, select, func, and_ from sqlalchemy import Table, select, func, and_
from sqlalchemy.sql.expression import text from sqlalchemy.sql.expression import text
   
import ckan.plugins as p import ckan.plugins as p
import ckan.model as model import ckan.model as model
   
  import re
   
cache_enabled = p.toolkit.asbool(config.get('ckanext.stats.cache_enabled', 'True')) cache_enabled = p.toolkit.asbool(config.get('ckanext.stats.cache_enabled', 'True'))
   
if cache_enabled: if cache_enabled:
from pylons import cache from pylons import cache
our_cache = cache.get_cache('stats', type='dbm') our_cache = cache.get_cache('stats', type='dbm')
   
DATE_FORMAT = '%Y-%m-%d' DATE_FORMAT = '%Y-%m-%d'
   
def table(name): def table(name):
return Table(name, model.meta.metadata, autoload=True) return Table(name, model.meta.metadata, autoload=True)
   
def datetime2date(datetime_): def datetime2date(datetime_):
return datetime.date(datetime_.year, datetime_.month, datetime_.day) return datetime.date(datetime_.year, datetime_.month, datetime_.day)
   
   
class Stats(object): class Stats(object):
@classmethod @classmethod
def top_rated_packages(cls, limit=10): def top_rated_packages(cls, limit=10):
# NB Not using sqlalchemy as sqla 0.4 doesn't work using both group_by # NB Not using sqlalchemy as sqla 0.4 doesn't work using both group_by
# and apply_avg # and apply_avg
package = table('package') package = table('package')
rating = table('rating') rating = table('rating')
sql = select([package.c.id, func.avg(rating.c.rating), func.count(rating.c.rating)], from_obj=[package.join(rating)]).\ sql = select([package.c.id, func.avg(rating.c.rating), func.count(rating.c.rating)], from_obj=[package.join(rating)]).\
where(package.c.private == 'f').\ where(package.c.private == 'f').\
group_by(package.c.id).\ group_by(package.c.id).\
order_by(func.avg(rating.c.rating).desc(), func.count(rating.c.rating).desc()).\ order_by(func.avg(rating.c.rating).desc(), func.count(rating.c.rating).desc()).\
limit(limit) limit(limit)
res_ids = model.Session.execute(sql).fetchall() res_ids = model.Session.execute(sql).fetchall()
res_pkgs = [(model.Session.query(model.Package).get(unicode(pkg_id)), avg, num) for pkg_id, avg, num in res_ids] res_pkgs = [(model.Session.query(model.Package).get(unicode(pkg_id)), avg, num) for pkg_id, avg, num in res_ids]
return res_pkgs return res_pkgs
   
@classmethod @classmethod
def most_edited_packages(cls, limit=10): def most_edited_packages(cls, limit=10):
package_revision = table('package_revision') package_revision = table('package_revision')
package = table('package') package = table('package')
s = select([package_revision.c.id, func.count(package_revision.c.revision_id)], from_obj=[package_revision.join(package)]).\ s = select([package_revision.c.id, func.count(package_revision.c.revision_id)], from_obj=[package_revision.join(package)]).\
where(package.c.private == 'f').\ where(package.c.private == 'f').\
group_by(package_revision.c.id).\ group_by(package_revision.c.id).\
order_by(func.count(package_revision.c.revision_id).desc()).\ order_by(func.count(package_revision.c.revision_id).desc()).\
limit(limit) limit(limit)
res_ids = model.Session.execute(s).fetchall() res_ids = model.Session.execute(s).fetchall()
res_pkgs = [(model.Session.query(model.Package).get(unicode(pkg_id)), val) for pkg_id, val in res_ids] res_pkgs = [(model.Session.query(model.Package).get(unicode(pkg_id)), val) for pkg_id, val in res_ids]
return res_pkgs return res_pkgs
   
@classmethod @classmethod
def largest_groups(cls, limit=10): def largest_groups(cls, limit=10):
member = table('member') member = table('member')
s = select([member.c.group_id, func.count(member.c.table_id)]).\ s = select([member.c.group_id, func.count(member.c.table_id)]).\
group_by(member.c.group_id).\ group_by(member.c.group_id).\
where(member.c.group_id!=None).\ where(member.c.group_id!=None).\
where(member.c.table_name=='package').\ where(member.c.table_name=='package').\
where(member.c.capacity=='public').\ where(member.c.capacity=='public').\
order_by(func.count(member.c.table_id).desc()) order_by(func.count(member.c.table_id).desc())
#limit(limit) #limit(limit)
   
res_ids = model.Session.execute(s).fetchall() res_ids = model.Session.execute(s).fetchall()
res_groups = [(model.Session.query(model.Group).get(unicode(group_id)), val) for group_id, val in res_ids] res_groups = [(model.Session.query(model.Group).get(unicode(group_id)), val) for group_id, val in res_ids]
return res_groups return res_groups
   
@classmethod @classmethod
def by_org(cls, limit=10): def by_org(cls, limit=10):
connection = model.Session.connection() connection = model.Session.connection()
res = connection.execute("select package.owner_org, package.private, count(*) from package \ res = connection.execute("select package.owner_org, package.private, count(*) from package \
  inner join (select distinct package_id from resource_group inner join resource on resource.resource_group_id = resource_group.id) as r on package.id = r.package_id \
inner join \"group\" on package.owner_org = \"group\".id \ inner join \"group\" on package.owner_org = \"group\".id \
where package.state='active'\ where package.state='active'\
group by package.owner_org,\"group\".name, package.private \ group by package.owner_org,\"group\".name, package.private \
order by \"group\".name, package.private;").fetchall(); order by \"group\".name, package.private;").fetchall();
res_groups = [(model.Session.query(model.Group).get(unicode(group_id)), private, val) for group_id, private, val in res] res_groups = [(model.Session.query(model.Group).get(unicode(group_id)), private, val) for group_id, private, val in res]
return res_groups return res_groups
   
@classmethod @classmethod
def top_tags(cls, limit=10, returned_tag_info='object'): # by package def res_by_org(cls, limit=10):
assert returned_tag_info in ('name', 'id', 'object') connection = model.Session.connection()
tag = table('tag') reses = connection.execute("select owner_org,format,count(*) from \
package_tag = table('package_tag') resource inner join resource_group on resource.resource_group_id = resource_group.id \
package = table('package') inner join package on resource_group.package_id = package.id group by owner_org,format order by count desc;").fetchall();
#TODO filter out tags with state=deleted group_ids = []
if returned_tag_info == 'name': group_tab = {}
from_obj = [package_tag.join(tag)] group_spatial = {}
tag_column = tag.c.name group_other = {}
else: for group_id,format,count in reses:
from_obj = None if group_id not in group_ids:
tag_column = package_tag.c.tag_id group_ids.append(group_id)
s = select([tag_column, func.count(package_tag.c.package_id)], group_tab[group_id] = 0
from_obj=from_obj) group_spatial[group_id] = 0
s = s.group_by(tag_column).\ group_other[group_id] = 0
where(package.c.private == 'f').\ if re.search('xls|csv|ms-excel|spreadsheetml.sheet|zip|netcdf',format, re.IGNORECASE):
order_by(func.count(package_tag.c.package_id).desc()).\ group_tab[group_id] = group_tab[group_id] + count
limit(limit) elif re.search('wms|wfs|wcs|shp|kml|kmz',format, re.IGNORECASE):
res_col = model.Session.execute(s).fetchall() group_spatial[group_id] = group_spatial[group_id] + count
if returned_tag_info in ('id', 'name'): else:
return res_col group_other[group_id] = group_other[group_id] + count
elif returned_tag_info == 'object': return [(model.Session.query(model.Group).get(unicode(group_id)), group_tab[group_id],group_spatial[group_id],group_other[group_id], group_tab[group_id]+group_spatial[group_id]+group_other[group_id]) for group_id in group_ids]
res_tags = [(model.Session.query(model.Tag).get(unicode(tag_id)), val) for tag_id, val in res_col]  
return res_tags @classmethod
  def top_active_orgs(cls, limit=10):
  connection = model.Session.connection()
  res = connection.execute("select package.owner_org, count(*) from package \
  inner join (select distinct package_id from resource_group inner join resource on resource.resource_group_id = resource_group.id) as r on package.id = r.package_id \
  inner join \"group\" on package.owner_org = \"group\".id \
  inner join (select distinct object_id from activity where activity.timestamp > (now() - interval '60 day')) \
  latestactivities on latestactivities.object_id = package.id \
  where package.state='active' \
  and package.private = 'f' \
  group by package.owner_org \
  order by count(*) desc;").fetchall();
  res_groups = [(model.Session.query(model.Group).get(unicode(group_id)), val) for group_id, val in res]
  return res_groups
   
@classmethod @classmethod
def top_package_owners(cls, limit=10): def top_package_owners(cls, limit=10):
package_role = table('package_role') package_role = table('package_role')
user_object_role = table('user_object_role') user_object_role = table('user_object_role')
package = table('package') package = table('package')
s = select([user_object_role.c.user_id, func.count(user_object_role.c.role)], from_obj=[user_object_role.join(package_role).join(package, package_role.c.package_id == package.c.id)]).\ s = select([user_object_role.c.user_id, func.count(user_object_role.c.role)], from_obj=[user_object_role.join(package_role).join(package, package_role.c.package_id == package.c.id)]).\
where(user_object_role.c.role==model.authz.Role.ADMIN).\ where(user_object_role.c.role==model.authz.Role.ADMIN).\
where(package.c.private == 'f').\ where(package.c.private == 'f').\
where(user_object_role.c.user_id!=None).\ where(user_object_role.c.user_id!=None).\
group_by(user_object_role.c.user_id).\ group_by(user_object_role.c.user_id).\
order_by(func.count(user_object_role.c.role).desc()).\ order_by(func.count(user_object_role.c.role).desc()).\
limit(limit) limit(limit)
res_ids = model.Session.execute(s).fetchall() res_ids = model.Session.execute(s).fetchall()
res_users = [(model.Session.query(model.User).get(unicode(user_id)), val) for user_id, val in res_ids] res_users = [(model.Session.query(model.User).get(unicode(user_id)), val) for user_id, val in res_ids]
return res_users return res_users
   
@classmethod @classmethod
def summary_stats(cls): def summary_stats(cls):
connection = model.Session.connection() connection = model.Session.connection()
   
res = connection.execute("SELECT 'Total Organisations', count(*) from \"group\" where type = 'organization' and state = 'active' union \ res = connection.execute("SELECT 'Total Organisations', count(*) from \"group\" where type = 'organization' and state = 'active' union \
select 'Total Datasets', count(*) from package where (state='active' or state='draft' or state='draft-complete') and private = 'f' union \ select 'Total Datasets', count(*) from package inner join (select distinct package_id from resource_group inner join resource on resource.resource_group_id = resource_group.id) as r on package.id = r.package_id where (package.state='active' or package.state='draft' or package.state='draft-complete') and private = 'f' union \
select 'Total Archived Datasets', count(*) from package where (state='active' or state='draft' or state='draft-complete') and private = 't' union \ select 'Total Archived Datasets', count(*) from package where (state='active' or state='draft' or state='draft-complete') and private = 't' union \
select 'Total Data Files/Resources', count(*) from resource where state='active' union \ select 'Total Data Files/Resources', count(*) from resource where state='active' union \
select 'Total Machine Readable/Data API Resources', count(*) from resource where state='active' and webstore_url = 'active'\ select 'Total Machine Readable/Data API Resources', count(*) from resource where state='active' and (webstore_url = 'active' or format='wms')").fetchall();
").fetchall();  
return res return res
   
   
@classmethod @classmethod
def activity_counts(cls): def activity_counts(cls):
connection = model.Session.connection() connection = model.Session.connection()
res = connection.execute("select to_char(timestamp, 'YYYY-MM') as month,activity_type, count(*) from activity group by month, activity_type order by month;").fetchall(); res = connection.execute("select to_char(timestamp, 'YYYY-MM') as month,activity_type, count(*) from activity group by month, activity_type order by month;").fetchall();
return res return res
   
@classmethod @classmethod
def user_access_list(cls): def user_access_list(cls):
connection = model.Session.connection() connection = model.Session.connection()
res = connection.execute("select name,sysadmin,role from user_object_role right outer join \"user\" on user_object_role.user_id = \"user\".id where name not in ('logged_in','visitor') group by name,sysadmin,role order by sysadmin desc, role asc;").fetchall(); res = connection.execute("select name,sysadmin,role from user_object_role right outer join \"user\" on user_object_role.user_id = \"user\".id where name not in ('logged_in','visitor') group by name,sysadmin,role order by sysadmin desc, role asc;").fetchall();
return res return res
   
@classmethod @classmethod
def recent_datasets(cls): def recent_datasets(cls):
activity = table('activity') activity = table('activity')
package = table('package') package = table('package')
s = select([func.max(activity.c.timestamp),package.c.id, activity.c.activity_type], from_obj=[activity.join(package,activity.c.object_id == package.c.id)]).where(package.c.private == 'f').\ s = select([func.max(activity.c.timestamp),package.c.id, activity.c.activity_type], from_obj=[activity.join(package,activity.c.object_id == package.c.id)]).where(package.c.private == 'f').\
where(activity.c.timestamp > func.now() - text("interval '60 day'")).group_by(package.c.id,activity.c.activity_type).order_by(func.max(activity.c.timestamp)) where(activity.c.timestamp > func.now() - text("interval '60 day'")).group_by(package.c.id,activity.c.activity_type).order_by(func.max(activity.c.timestamp))
result = model.Session.execute(s).fetchall() result = model.Session.execute(s).fetchall()
return [(datetime2date(timestamp), model.Session.query(model.Package).get(unicode(package_id)), activity_type) for timestamp,package_id,activity_type in result] return [(datetime2date(timestamp), model.Session.query(model.Package).get(unicode(package_id)), activity_type) for timestamp,package_id,activity_type in result]
   
   
   
class RevisionStats(object): class RevisionStats(object):
@classmethod @classmethod
def package_addition_rate(cls, weeks_ago=0): def package_addition_rate(cls, weeks_ago=0):
week_commenced = cls.get_date_weeks_ago(weeks_ago) week_commenced = cls.get_date_weeks_ago(weeks_ago)
return cls.get_objects_in_a_week(week_commenced, return cls.get_objects_in_a_week(week_commenced,
type_='package_addition_rate') type_='package_addition_rate')
   
@classmethod @classmethod
def package_revision_rate(cls, weeks_ago=0): def package_revision_rate(cls, weeks_ago=0):
week_commenced = cls.get_date_weeks_ago(weeks_ago) week_commenced = cls.get_date_weeks_ago(weeks_ago)
return cls.get_objects_in_a_week(week_commenced, return cls.get_objects_in_a_week(week_commenced,
type_='package_revision_rate') type_='package_revision_rate')
   
@classmethod @classmethod
def get_date_weeks_ago(cls, weeks_ago): def get_date_weeks_ago(cls, weeks_ago):
''' '''
@param weeks_ago: specify how many weeks ago to give count for @param weeks_ago: specify how many weeks ago to give count for
(0 = this week so far) (0 = this week so far)
''' '''
date_ = datetime.date.today() date_ = datetime.date.today()
return date_ - datetime.timedelta(days= return date_ - datetime.timedelta(days=
datetime.date.weekday(date_) + 7 * weeks_ago) datetime.date.weekday(date_) + 7 * weeks_ago)
   
@classmethod @classmethod
def get_week_dates(cls, weeks_ago): def get_week_dates(cls, weeks_ago):
''' '''
@param weeks_ago: specify how many weeks ago to give count for @param weeks_ago: specify how many weeks ago to give count for
(0 = this week so far) (0 = this week so far)
''' '''
package_revision = table('package_revision') package_revision = table('package_revision')
revision = table('revision') revision = table('revision')
today = datetime.date.today() today = datetime.date.today()
date_from = datetime.datetime(today.year, today.month, today.day) -\ date_from = datetime.datetime(today.year, today.month, today.day) -\
datetime.timedelta(days=datetime.date.weekday(today) + \ datetime.timedelta(days=datetime.date.weekday(today) + \
7 * weeks_ago) 7 * weeks_ago)
date_to = date_from + datetime.timedelta(days=7) date_to = date_from + datetime.timedelta(days=7)
return (date_from, date_to) return (date_from, date_to)
   
@classmethod @classmethod
def get_date_week_started(cls, date_): def get_date_week_started(cls, date_):
assert isinstance(date_, datetime.date) assert isinstance(date_, datetime.date)
if isinstance(date_, datetime.datetime): if isinstance(date_, datetime.datetime):
date_ = datetime2date(date_) date_ = datetime2date(date_)
return date_ - datetime.timedelta(days=datetime.date.weekday(date_)) return date_ - datetime.timedelta(days=datetime.date.weekday(date_))
   
@classmethod @classmethod
def get_package_revisions(cls): def get_package_revisions(cls):
''' '''
@return: Returns list of revisions and date of them, in @return: Returns list of revisions and date of them, in
format: [(id, date), ...] format: [(id, date), ...]
''' '''
package_revision = table('package_revision') package_revision = table('package_revision')
revision = table('revision') revision = table('revision')
s = select([package_revision.c.id, revision.c.timestamp], from_obj=[package_revision.join(revision)]).order_by(revision.c.timestamp) s = select([package_revision.c.id, revision.c.timestamp], from_obj=[package_revision.join(revision)]).order_by(revision.c.timestamp)
res = model.Session.execute(s).fetchall() # [(id, datetime), ...] res = model.Session.execute(s).fetchall() # [(id, datetime), ...]
return res return res
   
@classmethod @classmethod
def get_new_packages(cls): def get_new_packages(cls):
''' '''
@return: Returns list of new pkgs and date when they were created, in @return: Returns list of new pkgs and date when they were created, in
format: [(id, date_ordinal), ...] format: [(id, date_ordinal), ...]
''' '''
def new_packages(): def new_packages():
# Can't filter by time in select because 'min' function has to # Can't filter by time in select because 'min' function has to
# be 'for all time' else you get first revision in the time period. # be 'for all time' else you get first revision in the time period.
package_revision = table('package_revision') package_revision = table('package_revision')
revision = table('revision') revision = table('revision')
package = table('package') package = table('package')
s = select([package_revision.c.id, func.min(revision.c.timestamp)], from_obj=[package_revision.join(revision).join(package)]).\ s = select([package_revision.c.id, func.min(revision.c.timestamp)], from_obj=[package_revision.join(revision).join(package)]).\
where(package.c.private == 'f').\ where(package.c.private == 'f').\
group_by(package_revision.c.id).order_by(func.min(revision.c.timestamp)) group_by(package_revision.c.id).order_by(func.min(revision.c.timestamp))
res = model.Session.execute(s).fetchall() # [(id, datetime), ...] res = model.Session.execute(s).fetchall() # [(id, datetime), ...]
res_pickleable = [] res_pickleable = []
for pkg_id, created_datetime in res: for pkg_id, created_datetime in res:
res_pickleable.append((pkg_id, created_datetime.toordinal())) res_pickleable.append((pkg_id, created_datetime.toordinal()))
return res_pickleable return res_pickleable
if cache_enabled: if cache_enabled:
week_commences = cls.get_date_week_started(datetime.date.today()) week_commences = cls.get_date_week_started(datetime.date.today())
key = 'all_new_packages_%s' + week_commences.strftime(DATE_FORMAT) key = 'all_new_packages_%s' + week_commences.strftime(DATE_FORMAT)
new_packages = our_cache.get_value(key=key, new_packages = our_cache.get_value(key=key,
createfunc=new_packages) createfunc=new_packages)
else: else:
new_packages = new_packages() new_packages = new_packages()
return new_packages return new_packages
   
@classmethod @classmethod
def get_deleted_packages(cls): def get_deleted_packages(cls):
''' '''
@return: Returns list of deleted pkgs and date when they were deleted, in @return: Returns list of deleted pkgs and date when they were deleted, in
format: [(id, date_ordinal), ...] format: [(id, date_ordinal), ...]
''' '''
def deleted_packages(): def deleted_packages():
# Can't filter by time in select because 'min' function has to # Can't filter by time in select because 'min' function has to
# be 'for all time' else you get first revision in the time period. # be 'for all time' else you get first revision in the time period.
package_revision = table('package_revision') package_revision = table('package_revision')
revision = table('revision') revision = table('revision')
package = table('package') package = table('package')
s = select([package_revision.c.id, func.min(revision.c.timestamp)], from_obj=[package_revision.join(revision).join(package)]).\ s = select([package_revision.c.id, func.min(revision.c.timestamp)], from_obj=[package_revision.join(revision).join(package)]).\
where(package_revision.c.state==model.State.DELETED).\ where(package_revision.c.state==model.State.DELETED).\
where(package.c.private == 'f').\ where(package.c.private == 'f').\
group_by(package_revision.c.id).\ group_by(package_revision.c.id).\
order_by(func.min(revision.c.timestamp)) order_by(func.min(revision.c.timestamp))
res = model.Session.execute(s).fetchall() # [(id, datetime), ...] res = model.Session.execute(s).fetchall() # [(id, datetime), ...]
res_pickleable = [] res_pickleable = []
for pkg_id, deleted_datetime in res: for pkg_id, deleted_datetime in res:
res_pickleable.append((pkg_id, deleted_datetime.toordinal())) res_pickleable.append((pkg_id, deleted_datetime.toordinal()))
return res_pickleable return res_pickleable
if cache_enabled: if cache_enabled:
week_commences = cls.get_date_week_started(datetime.date.today()) week_commences = cls.get_date_week_started(datetime.date.today())
key = 'all_deleted_packages_%s' + week_commences.strftime(DATE_FORMAT) key = 'all_deleted_packages_%s' + week_commences.strftime(DATE_FORMAT)
deleted_packages = our_cache.get_value(key=key, deleted_packages = our_cache.get_value(key=key,
createfunc=deleted_packages) createfunc=deleted_packages)
else: else:
deleted_packages = deleted_packages() deleted_packages = deleted_packages()
return deleted_packages return deleted_packages
   
@classmethod @classmethod
def get_num_packages_by_week(cls): def get_num_packages_by_week(cls):
def num_packages(): def num_packages():
new_packages_by_week = cls.get_by_week('new_packages') new_packages_by_week = cls.get_by_week('new_packages')
deleted_packages_by_week = cls.get_by_week('deleted_packages') deleted_packages_by_week = cls.get_by_week('deleted_packages')
first_date = (min(datetime.datetime.strptime(new_packages_by_week[0][0], DATE_FORMAT), first_date = (min(datetime.datetime.strptime(new_packages_by_week[0][0], DATE_FORMAT),
datetime.datetime.strptime(deleted_packages_by_week[0][0], DATE_FORMAT))).date() datetime.datetime.strptime(deleted_packages_by_week[0][0], DATE_FORMAT))).date()
cls._cumulative_num_pkgs = 0 cls._cumulative_num_pkgs = 0
new_pkgs = [] new_pkgs = []
deleted_pkgs = [] deleted_pkgs = []
def build_weekly_stats(week_commences, new_pkg_ids, deleted_pkg_ids): def build_weekly_stats(week_commences, new_pkg_ids, deleted_pkg_ids):
num_pkgs = len(new_pkg_ids) - len(deleted_pkg_ids) num_pkgs = len(new_pkg_ids) - len(deleted_pkg_ids)
new_pkgs.extend([model.Session.query(model.Package).get(id).name for id in new_pkg_ids]) new_pkgs.extend([model.Session.query(model.Package).get(id).name for id in new_pkg_ids])
deleted_pkgs.extend([model.Session.query(model.Package).get(id).name for id in deleted_pkg_ids]) deleted_pkgs.extend([model.Session.query(model.Package).get(id).name for id in deleted_pkg_ids])
cls._cumulative_num_pkgs += num_pkgs cls._cumulative_num_pkgs += num_pkgs
return (week_commences.strftime(DATE_FORMAT), return (week_commences.strftime(DATE_FORMAT),
num_pkgs, cls._cumulative_num_pkgs) num_pkgs, cls._cumulative_num_pkgs)
week_ends = first_date week_ends = first_date
today = datetime.date.today() today = datetime.date.today()
new_package_week_index = 0 new_package_week_index = 0
deleted_package_week_index = 0 deleted_package_week_index = 0
weekly_numbers = [] # [(week_commences, num_packages, cumulative_num_pkgs])] weekly_numbers = [] # [(week_commences, num_packages, cumulative_num_pkgs])]
while week_ends <= today: while week_ends <= today:
week_commences = week_ends week_commences = week_ends
week_ends = week_commences + datetime.timedelta(days=7) week_ends = week_commences + datetime.timedelta(days=7)
if datetime.datetime.strptime(new_packages_by_week[new_package_week_index][0], DATE_FORMAT).date() == week_commences: if datetime.datetime.strptime(new_packages_by_week[new_package_week_index][0], DATE_FORMAT).date() == week_commences:
new_pkg_ids = new_packages_by_week[new_package_week_index][1] new_pkg_ids = new_packages_by_week[new_package_week_index][1]
new_package_week_index += 1 new_package_week_index += 1
else: else:
new_pkg_ids = [] new_pkg_ids = []
if datetime.datetime.strptime(deleted_packages_by_week[deleted_package_week_index][0], DATE_FORMAT).date() == week_commences: if datetime.datetime.strptime(deleted_packages_by_week[deleted_package_week_index][0], DATE_FORMAT).date() == week_commences:
deleted_pkg_ids = deleted_packages_by_week[deleted_package_week_index][1] deleted_pkg_ids = deleted_packages_by_week[deleted_package_week_index][1]
deleted_package_week_index += 1 deleted_package_week_index += 1
else: else:
deleted_pkg_ids = [] deleted_pkg_ids = []
weekly_numbers.append(build_weekly_stats(week_commences, new_pkg_ids, deleted_pkg_ids)) weekly_numbers.append(build_weekly_stats(week_commences, new_pkg_ids, deleted_pkg_ids))
# just check we got to the end of each count # just check we got to the end of each count
assert new_package_week_index == len(new_packages_by_week) assert new_package_week_index == len(new_packages_by_week)
assert deleted_package_week_index == len(deleted_packages_by_week) assert deleted_package_week_index == len(deleted_packages_by_week)
return weekly_numbers return weekly_numbers
if cache_enabled: if cache_enabled:
week_commences = cls.get_date_week_started(datetime.date.today()) week_commences = cls.get_date_week_started(datetime.date.today())
key = 'number_packages_%s' + week_commences.strftime(DATE_FORMAT) key = 'number_packages_%s' + week_commences.strftime(DATE_FORMAT)
num_packages = our_cache.get_value(key=key, num_packages = our_cache.get_value(key=key,
createfunc=num_packages) createfunc=num_packages)
else: else:
num_packages = num_packages() num_packages = num_packages()
return num_packages return num_packages
   
@classmethod @classmethod
def get_by_week(cls, object_type): def get_by_week(cls, object_type):
cls._object_type = object_type cls._object_type = object_type
def objects_by_week(): def objects_by_week():
if cls._object_type == 'new_packages': if cls._object_type == 'new_packages':
objects = cls.get_new_packages() objects = cls.get_new_packages()
def get_date(object_date): def get_date(object_date):
return datetime.date.fromordinal(object_date) return datetime.date.fromordinal(object_date)
elif cls._object_type == 'deleted_packages': elif cls._object_type == 'deleted_packages':
objects = cls.get_deleted_packages() objects = cls.get_deleted_packages()
def get_date(object_date): def get_date(object_date):
return datetime.date.fromordinal(object_date) return datetime.date.fromordinal(object_date)
elif cls._object_type == 'package_revisions': elif cls._object_type == 'package_revisions':
objects = cls.get_package_revisions() objects = cls.get_package_revisions()
def get_date(object_date): def get_date(object_date):
return datetime2date(object_date) return datetime2date(object_date)
else: else:
raise NotImplementedError() raise NotImplementedError()
first_date = get_date(objects[0][1]) if objects else datetime.date.today() first_date = get_date(objects[0][1]) if objects else datetime.date.today()
week_commences = cls.get_date_week_started(first_date) week_commences = cls.get_date_week_started(first_date)
week_ends = week_commences + datetime.timedelta(days=7) week_ends = week_commences + datetime.timedelta(days=7)
week_index = 0 week_index = 0
weekly_pkg_ids = [] # [(week_commences, [pkg_id1, pkg_id2, ...])] weekly_pkg_ids = [] # [(week_commences, [pkg_id1, pkg_id2, ...])]
pkg_id_stack = [] pkg_id_stack = []
cls._cumulative_num_pkgs = 0 cls._cumulative_num_pkgs = 0
def build_weekly_stats(week_commences, pkg_ids): def build_weekly_stats(week_commences, pkg_ids):
num_pkgs = len(pkg_ids) num_pkgs = len(pkg_ids)
cls._cumulative_num_pkgs += num_pkgs cls._cumulative_num_pkgs += num_pkgs
return (week_commences.strftime(DATE_FORMAT), return (week_commences.strftime(DATE_FORMAT),
pkg_ids, num_pkgs, cls._cumulative_num_pkgs) pkg_ids, num_pkgs, cls._cumulative_num_pkgs)
for pkg_id, date_field in objects: for pkg_id, date_field in objects:
date_ = get_date(date_field) date_ = get_date(date_field)
if date_ >= week_ends: if date_ >= week_ends:
weekly_pkg_ids.append(build_weekly_stats(week_commences, pkg_id_stack)) weekly_pkg_ids.append(build_weekly_stats(week_commences, pkg_id_stack))
pkg_id_stack = [] pkg_id_stack = []
week_commences = week_ends week_commences = week_ends
week_ends = week_commences + datetime.timedelta(days=7) week_ends = week_commences + datetime.timedelta(days=7)
pkg_id_stack.append(pkg_id) pkg_id_stack.append(pkg_id)
weekly_pkg_ids.append(build_weekly_stats(week_commences, pkg_id_stack)) weekly_pkg_ids.append(build_weekly_stats(week_commences, pkg_id_stack))
today = datetime.date.today() today = datetime.date.today()
while week_ends <= today: while week_ends <= today:
week_commences = week_ends week_commences = week_ends
week_ends = week_commences + datetime.timedelta(days=7) week_ends = week_commences + datetime.timedelta(days=7)
weekly_pkg_ids.append(build_weekly_stats(week_commences, [])) weekly_pkg_ids.append(build_weekly_stats(week_commences, []))
return weekly_pkg_ids return weekly_pkg_ids
if cache_enabled: if cache_enabled:
week_commences = cls.get_date_week_started(datetime.date.today()) week_commences = cls.get_date_week_started(datetime.date.today())
key = '%s_by_week_%s' % (cls._object_type, week_commences.strftime(DATE_FORMAT)) key = '%s_by_week_%s' % (cls._object_type, week_commences.strftime(DATE_FORMAT))
objects_by_week_ = our_cache.get_value(key=key, objects_by_week_ = our_cache.get_value(key=key,
createfunc=objects_by_week) createfunc=objects_by_week)
else: else:
objects_by_week_ = objects_by_week() objects_by_week_ = objects_by_week()
return objects_by_week_ return objects_by_week_
   
@classmethod @classmethod
def get_objects_in_a_week(cls, date_week_commences, def get_objects_in_a_week(cls, date_week_commences,
type_='new-package-rate'): type_='new-package-rate'):
''' '''
@param type: Specifies what to return about the specified week: @param type: Specifies what to return about the specified week:
"package_addition_rate" number of new packages "package_addition_rate" number of new packages
"package_revision_rate" number of package revisions "package_revision_rate" number of package revisions
"new_packages" a list of the packages created "new_packages" a list of the packages created
in a tuple with the date. in a tuple with the date.
"deleted_packages" a list of the packages deleted "deleted_packages" a list of the packages deleted
in a tuple with the date. in a tuple with the date.
@param dates: date range of interest - a tuple: @param dates: date range of interest - a tuple:
(start_date, end_date) (start_date, end_date)
''' '''
assert isinstance(date_week_commences, datetime.date) assert isinstance(date_week_commences, datetime.date)
if type_ in ('package_addition_rate', 'new_packages'): if type_ in ('package_addition_rate', 'new_packages'):
object_type = 'new_packages' object_type = 'new_packages'
elif type_ == 'deleted_packages': elif type_ == 'deleted_packages':
object_type = 'deleted_packages' object_type = 'deleted_packages'
elif type_ == 'package_revision_rate': elif type_ == 'package_revision_rate':
object_type = 'package_revisions' object_type = 'package_revisions'
else: else:
raise NotImplementedError() raise NotImplementedError()
objects_by_week = cls.get_by_week(object_type) objects_by_week = cls.get_by_week(object_type)
date_wc_str = date_week_commences.strftime(DATE_FORMAT) date_wc_str = date_week_commences.strftime(DATE_FORMAT)
object_ids = None object_ids = None
for objects_in_a_week in objects_by_week: for objects_in_a_week in objects_by_week:
if objects_in_a_week[0] == date_wc_str: if objects_in_a_week[0] == date_wc_str:
object_ids = objects_in_a_week[1] object_ids = objects_in_a_week[1]
break break
if object_ids is None: if object_ids is None:
raise TypeError('Week specified is outside range') raise TypeError('Week specified is outside range')
assert isinstance(object_ids, list) assert isinstance(object_ids, list)
if type_ in ('package_revision_rate', 'package_addition_rate'): if type_ in ('package_revision_rate', 'package_addition_rate'):
return len(object_ids) return len(object_ids)
elif type_ in ('new_packages', 'deleted_packages'): elif type_ in ('new_packages', 'deleted_packages'):
return [ model.Session.query(model.Package).get(pkg_id) \ return [ model.Session.query(model.Package).get(pkg_id) \
for pkg_id in object_ids ] for pkg_id in object_ids ]
   
   
{% extends "page.html" %} {% extends "page.html" %}
   
{% block breadcrumb_content %} {% block breadcrumb_content %}
<li class="active">{{ 'Statistics' }}</li> <li class="active">{{ 'Statistics' }}</li>
{% endblock %} {% endblock %}
   
{% block primary_content %} {% block primary_content %}
<article class="module"> <article class="module">
{% if h.check_access('sysadmin') %} {% if h.check_access('sysadmin') %}
<section id="stats-activity-counts" class="module-content tab-content"> <section id="stats-activity-counts" class="module-content tab-content">
<h2>{{ _('Site Activity Log') }}</h2> <h2>{{ _('Site Activity Log') }}</h2>
{% if c.activity_counts %} {% if c.activity_counts %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Month') }}</th> <th>{{ _('Month') }}</th>
<th>{{ _('Activity Type') }}</th> <th>{{ _('Activity Type') }}</th>
<th class="metric">{{ _('Count') }}</th> <th class="metric">{{ _('Count') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for month, type, count in c.activity_counts %} {% for month, type, count in c.activity_counts %}
<tr> <tr>
<td>{{ month }}</td> <td>{{ month }}</td>
<td>{{ type }}</td> <td>{{ type }}</td>
<td class="metric">{{ count }}</td> <td class="metric">{{ count }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
<section id="stats-recent-datasets" class="module-content tab-content"> <section id="stats-recent-datasets" class="module-content tab-content">
<h2>{{ _('Recent Datasets') }}</h2> <h2>{{ _('Recent Datasets') }}</h2>
{% if c.recent_datasets %} {% if c.recent_datasets %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Date') }}</th> <th>{{ _('Date') }}</th>
<th>{{ _('Dataset') }}</th> <th>{{ _('Dataset') }}</th>
<th>{{ _('New/Modified') }}</th> <th>{{ _('New/Modified') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for date,package,newmodified in c.recent_datasets %} {% for date,package,newmodified in c.recent_datasets %}
<tr> <tr>
<td>{{ date }}</td> <td>{{ date }}</td>
<td>{{ h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name)) }}</td> <td>{{ h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name)) }}</td>
<td>{{ newmodified }}</td> <td>{{ newmodified }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
<section id="stats-user-access-list" class="module-content tab-content"> <section id="stats-user-access-list" class="module-content tab-content">
<h2>{{ _('User Access List') }}</h2> <h2>{{ _('User Access List') }}</h2>
{% if c.user_access_list %} {% if c.user_access_list %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Username') }}</th> <th>{{ _('Username') }}</th>
<th>{{ _('Sysadmin') }}</th> <th>{{ _('Sysadmin') }}</th>
<th class="metric">{{ _('Organisational Role') }}</th> <th class="metric">{{ _('Organisational Role') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for username,sysadmin,role in c.user_access_list %} {% for username,sysadmin,role in c.user_access_list %}
<tr> <tr>
<td>{{ username }}</td> <td>{{ username }}</td>
<td>{{ sysadmin }}</td> <td>{{ sysadmin }}</td>
<td>{{ role }}</td> <td>{{ role }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
{% endif %} {% endif %}
<section id="stats-total-datasets" class="module-content tab-content active"> <section id="stats-total-datasets" class="module-content tab-content active">
<h2>{{ _('Total number of Datasets') }}</h2> <h2>{{ _('Total number of Datasets') }}</h2>
   
{% set xaxis = {'mode': 'time', 'timeformat': '%y-%b'} %} {% set xaxis = {'mode': 'time', 'timeformat': '%y-%b'} %}
{% set yaxis = {'min': 0} %} {% set yaxis = {'min': 0} %}
<table class="table table-chunky table-bordered table-striped" data-module="plot" data-module-xaxis="{{ h.dump_json(xaxis) }}" data-module-yaxis="{{ h.dump_json(yaxis) }}"> <table class="table table-chunky table-bordered table-striped" data-module="plot" data-module-xaxis="{{ h.dump_json(xaxis) }}" data-module-yaxis="{{ h.dump_json(yaxis) }}">
<thead> <thead>
<tr> <tr>
<th>{{ _("Date") }}</th> <th>{{ _("Date") }}</th>
<th>{{ _("Total datasets") }}</th> <th>{{ _("Total datasets") }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for row in c.raw_packages_by_week %} {% for row in c.raw_packages_by_week %}
<tr> <tr>
<th data-type="date" data-value="{{ row.date.strftime("%s") }}"><time datetime="{{ row.date.isoformat() }}">{{ h.render_datetime(row.date) }}</time></th> <th data-type="date" data-value="{{ row.date.strftime("%s") }}"><time datetime="{{ row.date.isoformat() }}">{{ h.render_datetime(row.date) }}</time></th>
<td>{{ row.total_packages }}</td> <td>{{ row.total_packages }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</section> </section>
   
<section id="stats-dataset-revisions" class="module-content tab-content"> <section id="stats-dataset-revisions" class="module-content tab-content">
<h2>{{ _('Dataset Revisions per Week') }}</h2> <h2>{{ _('Dataset Revisions per Week') }}</h2>
   
{% set xaxis = {'mode': 'time', 'timeformat': '%y-%b'} %} {% set xaxis = {'mode': 'time', 'timeformat': '%y-%b'} %}
{% set lines = {'fill': 1} %} {% set lines = {'fill': 1} %}
<table class="table table-chunky table-bordered table-striped" data-module="plot" data-module-xaxis="{{ h.dump_json(xaxis) }}" data-module-lines="{{ h.dump_json(lines) }}"> <table class="table table-chunky table-bordered table-striped" data-module="plot" data-module-xaxis="{{ h.dump_json(xaxis) }}" data-module-lines="{{ h.dump_json(lines) }}">
<thead> <thead>
<tr> <tr>
<th>{{ _("Date") }}</th> <th>{{ _("Date") }}</th>
<th>{{ _("All dataset revisions") }}</th> <th>{{ _("All dataset revisions") }}</th>
<th>{{ _("New datasets") }}</th> <th>{{ _("New datasets") }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for row in c.raw_all_package_revisions %} {% for row in c.raw_all_package_revisions %}
<tr> <tr>
<th data-type="date" data-value="{{ row.date.strftime("%s") }}"><time datetime="{{ row.date.isoformat() }}">{{ h.render_datetime(row.date) }}</time></th> <th data-type="date" data-value="{{ row.date.strftime("%s") }}"><time datetime="{{ row.date.isoformat() }}">{{ h.render_datetime(row.date) }}</time></th>
<td>{{ row.total_revisions }}</td> <td>{{ row.total_revisions }}</td>
<td>{{ c.raw_new_datasets[loop.index0].new_packages }}</td> <td>{{ c.raw_new_datasets[loop.index0].new_packages }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</section> </section>
   
   
<section id="stats-most-edited" class="module-content tab-content"> <section id="stats-most-edited" class="module-content tab-content">
<h2>{{ _('Most Edited Datasets') }}</h2> <h2>{{ _('Most Edited Datasets') }}</h2>
{% if c.most_edited_packages %} {% if c.most_edited_packages %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Dataset') }}</th> <th>{{ _('Dataset') }}</th>
<th class="metric">{{ _('Number of edits') }}</th> <th class="metric">{{ _('Number of edits') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for package, edits in c.most_edited_packages %} {% for package, edits in c.most_edited_packages %}
<tr py:for="package, edits in c.most_edited_packages"> <tr py:for="package, edits in c.most_edited_packages">
<td>{{ h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name)) }}</td> <td>{{ h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name)) }}</td>
<td class="metric">{{ edits }}</td> <td class="metric">{{ edits }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No edited datasets') }}</p> <p class="empty">{{ _('No edited datasets') }}</p>
{% endif %} {% endif %}
</section> </section>
   
<section id="stats-largest-groups" class="module-content tab-content"> <section id="stats-largest-groups" class="module-content tab-content">
<h2>{{ _('Largest Groups') }}</h2> <h2>{{ _('Largest Groups') }}</h2>
{% if c.largest_groups %} {% if c.largest_groups %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Group') }}</th> <th>{{ _('Group') }}</th>
<th class="metric">{{ _('Number of datasets') }}</th> <th class="metric">{{ _('Number of datasets') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for group, num_packages in c.largest_groups %} {% for group, num_packages in c.largest_groups %}
<tr> <tr>
<td>{{ h.link_to(group.title or group.name, h.url_for(controller='group', action='read', id=group.name)) }}</td> <td>{{ h.link_to(group.title or group.name, h.url_for(controller='group', action='read', id=group.name)) }}</td>
<td class="metric">{{ num_packages }}</td> <td class="metric">{{ num_packages }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
<section id="stats-by-org" class="module-content tab-content"> <section id="stats-by-org" class="module-content tab-content">
<h2>{{ _('Datasets by Organization') }}</h2> <h2>{{ _('Datasets by Organization') }}</h2>
{% if c.by_org %} {% if c.by_org %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Group') }}</th> <th>{{ _('Organisation') }}</th>
<th>{{ _('Public/Archived') }}</th> <th>{{ _('Public/Archived') }}</th>
<th class="metric">{{ _('Number of datasets') }}</th> <th class="metric">{{ _('Number of datasets') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for group,private, num_packages in c.by_org %} {% for group,private, num_packages in c.by_org %}
{% if private == False or h.check_access('sysadmin') %} {% if private == False or h.check_access('sysadmin') %}
<tr> <tr>
<td>{{ h.link_to(group.title or group.name, h.url_for(controller='organization', action='read', id=group.name)) }}</td> <td>{{ h.link_to(group.title or group.name, h.url_for(controller='organization', action='read', id=group.name)) }}</td>
{% if private == True %} {% if private == True %}
<td>Archived</td> <td>Archived</td>
{% else %} {% else %}
<td>Public</td> <td>Public</td>
{% endif %} {% endif %}
<td class="metric">{{ num_packages }}</td> <td class="metric">{{ num_packages }}</td>
</tr> </tr>
{% endif %} {% endif %}
  {% endfor %}
  </tbody>
  </table>
  {% else %}
  <p class="empty">{{ _('No groups') }}</p>
  {% endif %}
  </section>
  <section id="stats-res-by-org" class="module-content tab-content">
  <h2>{{ _('Resources by Organization') }}</h2>
  {% if c.res_by_org %}
  <table class="table table-chunky table-bordered table-striped">
  <thead>
  <tr>
  <th>{{ _('Organisation') }}</th>
  <th>{{ _('Tabular') }}</th>
  <th>{{ _('Spatial') }}</th>
  <th>{{ _('Other') }}</th>
  <th class="metric">{{ _('Total') }}</th>
  </tr>
  </thead>
  <tbody>
  {% for group,t,s,o,tot in c.res_by_org %}
  <tr>
  <td>{{ h.link_to(group.title or group.name, h.url_for(controller='organization', action='read', id=group.name)) }}</td>
  <td>{{ t }}</td>
  <td>{{ s }}</td>
  <td>{{ o }}</td>
  <td class="metric">{{ tot }}</td>
  </tr>
  {% endfor %}
  </tbody>
  </table>
  {% else %}
  <p class="empty">{{ _('No groups') }}</p>
  {% endif %}
  </section>
  <section id="stats-activity-org" class="module-content tab-content">
  <h2>{{ _('Most Active Organisations') }}</h2>
  {% if c.top_active_orgs %}
  <table class="table table-chunky table-bordered table-striped">
  <thead>
  <tr>
  <th>{{ _('Organisation') }}</th>
  <th class="metric">{{ _('Number of datasets updated recently') }}</th>
  </tr>
  </thead>
  <tbody>
  {% for group, num_packages in c.top_active_orgs %}
  <tr>
  <td>{{ h.link_to(group.title or group.name, h.url_for(controller='organization', action='read', id=group.name)) }}</td>
  <td class="metric">{{ num_packages }}</td>
  </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
<section id="stats-summary" class="module-content tab-content"> <section id="stats-summary" class="module-content tab-content">
<h2>{{ _('Summary') }}</h2> <h2>{{ _('Summary') }}</h2>
{% if c.summary_stats %} {% if c.summary_stats %}
<table class="table table-chunky table-bordered table-striped"> <table class="table table-chunky table-bordered table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ _('Measure') }}</th> <th>{{ _('Measure') }}</th>
<th class="metric">{{ _('Value') }}</th> <th class="metric">{{ _('Value') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for measure,value in c.summary_stats %} {% for measure,value in c.summary_stats %}
{% if 'Archived' not in measure or h.check_access('sysadmin') %} {% if 'Archived' not in measure or h.check_access('sysadmin') %}
<tr> <tr>
<td>{{measure}}</td> <td>{{measure}}</td>
<td class="metric">{{ value }}</td> <td class="metric">{{ value }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p class="empty">{{ _('No groups') }}</p> <p class="empty">{{ _('No groups') }}</p>
{% endif %} {% endif %}
</section> </section>
</article> </article>
{% endblock %} {% endblock %}
   
{% block secondary_content %} {% block secondary_content %}
<section class="module module-narrow"> <section class="module module-narrow">
<h2 class="module-heading"><i class="icon-bar-chart icon-medium"></i> {{ _('Statistics Menu') }}</h2> <h2 class="module-heading"><i class="icon-bar-chart icon-medium"></i> {{ _('Statistics Menu') }}</h2>
<nav data-module="stats-nav"> <nav data-module="stats-nav">
<ul class="unstyled nav nav-simple"> <ul class="unstyled nav nav-simple">
{% if h.check_access('sysadmin') %} {% if h.check_access('sysadmin') %}
<li class="nav-item"><a href="#stats-recent-datasets" data-toggle="tab">{{ _('Recent Datasets') }}</a></li> <li class="nav-item"><a href="#stats-recent-datasets" data-toggle="tab">{{ _('Recent Datasets') }}</a></li>
<li class="nav-item"><a href="#stats-user-access-list" data-toggle="tab">{{ _('User Access List') }}</a></li> <li class="nav-item"><a href="#stats-user-access-list" data-toggle="tab">{{ _('User Access List') }}</a></li>
{% endif %} {% endif %}
<li class="nav-item"><a href="#stats-total-datasets" data-toggle="tab">{{ _('Total Number of Datasets') }}</a></li> <li class="nav-item"><a href="#stats-total-datasets" data-toggle="tab">{{ _('Total Number of Datasets') }}</a></li>
<li class="nav-item"><a href="#stats-dataset-revisions" data-toggle="tab">{{ _('Dataset Revisions per Week') }}</a></li> <li class="nav-item"><a href="#stats-dataset-revisions" data-toggle="tab">{{ _('Dataset Revisions per Week') }}</a></li>
<li class="nav-item"><a href="#stats-most-edited" data-toggle="tab">{{ _('Most Edited Datasets') }}</a></li> <li class="nav-item"><a href="#stats-most-edited" data-toggle="tab">{{ _('Most Edited Datasets') }}</a></li>
<li class="nav-item"><a href="#stats-by-org" data-toggle="tab">{{ _('Datasets by Organization') }}</a></li> <li class="nav-item"><a href="#stats-by-org" data-toggle="tab">{{ _('Datasets by Organization') }}</a></li>
  <li class="nav-item"><a href="#stats-res-by-org" data-toggle="tab">{{ _('Resources by Organization') }}</a></li>
  <li class="nav-item"><a href="#stats-activity-org" data-toggle="tab">{{ _('Most Active Organisations') }}</a></li>
  <li class="nav-item"><a href="//data.gov.au/site-usage">Site Analytics</a></li>
<li class="nav-item active"><a href="#stats-summary" data-toggle="tab">{{ _('Summary') }}</a></li> <li class="nav-item active"><a href="#stats-summary" data-toggle="tab">{{ _('Summary') }}</a></li>
</ul> </ul>
</nav> </nav>
</section> </section>
{% endblock %} {% endblock %}
   
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
{# {#
Hellish hack to get excanvas to work in IE8. We disable html5shiv from Hellish hack to get excanvas to work in IE8. We disable html5shiv from
overriding the createElement() method on this page. overriding the createElement() method on this page.
See: http://stackoverflow.com/questions/10208062/using-flot-with-bootstrap-ie8-incompatibility See: http://stackoverflow.com/questions/10208062/using-flot-with-bootstrap-ie8-incompatibility
#} #}
{% resource "vendor/block_html5_shim" %} {% resource "vendor/block_html5_shim" %}
{% resource "ckanext_dga_stats/stats" %} {% resource "ckanext_dga_stats/stats" %}
{% endblock %} {% endblock %}