from unittest import mock import faker import pytest from ows_text_campaigns.adapters.ows_url_shortener import BulkShortenResponse, ShortUrl from ows_text_campaigns.artist.models import ArtistPhoneNumber, ArtistSettings from ows_text_campaigns.campaigns.enums import MessageChannel, ShorteningMethod from ows_text_campaigns.campaigns.exceptions import ( PersonalizedAttributesLimitExceededError, ) from ows_text_campaigns.campaigns.handlers import ( RenderCampaignMessagesBatchHandler, RenderCampaignMessagesBatchRequest, ) from ows_text_campaigns.campaigns.models import Campaign, UrlDomain from ows_text_campaigns.campaigns.types import FanRenderedMessage, ShortenedUrl from ows_text_campaigns.campaigns.utils import create_short_link_tag from tests.unit.types import BuildModel, CreateModel, OverrideSettings class TestRenderCampaignMessagesBatchHandler: @pytest.mark.db def test_render_messages_batch( self, handler: RenderCampaignMessagesBatchHandler, create_model: CreateModel, faker: faker.Faker, ) -> None: global_participant_id = faker.uuid4() content = "

Hello, World!

" fan_id_1 = "fan1" fan_id_2 = "fan2" sender = "+12345678900" recipient_1 = "+12345678901" recipient_2 = "+12345678902" create_model( ArtistSettings, global_participant_id=global_participant_id, phone_numbers=[ ArtistPhoneNumber( global_participant_id=global_participant_id, phone_number=sender, ) ], ) campaign = create_model( Campaign, content=content, global_participant_id=global_participant_id ) messages = handler.handle( RenderCampaignMessagesBatchRequest( campaign_id=campaign.id, personalized_attributes=[ { "fan_id": fan_id_1, "channel": MessageChannel.SMS, "phone_number": recipient_1, }, { "fan_id": fan_id_2, "channel": MessageChannel.WHATSAPP, "phone_number": recipient_2, }, ], ) ) expected_message = "Hello, World!\nReply STOP to unsubscribe." assert messages == [ FanRenderedMessage( fan_id=fan_id_1, channel=MessageChannel.SMS, recipient=recipient_1, sender=sender, message=expected_message, media_url=None, ), FanRenderedMessage( fan_id=fan_id_2, channel=MessageChannel.WHATSAPP, recipient=recipient_2, sender=sender, message=expected_message, media_url=None, ), ] @pytest.mark.db def test_render_messages_batch_with_shortened_links( self, handler: RenderCampaignMessagesBatchHandler, create_model: CreateModel, build_model: BuildModel, faker: faker.Faker, ows_url_shortener_client_mock: mock.MagicMock, ) -> None: global_participant_id = faker.uuid4() sender = "+12345678900" url_domain = create_model(UrlDomain, domain="sme.com") standard_url = build_model( ShortenedUrl, domain=url_domain.domain, method=ShorteningMethod.STANDARD, ) personalized_url = build_model( ShortenedUrl, domain=url_domain.domain, method=ShorteningMethod.PERSONALIZED, ) fan_id_1 = faker.uuid4() fan_id_2 = faker.uuid4() recipient_1 = "+12345678901" recipient_2 = "+12345678902" shortened_standard_url = standard_url.preview_url shortened_personalized_url_1 = "https://sme.com/fan-abc001" shortened_personalized_url_2 = "https://sme.com/fan-abc002" content = f""" Hello, World!

Standard link: {create_short_link_tag(standard_url)}

Personalized link: {create_short_link_tag(personalized_url)}

""" create_model( ArtistSettings, global_participant_id=global_participant_id, phone_numbers=[ ArtistPhoneNumber( global_participant_id=global_participant_id, phone_number=sender, ) ], ) campaign = create_model( Campaign, content=content, global_participant_id=global_participant_id, ) ows_url_shortener_client_mock.bulk_shorten.return_value = BulkShortenResponse( url=personalized_url.url, short_urls=[ ShortUrl( short_url=shortened_personalized_url_1, additional_attributes={ "fan_id": fan_id_1, }, ), ShortUrl( short_url=shortened_personalized_url_2, additional_attributes={ "fan_id": fan_id_2, }, ), ], ) messages = handler.handle( RenderCampaignMessagesBatchRequest( campaign_id=campaign.id, personalized_attributes=[ { "fan_id": fan_id_1, "channel": MessageChannel.SMS, "phone_number": recipient_1, }, { "fan_id": fan_id_2, "channel": MessageChannel.WHATSAPP, "phone_number": recipient_2, }, ], ) ) ows_url_shortener_client_mock.bulk_shorten.assert_called_once_with( url=personalized_url.url, domain=url_domain.domain, path_prefix=personalized_url.path, additional_attributes=[ { "campaign_id": campaign.id, "shortened_url_id": personalized_url.id, "fan_id": fan_id_1, }, { "campaign_id": campaign.id, "shortened_url_id": personalized_url.id, "fan_id": fan_id_2, }, ], ) assert messages == [ FanRenderedMessage( fan_id=fan_id_1, channel=MessageChannel.SMS, recipient=recipient_1, sender=sender, message=( f"Hello, World!\n" f"Standard link: {shortened_standard_url}\n" f"Personalized link: {shortened_personalized_url_1}\n" "Reply STOP to unsubscribe." ), media_url=None, ), FanRenderedMessage( fan_id=fan_id_2, channel=MessageChannel.WHATSAPP, recipient=recipient_2, sender=sender, message=( f"*Hello, World!*\n" f"Standard link: {shortened_standard_url}\n" f"Personalized link: {shortened_personalized_url_2}\n" "Reply STOP to unsubscribe." ), media_url=None, ), ] @pytest.mark.db def test_render_messages_batch_allowed_limit( self, handler: RenderCampaignMessagesBatchHandler, create_model: CreateModel, override_settings: OverrideSettings, faker: faker.Faker, ) -> None: campaign = create_model(Campaign) with ( override_settings(max_allowed_personalized_attributes_limit=1), pytest.raises(PersonalizedAttributesLimitExceededError), ): handler.handle( RenderCampaignMessagesBatchRequest( campaign_id=campaign.id, personalized_attributes=[ { "fan_id": f"fan{n}", "channel": MessageChannel.SMS, "phone_number": faker.phone_number(), } for n in range(2) ], ) )