Skip to content

Commit

Permalink
feat(subscriber): add channels fields on DTO (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
prathapbelli authored Oct 4, 2023
1 parent 40d4dac commit ce7ad38
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 4 deletions.
4 changes: 4 additions & 0 deletions novu/dto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
from novu.dto.step_filter import StepFilterDto
from novu.dto.subscriber import (
PaginatedSubscriberDto,
SubscriberChannelSettingsCredentialsDto,
SubscriberChannelSettingsDto,
SubscriberDto,
SubscriberPreferenceChannelDto,
SubscriberPreferenceDto,
Expand Down Expand Up @@ -92,6 +94,8 @@
"PaginatedTopicDto",
"StepFilterDto",
"SubscriberDto",
"SubscriberChannelSettingsDto",
"SubscriberChannelSettingsCredentialsDto",
"SubscriberPreferenceChannelDto",
"SubscriberPreferenceDto",
"SubscriberPreferencePreferenceDto",
Expand Down
43 changes: 40 additions & 3 deletions novu/dto/subscriber.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""This module is used to gather all DTO definitions related to the Subscriber resource in Novu"""
import dataclasses
from typing import Optional
from typing import List, Optional

from novu.dto.base import CamelCaseDto, DtoDescriptor, DtoIterableDescriptor
from novu.enums.provider import ProviderIdEnum


@dataclasses.dataclass
Expand Down Expand Up @@ -70,11 +71,44 @@ class SubscriberPreferenceDto(CamelCaseDto["SubscriberPreferenceDto"]):
"""The identifiers of the template linked to the preferences and its criticality"""


@dataclasses.dataclass
class SubscriberChannelSettingsCredentialsDto(CamelCaseDto["SubscriberChannelSettingsCredentialsDto"]):
"""Credentials payload for the specified provider."""

webhook_url: str
"""Webhook url used by chat app integrations. The webhook should be obtained from the chat app provider"""

channel: str
"""Channel specification for Mattermost chat notifications"""

device_tokens: Optional[List[str]] = None
"""Contains an array of the subscriber device tokens for a given provider. Used on Push integrations"""


@dataclasses.dataclass
class SubscriberChannelSettingsDto(CamelCaseDto["SubscriberChannelSettingsDto"]):
"""Definition of channel settings for subscriber."""

provider_id: ProviderIdEnum
"""The provider identifier for the credentials"""

_integration_id: str
"""Id of the integration that is used for this channel"""

credentials: DtoDescriptor[SubscriberChannelSettingsCredentialsDto] = DtoDescriptor[
SubscriberChannelSettingsCredentialsDto
](item_cls=SubscriberChannelSettingsCredentialsDto)
"""Credentials of this channel"""

integration_identifier: Optional[str] = None
"""The integration identifier"""


@dataclasses.dataclass
class SubscriberDto(CamelCaseDto["SubscriberDto"]): # pylint: disable=R0902
"""Definition of subscriber"""

camel_case_fields = ["subscriber_id", "email", "first_name", "last_name", "phone", "avatar", "locale"]
camel_case_fields = ["subscriber_id", "email", "first_name", "last_name", "phone", "avatar", "locale", "channels"]
# Actually, only these fields are editable in Novu, so prevent any activity on others

subscriber_id: str
Expand Down Expand Up @@ -107,7 +141,10 @@ class SubscriberDto(CamelCaseDto["SubscriberDto"]): # pylint: disable=R0902
_organization_id: Optional[str] = None
"""Organization ID in Novu internal storage system"""

# TODO: add channels
channels: DtoIterableDescriptor[SubscriberChannelSettingsDto] = DtoIterableDescriptor[SubscriberChannelSettingsDto](
default_factory=list, item_cls=SubscriberChannelSettingsDto
)
"""Subscriber provider specific credentials"""

deleted: Optional[bool] = None
"""If the subscriber is deleted"""
Expand Down
78 changes: 77 additions & 1 deletion tests/api/test_subscriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from novu.config import NovuConfig
from novu.dto.subscriber import (
PaginatedSubscriberDto,
SubscriberChannelSettingsCredentialsDto,
SubscriberChannelSettingsDto,
SubscriberDto,
SubscriberPreferenceChannelDto,
SubscriberPreferenceDto,
SubscriberPreferencePreferenceDto,
SubscriberPreferenceTemplateDto,
)
from novu.enums import Channel
from novu.enums import Channel, ChatProviderIdEnum
from tests.factories import MockResponse


Expand Down Expand Up @@ -50,6 +52,7 @@ def setUpClass(cls) -> None:
_id="63dafedbc037e013fd82d37a",
_environment_id="63dafed97779f59258e38445",
_organization_id="63dafed97779f59258e3843f",
channels=[],
deleted=False,
created_at="2023-02-02T00:07:55.459Z",
updated_at="2023-02-06T23:03:22.645Z",
Expand Down Expand Up @@ -134,6 +137,7 @@ def test_create_subscriber(self, mock_request: mock.MagicMock) -> None:
"phone": None,
"avatar": None,
"locale": None,
"channels": None,
},
params=None,
timeout=5,
Expand All @@ -156,6 +160,77 @@ def test_get_subscriber(self, mock_request: mock.MagicMock) -> None:
timeout=5,
)

@mock.patch("requests.request")
def test_get_subscriber_with_credentials_info(self, mock_request: mock.MagicMock) -> None:
mock_request.return_value = MockResponse(
200,
{
"data": {
"_id": "63dafedbc037e013fd82d37a",
"_organizationId": "63dafed97779f59258e3843f",
"_environmentId": "63dafed97779f59258e38445",
"subscriberId": "63dafed4117f8c850991ec4a",
"channels": [
{
"provider_id": "slack",
"_integration_id": "64f6d74be166fcd7f2751111",
"credentials": {"webhook_url": "TEST", "channel": "slack", "device_tokens": ["TEST"]},
"integration_identifier": None,
}
],
"deleted": False,
"createdAt": "2023-02-02T00:07:55.459Z",
"updatedAt": "2023-02-06T23:03:22.645Z",
"__v": 0,
"isOnline": False,
"email": "[email protected]",
"lastOnlineAt": "2023-02-06T23:03:22.645Z",
}
},
)

res = self.api.get("subscriber-id")
self.assertIsInstance(res, SubscriberDto)
self.assertEqual(
res,
SubscriberDto(
subscriber_id="63dafed4117f8c850991ec4a",
email="[email protected]",
first_name=None,
last_name=None,
phone=None,
avatar=None,
locale=None,
_id="63dafedbc037e013fd82d37a",
_environment_id="63dafed97779f59258e38445",
_organization_id="63dafed97779f59258e3843f",
channels=[
SubscriberChannelSettingsDto(
provider_id=ChatProviderIdEnum.SLACK,
_integration_id="64f6d74be166fcd7f2751111",
credentials=SubscriberChannelSettingsCredentialsDto(
webhook_url="TEST", channel="slack", device_tokens=["TEST"]
),
integration_identifier=None,
)
],
deleted=False,
created_at="2023-02-02T00:07:55.459Z",
updated_at="2023-02-06T23:03:22.645Z",
is_online=False,
last_online_at="2023-02-06T23:03:22.645Z",
),
)

mock_request.assert_called_once_with(
method="GET",
url="sample.novu.com/v1/subscribers/subscriber-id",
headers={"Authorization": "ApiKey api-key"},
json=None,
params=None,
timeout=5,
)

@mock.patch("requests.request")
def test_update_subscriber(self, mock_request: mock.MagicMock) -> None:
mock_request.return_value = MockResponse(200, self.response_get)
Expand All @@ -176,6 +251,7 @@ def test_update_subscriber(self, mock_request: mock.MagicMock) -> None:
"phone": "+33612345678",
"avatar": None,
"locale": None,
"channels": None,
},
params=None,
timeout=5,
Expand Down

0 comments on commit ce7ad38

Please sign in to comment.