diff --git a/mpt_api_client/resources/notifications/contacts.py b/mpt_api_client/resources/notifications/contacts.py new file mode 100644 index 00000000..8028685e --- /dev/null +++ b/mpt_api_client/resources/notifications/contacts.py @@ -0,0 +1,57 @@ +from mpt_api_client.http import AsyncService, CreateMixin, Service +from mpt_api_client.http.mixins import ( + AsyncCreateMixin, + AsyncDeleteMixin, + AsyncUpdateMixin, + DeleteMixin, + UpdateMixin, +) +from mpt_api_client.models import Model, ResourceData + + +class Contact(Model): + """Notifications Contact resource.""" + + +class ContactsServiceConfig: + """Notifications Contacts service configuration.""" + + _endpoint = "/public/v1/notifications/contacts" + _model_class = Contact + _collection_key = "data" + + +class ContactsService( + CreateMixin[Contact], + UpdateMixin[Contact], + DeleteMixin, + Service[Contact], + ContactsServiceConfig, +): + """Notifications Contacts service.""" + + def block(self, resource_id: str, resource_data: ResourceData | None = None) -> Model: + """Block a contact.""" + return self._resource_action(resource_id, "POST", "block", json=resource_data) + + def unblock(self, resource_id: str, resource_data: ResourceData | None = None) -> Model: + """Unblock a contact.""" + return self._resource_action(resource_id, "POST", "unblock", json=resource_data) + + +class AsyncContactsService( + AsyncCreateMixin[Contact], + AsyncUpdateMixin[Contact], + AsyncDeleteMixin, + AsyncService[Contact], + ContactsServiceConfig, +): + """Async Notifications Contacts service.""" + + async def block(self, resource_id: str, resource_data: ResourceData | None = None) -> Model: + """Block a contact.""" + return await self._resource_action(resource_id, "POST", "block", json=resource_data) + + async def unblock(self, resource_id: str, resource_data: ResourceData | None = None) -> Model: + """Unblock a contact.""" + return await self._resource_action(resource_id, "POST", "unblock", json=resource_data) diff --git a/mpt_api_client/resources/notifications/notifications.py b/mpt_api_client/resources/notifications/notifications.py index 2a1778db..7c283d60 100644 --- a/mpt_api_client/resources/notifications/notifications.py +++ b/mpt_api_client/resources/notifications/notifications.py @@ -3,6 +3,7 @@ AsyncCategoriesService, CategoriesService, ) +from mpt_api_client.resources.notifications.contacts import AsyncContactsService, ContactsService class Notifications: @@ -16,6 +17,11 @@ def categories(self) -> CategoriesService: """Categories service.""" return CategoriesService(http_client=self.http_client) + @property + def contacts(self) -> ContactsService: + """Contacts service.""" + return ContactsService(http_client=self.http_client) + class AsyncNotifications: """Notifications MPT API Module.""" @@ -27,3 +33,8 @@ def __init__(self, http_client: AsyncHTTPClient): def categories(self) -> AsyncCategoriesService: """Categories service.""" return AsyncCategoriesService(http_client=self.http_client) + + @property + def contacts(self) -> AsyncContactsService: + """Async Contacts service.""" + return AsyncContactsService(http_client=self.http_client) diff --git a/setup.cfg b/setup.cfg index 4f1ca682..c863dc31 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,17 +32,14 @@ extend-ignore = per-file-ignores = - mpt_api_client/resources/accounts/*.py: WPS215 + mpt_api_client/mpt_client.py: WPS214 WPS235 - mpt_api_client/resources/audit/*.py: WPS215 - mpt_api_client/resources/billing/*.py: WPS215 WPS202 WPS214 WPS204 - mpt_api_client/resources/catalog/*.py: WPS110 WPS215 WPS214 - mpt_api_client/resources/commerce/*.py: WPS215 - mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214 - mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 - mpt_api_client/resources/notifications/categories.py: WPS215 mpt_api_client/http/mixins.py: WPS202 - mpt_api_client/mpt_client.py: WPS235 + mpt_api_client/resources/*: WPS215 + mpt_api_client/resources/billing/*.py: WPS202 WPS204 WPS214 WPS215 + mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215 + mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 + mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214 tests/http/test_async_service.py: WPS204 WPS202 tests/http/test_service.py: WPS204 WPS202 tests/http/test_mixins.py: WPS204 WPS202 diff --git a/tests/resources/notifications/test_categories.py b/tests/resources/notifications/test_categories.py index 878dd5e2..58bc9ed7 100644 --- a/tests/resources/notifications/test_categories.py +++ b/tests/resources/notifications/test_categories.py @@ -53,7 +53,6 @@ def test_custom_category_actions(categories_service, action, input_status): ("unpublish", {"id": "CAT-123", "status": "to_unpublish"}), ], ) -@pytest.mark.asyncio async def test_async_custom_category_actions(async_categories_service, action, input_status): request_expected_content = b'{"id":"CAT-123","status":"%s"}' % input_status["status"].encode() response_expected_data = {"id": "CAT-123", "status": "new_status"} diff --git a/tests/resources/notifications/test_contacts.py b/tests/resources/notifications/test_contacts.py new file mode 100644 index 00000000..1549caa7 --- /dev/null +++ b/tests/resources/notifications/test_contacts.py @@ -0,0 +1,74 @@ +import httpx +import pytest +import respx + +from mpt_api_client.resources.notifications.contacts import ( + AsyncContactsService, + ContactsService, +) + + +@pytest.fixture +def contacts_service(http_client): + return ContactsService(http_client=http_client) + + +@pytest.fixture +def async_contacts_service(async_http_client): + return AsyncContactsService(http_client=async_http_client) + + +@pytest.mark.parametrize( + ("action", "input_status"), + [ + ("block", {"id": "CON-123", "status": "to_block"}), + ("unblock", {"id": "CON-123", "status": "to_unblock"}), + ], +) +def test_custom_contact_actions(contacts_service, action, input_status): + request_expected_content = b'{"id":"CON-123","status":"%s"}' % input_status["status"].encode() + response_expected_data = {"id": "CON-123", "status": "new_status"} + with respx.mock: + mock_route = respx.post( + f"https://api.example.com/public/v1/notifications/contacts/CON-123/{action}" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": "application/json"}, + json=response_expected_data, + ) + ) + contact = getattr(contacts_service, action)("CON-123", input_status) + + assert mock_route.call_count == 1 + assert contact.to_dict() == response_expected_data + request = mock_route.calls[0].request + assert request.content == request_expected_content + + +@pytest.mark.parametrize( + ("action", "input_status"), + [ + ("block", {"id": "CON-123", "status": "to_block"}), + ("unblock", {"id": "CON-123", "status": "to_unblock"}), + ], +) +async def test_async_custom_contact_actions(async_contacts_service, action, input_status): + request_expected_content = b'{"id":"CON-123","status":"%s"}' % input_status["status"].encode() + response_expected_data = {"id": "CON-123", "status": "new_status"} + with respx.mock: + mock_route = respx.post( + f"https://api.example.com/public/v1/notifications/contacts/CON-123/{action}" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": "application/json"}, + json=response_expected_data, + ) + ) + contact = await getattr(async_contacts_service, action)("CON-123", input_status) + + assert contact.to_dict() == response_expected_data + assert mock_route.call_count == 1 + request = mock_route.calls[0].request + assert request.content == request_expected_content diff --git a/tests/resources/notifications/test_notifications.py b/tests/resources/notifications/test_notifications.py index feeada44..21eecc34 100644 --- a/tests/resources/notifications/test_notifications.py +++ b/tests/resources/notifications/test_notifications.py @@ -5,6 +5,7 @@ AsyncCategoriesService, CategoriesService, ) +from mpt_api_client.resources.notifications.contacts import AsyncContactsService, ContactsService def test_notifications_init(http_client): @@ -25,6 +26,7 @@ def test_async_notifications_init(async_http_client): ("attr_name", "expected"), [ ("categories", CategoriesService), + ("contacts", ContactsService), ], ) def test_notifications_properties(http_client, attr_name, expected): @@ -39,6 +41,7 @@ def test_notifications_properties(http_client, attr_name, expected): ("attr_name", "expected"), [ ("categories", AsyncCategoriesService), + ("contacts", AsyncContactsService), ], ) def test_async_notifications_properties(http_client, attr_name, expected):