Skip to content

Commit 1f25a70

Browse files
fix: Fix matomo api client to support POST for authen in Matomo 5
1 parent 78525b5 commit 1f25a70

File tree

1 file changed

+63
-37
lines changed

1 file changed

+63
-37
lines changed

sources/matomo/helpers/matomo_client.py

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""This module contains an implementation of a Matomo API client for python."""
2-
from typing import Iterator, List, Union
3-
from dlt.common.typing import DictStrAny, DictStrStr, TDataItem, TDataItems
2+
from typing import Iterator, List
3+
4+
from dlt.common.typing import DictStrAny, TDataItem, TDataItems
45
from dlt.sources.helpers.requests import client
56

67

@@ -17,34 +18,50 @@ class MatomoAPIClient:
1718
API client used to make requests to Matomo API.
1819
"""
1920

20-
def __init__(self, api_token: str, url: str) -> None:
21+
def __init__(self, api_token: str, url: str, call_method: str = "GET") -> None:
2122
"""
2223
Initializes the client.
2324
2425
Args:
2526
api_token (str): Token used to authenticate for Matomo API.
2627
url (str): URL of the Matomo website.
28+
call_method (str): HTTP method for API calls, related to authentication
2729
"""
2830

2931
self.base_url = url
3032
self.auth_token = api_token
33+
if call_method.upper() not in ["GET", "POST"]:
34+
raise ValueError("call_method must be either 'GET' or 'POST'")
35+
self.call_method = call_method
3136

32-
def _request(self, params: DictStrAny) -> TDataItem:
37+
def _request(
38+
self, base_params: DictStrAny, detailed_params: DictStrAny
39+
) -> TDataItem:
3340
"""
3441
Helper method that retrieves data and returns the JSON response from the API.
3542
3643
Args:
37-
params (DictStrAny): Parameters for the API request.
44+
base_params (DictStrAny): Parameters for the API request.
45+
detailed_params (DictStrAny): Detailed parameters for the API request.
3846
3947
Returns:
4048
TDataItem: JSON response from the API.
4149
"""
4250

4351
# loop through all the pages
4452
# the total number of rows is received after the first request, for the first request to be sent through, initializing the row_count to 1 would suffice
45-
headers = {"Content-type": "application/json"}
53+
4654
url = f"{self.base_url}/index.php"
47-
response = client.get(url=url, headers=headers, params=params)
55+
if self.call_method.upper() == "POST":
56+
headers = {"Content-type": "application/x-www-form-urlencoded"}
57+
response = client.post(
58+
url=url, headers=headers, data=detailed_params, params=base_params
59+
)
60+
else:
61+
headers = {"Content-type": "application/json"}
62+
final_params = base_params.copy()
63+
final_params.update(detailed_params)
64+
response = client.get(url=url, headers=headers, params=final_params)
4865
response.raise_for_status()
4966
json_response = response.json()
5067
# matomo returns error with HTTP 200
@@ -78,20 +95,22 @@ def get_query(
7895
# Set up the API URL and parameters
7996
if not extra_params:
8097
extra_params = {}
81-
params = {
98+
base_params = {
8299
"module": "API",
83100
"method": "API.getBulkRequest",
84101
"format": "json",
102+
}
103+
detailed_params = {
85104
"token_auth": self.auth_token,
86105
}
87106
for i, method in enumerate(methods):
88-
params[
107+
detailed_params[
89108
f"urls[{i}]"
90109
] = f"method={method}&idSite={site_id}&period={period}&date={date}"
91110
# Merge the additional parameters into the request parameters
92-
params.update(extra_params)
111+
detailed_params.update(extra_params)
93112
# Send the API request
94-
return self._request(params=params)
113+
return self._request(base_params=base_params, detailed_params=detailed_params)
95114

96115
def get_method(
97116
self,
@@ -112,32 +131,39 @@ def get_method(
112131
Yields:
113132
Iterator[TDataItems]: JSON data from the response.
114133
"""
115-
116-
# Set up the API URL and parameters
117134
if not extra_params:
118135
extra_params = {}
136+
119137
filter_offset = 0
120-
params = {
138+
139+
base_params = {
121140
"module": "API",
122141
"method": "API.getBulkRequest",
123142
"format": "json",
124-
"token_auth": self.auth_token,
125-
"urls[0]": f"method={method}&idSite={site_id}&filter_limit={rows_per_page}&filter_offset={filter_offset}",
126143
}
127-
# Merge the additional parameters into the request parameters
128-
params.update(extra_params)
129-
# Send the API request
130-
method_data = self._request(params=params)[0]
131-
while len(method_data):
132-
yield method_data
133-
filter_offset += len(method_data)
134-
params[
135-
"urls[0]"
136-
] = f"method={method}&idSite={site_id}&filter_limit={rows_per_page}&filter_offset={filter_offset}"
137-
method_data = self._request(params=params)[0]
144+
145+
while True:
146+
detailed_params = {
147+
"urls[0]": f"method={method}&idSite={site_id}&filter_limit={rows_per_page}&filter_offset={filter_offset}",
148+
"token_auth": self.auth_token,
149+
}
150+
detailed_params.update(extra_params)
151+
response_data = self._request(
152+
base_params=base_params, detailed_params=detailed_params
153+
)
154+
if not response_data or not isinstance(response_data, list):
155+
break
156+
batch = response_data[0] if len(response_data) > 0 else []
157+
if not batch:
158+
break
159+
yield batch
160+
filter_offset += len(batch)
138161

139162
def get_visitors_batch(
140-
self, visitor_list: List[str], site_id: int, extra_params: DictStrAny = None
163+
self,
164+
visitor_list: List[str],
165+
site_id: int,
166+
extra_params: DictStrAny = None,
141167
) -> TDataItems:
142168
"""
143169
Gets visitors for Matomo.
@@ -152,19 +178,19 @@ def get_visitors_batch(
152178
"""
153179
if not extra_params:
154180
extra_params = {}
155-
params = {
181+
base_params = {
156182
"module": "API",
157183
"method": "API.getBulkRequest",
158184
"format": "json",
159185
"site_id": site_id,
160-
"token_auth": self.auth_token,
161186
}
162-
params.update(
163-
{
164-
f"urls[{i}]": f"method=Live.getVisitorProfile&idSite={site_id}&visitorId={visitor_list[i]}"
165-
for i in range(len(visitor_list))
166-
}
187+
detailed_params = {
188+
f"urls[{i}]": f"method=Live.getVisitorProfile&idSite={site_id}&visitorId={visitor_list[i]}"
189+
for i in range(len(visitor_list))
190+
}
191+
detailed_params["token_auth"] = self.auth_token
192+
detailed_params.update(extra_params)
193+
method_data = self._request(
194+
base_params=base_params, detailed_params=detailed_params
167195
)
168-
params.update(extra_params)
169-
method_data = self._request(params=params)
170196
return method_data

0 commit comments

Comments
 (0)