Skip to content

Commit 200a993

Browse files
committed
MPT-14075 Add notifications contacts
1 parent c69aaff commit 200a993

File tree

5 files changed

+152
-9
lines changed

5 files changed

+152
-9
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from mpt_api_client.http import AsyncService, CreateMixin, Service
2+
from mpt_api_client.http.mixins import (
3+
AsyncCreateMixin,
4+
AsyncDeleteMixin,
5+
AsyncUpdateMixin,
6+
DeleteMixin,
7+
UpdateMixin,
8+
)
9+
from mpt_api_client.models import Model, ResourceData
10+
11+
12+
class Contact(Model):
13+
"""Notifications Contact resource."""
14+
15+
16+
class ContactsServiceConfig:
17+
"""Notifications Contacts service configuration."""
18+
19+
_endpoint = "/public/v1/notifications/contacts"
20+
_model_class = Contact
21+
_collection_key = "data"
22+
23+
24+
class ContactsService(
25+
CreateMixin[Contact],
26+
UpdateMixin[Contact],
27+
DeleteMixin,
28+
Service[Contact],
29+
ContactsServiceConfig,
30+
):
31+
"""Notifications Contacts service."""
32+
33+
def block(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
34+
"""Block a contact."""
35+
return self._resource_action(resource_id, "POST", "block", json=resource_data)
36+
37+
def unblock(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
38+
"""Unblock a contact."""
39+
return self._resource_action(resource_id, "POST", "unblock", json=resource_data)
40+
41+
42+
class AsyncContactsService(
43+
AsyncCreateMixin[Contact],
44+
AsyncUpdateMixin[Contact],
45+
AsyncDeleteMixin,
46+
AsyncService[Contact],
47+
ContactsServiceConfig,
48+
):
49+
"""Async Notifications Contacts service."""
50+
51+
async def block(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
52+
"""Block a contact."""
53+
return await self._resource_action(resource_id, "POST", "block", json=resource_data)
54+
55+
async def unblock(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
56+
"""Unblock a contact."""
57+
return await self._resource_action(resource_id, "POST", "unblock", json=resource_data)

mpt_api_client/resources/notifications/notifications.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
AsyncCategoriesService,
44
CategoriesService,
55
)
6+
from mpt_api_client.resources.notifications.contacts import AsyncContactsService, ContactsService
67

78

89
class Notifications:
@@ -16,6 +17,11 @@ def categories(self) -> CategoriesService:
1617
"""Categories service."""
1718
return CategoriesService(http_client=self.http_client)
1819

20+
@property
21+
def contacts(self) -> ContactsService:
22+
"""Contacts service."""
23+
return ContactsService(http_client=self.http_client)
24+
1925

2026
class AsyncNotifications:
2127
"""Notifications MPT API Module."""
@@ -27,3 +33,8 @@ def __init__(self, http_client: AsyncHTTPClient):
2733
def categories(self) -> AsyncCategoriesService:
2834
"""Categories service."""
2935
return AsyncCategoriesService(http_client=self.http_client)
36+
37+
@property
38+
def contacts(self) -> AsyncContactsService:
39+
"""Async Contacts service."""
40+
return AsyncContactsService(http_client=self.http_client)

setup.cfg

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,14 @@ extend-ignore =
3232

3333

3434
per-file-ignores =
35-
mpt_api_client/resources/accounts/*.py: WPS215
35+
3636
mpt_api_client/mpt_client.py: WPS214 WPS235
37-
mpt_api_client/resources/audit/*.py: WPS215
38-
mpt_api_client/resources/billing/*.py: WPS215 WPS202 WPS214 WPS204
39-
mpt_api_client/resources/catalog/*.py: WPS110 WPS215 WPS214
40-
mpt_api_client/resources/commerce/*.py: WPS215
41-
mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214
42-
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215
43-
mpt_api_client/resources/notifications/categories.py: WPS215
4437
mpt_api_client/http/mixins.py: WPS202
45-
mpt_api_client/mpt_client.py: WPS235
38+
mpt_api_client/resources/*: WPS215
39+
mpt_api_client/resources/billing/*.py: WPS202 WPS204 WPS214 WPS215
40+
mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215
41+
mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215
42+
mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214
4643
tests/http/test_async_service.py: WPS204 WPS202
4744
tests/http/test_service.py: WPS204 WPS202
4845
tests/http/test_mixins.py: WPS204 WPS202
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import httpx
2+
import pytest
3+
import respx
4+
5+
from mpt_api_client.resources.notifications.contacts import (
6+
AsyncContactsService,
7+
ContactsService,
8+
)
9+
10+
11+
@pytest.fixture
12+
def contacts_service(http_client):
13+
return ContactsService(http_client=http_client)
14+
15+
16+
@pytest.fixture
17+
def async_contacts_service(async_http_client):
18+
return AsyncContactsService(http_client=async_http_client)
19+
20+
21+
@pytest.mark.parametrize(
22+
("action", "input_status"),
23+
[
24+
("block", {"id": "CON-123", "status": "to_block"}),
25+
("unblock", {"id": "CON-123", "status": "to_unblock"}),
26+
],
27+
)
28+
def test_custom_contact_actions(contacts_service, action, input_status):
29+
request_expected_content = b'{"id":"CON-123","status":"%s"}' % input_status["status"].encode()
30+
response_expected_data = {"id": "CON-123", "status": "new_status"}
31+
with respx.mock:
32+
mock_route = respx.post(
33+
f"https://api.example.com/public/v1/notifications/contacts/CON-123/{action}"
34+
).mock(
35+
return_value=httpx.Response(
36+
status_code=200,
37+
headers={"content-type": "application/json"},
38+
json=response_expected_data,
39+
)
40+
)
41+
contact = getattr(contacts_service, action)("CON-123", input_status)
42+
43+
assert mock_route.call_count == 1
44+
assert contact.to_dict() == response_expected_data
45+
request = mock_route.calls[0].request
46+
assert request.content == request_expected_content
47+
48+
49+
@pytest.mark.parametrize(
50+
("action", "input_status"),
51+
[
52+
("block", {"id": "CON-123", "status": "to_block"}),
53+
("unblock", {"id": "CON-123", "status": "to_unblock"}),
54+
],
55+
)
56+
@pytest.mark.asyncio
57+
async def test_async_custom_contact_actions(async_contacts_service, action, input_status):
58+
request_expected_content = b'{"id":"CON-123","status":"%s"}' % input_status["status"].encode()
59+
response_expected_data = {"id": "CON-123", "status": "new_status"}
60+
with respx.mock:
61+
mock_route = respx.post(
62+
f"https://api.example.com/public/v1/notifications/contacts/CON-123/{action}"
63+
).mock(
64+
return_value=httpx.Response(
65+
status_code=200,
66+
headers={"content-type": "application/json"},
67+
json=response_expected_data,
68+
)
69+
)
70+
contact = await getattr(async_contacts_service, action)("CON-123", input_status)
71+
72+
assert contact.to_dict() == response_expected_data
73+
assert mock_route.call_count == 1
74+
request = mock_route.calls[0].request
75+
assert request.content == request_expected_content

tests/resources/notifications/test_notifications.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
AsyncCategoriesService,
66
CategoriesService,
77
)
8+
from mpt_api_client.resources.notifications.contacts import AsyncContactsService, ContactsService
89

910

1011
def test_notifications_init(http_client):
@@ -25,6 +26,7 @@ def test_async_notifications_init(async_http_client):
2526
("attr_name", "expected"),
2627
[
2728
("categories", CategoriesService),
29+
("contacts", ContactsService),
2830
],
2931
)
3032
def test_notifications_properties(http_client, attr_name, expected):
@@ -39,6 +41,7 @@ def test_notifications_properties(http_client, attr_name, expected):
3941
("attr_name", "expected"),
4042
[
4143
("categories", AsyncCategoriesService),
44+
("contacts", AsyncContactsService),
4245
],
4346
)
4447
def test_async_notifications_properties(http_client, attr_name, expected):

0 commit comments

Comments
 (0)