Add webassets / some clean-up
This commit is contained in:
parent
0951971783
commit
f67777c547
30
README.rst
30
README.rst
|
@ -26,28 +26,6 @@ Features
|
||||||
|
|
||||||
``ckanext.googleanalytics.plugin._post_analytics``
|
``ckanext.googleanalytics.plugin._post_analytics``
|
||||||
|
|
||||||
* Adds Google Analytics Event Tracking to group links on the home page,
|
|
||||||
user profile links, editing and saving user profiles, etc.
|
|
||||||
|
|
||||||
*Only if* ``googleanalytics.track_events = true`` *is in your CKAN ini file.*
|
|
||||||
|
|
||||||
*CKAN 1.x only*.
|
|
||||||
|
|
||||||
* Puts download stats into dataset pages, e.g. "[downloaded 4 times]".
|
|
||||||
|
|
||||||
*CKAN 1.x only.*
|
|
||||||
|
|
||||||
* Provides a ``/analytics/dataset/top`` page that shows the most popular
|
|
||||||
datasets and resources
|
|
||||||
|
|
||||||
*CKAN 1.x only*
|
|
||||||
|
|
||||||
CKAN 1.x Support
|
|
||||||
----------------
|
|
||||||
|
|
||||||
To use ckanext-googleanalytics with CKAN 1.x, make sure you have
|
|
||||||
``ckan.legacy_templates = true`` in your CKAN ini file.
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -81,13 +59,7 @@ Installation
|
||||||
(If there are other plugins activated, add this to the list. Each
|
(If there are other plugins activated, add this to the list. Each
|
||||||
plugin should be separated with a space).
|
plugin should be separated with a space).
|
||||||
|
|
||||||
4. If you are using this plugin with a version of CKAN < 2.0 then you should
|
4. Finally, there are some optional configuration settings (shown here
|
||||||
also put the following in your ini file::
|
|
||||||
|
|
||||||
ckan.legacy_templates = true
|
|
||||||
|
|
||||||
|
|
||||||
5. Finally, there are some optional configuration settings (shown here
|
|
||||||
with their default settings)::
|
with their default settings)::
|
||||||
|
|
||||||
googleanalytics_resource_prefix = /downloads/
|
googleanalytics_resource_prefix = /downloads/
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Add Google Analytics Event Tracking to resource download links.
|
||||||
|
this.ckan.module("google-analytics", function(jQuery, _) {
|
||||||
|
"use strict";
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
googleanalytics_resource_prefix: ""
|
||||||
|
},
|
||||||
|
initialize: function() {
|
||||||
|
jQuery("a.resource-url-analytics").on("click", function() {
|
||||||
|
var resource_url = encodeURIComponent(jQuery(this).prop("href"));
|
||||||
|
if (resource_url) {
|
||||||
|
ga("send", "event", "Resource", "Download", resource_url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
event_tracking:
|
||||||
|
filters: rjsmin
|
||||||
|
output: ckanext-googleanalytics/event_tracking.js
|
||||||
|
contents:
|
||||||
|
- googleanalytics_event_tracking.js
|
|
@ -1,16 +0,0 @@
|
||||||
// Add Google Analytics Event Tracking to resource download links.
|
|
||||||
this.ckan.module('google-analytics', function(jQuery, _) {
|
|
||||||
return {
|
|
||||||
options: {
|
|
||||||
googleanalytics_resource_prefix: ''
|
|
||||||
},
|
|
||||||
initialize: function() {
|
|
||||||
jQuery('a.resource-url-analytics').on('click', function() {
|
|
||||||
var resource_url = encodeURIComponent(jQuery(this).prop('href'));
|
|
||||||
if (resource_url) {
|
|
||||||
ga('send', 'event', 'Resource', 'Download', resource_url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -2,7 +2,15 @@ import httplib2
|
||||||
from apiclient.discovery import build
|
from apiclient.discovery import build
|
||||||
from oauth2client.service_account import ServiceAccountCredentials
|
from oauth2client.service_account import ServiceAccountCredentials
|
||||||
|
|
||||||
from pylons import config
|
from ckan.exceptions import CkanVersionException
|
||||||
|
import ckan.plugins.toolkit as tk
|
||||||
|
|
||||||
|
try:
|
||||||
|
tk.requires_ckan_version("2.9")
|
||||||
|
except CkanVersionException:
|
||||||
|
from pylons import config
|
||||||
|
else:
|
||||||
|
config = tk.config
|
||||||
|
|
||||||
|
|
||||||
def _prepare_credentials(credentials_filename):
|
def _prepare_credentials(credentials_filename):
|
||||||
|
@ -43,7 +51,6 @@ def get_profile_id(service):
|
||||||
|
|
||||||
if not accounts.get("items"):
|
if not accounts.get("items"):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
accountName = config.get("googleanalytics.account")
|
accountName = config.get("googleanalytics.account")
|
||||||
webPropertyId = config.get("googleanalytics.id")
|
webPropertyId = config.get("googleanalytics.id")
|
||||||
for acc in accounts.get("items"):
|
for acc in accounts.get("items"):
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
(function ($) {
|
|
||||||
$(document).ready(function () {
|
|
||||||
// Google Analytics event tracking
|
|
||||||
|
|
||||||
// group links on home page
|
|
||||||
$('body.home div.group a').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Home', 'Click: Group Link', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// clicking on user name (go to profile)
|
|
||||||
$('div.account span.ckan-logged-in a').first().click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'User', 'Click: User Name', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// In user profile, clicking on Edit Profile
|
|
||||||
$('body.user div#minornavigation a')
|
|
||||||
.filter(function(index) {return $(this).text() === "Edit Profile";})
|
|
||||||
.click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'User', 'Click: Tab', 'Edit Profile']);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clicking Save Changes on Edit Profile page
|
|
||||||
$('body.user.edit input#save').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'User', 'Click: Button', 'Save Profile Changes']);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clicking on any dataset link on User Profile page
|
|
||||||
$('body.user.read ul.datasets a').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'User', 'Click: Dataset Link', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Compare Button on /dataset/history/X
|
|
||||||
$('body.package.history form#dataset-revisions input[name="diff"]').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Dataset', 'Click: Button', 'Compare History']);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tags on right hand sidebar of /dataset/X
|
|
||||||
$('body.package.read div#sidebar h3')
|
|
||||||
.filter(function(index) {return $(this).text().indexOf("Tags") != -1;})
|
|
||||||
.next('ul')
|
|
||||||
.find('a')
|
|
||||||
.click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Dataset', 'Click: Tag', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Any of the group links on /group
|
|
||||||
$('body.group.index table.groups a').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Group', 'Click: Group Link', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clicking any of the right hand sidebar tags on /group/X
|
|
||||||
$('body.group.read div#sidebar h2')
|
|
||||||
.filter(function(index) {return $(this).text().indexOf("Tags") != -1;})
|
|
||||||
.next('ul')
|
|
||||||
.find('a')
|
|
||||||
.click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Group', 'Click: Tag', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Visiting /group/history/X
|
|
||||||
$('body.group div#minornavigation ul.nav a')
|
|
||||||
.filter(function(index) {return $(this).text().indexOf("History") != -1;})
|
|
||||||
.click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Group', 'Click: History Tab', $(this).attr('href')]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Compare Button on /group/history/X
|
|
||||||
$('body.group.history form#group-revisions input[name="diff"]').click(function() {
|
|
||||||
_gaq.push(['_trackEvent', 'Group', 'Click: Button', 'Compare History']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}(jQuery));
|
|
|
@ -1,53 +0,0 @@
|
||||||
<html xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:i18n="http://genshi.edgewall.org/i18n"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
||||||
py:strip="">
|
|
||||||
|
|
||||||
<py:def function="page_title">Analytics for ${g.site_title}</py:def>
|
|
||||||
|
|
||||||
<div py:match="content">
|
|
||||||
|
|
||||||
<h2>Most viewed datasets</h2>
|
|
||||||
<p><em>Note: this data does not include API calls</em></p>
|
|
||||||
|
|
||||||
<table class="table table-condensed table-bordered table-striped">
|
|
||||||
<tr>
|
|
||||||
<th>Dataset</th>
|
|
||||||
<th>Unique views (last 14 days)</th>
|
|
||||||
<th>Unique views (since recording started)</th>
|
|
||||||
</tr>
|
|
||||||
<py:for each="package, recent, ever in c.top_packages">
|
|
||||||
<tr>
|
|
||||||
<td>${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))}
|
|
||||||
</td>
|
|
||||||
<td>${recent}</td>
|
|
||||||
<td>${ever}</td>
|
|
||||||
</tr>
|
|
||||||
</py:for>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2>Most downloaded resources</h2>
|
|
||||||
<table class="table table-condensed table-bordered table-striped">
|
|
||||||
<tr>
|
|
||||||
<th>Resource</th>
|
|
||||||
<th>Downloads (last 14 days)</th>
|
|
||||||
<th>Downloads (since recording started)</th>
|
|
||||||
</tr>
|
|
||||||
<py:for each="resource, recent, ever in c.top_resources">
|
|
||||||
<tr>
|
|
||||||
<td>${h.link_to(h.truncate(resource.description, length=50,whole_word=True) if resource.description else resource.format, h.url_for(controller='package',action='resource_read',id=resource.resource_group.package.id,resource_id=resource.id))}<br />
|
|
||||||
<em>in ${h.link_to(resource.resource_group.package.title or resource.resource_group.package.name, h.url_for(controller='package', action='read', id=resource.resource_group.package.name))}</em>
|
|
||||||
</td>
|
|
||||||
<td>${recent}</td>
|
|
||||||
<td>${ever}</td>
|
|
||||||
</tr>
|
|
||||||
</py:for>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from future import standard_library
|
from future import standard_library
|
||||||
|
|
||||||
standard_library.install_aliases()
|
standard_library.install_aliases()
|
||||||
from builtins import str
|
|
||||||
from builtins import range
|
import urllib.parse
|
||||||
import ast
|
import ast
|
||||||
import logging
|
import logging
|
||||||
import ckanext.googleanalytics.commands as commands
|
import threading
|
||||||
import paste.deploy.converters as converters
|
|
||||||
|
from builtins import str, range
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
import ckan.lib.helpers as h
|
import ckan.lib.helpers as h
|
||||||
import ckan.plugins as p
|
import ckan.plugins as p
|
||||||
import ckan.plugins.toolkit as tk
|
import ckan.plugins.toolkit as tk
|
||||||
import urllib.parse
|
|
||||||
from ckan.exceptions import CkanVersionException
|
from ckan.exceptions import CkanVersionException
|
||||||
import threading
|
|
||||||
import requests
|
import ckanext.googleanalytics.commands as commands
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -46,9 +53,7 @@ class AnalyticsPostThread(threading.Thread):
|
||||||
log.debug("Sending API event to Google Analytics: " + data)
|
log.debug("Sending API event to Google Analytics: " + data)
|
||||||
# send analytics
|
# send analytics
|
||||||
res = requests.post(
|
res = requests.post(
|
||||||
"http://www.google-analytics.com/collect",
|
"http://www.google-analytics.com/collect", data, timeout=10,
|
||||||
data,
|
|
||||||
timeout=10,
|
|
||||||
)
|
)
|
||||||
# signals to queue job is done
|
# signals to queue job is done
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
@ -101,22 +106,19 @@ class GoogleAnalyticsPlugin(GAMixinPlugin, p.SingletonPlugin):
|
||||||
"googleanalytics_resource_prefix"
|
"googleanalytics_resource_prefix"
|
||||||
]
|
]
|
||||||
|
|
||||||
self.show_downloads = converters.asbool(
|
self.show_downloads = tk.asbool(
|
||||||
config.get("googleanalytics.show_downloads", True)
|
config.get("googleanalytics.show_downloads", True)
|
||||||
)
|
)
|
||||||
self.track_events = converters.asbool(
|
self.track_events = tk.asbool(
|
||||||
config.get("googleanalytics.track_events", False)
|
config.get("googleanalytics.track_events", False)
|
||||||
)
|
)
|
||||||
self.enable_user_id = converters.asbool(
|
self.enable_user_id = tk.asbool(
|
||||||
config.get("googleanalytics.enable_user_id", False)
|
config.get("googleanalytics.enable_user_id", False)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not converters.asbool(config.get("ckan.legacy_templates", "false")):
|
p.toolkit.add_resource("../assets", "ckanext-googleanalytics")
|
||||||
p.toolkit.add_resource(
|
|
||||||
"../fanstatic_library", "ckanext-googleanalytics"
|
|
||||||
)
|
|
||||||
|
|
||||||
# spawn a pool of 5 threads, and pass them queue instance
|
# spawn a pool of 5 threads, and pass them queue instance
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
t = AnalyticsPostThread(self.analytics_queue)
|
t = AnalyticsPostThread(self.analytics_queue)
|
||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
|
@ -128,11 +130,7 @@ class GoogleAnalyticsPlugin(GAMixinPlugin, p.SingletonPlugin):
|
||||||
See IConfigurer.
|
See IConfigurer.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if converters.asbool(config.get("ckan.legacy_templates", "false")):
|
p.toolkit.add_template_directory(config, "../templates")
|
||||||
p.toolkit.add_template_directory(config, "../legacy_templates")
|
|
||||||
p.toolkit.add_public_directory(config, "../legacy_public")
|
|
||||||
else:
|
|
||||||
p.toolkit.add_template_directory(config, "../templates")
|
|
||||||
|
|
||||||
def get_helpers(self):
|
def get_helpers(self):
|
||||||
"""Return the CKAN 2.0 template helper functions this plugin provides.
|
"""Return the CKAN 2.0 template helper functions this plugin provides.
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
{% ckan_extends %}
|
{% ckan_extends %}
|
||||||
|
|
||||||
{% block links %}
|
{% block links %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{% block googleanalytics_header %}
|
{% block googleanalytics_header %}
|
||||||
{{ h.googleanalytics_header() }}
|
{{ h.googleanalytics_header() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{% block googleanalytics_event_tracking %}
|
{% block googleanalytics_event_tracking %}
|
||||||
{% resource 'ckanext-googleanalytics/googleanalytics_event_tracking.js' %}
|
{% set type = 'asset' if h.ckan_version() > '2.9' else 'resource' %}
|
||||||
<div class="js-hide" data-module="google-analytics"
|
{% include 'googleanalytics/snippets/event_tracking_' ~ type ~ '.html' %}
|
||||||
data-module-googleanalytics_resource_prefix="{{ g.googleanalytics_resource_prefix }}">
|
<div class="js-hide" data-module="google-analytics"
|
||||||
</div>
|
data-module-googleanalytics_resource_prefix="{{ g.googleanalytics_resource_prefix }}">
|
||||||
{% endblock %}
|
</div>
|
||||||
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{% asset 'ckanext-googleanalytics/event_tracking' %}
|
|
@ -0,0 +1 @@
|
||||||
|
{% resource 'ckanext-googleanalytics/googleanalytics_event_tracking.js' %}
|
|
@ -1,16 +1,19 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from flask import Blueprint
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
import ckan.logic as logic
|
||||||
|
import ckan.plugins.toolkit as tk
|
||||||
import ckan.views.api as api
|
import ckan.views.api as api
|
||||||
import ckan.views.resource as resource
|
import ckan.views.resource as resource
|
||||||
import ckan.logic as logic
|
|
||||||
import logging
|
|
||||||
from ckan.common import g
|
from ckan.common import g
|
||||||
import ckan.plugins.toolkit as tk
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
ga = Blueprint("google_analytics", "google_analytics")
|
||||||
ga = Blueprint(u"google_analytics", "google_analytics",)
|
|
||||||
|
|
||||||
|
|
||||||
def action(logic_function, ver=api.API_MAX_VERSION):
|
def action(logic_function, ver=api.API_MAX_VERSION):
|
||||||
|
@ -23,7 +26,7 @@ def action(logic_function, ver=api.API_MAX_VERSION):
|
||||||
if "q" in request_data:
|
if "q" in request_data:
|
||||||
id = request_data["q"]
|
id = request_data["q"]
|
||||||
if "query" in request_data:
|
if "query" in request_data:
|
||||||
id = request_data["query"]
|
id = request_data[u"query"]
|
||||||
_post_analytics(g.user, "CKAN API Request", logic_function, "", id)
|
_post_analytics(g.user, "CKAN API Request", logic_function, "", id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(e)
|
log.debug(e)
|
||||||
|
@ -33,15 +36,13 @@ def action(logic_function, ver=api.API_MAX_VERSION):
|
||||||
|
|
||||||
|
|
||||||
ga.add_url_rule(
|
ga.add_url_rule(
|
||||||
u"/api/action/<logic_function>",
|
"/api/action/<logic_function>", methods=["GET", "POST"], view_func=action,
|
||||||
methods=[u"GET", u"POST"],
|
|
||||||
view_func=action,
|
|
||||||
)
|
)
|
||||||
ga.add_url_rule(
|
ga.add_url_rule(
|
||||||
u"/<int(min=3, max={0}):ver>/action/<logic_function>".format(
|
u"/<int(min=3, max={0}):ver>/action/<logic_function>".format(
|
||||||
api.API_MAX_VERSION
|
api.API_MAX_VERSION
|
||||||
),
|
),
|
||||||
methods=[u"GET", u"POST"],
|
methods=["GET", "POST"],
|
||||||
view_func=action,
|
view_func=action,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,10 +59,10 @@ def download(id, resource_id, filename=None, package_type="dataset"):
|
||||||
|
|
||||||
|
|
||||||
ga.add_url_rule(
|
ga.add_url_rule(
|
||||||
u"/dataset/<id>/resource/<resource_id>/download", view_func=download
|
"/dataset/<id>/resource/<resource_id>/download", view_func=download
|
||||||
)
|
)
|
||||||
ga.add_url_rule(
|
ga.add_url_rule(
|
||||||
u"/dataset/<id>/resource/<resource_id>/download/<filename>",
|
"/dataset/<id>/resource/<resource_id>/download/<filename>",
|
||||||
view_func=download,
|
view_func=download,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ def _post_analytics(
|
||||||
):
|
):
|
||||||
|
|
||||||
from ckanext.googleanalytics.plugin import GoogleAnalyticsPlugin
|
from ckanext.googleanalytics.plugin import GoogleAnalyticsPlugin
|
||||||
|
|
||||||
if tk.config.get("googleanalytics.id"):
|
if tk.config.get("googleanalytics.id"):
|
||||||
data_dict = {
|
data_dict = {
|
||||||
"v": 1,
|
"v": 1,
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[tool.black]
|
||||||
|
line-length = 79
|
||||||
|
include = '\.py$'
|
Loading…
Reference in New Issue