diff --git a/README.md b/README.md index 2bebcbf7..dc8da916 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,11 @@ CKAN version | Compatibility ### Configuration -_TODO: what configuraiton options exist?_ +[Optional] +`ckanext.datagovtheme.js_recent_view = true` + + +This defaults to `false`. If displaying the recent view count slows down page loading, the optional parameter can be set to `true` to make the recent view count an AJAX call, improving page loading speed. If the recent view count information (package['tracking_summary']) is already present, the AJAX call is disabled to reduce overhead. Therefore, the built-in recent view count rendering must be disabled for this mechanism to take effect. ## Development diff --git a/ckanext/datagovtheme/blueprint.py b/ckanext/datagovtheme/blueprint.py index 2bef2a37..5e427a82 100644 --- a/ckanext/datagovtheme/blueprint.py +++ b/ckanext/datagovtheme/blueprint.py @@ -3,13 +3,14 @@ from ckan.plugins.toolkit import config from ckan.lib.base import abort from ckan.common import c, request +from ckanext.datagovtheme import helpers -from flask import Blueprint, redirect +from flask import Blueprint, redirect, jsonify import logging log = logging.getLogger(__name__) -pusher = Blueprint('datagovtheme', __name__) +datagovtheme_bp = Blueprint('datagovtheme', __name__) def show(): @@ -35,7 +36,15 @@ def show(): def redirect_homepage(): CKAN_SITE_URL = config.get("ckan.site_url") - return redirect(CKAN_SITE_URL + "/dataset", code=302) + return redirect(CKAN_SITE_URL + "/dataset/", code=302) -pusher.add_url_rule('/', view_func=redirect_homepage) +def get_popuplar_count(): + pkgs = request.args.get('pkgs') + return jsonify(helpers.get_pkgs_popular_count(pkgs)) + + +datagovtheme_bp.add_url_rule('/', view_func=redirect_homepage) +datagovtheme_bp.add_url_rule("/datagovtheme/get-popular-count", + methods=['GET'], + view_func=get_popuplar_count) diff --git a/ckanext/datagovtheme/fanstatic_library/scripts/popular.js b/ckanext/datagovtheme/fanstatic_library/scripts/popular.js new file mode 100644 index 00000000..261244b5 --- /dev/null +++ b/ckanext/datagovtheme/fanstatic_library/scripts/popular.js @@ -0,0 +1,36 @@ +// This js file loads with datagov-popular.html snippet + +jQuery(function ($) { + + // This api takes a list of package ids from querystring and returns the view count for each package + var pupolar_api = "/datagovtheme/get-popular-count"; + + // all ids in a string, comma separated + var pkgs = {'pkgs': collect_all_packages().join(',')}; + + $.getJSON(pupolar_api, pkgs, function(data) { + $.each( data, function( key, val ) { + $("ul.dataset-list li.dataset-item h3.dataset-heading").each(function() { + if ($(this).attr('pkg_id') == key) { + $(this).find('span.recent-views-datagov').attr('title', val['recent']).html(' ' + val['recent'] + ' recent views'); + // If the view count is greater than 10, make it visible + if (val['recent'] >= 10) { + $(this).find('span.recent-views').css('visibility', 'visible'); + }else{ + $(this).find('span.recent-views').css('display', 'hidden'); + } + } + }); + }); + }); + + // We have pkg_id in each dataset-item, added in the template. + function collect_all_packages() { + var pkgs = []; + $("ul.dataset-list li.dataset-item h3.dataset-heading").each(function() { + pkgs.push($(this).attr('pkg_id')); + }); + + return pkgs; + } +}); diff --git a/ckanext/datagovtheme/fanstatic_library/styles/datagovtheme.css b/ckanext/datagovtheme/fanstatic_library/styles/datagovtheme.css index 460483c9..b64506b4 100644 --- a/ckanext/datagovtheme/fanstatic_library/styles/datagovtheme.css +++ b/ckanext/datagovtheme/fanstatic_library/styles/datagovtheme.css @@ -2239,6 +2239,9 @@ body .tagged-ngda { padding-left: 5px; display: inline-block; } +.recent-views-datagov { + visibility: hidden; +} .bar-image { width: 18px; display: inline-block; diff --git a/ckanext/datagovtheme/fanstatic_library/webassets.yml b/ckanext/datagovtheme/fanstatic_library/webassets.yml index 32f01cd1..783e9fd8 100644 --- a/ckanext/datagovtheme/fanstatic_library/webassets.yml +++ b/ckanext/datagovtheme/fanstatic_library/webassets.yml @@ -38,3 +38,8 @@ location_autocomplete_js: # TODO can this custom location search be replaced by ckanext-spatial? Can # this be pushed upstream to ckanext-spatial as an enhancement? - scripts/location_autocomplete.js + +popular-js: + output: datagovtheme/popular.js + contents: + - scripts/popular.js diff --git a/ckanext/datagovtheme/helpers.py b/ckanext/datagovtheme/helpers.py index c0cd518e..507ea378 100644 --- a/ckanext/datagovtheme/helpers.py +++ b/ckanext/datagovtheme/helpers.py @@ -10,6 +10,7 @@ import pkg_resources from ckan import plugins as p +from ckan.lib import base from ckan.lib import helpers as h from ckan import model from ckanext.harvest.model import HarvestObject @@ -762,3 +763,24 @@ def get_login_url(): return h.url_for(controller='user', action='login') return '/user/saml2login' + + +def get_pkgs_popular_count(ids): + populars = {} + if ids: + pkg_ids = ids.split(',') + for pkg_id in pkg_ids: + populars[pkg_id] = model.TrackingSummary.get_for_package(pkg_id) + return populars + + +def render_popular(type, pkg, min, title=''): + # If the package has tracking_summary, call core helper function to render it. + if pkg.get('tracking_summary'): + return h.popular(type, pkg['tracking_summary']['recent'], min, title) + + js_recent_view = asbool(config.get('ckanext.datagovtheme.js_recent_view', False)) + if js_recent_view: + return base.render_snippet('snippets/datagov_popular.html') + + return '' diff --git a/ckanext/datagovtheme/plugin.py b/ckanext/datagovtheme/plugin.py index c48f659d..b27bcfc7 100644 --- a/ckanext/datagovtheme/plugin.py +++ b/ckanext/datagovtheme/plugin.py @@ -109,6 +109,8 @@ def get_helpers(self): 'convert_top_category_to_list': datagovtheme_helpers.convert_top_category_to_list, 'get_pkg_dict_extra': datagovtheme_helpers.get_pkg_dict_extra, 'get_login_url': datagovtheme_helpers.get_login_url, + 'get_pkgs_popular_count': datagovtheme_helpers.get_pkgs_popular_count, + 'render_popular': datagovtheme_helpers.render_popular, } # https://github.com/GSA/ckan/blob/datagov/ckan/config/environment.py#L70:L70 @@ -125,4 +127,4 @@ def get_helpers(self): return helpers def get_blueprint(self): - return blueprint.pusher + return blueprint.datagovtheme_bp diff --git a/ckanext/datagovtheme/templates/package/snippets/resource_item.html b/ckanext/datagovtheme/templates/package/snippets/resource_item.html index 394be709..d2b18d75 100644 --- a/ckanext/datagovtheme/templates/package/snippets/resource_item.html +++ b/ckanext/datagovtheme/templates/package/snippets/resource_item.html @@ -14,12 +14,12 @@ {% if res.name == 'Comma Seperated Values File' %} Comma Separated Values File{{ res.format }} - {{ h.popular('views', res.tracking_summary.total, min=10) }} + {{ h.popular('views', res.tracking_summary.total, min=10) if res.tracking_summary }} {% else %} {{ h.resource_display_name(res) | truncate(50) }}{{ res.format }} - {{ h.popular('views', res.tracking_summary.total, min=10) }} + {{ h.popular('views', res.tracking_summary.total, min=10) if res.tracking_summary }} {% endif %} {% endblock %} diff --git a/ckanext/datagovtheme/templates/snippets/datagov_popular.html b/ckanext/datagovtheme/templates/snippets/datagov_popular.html new file mode 100644 index 00000000..e28efeb7 --- /dev/null +++ b/ckanext/datagovtheme/templates/snippets/datagov_popular.html @@ -0,0 +1,5 @@ + +    recent views + +{% asset 'datagovtheme/popular-js' %} + diff --git a/ckanext/datagovtheme/templates/snippets/package_item.html b/ckanext/datagovtheme/templates/snippets/package_item.html index df07c199..a82ec6d0 100755 --- a/ckanext/datagovtheme/templates/snippets/package_item.html +++ b/ckanext/datagovtheme/templates/snippets/package_item.html @@ -35,7 +35,7 @@ {% endif %} -

+

{% if package.private %} @@ -63,7 +63,7 @@

{% endif %} - {{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }} + {{ h.render_popular('recent views', package, min=10) }}

{% if organization and show_organization %} diff --git a/ckanext/datagovtheme/tests/test_helpers.py b/ckanext/datagovtheme/tests/test_helpers.py index 9d1649e2..6e5eabc2 100644 --- a/ckanext/datagovtheme/tests/test_helpers.py +++ b/ckanext/datagovtheme/tests/test_helpers.py @@ -1,12 +1,14 @@ # encoding: utf-8 import logging import re +import datetime import mock import pytest from ckanext.datagovtheme import helpers import ckan.tests.factories as factories +import ckan.lib.helpers as h ################ @@ -136,3 +138,64 @@ def test_is_tagged_ngda(): assert helpers.is_tagged_ngda(dataset_ngda) is True assert helpers.is_tagged_ngda(dataset_non_ngda) is False + + +################## +# recent view +################## + + +@pytest.fixture +def track(app): + """Post some data to /_tracking directly. + + This simulates what's supposed when you view a page with tracking + enabled (an ajax request posts to /_tracking). + + """ + + def func(url, type_="page", ip="199.204.138.90", browser="firefox"): + params = {"url": url, "type": type_} + extra_environ = { + # The tracking middleware crashes if these aren't present. + "HTTP_USER_AGENT": browser, + "REMOTE_ADDR": ip, + "HTTP_ACCEPT_LANGUAGE": "en", + "HTTP_ACCEPT_ENCODING": "gzip, deflate", + } + app.post("/_tracking", params=params, extra_environ=extra_environ) + + return func + + +def update_tracking_summary(): + """Update CKAN's tracking summary data.""" + + import ckan.cli.tracking as tracking + import ckan.model + + date = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime( + "%Y-%m-%d" + ) + tracking.update_all(engine=ckan.model.meta.engine, start_date=date) + + +def test_get_pkgs_popular_count(track): + factories.Dataset(id="view-id-1", name="view-id-1") + factories.Dataset(id="view-id-2", name="view-id-2") + + ids = "view-id-1,view-id-2" + assert helpers.get_pkgs_popular_count(ids) == { + 'view-id-1': {'recent': 0, 'total': 0}, + 'view-id-2': {'recent': 0, 'total': 0} + } + + url = h.url_for("dataset.read", id="view-id-1") + track(url) + update_tracking_summary() + + # after dataset 1 is viewed, it should have a view count of 1, dataset 2 should still have 0 + assert helpers.get_pkgs_popular_count(ids) == { + 'view-id-1': {'recent': 1, 'total': 1}, + 'view-id-2': {'recent': 0, 'total': 0} + } diff --git a/setup.py b/setup.py index 306f82f1..f8048c64 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="ckanext-datagovtheme", - version="0.2.24", + version="0.2.25", description="CKAN Extension to manage data.gov theme", long_description=long_description, classifiers=[