incognia-python 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {incognia_python-2.0.0 → incognia_python-2.1.0}/PKG-INFO +1 -1
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/api.py +20 -7
- incognia_python-2.1.0/incognia/datetime_util.py +9 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/PKG-INFO +1 -1
- incognia_python-2.1.0/requirements.txt +2 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_api.py +81 -11
- incognia_python-2.0.0/incognia/datetime_util.py +0 -5
- incognia_python-2.0.0/requirements.txt +0 -2
- {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/dependabot.yml +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/workflows/codeql.yaml +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/.github/workflows/continuous.yaml +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/.gitignore +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/CODEOWNERS +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/LICENSE.txt +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/MANIFEST.in +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/README.md +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/__init__.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/base_request.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/endpoints.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/exceptions.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/feedback_events.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/json_util.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/models.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia/token_manager.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/SOURCES.txt +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/dependency_links.txt +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/not-zip-safe +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/requires.txt +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/top_level.txt +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/pyproject.toml +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/setup.cfg +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/__init__.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_base_request.py +0 -0
- {incognia_python-2.0.0 → incognia_python-2.1.0}/tests/test_token_manager.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
2
|
from typing import Optional, List
|
|
3
3
|
|
|
4
|
-
from .datetime_util import total_milliseconds_since_epoch
|
|
4
|
+
from .datetime_util import total_milliseconds_since_epoch, has_timezone
|
|
5
5
|
from .endpoints import Endpoints
|
|
6
6
|
from .exceptions import IncogniaHTTPError, IncogniaError
|
|
7
7
|
from .json_util import encode
|
|
@@ -50,33 +50,46 @@ class IncogniaAPI:
|
|
|
50
50
|
|
|
51
51
|
def register_feedback(self,
|
|
52
52
|
event: str,
|
|
53
|
-
timestamp: dt.datetime,
|
|
53
|
+
timestamp: dt.datetime = None,
|
|
54
54
|
external_id: Optional[str] = None,
|
|
55
55
|
login_id: Optional[str] = None,
|
|
56
56
|
payment_id: Optional[str] = None,
|
|
57
57
|
signup_id: Optional[str] = None,
|
|
58
58
|
account_id: Optional[str] = None,
|
|
59
59
|
installation_id: Optional[str] = None,
|
|
60
|
-
session_token: Optional[str] = None
|
|
60
|
+
session_token: Optional[str] = None,
|
|
61
|
+
request_token: Optional[str] = None,
|
|
62
|
+
occurred_at: dt.datetime = None,
|
|
63
|
+
expires_at: dt.datetime = None) -> None:
|
|
61
64
|
if not event:
|
|
62
65
|
raise IncogniaError('event is required.')
|
|
63
|
-
if not timestamp:
|
|
64
|
-
raise IncogniaError('timestamp
|
|
66
|
+
if timestamp is not None and not has_timezone(timestamp):
|
|
67
|
+
raise IncogniaError('timestamp must have timezone')
|
|
68
|
+
if occurred_at is not None and not has_timezone(occurred_at):
|
|
69
|
+
raise IncogniaError('occurred_at must have timezone')
|
|
70
|
+
if expires_at is not None and not has_timezone(expires_at):
|
|
71
|
+
raise IncogniaError('expires_at must have timezone')
|
|
65
72
|
|
|
66
73
|
try:
|
|
67
74
|
headers = self.__get_authorization_header()
|
|
68
75
|
headers.update(JSON_CONTENT_HEADER)
|
|
69
76
|
body = {
|
|
70
77
|
'event': event,
|
|
71
|
-
'timestamp': total_milliseconds_since_epoch(timestamp),
|
|
72
78
|
'external_id': external_id,
|
|
73
79
|
'login_id': login_id,
|
|
74
80
|
'payment_id': payment_id,
|
|
75
81
|
'signup_id': signup_id,
|
|
76
82
|
'account_id': account_id,
|
|
77
83
|
'installation_id': installation_id,
|
|
78
|
-
'session_token': session_token
|
|
84
|
+
'session_token': session_token,
|
|
85
|
+
'request_token': request_token
|
|
79
86
|
}
|
|
87
|
+
if timestamp is not None:
|
|
88
|
+
body['timestamp'] = total_milliseconds_since_epoch(timestamp)
|
|
89
|
+
if occurred_at is not None:
|
|
90
|
+
body['occurred_at'] = occurred_at.isoformat()
|
|
91
|
+
if expires_at is not None:
|
|
92
|
+
body['expires_at'] = expires_at.isoformat()
|
|
80
93
|
data = encode(body)
|
|
81
94
|
return self.__request.post(Endpoints.FEEDBACKS, headers=headers, data=data)
|
|
82
95
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def total_milliseconds_since_epoch(t: dt.datetime) -> int:
|
|
5
|
+
return int((t - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def has_timezone(d: dt.datetime) -> bool:
|
|
9
|
+
return d.tzinfo is not None and d.tzinfo.utcoffset(d) is not None
|
|
@@ -16,6 +16,7 @@ class TestIncogniaAPI(TestCase):
|
|
|
16
16
|
CLIENT_SECRET: Final[str] = 'ANY_SECRET'
|
|
17
17
|
INSTALLATION_ID: Final[str] = 'ANY_INSTALLATION_ID'
|
|
18
18
|
SESSION_TOKEN: Final[str] = 'ANY_SESSION_TOKEN'
|
|
19
|
+
REQUEST_TOKEN: Final[str] = 'ANY_REQUEST_TOKEN'
|
|
19
20
|
INVALID_INSTALLATION_ID: Final[str] = 'INVALID_INSTALLATION_ID'
|
|
20
21
|
INVALID_SESSION_TOKEN: Final[str] = 'INVALID_SESSION_TOKEN'
|
|
21
22
|
ACCOUNT_ID: Final[str] = 'ANY_ACCOUNT_ID'
|
|
@@ -71,14 +72,30 @@ class TestIncogniaAPI(TestCase):
|
|
|
71
72
|
CLIENT_ERROR_CODE: Final[int] = 400
|
|
72
73
|
VALID_EVENT_FEEDBACK_TYPE: Final[str] = 'valid_event_feedback_type'
|
|
73
74
|
INVALID_EVENT_FEEDBACK_TYPE: Final[str] = 'invalid_event_feedback_type'
|
|
74
|
-
TIMESTAMP: Final[dt.datetime] = dt.datetime.
|
|
75
|
+
TIMESTAMP: Final[dt.datetime] = dt.datetime.now(dt.timezone.utc)
|
|
76
|
+
TIMESTAMP_WITHOUT_TIMEZONE: Final[dt.datetime] = dt.datetime.now()
|
|
77
|
+
LOGIN_ID: Final[str] = 'ANY_LOGIN_ID'
|
|
78
|
+
PAYMENT_ID: Final[str] = 'ANY_PAYMENT_ID'
|
|
75
79
|
REGISTER_VALID_FEEDBACK_DATA: Final[bytes] = encode({
|
|
80
|
+
'event': f'{VALID_EVENT_FEEDBACK_TYPE}'
|
|
81
|
+
})
|
|
82
|
+
REGISTER_VALID_FEEDBACK_DATA_FULL: Final[bytes] = encode({
|
|
76
83
|
'event': f'{VALID_EVENT_FEEDBACK_TYPE}',
|
|
77
|
-
'
|
|
84
|
+
'external_id': f'{EXTERNAL_ID}',
|
|
85
|
+
'login_id': f'{LOGIN_ID}',
|
|
86
|
+
'payment_id': f'{PAYMENT_ID}',
|
|
87
|
+
'signup_id': f'{SIGNUP_ID}',
|
|
88
|
+
'account_id': f'{ACCOUNT_ID}',
|
|
89
|
+
'installation_id': f'{INSTALLATION_ID}',
|
|
90
|
+
'session_token': f'{SESSION_TOKEN}',
|
|
91
|
+
'request_token': f'{REQUEST_TOKEN}',
|
|
92
|
+
'timestamp': int((
|
|
93
|
+
TIMESTAMP - dt.datetime.fromtimestamp(0, dt.timezone.utc)).total_seconds() * 1000.0),
|
|
94
|
+
'occurred_at': TIMESTAMP.isoformat(),
|
|
95
|
+
'expires_at': TIMESTAMP.isoformat(),
|
|
78
96
|
})
|
|
79
97
|
REGISTER_INVALID_FEEDBACK_DATA: Final[bytes] = encode({
|
|
80
|
-
'event': f'{INVALID_EVENT_FEEDBACK_TYPE}'
|
|
81
|
-
'timestamp': 0
|
|
98
|
+
'event': f'{INVALID_EVENT_FEEDBACK_TYPE}'
|
|
82
99
|
})
|
|
83
100
|
REGISTER_VALID_PAYMENT_DATA: Final[bytes] = encode({
|
|
84
101
|
'type': 'payment',
|
|
@@ -185,32 +202,86 @@ class TestIncogniaAPI(TestCase):
|
|
|
185
202
|
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
186
203
|
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
187
204
|
|
|
188
|
-
api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE
|
|
205
|
+
api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE)
|
|
189
206
|
|
|
190
207
|
mock_token_manager_get.assert_called()
|
|
191
208
|
mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
|
|
192
209
|
headers=self.AUTH_AND_JSON_CONTENT_HEADERS,
|
|
193
210
|
data=self.REGISTER_VALID_FEEDBACK_DATA)
|
|
194
211
|
|
|
212
|
+
@patch.object(BaseRequest, 'post')
|
|
213
|
+
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
|
|
214
|
+
def test_register_feedback_when_all_fields_are_valid_should_work(
|
|
215
|
+
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
216
|
+
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
217
|
+
|
|
218
|
+
api.register_feedback(self.VALID_EVENT_FEEDBACK_TYPE,
|
|
219
|
+
timestamp=self.TIMESTAMP,
|
|
220
|
+
occurred_at=self.TIMESTAMP,
|
|
221
|
+
expires_at=self.TIMESTAMP,
|
|
222
|
+
external_id=self.EXTERNAL_ID,
|
|
223
|
+
login_id=self.LOGIN_ID,
|
|
224
|
+
payment_id=self.PAYMENT_ID,
|
|
225
|
+
signup_id=self.SIGNUP_ID,
|
|
226
|
+
account_id=self.ACCOUNT_ID,
|
|
227
|
+
installation_id=self.INSTALLATION_ID,
|
|
228
|
+
session_token=self.SESSION_TOKEN,
|
|
229
|
+
request_token=self.REQUEST_TOKEN)
|
|
230
|
+
|
|
231
|
+
mock_token_manager_get.assert_called()
|
|
232
|
+
mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
|
|
233
|
+
headers=self.AUTH_AND_JSON_CONTENT_HEADERS,
|
|
234
|
+
data=self.REGISTER_VALID_FEEDBACK_DATA_FULL)
|
|
235
|
+
|
|
195
236
|
@patch.object(BaseRequest, 'post')
|
|
196
237
|
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
|
|
197
238
|
def test_register_feedback_when_event_is_empty_should_raise_an_IncogniaError(
|
|
198
239
|
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
199
240
|
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
200
241
|
|
|
201
|
-
self.assertRaises(IncogniaError, api.register_feedback, event=''
|
|
242
|
+
self.assertRaises(IncogniaError, api.register_feedback, event='')
|
|
243
|
+
|
|
244
|
+
mock_token_manager_get.assert_not_called()
|
|
245
|
+
mock_base_request_post.assert_not_called()
|
|
246
|
+
|
|
247
|
+
@patch.object(BaseRequest, 'post')
|
|
248
|
+
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
|
|
249
|
+
def test_register_feedback_when_timestamp_does_not_have_timezone_should_raise_IncogniaError(
|
|
250
|
+
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
251
|
+
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
252
|
+
|
|
253
|
+
self.assertRaises(IncogniaError,
|
|
254
|
+
api.register_feedback,
|
|
255
|
+
event=self.VALID_EVENT_FEEDBACK_TYPE,
|
|
256
|
+
timestamp=self.TIMESTAMP_WITHOUT_TIMEZONE)
|
|
257
|
+
|
|
258
|
+
mock_token_manager_get.assert_not_called()
|
|
259
|
+
mock_base_request_post.assert_not_called()
|
|
260
|
+
|
|
261
|
+
@patch.object(BaseRequest, 'post')
|
|
262
|
+
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
|
|
263
|
+
def test_register_feedback_when_occurred_at_does_not_have_timezone_should_raise_IncogniaError(
|
|
264
|
+
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
265
|
+
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
266
|
+
|
|
267
|
+
self.assertRaises(IncogniaError,
|
|
268
|
+
api.register_feedback,
|
|
269
|
+
event=self.VALID_EVENT_FEEDBACK_TYPE,
|
|
270
|
+
occurred_at=self.TIMESTAMP_WITHOUT_TIMEZONE)
|
|
202
271
|
|
|
203
272
|
mock_token_manager_get.assert_not_called()
|
|
204
273
|
mock_base_request_post.assert_not_called()
|
|
205
274
|
|
|
206
275
|
@patch.object(BaseRequest, 'post')
|
|
207
276
|
@patch.object(TokenManager, 'get', return_value=TOKEN_VALUES)
|
|
208
|
-
def
|
|
277
|
+
def test_register_feedback_when_expires_at_does_not_have_timezone_should_raise_IncogniaError(
|
|
209
278
|
self, mock_token_manager_get: Mock, mock_base_request_post: Mock):
|
|
210
279
|
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
211
280
|
|
|
212
|
-
self.assertRaises(IncogniaError,
|
|
213
|
-
|
|
281
|
+
self.assertRaises(IncogniaError,
|
|
282
|
+
api.register_feedback,
|
|
283
|
+
event=self.VALID_EVENT_FEEDBACK_TYPE,
|
|
284
|
+
expires_at=self.TIMESTAMP_WITHOUT_TIMEZONE)
|
|
214
285
|
|
|
215
286
|
mock_token_manager_get.assert_not_called()
|
|
216
287
|
mock_base_request_post.assert_not_called()
|
|
@@ -224,8 +295,7 @@ class TestIncogniaAPI(TestCase):
|
|
|
224
295
|
api = IncogniaAPI(self.CLIENT_ID, self.CLIENT_SECRET)
|
|
225
296
|
|
|
226
297
|
self.assertRaises(IncogniaHTTPError, api.register_feedback,
|
|
227
|
-
event=self.INVALID_EVENT_FEEDBACK_TYPE
|
|
228
|
-
timestamp=self.TIMESTAMP)
|
|
298
|
+
event=self.INVALID_EVENT_FEEDBACK_TYPE)
|
|
229
299
|
|
|
230
300
|
mock_token_manager_get.assert_called()
|
|
231
301
|
mock_base_request_post.assert_called_with(Endpoints.FEEDBACKS,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{incognia_python-2.0.0 → incognia_python-2.1.0}/incognia_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|