From 913908fc611f59be80322238953edcc84e3b0f06 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 15:29:36 +0300 Subject: [PATCH 01/19] feat: add blocks to gtag snippet --- .../googleanalytics/snippets/_gtag.html | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtag.html b/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtag.html index 2ed2219a..fa0ee913 100644 --- a/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtag.html +++ b/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtag.html @@ -1,16 +1,26 @@ - - - + + gtag('js', new Date()); + + gtag('config', '{{googleanalytics_id}}', { + anonymize_ip: true, + linker: { + domains: {{ googleanalytics_linked_domains|tojson }} + } + }); + {% endblock setup %} + + {% block extra %} + {% endblock extra %} + + + +{% endblock %} From cf75e577cb70fc9c5b0be270c07fb68376646c46 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 15:36:29 +0300 Subject: [PATCH 02/19] fix: report empty googleanalytics.id --- ckanext/googleanalytics/plugin/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ckanext/googleanalytics/plugin/__init__.py b/ckanext/googleanalytics/plugin/__init__.py index 13773895..1f2ed221 100644 --- a/ckanext/googleanalytics/plugin/__init__.py +++ b/ckanext/googleanalytics/plugin/__init__.py @@ -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): From b6b3f91936fe415a51289ec94d882fd21af23c51 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 15:50:55 +0300 Subject: [PATCH 03/19] chore: update version --- ckanext/googleanalytics/config.py | 13 +++++++++++ .../googleanalytics/config_declaration.yaml | 22 +++++++++++++++++++ ckanext/googleanalytics/views.py | 2 -- setup.cfg | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ckanext/googleanalytics/config.py b/ckanext/googleanalytics/config.py index adf17f44..3711479b 100644 --- a/ckanext/googleanalytics/config.py +++ b/ckanext/googleanalytics/config.py @@ -15,6 +15,7 @@ def tracking_id(): + # type: () -> str return tk.config["googleanalytics.id"] @@ -31,6 +32,7 @@ def download_handler(): def tracking_mode(): + # type: () -> Literal["ga", "gtag"] type_ = tk.config.get("googleanalytics.tracking_mode") if type_: return type_ @@ -47,10 +49,21 @@ def tracking_mode(): 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") diff --git a/ckanext/googleanalytics/config_declaration.yaml b/ckanext/googleanalytics/config_declaration.yaml index 76effb0d..87920d3b 100644 --- a/ckanext/googleanalytics/config_declaration.yaml +++ b/ckanext/googleanalytics/config_declaration.yaml @@ -5,9 +5,31 @@ groups: - key: googleanalytics.id required: true placeholder: UA-000000000-1 + validators: not_empty + description: | + Google tag ID(`G-*`) for Google Analytics 4 properties or the + Tracking ID(`UA-*`) for Universal Analytics properties. - 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 either `ga`(enables `googleanalytics.js`) or `gtag`(enables + `gtag.js`). The plugin will check `googleanalytics.id` and set + appropriate value depending on the prefix: `G-` enables `gtag`, while + `UA-` enables `ga` mode. + + Use this option only if you know better which snippet you need. In + future, after dropping UniversalAnalytics, this option will be + removed. - key: googleanalytics.account diff --git a/ckanext/googleanalytics/views.py b/ckanext/googleanalytics/views.py index 39524071..7f066f8e 100644 --- a/ckanext/googleanalytics/views.py +++ b/ckanext/googleanalytics/views.py @@ -15,8 +15,6 @@ from ckanext.googleanalytics import utils, config, interfaces -CONFIG_HANDLER_PATH = "googleanalytics.download_handler" - log = logging.getLogger(__name__) ga = Blueprint("google_analytics", "google_analytics") diff --git a/setup.cfg b/setup.cfg index ebdb8e4b..4847d97e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ckanext-googleanalytics -version = 2.2.2 +version = 2.2.3 description = Add GA tracking and reporting to CKAN instance long_description = file: README.md long_description_content_type = text/markdown From 2a74be2e27fa17f96e977f4c85f06b2d78720aee Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 15:51:35 +0300 Subject: [PATCH 04/19] chore(release): 2.2.3 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f31d452..38306614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ 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.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) From 52689855758ad1368bd8ae8a785443761ba0abe4 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 18:24:48 +0300 Subject: [PATCH 05/19] feat: add GTM tracking support --- ckanext/googleanalytics/config.py | 6 +++++- ckanext/googleanalytics/helpers.py | 4 ++++ .../templates/googleanalytics/snippets/_gtm.html | 7 +++++++ ckanext/googleanalytics/templates/page.html | 16 ++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 ckanext/googleanalytics/templates/googleanalytics/snippets/_gtm.html create mode 100644 ckanext/googleanalytics/templates/page.html diff --git a/ckanext/googleanalytics/config.py b/ckanext/googleanalytics/config.py index 3711479b..929950b5 100644 --- a/ckanext/googleanalytics/config.py +++ b/ckanext/googleanalytics/config.py @@ -32,7 +32,7 @@ def download_handler(): def tracking_mode(): - # type: () -> Literal["ga", "gtag"] + # type: () -> Literal["ga", "gtag", "gtm"] type_ = tk.config.get("googleanalytics.tracking_mode") if type_: return type_ @@ -45,6 +45,10 @@ def tracking_mode(): if id_.startswith("G-"): return "gtag" + if id_.startswith("GTM-"): + return "gtm" + + return "ga" diff --git a/ckanext/googleanalytics/helpers.py b/ckanext/googleanalytics/helpers.py index 0754d998..52be647d 100644 --- a/ckanext/googleanalytics/helpers.py +++ b/ckanext/googleanalytics/helpers.py @@ -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, } @@ -43,3 +44,6 @@ def googleanalytics_header(): def googleanalytics_tracking_mode(): return config.tracking_mode() + +def googleanalytics_id(): + return config.tracking_id() diff --git a/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtm.html b/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtm.html new file mode 100644 index 00000000..d74f7a93 --- /dev/null +++ b/ckanext/googleanalytics/templates/googleanalytics/snippets/_gtm.html @@ -0,0 +1,7 @@ + + + diff --git a/ckanext/googleanalytics/templates/page.html b/ckanext/googleanalytics/templates/page.html new file mode 100644 index 00000000..9278733d --- /dev/null +++ b/ckanext/googleanalytics/templates/page.html @@ -0,0 +1,16 @@ +{% ckan_extends %} + +{% block page %} + {% block googleanalytics_body_script %} + {% if h.googleanalytics_tracking_mode() == "gtm" %} + {% with id = h.googleanalytics_id() %} + + + + {% endwith %} + {% endif %} + {% endblock %} + + {{ super() }} +{% endblock page %} From acb7a81bc43f7c0eef94f78a2a605dfb8a8db20b Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 20:23:38 +0300 Subject: [PATCH 06/19] feat: track downloads via MeasurementProtocol --- ckanext/googleanalytics/config.py | 12 ++++- .../googleanalytics/config_declaration.yaml | 16 ++++--- ckanext/googleanalytics/tests/test_view.py | 22 +++++++++ ckanext/googleanalytics/utils.py | 45 +++++++++++++------ ckanext/googleanalytics/views.py | 9 +++- 5 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 ckanext/googleanalytics/tests/test_view.py diff --git a/ckanext/googleanalytics/config.py b/ckanext/googleanalytics/config.py index 929950b5..b73b4d75 100644 --- a/ckanext/googleanalytics/config.py +++ b/ckanext/googleanalytics/config.py @@ -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 @@ -30,10 +32,9 @@ def download_handler(): return handler - def tracking_mode(): # type: () -> Literal["ga", "gtag", "gtm"] - type_ = tk.config.get("googleanalytics.tracking_mode") + type_ = tk.config.get(CONFIG_TRACKING_MODE) if type_: return type_ @@ -75,6 +76,13 @@ 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") diff --git a/ckanext/googleanalytics/config_declaration.yaml b/ckanext/googleanalytics/config_declaration.yaml index 87920d3b..9ef0c2e9 100644 --- a/ckanext/googleanalytics/config_declaration.yaml +++ b/ckanext/googleanalytics/config_declaration.yaml @@ -7,8 +7,9 @@ groups: placeholder: UA-000000000-1 validators: not_empty description: | - Google tag ID(`G-*`) for Google Analytics 4 properties or the - Tracking ID(`UA-*`) for Universal Analytics properties. + 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 @@ -22,13 +23,14 @@ groups: example: gtag description: | Defines the type of code snippet embedded into the page. Can be set - to either `ga`(enables `googleanalytics.js`) or `gtag`(enables - `gtag.js`). The plugin will check `googleanalytics.id` and set - appropriate value depending on the prefix: `G-` enables `gtag`, while - `UA-` enables `ga` mode. + 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 will be + future, after dropping UniversalAnalytics, this option may be removed. - key: googleanalytics.account diff --git a/ckanext/googleanalytics/tests/test_view.py b/ckanext/googleanalytics/tests/test_view.py new file mode 100644 index 00000000..cb73da3a --- /dev/null +++ b/ckanext/googleanalytics/tests/test_view.py @@ -0,0 +1,22 @@ +import pytest + +import ckan.plugins.toolkit as tk +from ckanext.googleanalytics import config + + +@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 = 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() + }) + resp = app.get("/") + assert snippet in resp.body diff --git a/ckanext/googleanalytics/utils.py b/ckanext/googleanalytics/utils.py index 8f5368b8..c2416331 100644 --- a/ckanext/googleanalytics/utils.py +++ b/ckanext/googleanalytics/utils.py @@ -9,19 +9,24 @@ log = logging.getLogger(__name__) EVENT_API = "CKAN API Request" +EVENT_DOWNLOAD = "CKAN Resource Download Request" def send_event(data): if isinstance(data, MeasurementProtocolData): - if data["event"] != EVENT_API: - log.warning("Only API event supported by Measurement Protocol at the moment") - return + if data["event"] == EVENT_API: + return _mp_api_handler({ + "action": data["object"], + "payload": data["payload"], + }) - return _mp_api_handler({ - "action": data["object"], - "payload": data["payload"], - }) + if data["event"] == EVENT_DOWNLOAD: + return _mp_download_handler({"payload": { + "resource_id": data["id"], + }}) + log.warning("Only API and Download events supported by Measurement Protocol at the moment") + return return _ga_handler(data) @@ -32,11 +37,28 @@ def default(self, _): def _mp_api_handler(data_dict): - log.debug( "Sending API event to Google Analytics using the Measurement Protocol: %s", data_dict ) + _mp_event({ + "name": data_dict["action"], + "params": data_dict["payload"] + }) + + +def _mp_download_handler(data_dict): + log.debug( + "Sending Downlaod event to Google Analytics using the Measurement Protocol: %s", + data_dict + ) + _mp_event({ + "name": "file_download", + "params": data_dict["payload"], + }) + + +def _mp_event(event): resp = requests.post( "https://www.google-analytics.com/mp/collect", params={ @@ -46,13 +68,10 @@ def _mp_api_handler(data_dict): data=json.dumps({ "client_id": config.measurement_protocol_client_id(), "non_personalized_ads": False, - "events":[{ - "name": data_dict["action"], - "params": data_dict["payload"] - }] + "events":[event] }, cls=SafeJSONEncoder) ) - # breakpoint() + if resp.status_code >= 300: log.error("Cannot post event: %s", resp) diff --git a/ckanext/googleanalytics/views.py b/ckanext/googleanalytics/views.py index 7f066f8e..4b67c339 100644 --- a/ckanext/googleanalytics/views.py +++ b/ckanext/googleanalytics/views.py @@ -59,7 +59,7 @@ def download(id, resource_id, filename=None, package_type="dataset"): handler = resource.download _post_analytics( g.user, - "CKAN Resource Download Request", + utils.EVENT_DOWNLOAD, "Resource", "Download", resource_id, @@ -90,7 +90,11 @@ def _post_analytics( from ckanext.googleanalytics.plugin import GoogleAnalyticsPlugin if config.tracking_id(): - if config.measurement_protocol_client_id() and event_type == utils.EVENT_API: + mp_client_id = config.measurement_protocol_client_id() + if mp_client_id and ( + event_type == utils.EVENT_API + or (event_type == utils.EVENT_DOWNLOAD and config.measurement_protocol_track_downloads()) + ): data_dict = utils.MeasurementProtocolData({ "event": event_type, "object": request_obj_type, @@ -98,6 +102,7 @@ def _post_analytics( "id": request_id, "payload": request_payload, }) + else: data_dict = utils.UniversalAnalyticsData({ "v": 1, From 2cee663cf3855ab0482e863398d6abfe36488a58 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 20:28:47 +0300 Subject: [PATCH 07/19] chore: add tests for tracking mode --- ckanext/googleanalytics/tests/test_config.py | 14 ++++++++++++++ ckanext/googleanalytics/tests/test_view.py | 17 ++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 ckanext/googleanalytics/tests/test_config.py diff --git a/ckanext/googleanalytics/tests/test_config.py b/ckanext/googleanalytics/tests/test_config.py new file mode 100644 index 00000000..5abf3593 --- /dev/null +++ b/ckanext/googleanalytics/tests/test_config.py @@ -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() diff --git a/ckanext/googleanalytics/tests/test_view.py b/ckanext/googleanalytics/tests/test_view.py index cb73da3a..80ef9e90 100644 --- a/ckanext/googleanalytics/tests/test_view.py +++ b/ckanext/googleanalytics/tests/test_view.py @@ -3,6 +3,14 @@ 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: @@ -12,11 +20,6 @@ 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 = 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() - }) - resp = app.get("/") + snippet = _render_header(mode, tracking_id) + resp = app.get("/about") assert snippet in resp.body From 78765390f684666ea7d48d69004cadbffe0af7a0 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 20:29:01 +0300 Subject: [PATCH 08/19] chore(release): 2.3.0 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38306614..c1456c82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ 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) From 84c1cf157eab9933f494b71c55808e77d34f6ae8 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Wed, 14 Jun 2023 20:29:43 +0300 Subject: [PATCH 09/19] bump version --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 4847d97e..a0f964dd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ckanext-googleanalytics -version = 2.2.3 +version = 2.3.0 description = Add GA tracking and reporting to CKAN instance long_description = file: README.md long_description_content_type = text/markdown From 5931ef08fff9dbfa9591df827eed5b1ed6075935 Mon Sep 17 00:00:00 2001 From: Jari Voutilainen Date: Thu, 15 Jun 2023 10:38:05 +0300 Subject: [PATCH 10/19] Fix download_handler config option in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 117ae253..99b2855b 100644 --- a/README.md +++ b/README.md @@ -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 From 776a0260ccb7f63974905d40b3422217c7faf892 Mon Sep 17 00:00:00 2001 From: Nicholas Kumia Date: Fri, 11 Aug 2023 17:10:48 -0400 Subject: [PATCH 11/19] update: python actions + version update: python actions + version --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 67476725..8f9c2ab4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 From 9306edb3b257b8969af136d3d077187804ff515d Mon Sep 17 00:00:00 2001 From: Nicholas Kumia Date: Fri, 11 Aug 2023 17:17:56 -0400 Subject: [PATCH 12/19] lint: get action to pass lint: add reference for called function --- ckanext/googleanalytics/cli.py | 1 + ckanext/googleanalytics/config.py | 1 - ckanext/googleanalytics/ga_auth.py | 2 +- ckanext/googleanalytics/helpers.py | 1 + ckanext/googleanalytics/logic/action.py | 2 +- ckanext/googleanalytics/tests/test_view.py | 1 + ckanext/googleanalytics/utils.py | 2 +- 7 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ckanext/googleanalytics/cli.py b/ckanext/googleanalytics/cli.py index 073490fc..e4b5e62a 100644 --- a/ckanext/googleanalytics/cli.py +++ b/ckanext/googleanalytics/cli.py @@ -7,6 +7,7 @@ import logging import click import ckan.model as model +import ckan.plugins.toolkit as tk from . import dbutil, config diff --git a/ckanext/googleanalytics/config.py b/ckanext/googleanalytics/config.py index b73b4d75..149e3dd1 100644 --- a/ckanext/googleanalytics/config.py +++ b/ckanext/googleanalytics/config.py @@ -49,7 +49,6 @@ def tracking_mode(): if id_.startswith("GTM-"): return "gtm" - return "ga" diff --git a/ckanext/googleanalytics/ga_auth.py b/ckanext/googleanalytics/ga_auth.py index 4c706758..cd3bf23d 100644 --- a/ckanext/googleanalytics/ga_auth.py +++ b/ckanext/googleanalytics/ga_auth.py @@ -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 def init_service(credentials_file): diff --git a/ckanext/googleanalytics/helpers.py b/ckanext/googleanalytics/helpers.py index 52be647d..ddd75717 100644 --- a/ckanext/googleanalytics/helpers.py +++ b/ckanext/googleanalytics/helpers.py @@ -45,5 +45,6 @@ def googleanalytics_header(): def googleanalytics_tracking_mode(): return config.tracking_mode() + def googleanalytics_id(): return config.tracking_id() diff --git a/ckanext/googleanalytics/logic/action.py b/ckanext/googleanalytics/logic/action.py index 83560660..fd648607 100644 --- a/ckanext/googleanalytics/logic/action.py +++ b/ckanext/googleanalytics/logic/action.py @@ -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 diff --git a/ckanext/googleanalytics/tests/test_view.py b/ckanext/googleanalytics/tests/test_view.py index 80ef9e90..48787fb9 100644 --- a/ckanext/googleanalytics/tests/test_view.py +++ b/ckanext/googleanalytics/tests/test_view.py @@ -3,6 +3,7 @@ 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, diff --git a/ckanext/googleanalytics/utils.py b/ckanext/googleanalytics/utils.py index c2416331..bd97b177 100644 --- a/ckanext/googleanalytics/utils.py +++ b/ckanext/googleanalytics/utils.py @@ -68,7 +68,7 @@ def _mp_event(event): data=json.dumps({ "client_id": config.measurement_protocol_client_id(), "non_personalized_ads": False, - "events":[event] + "events": [event] }, cls=SafeJSONEncoder) ) From 0c6df3f73753c2a04a943e879a7f5d35e8ba40c5 Mon Sep 17 00:00:00 2001 From: Fuhu Xia Date: Mon, 23 Oct 2023 12:53:13 -0400 Subject: [PATCH 13/19] use HTTPS for www.google.com --- ckanext/googleanalytics/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckanext/googleanalytics/utils.py b/ckanext/googleanalytics/utils.py index bd97b177..8477d818 100644 --- a/ckanext/googleanalytics/utils.py +++ b/ckanext/googleanalytics/utils.py @@ -81,7 +81,7 @@ def _ga_handler(data_dict): log.debug("Sending API event to Google Analytics: %s", data) requests.post( - "http://www.google-analytics.com/collect", + "https://www.google-analytics.com/collect", data, timeout=10, ) From c9c813ec4effb8139d9282c67790a16b01c441dc Mon Sep 17 00:00:00 2001 From: mc18g13 Date: Sun, 12 May 2024 21:37:33 +0100 Subject: [PATCH 14/19] add user id to api calls --- ckanext/googleanalytics/utils.py | 27 ++++++++++++++++----------- ckanext/googleanalytics/views.py | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/ckanext/googleanalytics/utils.py b/ckanext/googleanalytics/utils.py index 8477d818..7290507d 100644 --- a/ckanext/googleanalytics/utils.py +++ b/ckanext/googleanalytics/utils.py @@ -18,11 +18,11 @@ def send_event(data): return _mp_api_handler({ "action": data["object"], "payload": data["payload"], - }) + }, user_id=data["user_id"]) if data["event"] == EVENT_DOWNLOAD: return _mp_download_handler({"payload": { - "resource_id": data["id"], + "resource_id": data["id"] }}) log.warning("Only API and Download events supported by Measurement Protocol at the moment") @@ -36,7 +36,7 @@ def default(self, _): return None -def _mp_api_handler(data_dict): +def _mp_api_handler(data_dict, user_id=None): log.debug( "Sending API event to Google Analytics using the Measurement Protocol: %s", data_dict @@ -44,7 +44,7 @@ def _mp_api_handler(data_dict): _mp_event({ "name": data_dict["action"], "params": data_dict["payload"] - }) + }, user_id=user_id) def _mp_download_handler(data_dict): @@ -58,18 +58,23 @@ def _mp_download_handler(data_dict): }) -def _mp_event(event): +def _mp_event(event, user_id=None): + data = { + "client_id": config.measurement_protocol_client_id(), + "non_personalized_ads": False, + "events": [event] + } + + if user_id: + data["user_id"] = user_id + resp = requests.post( "https://www.google-analytics.com/mp/collect", params={ "api_secret": config.measurement_protocol_client_secret(), - "measurement_id": config.measurement_id() + "measurement_id": config.measurement_id(), }, - data=json.dumps({ - "client_id": config.measurement_protocol_client_id(), - "non_personalized_ads": False, - "events": [event] - }, cls=SafeJSONEncoder) + data=json.dumps(data, cls=SafeJSONEncoder) ) if resp.status_code >= 300: diff --git a/ckanext/googleanalytics/views.py b/ckanext/googleanalytics/views.py index 4b67c339..2e51bccf 100644 --- a/ckanext/googleanalytics/views.py +++ b/ckanext/googleanalytics/views.py @@ -101,6 +101,7 @@ def _post_analytics( "function": request_function, "id": request_id, "payload": request_payload, + "user_id": hashlib.md5(six.ensure_binary(tk.c.user)).hexdigest() }) else: From 5a4f3d35d242e5e466f72653ca64a5aa7e1fb516 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Fri, 28 Jun 2024 18:52:15 +0300 Subject: [PATCH 15/19] feat: CKAN v2.11 support --- .github/workflows/test.yml | 2 +- ckanext/googleanalytics/tests/test_plugin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f9c2ab4..d76db570 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: needs: lint strategy: matrix: - ckan-version: ["2.10", 2.9, 2.9-py2, 2.8] + ckan-version: ["2.11", "2.10", 2.9, 2.9-py2, 2.8] fail-fast: false name: CKAN ${{ matrix.ckan-version }} diff --git a/ckanext/googleanalytics/tests/test_plugin.py b/ckanext/googleanalytics/tests/test_plugin.py index 15682bf5..0e38b2f3 100644 --- a/ckanext/googleanalytics/tests/test_plugin.py +++ b/ckanext/googleanalytics/tests/test_plugin.py @@ -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 From 5eff018a314529a428b81413614497d2e0ede168 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Fri, 28 Jun 2024 19:09:59 +0300 Subject: [PATCH 16/19] chore: fix py2 tests --- ckanext/googleanalytics/tests/test_view.py | 4 ++-- setup.cfg | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ckanext/googleanalytics/tests/test_view.py b/ckanext/googleanalytics/tests/test_view.py index 48787fb9..03162df2 100644 --- a/ckanext/googleanalytics/tests/test_view.py +++ b/ckanext/googleanalytics/tests/test_view.py @@ -1,5 +1,5 @@ import pytest - +import six import ckan.plugins.toolkit as tk from ckanext.googleanalytics import config @@ -23,4 +23,4 @@ def test_tracking_(self, mode, tracking_id, app, ckan_config, monkeypatch): monkeypatch.setitem(ckan_config, config.CONFIG_TRACKING_MODE, mode) snippet = _render_header(mode, tracking_id) resp = app.get("/about") - assert snippet in resp.body + assert six.ensure_str(snippet) in resp diff --git a/setup.cfg b/setup.cfg index a0f964dd..537092b5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,6 +16,8 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 keywords = CKAN From 80b14a18d6be6b0b9bd22989be3e34f49cfc769b Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Fri, 28 Jun 2024 19:10:49 +0300 Subject: [PATCH 17/19] chore: switch to ckan docker image --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d76db570..c8efb9f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: 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 }} From da1288da0574ee3d694b10f18e848804b91f0433 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Fri, 28 Jun 2024 19:13:48 +0300 Subject: [PATCH 18/19] chore: switch to ckan-solr-9 docker image --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8efb9f8..a9a3f7af 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: needs: lint strategy: matrix: - ckan-version: ["2.11", "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 }} @@ -28,7 +28,7 @@ jobs: 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: From 0dedda1fc276ca027bd90d60411948afb6d6e408 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Fri, 28 Jun 2024 19:17:58 +0300 Subject: [PATCH 19/19] chore: fix workflow configuration for 2.11 --- .github/workflows/test.yml | 10 ++-------- setup.cfg | 5 ++--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9a3f7af..9ec73d6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 diff --git a/setup.cfg b/setup.cfg index 537092b5..89c22a03 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ckanext-googleanalytics -version = 2.3.0 +version = 2.4.0 description = Add GA tracking and reporting to CKAN instance long_description = file: README.md long_description_content_type = text/markdown @@ -11,7 +11,6 @@ license = AGPL classifiers = Development Status :: 4 - Beta License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+) - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -22,7 +21,7 @@ keywords = CKAN [options] -# python_requires = >= 3.7 +python_requires = >= 3.7 install_requires = ckantoolkit google-api-python-client