from unittest import mock from unittest.mock import MagicMock import httpx import pytest from anydi import Container from faker import Faker from fansifter_common.adapters.graphql_router import GlobalParticipant from fansifter_common.adapters.twilio.models import MessagingService, PhoneNumber from pydantic import SecretStr from pytest_mock import MockerFixture from ows_text_campaigns.adapters.scanner import ContentRecommendations, ContentScanner from ows_text_campaigns.artist.exceptions import ArtistNotFoundError from ows_text_campaigns.artist.handlers import ( CreateOrUpdateArtistSettingsHandler, CreateOrUpdateArtistSettingsRequest, ) from ows_text_campaigns.artist.models import ArtistSettings from ows_text_campaigns.assets.models import Asset from ows_text_campaigns.assets.services import AssetService from ows_text_campaigns.assets.types import BinaryAsset from ows_text_campaigns.rosters.models import ArtistRosterMainRep from ows_text_campaigns.twilio.services import TwilioAccountService from tests.unit.types import BuildModel, CreateModel class TestCreateOrUpdateArtistSettingsHandler: @pytest.mark.db def test_create_settings_not_found( self, handler: CreateOrUpdateArtistSettingsHandler, graphql_router_client_mock: mock.MagicMock, faker: Faker, identity_id: str, create_model: CreateModel, ) -> None: global_participant_id = faker.uuid4() create_model( ArtistRosterMainRep, global_participant_id=global_participant_id, vendor_id=1, subaccount_id=0, ) graphql_router_client_mock.get_global_participant_by_gp_id.return_value = None with pytest.raises(ArtistNotFoundError): handler.handle( CreateOrUpdateArtistSettingsRequest( identity_id=identity_id, global_participant_id=global_participant_id, artist_name=None, welcome_message="Hello, world!", opt_in_message=None, phone_numbers=[ "+1234567890", ], twilio_account_sid="", twilio_auth_token=SecretStr(""), twilio_messaging_service_sid="", ) ) @pytest.mark.db def test_create_settings_invalid_response( self, handler: CreateOrUpdateArtistSettingsHandler, graphql_router_client_mock: mock.MagicMock, faker: Faker, identity_id: str, create_model: CreateModel, ) -> None: global_participant_id = faker.uuid4() create_model( ArtistRosterMainRep, global_participant_id=global_participant_id, vendor_id=1, subaccount_id=0, ) graphql_router_client_mock.get_global_participant_by_gp_id.side_effect = ( httpx.HTTPError("invalid") ) with pytest.raises(ArtistNotFoundError): handler.handle( CreateOrUpdateArtistSettingsRequest( identity_id=identity_id, global_participant_id=global_participant_id, artist_name=None, welcome_message="Hello, world!", opt_in_message=None, phone_numbers=[ "+1234567890", ], twilio_account_sid="", twilio_auth_token=SecretStr(""), twilio_messaging_service_sid="", ) ) @pytest.mark.db def test_create_settings_with_save_default_image( self, container: Container, handler: CreateOrUpdateArtistSettingsHandler, build_model: BuildModel, create_model: CreateModel, identity_id: str, faker: Faker, mocker: MockerFixture, graphql_router_client_mock: mock.MagicMock, twilio_client_mock: mock.MagicMock, ) -> None: global_participant = build_model( GlobalParticipant, imageUrl=faker.image_url(), name=faker.name() ) create_model( ArtistRosterMainRep, global_participant_id=global_participant.id, vendor_id=1, subaccount_id=0, ) graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( global_participant ) asset = create_model(Asset) asset_service_mock = mock.MagicMock(spec=AssetService) asset_service_mock.get_asset_from_url.return_value = BinaryAsset.from_data( faker.image(size=(1000, 1000), image_format="JPEG"), ) asset_service_mock.create_and_upload_image_to_s3.return_value = asset mocker.patch( "ows_text_campaigns.assets.utils.unique_hash", return_value="abc123", ) welcome_message = "Hello, world!" opt_in_message = "Start!" phone_number = "+14155552671" twilio_account_sid = faker.pystr() twilio_auth_token = faker.password() twilio_messaging_service_sid = faker.pystr() twilio_client_mock.get_messaging_service.return_value = MessagingService( sid=twilio_messaging_service_sid, friendly_name="messaging", account_sid=twilio_account_sid, ) twilio_client_mock.get_messaging_phone_numbers.return_value = [ PhoneNumber( sid=faker.pystr(), phone_number=phone_number, capabilities=[], ) ] twilio_account_service_mock = mock.MagicMock(spec=TwilioAccountService) content_scanner_mock = MagicMock(spec=ContentScanner) content_scanner_mock.scan.return_value = ContentRecommendations( sensitiveWords=[], includedArtistName=True ) with ( container.override(AssetService, asset_service_mock), container.override(TwilioAccountService, twilio_account_service_mock), container.override(ContentScanner, content_scanner_mock), ): artist_settings = handler.handle( CreateOrUpdateArtistSettingsRequest( identity_id=identity_id, global_participant_id=global_participant.id, artist_name=None, welcome_message=welcome_message, opt_in_message=opt_in_message, phone_numbers=[phone_number], twilio_account_sid=twilio_account_sid, twilio_auth_token=SecretStr(twilio_auth_token), twilio_messaging_service_sid=twilio_messaging_service_sid, ) ) assert artist_settings.welcome_message == welcome_message assert artist_settings.phone_numbers assert artist_settings.phone_numbers[0]["phone_number"] == phone_number assert artist_settings.phone_numbers[0]["country_code"] == "US" assert artist_settings.welcome_message_scan_result == ContentRecommendations( includedArtistName=True, sensitiveWords=[], ) assert artist_settings.opt_in_message_scan_result == ContentRecommendations( includedArtistName=True, sensitiveWords=[], ) asset_service_mock.create_and_upload_image_to_s3.assert_called_once() twilio_account_service_mock.save_account.assert_called_once() @pytest.mark.db def test_update_artist_settings( self, container: Container, handler: CreateOrUpdateArtistSettingsHandler, build_model: BuildModel, create_model: CreateModel, graphql_router_client_mock: mock.MagicMock, twilio_client_mock: mock.MagicMock, faker: Faker, identity_id: str, ) -> None: global_participant = build_model(GlobalParticipant, imageUrl=None) asset = create_model( Asset, object_type="artist", object_id=global_participant.id, ) artist_settings = create_model( ArtistSettings, global_participant_id=global_participant.id, asset_id=asset.id, ) create_model( ArtistRosterMainRep, global_participant_id=global_participant.id, vendor_id=1, subaccount_id=0, ) new_welcome_message = faker.text(max_nb_chars=100) new_opt_in_message = faker.text(max_nb_chars=100) new_artist_name = faker.pystr() new_twilio_account_sid = faker.pystr() new_twilio_auth_token = faker.password() new_twilio_messaging_service_sid = faker.pystr() new_phone_number = "+14155552671" graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( global_participant ) content_scanner_mock = MagicMock(spec=ContentScanner) content_scanner_mock.scan.return_value = ContentRecommendations( sensitiveWords=[], includedArtistName=True ) asset_service_mock = mock.MagicMock(spec=AssetService) asset_service_mock.get_asset_from_s3.return_value = BinaryAsset.from_data( faker.image((500, 500), image_format="JPEG"), ) twilio_client_mock.get_messaging_service.return_value = MessagingService( sid=new_twilio_messaging_service_sid, friendly_name="messaging", account_sid=new_twilio_account_sid, ) twilio_client_mock.get_messaging_phone_numbers.return_value = [ PhoneNumber( sid=faker.pystr(), phone_number=new_phone_number, capabilities=[], ) ] twilio_account_service_mock = mock.MagicMock(spec=TwilioAccountService) with ( container.override(AssetService, asset_service_mock), container.override(TwilioAccountService, twilio_account_service_mock), container.override(ContentScanner, content_scanner_mock), ): updated_artist_settings = handler.handle( CreateOrUpdateArtistSettingsRequest( identity_id=identity_id, global_participant_id=artist_settings.global_participant_id, artist_name=new_artist_name, welcome_message=new_welcome_message, opt_in_message=new_opt_in_message, phone_numbers=[new_phone_number], twilio_account_sid=new_twilio_account_sid, twilio_auth_token=SecretStr(new_twilio_auth_token), twilio_messaging_service_sid=new_twilio_messaging_service_sid, ) ) assert updated_artist_settings.welcome_message == new_welcome_message assert updated_artist_settings.opt_in_message == new_opt_in_message assert artist_settings.phone_numbers assert artist_settings.phone_numbers[0].phone_number == new_phone_number assert artist_settings.phone_numbers[0].country_code == "US" assert ( updated_artist_settings.welcome_message_scan_result == ContentRecommendations( includedArtistName=True, sensitiveWords=[], ) ) assert ( updated_artist_settings.opt_in_message_scan_result == ContentRecommendations( includedArtistName=True, sensitiveWords=[], ) )