Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkCalvert committed Aug 13, 2024
2 parents 4a8e06b + 44cb284 commit f041385
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 64 deletions.
22 changes: 8 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.6'
python-version: '3.9'
- name: Install requirements
run: pip install flake8 pycodestyle
- name: Check syntax
Expand All @@ -19,16 +19,16 @@ jobs:
needs: lint
strategy:
matrix:
ckan-version: ["2.10", 2.9, 2.9-py2, 2.8]
ckan-version: ["2.11", "2.10", 2.9]
fail-fast: false

name: CKAN ${{ matrix.ckan-version }}
runs-on: ubuntu-latest
container:
image: openknowledge/ckan-dev:${{ matrix.ckan-version }}
image: ckan/ckan-dev:${{ matrix.ckan-version }}
services:
solr:
image: ckan/ckan-solr:${{ matrix.ckan-version }}
image: ckan/ckan-solr:${{ matrix.ckan-version }}-solr9
postgres:
image: ckan/ckan-postgres-dev:${{ matrix.ckan-version }}
env:
Expand All @@ -54,22 +54,16 @@ jobs:
# Replace default path to CKAN core config file with the one on the container
sed -i -e 's/use = config:.*/use = config:\/srv\/app\/src\/ckan\/test-core.ini/' test.ini
- name: Setup extension (CKAN 2.10)
if: ${{ matrix.ckan-version == '2.10' }}
if: ${{ matrix.ckan-version >= '2.10' }}
run: |
pip install -r dev-requirements.txt
ckan -c test.ini db init
ckan -c test.ini db upgrade -p googleanalytics
- name: Setup extension (CKAN == 2.9)
if: ${{ matrix.ckan-version == '2.9' || matrix.ckan-version == '2.9-py2' }}
if: ${{ matrix.ckan-version == '2.9' }}
run: |
pip install -r dev-requirements-2.9.txt
ckan -c test.ini db init
ckan -c test.ini db upgrade -p googleanalytics
- name: Setup extension (CKAN < 2.9)
if: ${{ matrix.ckan-version == '2.8' }}
run: |
pip install -r dev-requirements-2.9.txt
paster --plugin=ckan db init -c test.ini
paster --plugin=ckanext-googleanalytics initdb -c test.ini
- name: Run tests
run: pytest --ckan-ini=test.ini --cov=ckanext.googleanalytics --disable-warnings ckanext/googleanalytics/tests
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [2.3.0](https://github.com/ckan/ckanext-googleanalytics/compare/v2.2.3...v2.3.0) (2023-06-14)


### Features

* add GTM tracking support ([5268985](https://github.com/ckan/ckanext-googleanalytics/commit/52689855758ad1368bd8ae8a785443761ba0abe4))
* track downloads via MeasurementProtocol ([acb7a81](https://github.com/ckan/ckanext-googleanalytics/commit/acb7a81bc43f7c0eef94f78a2a605dfb8a8db20b))

### [2.2.3](https://github.com/ckan/ckanext-googleanalytics/compare/v2.2.2...v2.2.3) (2023-06-14)


### Features

* add blocks to gtag snippet ([913908f](https://github.com/ckan/ckanext-googleanalytics/commit/913908fc611f59be80322238953edcc84e3b0f06))


### Bug Fixes

* report empty googleanalytics.id ([cf75e57](https://github.com/ckan/ckanext-googleanalytics/commit/cf75e577cb70fc9c5b0be270c07fb68376646c46))

### [2.2.2](https://github.com/ckan/ckanext-googleanalytics/compare/v2.2.1...v2.2.2) (2023-03-03)


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ retrieves statistics from Google Analytics and inserts them into CKAN pages.
function must be called instead of `ckan.views.resource:download`
via `ckanext.googleanalytics.download_handler` config variable. For ckanext-cloudstorage you can use:

ckanext.googleanalytics.download_handler = ckanext.cloudstorage.views:download
googleanalytics.download_handler = ckanext.cloudstorage.views:download

# Domain Linking

Expand Down
2 changes: 1 addition & 1 deletion ckanext/googleanalytics/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import logging
import click
import ckan.model as model
from ckan.plugins import toolkit as tk
import ckan.plugins.toolkit as tk

from . import dbutil, config

Expand Down
30 changes: 27 additions & 3 deletions ckanext/googleanalytics/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import ckan.plugins.toolkit as tk

CONFIG_TRACKING_ID = "googleanalytics.id"
CONFIG_HANDLER_PATH = "googleanalytics.download_handler"
CONFIG_TRACKING_MODE = "googleanalytics.tracking_mode"

DEFAULT_RESOURCE_URL_TAG = "/downloads/"
DEFAULT_RECENT_VIEW_DAYS = 14
Expand All @@ -15,7 +17,8 @@


def tracking_id():
return tk.config.get("googleanalytics.id")
# type: () -> str
return tk.config["googleanalytics.id"]


def download_handler():
Expand All @@ -29,9 +32,9 @@ def download_handler():
return handler



def tracking_mode():
type_ = tk.config.get("googleanalytics.tracking_mode")
# type: () -> Literal["ga", "gtag", "gtm"]
type_ = tk.config.get(CONFIG_TRACKING_MODE)
if type_:
return type_

Expand All @@ -43,21 +46,42 @@ def tracking_mode():
if id_.startswith("G-"):
return "gtag"

if id_.startswith("GTM-"):
return "gtm"

return "ga"


def measurement_id():
# type: () -> str
"""Set the MeasurementID for tracking API actions. By default,
`googleanalytics.id` is used.
Use this option during migration from Universal Analytics, to track API
requests using Measurement Protocol, while tracking browser event using
Universal Analytics.
Requires `googleanalytics.measurement_protocol.client_id`.
"""
return tk.config.get("googleanalytics.measurement_protocol.id") or tracking_id()


def measurement_protocol_client_id():
# type: () -> str | None
return tk.config.get("googleanalytics.measurement_protocol.client_id")


def measurement_protocol_client_secret():
return tk.config.get("googleanalytics.measurement_protocol.client_secret")


def measurement_protocol_track_downloads():
# type: () -> bool
return tk.asbool(
tk.config.get("googleanalytics.measurement_protocol.track_downloads")
)


def account():
return tk.config.get("googleanalytics.account")

Expand Down
24 changes: 24 additions & 0 deletions ckanext/googleanalytics/config_declaration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,33 @@ groups:
- key: googleanalytics.id
required: true
placeholder: UA-000000000-1
validators: not_empty
description: |
Google tag ID(`G-*`) for Google Analytics 4, the Tracking ID(`UA-*`)
for Universal Analytics, or container ID(`GTM-*`) for Google Tag
Manager.
- key: googleanalytics.download_handler
default: ckan.views.resource:download
description: |
Import path of the CKAN view that handles resource downloads. It can
be used in combination with plugins that replace download
view(`ckanext-cloudstorage`, `ckanext-s3filestore`).
- key: googleanalytics.tracking_mode
experimental: true
example: gtag
description: |
Defines the type of code snippet embedded into the page. Can be set
to `ga`(enables `googleanalytics.js`), `gtag`(enables `gtag.js`), or
`gtm`(enables Google Tag Manager). The plugin will check
`googleanalytics.id` and set appropriate value depending on the
prefix: `G-` enables `gtag`, `UA-` enables `ga` mode, and `GTM-`
enables Google Tag Manager.
Use this option only if you know better which snippet you need. In
future, after dropping UniversalAnalytics, this option may be
removed.
- key: googleanalytics.account

Expand Down
2 changes: 1 addition & 1 deletion ckanext/googleanalytics/ga_auth.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials

from ckanext.googleanalytics import utils, config
from ckanext.googleanalytics import config
from google.analytics.data_v1beta import BetaAnalyticsDataClient


Expand Down
5 changes: 5 additions & 0 deletions ckanext/googleanalytics/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
def get_helpers():
return {
"googleanalytics_header": googleanalytics_header,
"googleanalytics_id": googleanalytics_id,
"googleanalytics_resource_prefix": googleanalytics_resource_prefix,
"googleanalytics_tracking_mode": googleanalytics_tracking_mode,
}
Expand Down Expand Up @@ -43,3 +44,7 @@ def googleanalytics_header():

def googleanalytics_tracking_mode():
return config.tracking_mode()


def googleanalytics_id():
return config.tracking_id()
2 changes: 1 addition & 1 deletion ckanext/googleanalytics/logic/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ckan.logic import validate

from . import schema
from .. import utils, config
from .. import config
from ..model import PackageStats, ResourceStats
from ..ga_auth import init_service, get_profile_id

Expand Down
4 changes: 2 additions & 2 deletions ckanext/googleanalytics/plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def update_config(self, config):
tk.add_template_directory(config, "../templates")
tk.add_resource("../assets", "ckanext-googleanalytics")

if "googleanalytics.id" not in config:
msg = "Missing googleanalytics.id in config"
if not config.get("googleanalytics.id"):
msg = "Missing or empty googleanalytics.id in config"
raise GoogleAnalyticsException(msg)

def get_helpers(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{googleanalytics_id}}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
{% block main %}
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{googleanalytics_id}}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}

gtag('set', 'linker', );
gtag('js', new Date());
{% block setup %}
gtag('set', 'linker');

gtag('config', '{{googleanalytics_id}}', {
anonymize_ip: true,
linker: {
domains: {{ googleanalytics_linked_domains|tojson }}
}
});
</script>
gtag('js', new Date());

gtag('config', '{{googleanalytics_id}}', {
anonymize_ip: true,
linker: {
domains: {{ googleanalytics_linked_domains|tojson }}
}
});
{% endblock setup %}

{% block extra %}
{% endblock extra %}

</script>

{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','{{googleanalytics_id}}');</script>
<!-- End Google Tag Manager -->
16 changes: 16 additions & 0 deletions ckanext/googleanalytics/templates/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% ckan_extends %}

{% block page %}
{% block googleanalytics_body_script %}
{% if h.googleanalytics_tracking_mode() == "gtm" %}
{% with id = h.googleanalytics_id() %}
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ id }}"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
{% endwith %}
{% endif %}
{% endblock %}

{{ super() }}
{% endblock page %}
14 changes: 14 additions & 0 deletions ckanext/googleanalytics/tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import pytest

from ckanext.googleanalytics import config


@pytest.mark.parametrize(("tracking_id", "mode"), [
("UA-123", "ga"),
("G-123", "gtag"),
("GTM-123", "gtm"),
("HELLO-123", "ga"),
])
def test_tracking_mode(tracking_id, mode, monkeypatch, ckan_config):
monkeypatch.setitem(ckan_config, config.CONFIG_TRACKING_ID, tracking_id)
assert mode == config.tracking_mode()
2 changes: 1 addition & 1 deletion ckanext/googleanalytics/tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest


@pytest.mark.usefixtures("clean_db")
@pytest.mark.usefixtures("with_plugins", "clean_db")
def test_script(app):
resp = app.get("/")
assert "GoogleAnalyticsObject" in resp
26 changes: 26 additions & 0 deletions ckanext/googleanalytics/tests/test_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pytest
import six
import ckan.plugins.toolkit as tk
from ckanext.googleanalytics import config


def _render_header(mode, tracking_id):
return tk.render_snippet("googleanalytics/snippets/_{}.html".format(mode), {
"googleanalytics_id": tracking_id,
"googleanalytics_domain": config.domain(),
"googleanalytics_fields": config.fields(),
"googleanalytics_linked_domains": config.linked_domains()
})


@pytest.mark.usefixtures("with_plugins", "with_request_context")
class TestCodeSnippets:
@pytest.mark.parametrize("mode", ["ga", "gtag", "gtm"])
@pytest.mark.parametrize("tracking_id", ["UA-123", "G-123", "GTM-123"])
def test_tracking_(self, mode, tracking_id, app, ckan_config, monkeypatch):
snippet = tk.h.googleanalytics_header()
monkeypatch.setitem(ckan_config, config.CONFIG_TRACKING_ID, tracking_id)
monkeypatch.setitem(ckan_config, config.CONFIG_TRACKING_MODE, mode)
snippet = _render_header(mode, tracking_id)
resp = app.get("/about")
assert six.ensure_str(snippet) in resp
Loading

0 comments on commit f041385

Please sign in to comment.