diff --git a/CHANGELOG.md b/CHANGELOG.md index e1dd6460..276e283d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx&utm_medium=paddle-python-sdk) for information about changes to the Paddle Billing platform, the Paddle API, and other developer tools. +## [Unreleased] + +### Added +- Added `traffic_source` property to `paddle_billing.Entities.NotificationSetting` entity + ## 1.1.1 - 2024-11-14 ### Fixed diff --git a/paddle_billing/Entities/NotificationSetting.py b/paddle_billing/Entities/NotificationSetting.py index 90cbfb99..e0ecd1a0 100644 --- a/paddle_billing/Entities/NotificationSetting.py +++ b/paddle_billing/Entities/NotificationSetting.py @@ -3,7 +3,7 @@ from paddle_billing.Entities.Entity import Entity from paddle_billing.Entities.EventType import EventType -from paddle_billing.Entities.NotificationSettings import NotificationSettingType +from paddle_billing.Entities.NotificationSettings import NotificationSettingType, NotificationSettingTrafficSource @dataclass @@ -17,6 +17,7 @@ class NotificationSetting(Entity): include_sensitive_fields: bool subscribed_events: list[EventType] endpoint_secret_key: str + traffic_source: NotificationSettingTrafficSource @staticmethod def from_dict(data: dict) -> NotificationSetting: @@ -30,4 +31,5 @@ def from_dict(data: dict) -> NotificationSetting: include_sensitive_fields=data["include_sensitive_fields"], subscribed_events=[EventType.from_dict(event) for event in data.get("subscribed_events", [])], endpoint_secret_key=data["endpoint_secret_key"], + traffic_source=NotificationSettingTrafficSource(data["traffic_source"]), ) diff --git a/paddle_billing/Entities/NotificationSettings/NotificationSettingTrafficSource.py b/paddle_billing/Entities/NotificationSettings/NotificationSettingTrafficSource.py new file mode 100644 index 00000000..319a20c0 --- /dev/null +++ b/paddle_billing/Entities/NotificationSettings/NotificationSettingTrafficSource.py @@ -0,0 +1,7 @@ +from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta + + +class NotificationSettingTrafficSource(PaddleStrEnum, metaclass=PaddleStrEnumMeta): + All: "NotificationSettingTrafficSource" = "all" + Platform: "NotificationSettingTrafficSource" = "platform" + Simulation: "NotificationSettingTrafficSource" = "simulation" diff --git a/paddle_billing/Entities/NotificationSettings/__init__.py b/paddle_billing/Entities/NotificationSettings/__init__.py index bb3e6812..83cb0d68 100644 --- a/paddle_billing/Entities/NotificationSettings/__init__.py +++ b/paddle_billing/Entities/NotificationSettings/__init__.py @@ -1 +1,4 @@ +from paddle_billing.Entities.NotificationSettings.NotificationSettingTrafficSource import ( + NotificationSettingTrafficSource, +) from paddle_billing.Entities.NotificationSettings.NotificationSettingType import NotificationSettingType diff --git a/paddle_billing/Resources/NotificationSettings/Operations/CreateNotificationSetting.py b/paddle_billing/Resources/NotificationSettings/Operations/CreateNotificationSetting.py index d23f72cc..4b9de7ec 100644 --- a/paddle_billing/Resources/NotificationSettings/Operations/CreateNotificationSetting.py +++ b/paddle_billing/Resources/NotificationSettings/Operations/CreateNotificationSetting.py @@ -3,7 +3,7 @@ from paddle_billing.Operation import Operation from paddle_billing.Undefined import Undefined from paddle_billing.Entities.Events import EventTypeName -from paddle_billing.Entities.NotificationSettings import NotificationSettingType +from paddle_billing.Entities.NotificationSettings import NotificationSettingType, NotificationSettingTrafficSource @dataclass @@ -14,3 +14,4 @@ class CreateNotificationSetting(Operation): type: NotificationSettingType include_sensitive_fields: bool api_version: int | Undefined = Undefined() + traffic_source: NotificationSettingTrafficSource | Undefined = Undefined() diff --git a/paddle_billing/Resources/NotificationSettings/Operations/ListNotificationSettings.py b/paddle_billing/Resources/NotificationSettings/Operations/ListNotificationSettings.py index e93a15c5..bbd6170e 100644 --- a/paddle_billing/Resources/NotificationSettings/Operations/ListNotificationSettings.py +++ b/paddle_billing/Resources/NotificationSettings/Operations/ListNotificationSettings.py @@ -2,15 +2,19 @@ from paddle_billing.Resources.Shared.Operations import Pager +from paddle_billing.Entities.NotificationSettings import NotificationSettingTrafficSource + class ListNotificationSettings(HasParameters): def __init__( self, pager: Pager | None = None, active: bool | None = None, + traffic_source: NotificationSettingTrafficSource | None = None, ): self.pager = pager self.active = active + self.traffic_source = traffic_source def get_parameters(self) -> dict: parameters = {} @@ -18,5 +22,7 @@ def get_parameters(self) -> dict: parameters.update(self.pager.get_parameters()) if self.active is not None: parameters["active"] = "true" if self.active else "false" + if self.traffic_source is not None: + parameters["traffic_source"] = self.traffic_source.value return parameters diff --git a/paddle_billing/Resources/NotificationSettings/Operations/UpdateNotificationSetting.py b/paddle_billing/Resources/NotificationSettings/Operations/UpdateNotificationSetting.py index 09c63710..b1b9ca7f 100644 --- a/paddle_billing/Resources/NotificationSettings/Operations/UpdateNotificationSetting.py +++ b/paddle_billing/Resources/NotificationSettings/Operations/UpdateNotificationSetting.py @@ -3,6 +3,7 @@ from paddle_billing.Operation import Operation from paddle_billing.Undefined import Undefined from paddle_billing.Entities.Events import EventTypeName +from paddle_billing.Entities.NotificationSettings import NotificationSettingTrafficSource @dataclass @@ -13,3 +14,4 @@ class UpdateNotificationSetting(Operation): api_version: int | Undefined = Undefined() include_sensitive_fields: bool | Undefined = Undefined() subscribed_events: list[EventTypeName] | Undefined = Undefined() + traffic_source: NotificationSettingTrafficSource | Undefined = Undefined() diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_all.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_all.json new file mode 100644 index 00000000..c30b400b --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_all.json @@ -0,0 +1,10 @@ +{ + "description": "Slack notifications", + "type": "url", + "destination": "https://hooks.slack.com/example", + "include_sensitive_fields": false, + "subscribed_events": [ + "transaction.created" + ], + "traffic_source": "all" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_platform.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_platform.json new file mode 100644 index 00000000..9dce20f0 --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_platform.json @@ -0,0 +1,10 @@ +{ + "description": "Slack notifications", + "type": "url", + "destination": "https://hooks.slack.com/example", + "include_sensitive_fields": false, + "subscribed_events": [ + "transaction.created" + ], + "traffic_source": "platform" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_simulation.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_simulation.json new file mode 100644 index 00000000..13328a30 --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/create_traffic_simulation.json @@ -0,0 +1,10 @@ +{ + "description": "Slack notifications", + "type": "url", + "destination": "https://hooks.slack.com/example", + "include_sensitive_fields": false, + "subscribed_events": [ + "transaction.created" + ], + "traffic_source": "simulation" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_all.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_all.json new file mode 100644 index 00000000..678ec21b --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_all.json @@ -0,0 +1,3 @@ +{ + "traffic_source": "all" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_platform.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_platform.json new file mode 100644 index 00000000..40b91c6e --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_platform.json @@ -0,0 +1,3 @@ +{ + "traffic_source": "platform" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_simulation.json b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_simulation.json new file mode 100644 index 00000000..6cb71415 --- /dev/null +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/request/update_traffic_simulation.json @@ -0,0 +1,3 @@ +{ + "traffic_source": "simulation" +} diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/response/full_entity.json b/tests/Functional/Resources/NotificationSettings/_fixtures/response/full_entity.json index f19c141a..9d120a35 100644 --- a/tests/Functional/Resources/NotificationSettings/_fixtures/response/full_entity.json +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/response/full_entity.json @@ -99,7 +99,8 @@ "available_versions": [1] } ], - "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "platform" }, "meta": { "request_id": "fd55d51a-6242-4645-8572-af2a8b6f41b6" diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_default.json b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_default.json index 56b237e3..5677d4e4 100644 --- a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_default.json +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_default.json @@ -100,7 +100,8 @@ "available_versions": [1] } ], - "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "all" }, { "id": "ntfset_01gkpop8bkm3tm53itgkx6klk7", @@ -202,7 +203,27 @@ "available_versions": [1] } ], - "endpoint_secret_key": "ntfset_01gkpop8bkm3tm53itgkx6klk7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "ntfset_01gkpop8bkm3tm53itgkx6klk7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "platform" + }, + { + "id": "ntfset_02gkpop8bkm3tm53itgkx6klk7", + "description": "Discord notifications", + "type": "url", + "destination": "https://hooks.discord.com/example", + "active": true, + "api_version": 1, + "include_sensitive_fields": false, + "subscribed_events": [ + { + "name": "transaction.billed", + "description": "Occurs when a transaction is billed.", + "group": "Transaction", + "available_versions": [1] + } + ], + "endpoint_secret_key": "ntfset_02gkpop8bkm3tm53itgkx6klk7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "simulation" } ], "meta": { diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_one.json b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_one.json index 8f50c1ff..435cb7ea 100644 --- a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_one.json +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_one.json @@ -100,7 +100,8 @@ "available_versions": [1] } ], - "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "platform" } ], "meta": { diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_two.json b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_two.json index 4dc05584..0a9363c6 100644 --- a/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_two.json +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/response/list_paginated_page_two.json @@ -100,7 +100,8 @@ "available_versions": [1] } ], - "endpoint_secret_key": "ntfset_01gkpop8bkm3tm53itgkx6klk7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "ntfset_01gkpop8bkm3tm53itgkx6klk7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "platform" } ], "meta": { diff --git a/tests/Functional/Resources/NotificationSettings/_fixtures/response/minimal_entity.json b/tests/Functional/Resources/NotificationSettings/_fixtures/response/minimal_entity.json index bd2c92a5..d799ac0d 100644 --- a/tests/Functional/Resources/NotificationSettings/_fixtures/response/minimal_entity.json +++ b/tests/Functional/Resources/NotificationSettings/_fixtures/response/minimal_entity.json @@ -45,7 +45,8 @@ "available_versions": [1] } ], - "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI" + "endpoint_secret_key": "pdl_ntfset_01gkpjp8bkm3tm53kdgkx6sms7_6h3qd3uFSi9YCD3OLYAShQI90XTI5vEI", + "traffic_source": "platform" }, "meta": { "request_id": "fd55d51a-6242-4645-8572-af2a8b6f41b6" diff --git a/tests/Functional/Resources/NotificationSettings/test_NotificationSettingsClient.py b/tests/Functional/Resources/NotificationSettings/test_NotificationSettingsClient.py index abb9dea7..394075cf 100644 --- a/tests/Functional/Resources/NotificationSettings/test_NotificationSettingsClient.py +++ b/tests/Functional/Resources/NotificationSettings/test_NotificationSettingsClient.py @@ -5,7 +5,7 @@ from paddle_billing.Entities.Collections import NotificationSettingCollection from paddle_billing.Entities.Events import EventTypeName from paddle_billing.Entities.NotificationSetting import NotificationSetting -from paddle_billing.Entities.NotificationSettings import NotificationSettingType +from paddle_billing.Entities.NotificationSettings import NotificationSettingType, NotificationSettingTrafficSource from paddle_billing.Resources.Shared.Operations import Pager @@ -71,10 +71,61 @@ class TestNotificationSettingsClient: ReadsFixtures.read_raw_json_fixture("response/full_entity"), "/notification-settings", ), + ( + CreateNotificationSetting( + description="Slack notifications", + type=NotificationSettingType.Url, + destination="https://hooks.slack.com/example", + include_sensitive_fields=False, + subscribed_events=[ + EventTypeName.TransactionCreated, + ], + traffic_source=NotificationSettingTrafficSource.All, + ), + ReadsFixtures.read_raw_json_fixture("request/create_traffic_all"), + 200, + ReadsFixtures.read_raw_json_fixture("response/minimal_entity"), + "/notification-settings", + ), + ( + CreateNotificationSetting( + description="Slack notifications", + type=NotificationSettingType.Url, + destination="https://hooks.slack.com/example", + include_sensitive_fields=False, + subscribed_events=[ + EventTypeName.TransactionCreated, + ], + traffic_source=NotificationSettingTrafficSource.Platform, + ), + ReadsFixtures.read_raw_json_fixture("request/create_traffic_platform"), + 200, + ReadsFixtures.read_raw_json_fixture("response/minimal_entity"), + "/notification-settings", + ), + ( + CreateNotificationSetting( + description="Slack notifications", + type=NotificationSettingType.Url, + destination="https://hooks.slack.com/example", + include_sensitive_fields=False, + subscribed_events=[ + EventTypeName.TransactionCreated, + ], + traffic_source=NotificationSettingTrafficSource.Simulation, + ), + ReadsFixtures.read_raw_json_fixture("request/create_traffic_simulation"), + 200, + ReadsFixtures.read_raw_json_fixture("response/minimal_entity"), + "/notification-settings", + ), ], ids=[ "Create notification-setting with basic data", "Create notification-setting with full data", + "Create notification-setting for all traffic", + "Create notification-setting for platform traffic", + "Create notification-setting for simulation traffic", ], ) def test_create_notification_setting_uses_expected_payload( @@ -158,11 +209,44 @@ def test_create_notification_setting_uses_expected_payload( ReadsFixtures.read_raw_json_fixture("response/full_entity"), "/notification-settings/ntfset_01gkpjp8bkm3tm53kdgkx6sms7", ), + ( + "ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + UpdateNotificationSetting( + traffic_source=NotificationSettingTrafficSource.All, + ), + ReadsFixtures.read_raw_json_fixture("request/update_traffic_all"), + 200, + ReadsFixtures.read_raw_json_fixture("response/full_entity"), + "/notification-settings/ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + ), + ( + "ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + UpdateNotificationSetting( + traffic_source=NotificationSettingTrafficSource.Platform, + ), + ReadsFixtures.read_raw_json_fixture("request/update_traffic_platform"), + 200, + ReadsFixtures.read_raw_json_fixture("response/full_entity"), + "/notification-settings/ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + ), + ( + "ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + UpdateNotificationSetting( + traffic_source=NotificationSettingTrafficSource.Simulation, + ), + ReadsFixtures.read_raw_json_fixture("request/update_traffic_simulation"), + 200, + ReadsFixtures.read_raw_json_fixture("response/full_entity"), + "/notification-settings/ntfset_01gkpjp8bkm3tm53kdgkx6sms7", + ), ], ids=[ "Update notification setting with basic data", "Update notification setting with partial data", "Update notification setting with full data", + "Create notification-setting for all traffic", + "Create notification-setting for platform traffic", + "Create notification-setting for simulation traffic", ], ) def test_update_notification_setting_uses_expected_payload( @@ -272,6 +356,24 @@ def test_list_notification_settings_returns_expected_response( ), "/notification-settings?after=ntfset_01gkpjp8bkm3tm53kdgkx6sms7&order_by=id[desc]&per_page=100", ), + ( + ListNotificationSettings( + traffic_source=NotificationSettingTrafficSource.All, + ), + "/notification-settings?traffic_source=all", + ), + ( + ListNotificationSettings( + traffic_source=NotificationSettingTrafficSource.Platform, + ), + "/notification-settings?traffic_source=platform", + ), + ( + ListNotificationSettings( + traffic_source=NotificationSettingTrafficSource.Simulation, + ), + "/notification-settings?traffic_source=simulation", + ), ], ids=[ "List all notification-settings", @@ -279,6 +381,9 @@ def test_list_notification_settings_returns_expected_response( "List inactive notification-settings", "List notification-settings with pagination", "List notification-settings with pagination after", + "List notification-settings for all traffic", + "List notification-settings for platform traffic", + "List notification-settings for simulation traffic", ], ) def test_list_notification_settings_hits_expected_url( @@ -331,6 +436,24 @@ def test_list_notification_settings_can_paginate( assert len(allNotificationSettings) == 2 + def test_list_notification_entities_have_traffic_source( + self, + test_client, + mock_requests, + ): + mock_requests.get( + f"{test_client.base_url}/notification-settings", + status_code=200, + text=ReadsFixtures.read_raw_json_fixture("response/list_default"), + ) + + response = test_client.client.notification_settings.list() + + assert isinstance(response, NotificationSettingCollection) + assert response.items[0].traffic_source == NotificationSettingTrafficSource.All + assert response.items[1].traffic_source == NotificationSettingTrafficSource.Platform + assert response.items[2].traffic_source == NotificationSettingTrafficSource.Simulation + @mark.parametrize( "notification_setting_id, expected_response_status, expected_response_body, expected_url", [ @@ -370,6 +493,9 @@ def test_get_notification_settings_returns_expected_response( str(expected_response_body) ), "The response JSON generated by ResponseParser() doesn't match the expected fixture JSON" + assert response.type == NotificationSettingType.Url + assert response.traffic_source == NotificationSettingTrafficSource.Platform + @mark.parametrize( "notification_setting_id, expected_response_status, expected_path", [