Skip to content

Commit

Permalink
Merge pull request #16 from notificationapi-com/lKewaViV/2195-inapp-u…
Browse files Browse the repository at this point in the history
…pdate-and-pref-libraries

add update_in_app_notification
  • Loading branch information
mbasadi authored Jul 16, 2024
2 parents 8afb491 + fe34aa2 commit 21bdc2d
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 1 deletion.
22 changes: 21 additions & 1 deletion notificationapi_python_server_sdk/notificationapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def init(client_id, client_secret):
__client_secret = client_secret


async def request(method, uri, data=None, custom_auth=None):
async def request(method, uri, data=None, custom_auth=None, queryStrings=None):
api_url = "https://api.notificationapi.com/" + __client_id + "/" + uri

headers = {}
Expand All @@ -34,6 +34,7 @@ async def request(method, uri, data=None, custom_auth=None):
response = await client.request(
method,
api_url,
params=queryStrings,
headers=headers,
json=data,
)
Expand Down Expand Up @@ -97,6 +98,17 @@ async def set_user_preferences(params):
)


async def delete_user_preferences(params):
user_id = params.pop('id')

hashed_user_id = hashlib.sha256((__client_secret + user_id).encode()).digest()
hashed_user_id_base64 = base64.b64encode(hashed_user_id).decode()

custom_auth = 'Basic ' + base64.b64encode(f'{__client_id}:{user_id}:{hashed_user_id_base64}'.encode()).decode()

await request('DELETE', f'users/{user_id}/preferences', None, custom_auth, params)


async def identify_user(params):
user_id = params.pop('id')

Expand All @@ -111,3 +123,11 @@ async def identify_user(params):
async def query_logs(params):
response = await request("POST", "logs/query", params)
return response


async def update_in_app_notification(user_id, params):
hashed_user_id = hashlib.sha256((__client_secret + user_id).encode()).digest()
hashed_user_id_base64 = base64.b64encode(hashed_user_id).decode()
custom_auth = 'Basic ' + base64.b64encode(f'{__client_id}:{user_id}:{hashed_user_id_base64}'.encode()).decode()

return await request('PATCH', f'users/{user_id}/notifications/INAPP_WEB', params, custom_auth)
83 changes: 83 additions & 0 deletions tests/test_notificationapi_delete_user_preferences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python

"""Tests for `notificationapi_python_server_sdk` package."""

import pytest
import urllib.parse
import hashlib
import base64
from httpx import Response
from notificationapi_python_server_sdk import notificationapi

client_id = "client_id"
client_secret = "client_secret"
user_id = "userId"
notification_id = "notification_id"

api_paths = {
"delete_user_preferences":
f"https://api.notificationapi.com/{client_id}/users/{urllib.parse.quote(user_id)}/preferences?notificationId={notification_id}",
}

delete_user_preferences_params = {
"id": user_id,
"notificationId": notification_id
}


@pytest.mark.asyncio
@pytest.mark.parametrize(
"func,params",
[
("delete_user_preferences", delete_user_preferences_params),
],
)
async def test_makes_one_delete_api_call(respx_mock, func, params):
route = respx_mock.delete(api_paths[func]).mock(return_value=Response(200))
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(params)
assert route.called


delete_user_preferences_params = {
"id": user_id,
"notificationId": notification_id
}
@pytest.mark.asyncio
@pytest.mark.parametrize(
"func,params",
[
("delete_user_preferences", delete_user_preferences_params),
],
)
async def test_uses_custom_authorization(respx_mock, func, params):
route = respx_mock.delete(api_paths[func]).mock(return_value=Response(200))
hashed_user_id = hashlib.sha256((client_secret + user_id).encode()).digest()
hashed_user_id_base64 = base64.b64encode(hashed_user_id).decode()

# Create custom authorization header
custom_auth = 'Basic ' + base64.b64encode(f'{client_id}:{user_id}:{hashed_user_id_base64}'.encode()).decode()
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(params)
assert "Authorization" in route.calls.last.request.headers
assert route.calls.last.request.headers["Authorization"] == custom_auth


delete_user_preferences_params = {
"id": user_id,
"notificationId": notification_id
}


@pytest.mark.asyncio
@pytest.mark.parametrize(
"func,params",
[
("delete_user_preferences", delete_user_preferences_params),
],
)
async def test_logs_and_throws_on_500(respx_mock, caplog, func, params):
respx_mock.delete(api_paths[func]).mock(return_value=Response(500, text="big oof 500"))
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(params)
assert "NotificationAPI request failed. Response: big oof 500" in caplog.text
143 changes: 143 additions & 0 deletions tests/test_notificationapi_update_in_app_notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env python

"""Tests for `notificationapi_python_server_sdk` package."""

import pytest
import hashlib
import base64
import urllib.parse
import json
from httpx import Response
from notificationapi_python_server_sdk import notificationapi

client_id = "client_id"
client_secret = "client_secret"
user_id = "userId"

api_paths = {
"update_in_app_notification": f"https://api.notificationapi.com/{client_id}/users/{urllib.parse.quote(user_id)}/notifications/INAPP_WEB",
}


@pytest.mark.asyncio
@pytest.mark.parametrize(
"func,params",
[
(
"update_in_app_notification",
(
user_id,
{
"trackingIds": ["sampleTrackingId"],
"opened": "1970-01-01T00:00:00.000Z",
"clicked": "1970-01-01T00:00:00.000Z",
"archived": "1970-01-01T00:00:00.000Z",
"actioned1": "1970-01-01T00:00:00.000Z",
"actioned2": "1970-01-01T00:00:00.000Z",
"reply": {"date": "1970-01-01T00:00:00.000Z", "message": "nice!"}
}
),
),
],
)
async def test_makes_one_patch_api_call(respx_mock, func, params):
route = respx_mock.patch(api_paths[func]).mock(return_value=Response(200))
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(*params)
assert route.called


@pytest.mark.parametrize(
"func,params",
[
(
"update_in_app_notification",
(
user_id,
{
"trackingIds": ["sampleTrackingId"],
"opened": "1970-01-01T00:00:00.000Z",
"clicked": "1970-01-01T00:00:00.000Z",
"archived": "1970-01-01T00:00:00.000Z",
"actioned1": "1970-01-01T00:00:00.000Z",
"actioned2": "1970-01-01T00:00:00.000Z",
"reply": {"date": "1970-01-01T00:00:00.000Z", "message": "nice!"}
}
),
),
],
)
async def test_uses_custom_authorization(respx_mock, func, params):
route = respx_mock.patch(api_paths[func]).mock(return_value=Response(200))
hashed_user_id = hashlib.sha256((client_secret + user_id).encode()).digest()
hashed_user_id_base64 = base64.b64encode(hashed_user_id).decode()

# Create custom authorization header
custom_auth = 'Basic ' + base64.b64encode(f'{client_id}:{user_id}:{hashed_user_id_base64}'.encode()).decode()
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(*params)
assert "Authorization" in route.calls.last.request.headers
assert route.calls.last.request.headers["Authorization"] == custom_auth


@pytest.mark.parametrize(
"func,params",
[
(
"update_in_app_notification",
(
user_id,
{
"trackingIds": ["sampleTrackingId"],
"opened": "1970-01-01T00:00:00.000Z",
"clicked": "1970-01-01T00:00:00.000Z",
"archived": "1970-01-01T00:00:00.000Z",
"actioned1": "1970-01-01T00:00:00.000Z",
"actioned2": "1970-01-01T00:00:00.000Z",
"reply": {"date": "1970-01-01T00:00:00.000Z", "message": "nice!"}
}
),
),
],
)
async def test_passes_data_as_json_body(respx_mock, func, params):
route = respx_mock.patch(api_paths[func]).mock(return_value=Response(200))
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(*params)
sent_data = json.loads(route.calls.last.request.content)
assert sent_data == {
"trackingIds": ["sampleTrackingId"],
"opened": "1970-01-01T00:00:00.000Z",
"clicked": "1970-01-01T00:00:00.000Z",
"archived": "1970-01-01T00:00:00.000Z",
"actioned1": "1970-01-01T00:00:00.000Z",
"actioned2": "1970-01-01T00:00:00.000Z",
"reply": {"date": "1970-01-01T00:00:00.000Z", "message": "nice!"}
}


@pytest.mark.parametrize(
"func,params",
[
(
"update_in_app_notification",
(
user_id,
{
"trackingIds": ["sampleTrackingId"],
"opened": "1970-01-01T00:00:00.000Z",
"clicked": "1970-01-01T00:00:00.000Z",
"archived": "1970-01-01T00:00:00.000Z",
"actioned1": "1970-01-01T00:00:00.000Z",
"actioned2": "1970-01-01T00:00:00.000Z",
"reply": {"date": "1970-01-01T00:00:00.000Z", "message": "nice!"}
}
),
),
],
)
async def test_logs_and_throws_on_500(respx_mock, caplog, func, params):
respx_mock.patch(api_paths[func]).mock(return_value=Response(500, text="big oof 500"))
notificationapi.init(client_id, client_secret)
await getattr(notificationapi, func)(*params)
assert "NotificationAPI request failed. Response: big oof 500" in caplog.text

0 comments on commit 21bdc2d

Please sign in to comment.