feat: track downloads via MeasurementProtocol
This commit is contained in:
parent
5268985575
commit
acb7a81bc4
|
@ -5,7 +5,9 @@ from werkzeug.utils import import_string
|
|||
|
||||
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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -9,19 +9,24 @@ from ckanext.googleanalytics import config
|
|||
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 @@ class SafeJSONEncoder(json.JSONEncoder):
|
|||
|
||||
|
||||
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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue