from typing import get_args import faker import pytest from fansifter_common.utils import timezone from email_campaigns.automated.enums import AutomatedEmailType from email_campaigns.automated.models import ( AutomatedEmail, AutomatedEmailTrigger, SourceCampaign, ) from email_campaigns.automated.repositories import AutomatedEmailRepository from email_campaigns.automated.types import ( AutomatedEmailCriteria, AutomatedEmailOrderBy, ) from tests.unit.types import CreateModel class TestAutomatedEmailRepository: @pytest.mark.db def test_get( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: automated_email = create_model(AutomatedEmail) result = repository.get(automated_email.id) assert result is not None assert result.id == automated_email.id @pytest.mark.db def test_get_excludes_deleted( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: automated_email = create_model( AutomatedEmail, deleted_at=timezone.now(), ) result = repository.get(automated_email.id) assert result is None @pytest.mark.db def test_find_by_source_campaign_id( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() source_campaign = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) automated_email = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger( source_campaign_id=source_campaign.id, ) ], ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) result = repository.find_by_source_campaign_id(source_campaign.id) assert len(result) == 1 assert result[0].id == automated_email.id @pytest.mark.db def test_find_by_source_campaign_id_excludes_deleted( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() source_campaign = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, deleted_at=timezone.now(), source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign.id) ], ) result = repository.find_by_source_campaign_id(source_campaign.id) assert len(result) == 0 @pytest.mark.db def test_find_by_source_campaign_id_empty( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: source_campaign = create_model(SourceCampaign) result = repository.find_by_source_campaign_id(source_campaign.id) assert len(result) == 0 @pytest.mark.db def test_find_by_criteria_with_is_automated_true( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() # Create automated email with source campaign (is_automated=True) source_campaign_1 = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) automated_email_1 = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign_1.id) ], ) # Create automated email without source campaign (is_automated=False) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=True, search=None, ) result = repository.find_by_criteria( criteria, order_by=["name.asc"], limit=10, offset=0 ) assert len(result) == 1 assert result[0].id == automated_email_1.id @pytest.mark.db def test_find_by_criteria_with_is_automated_false( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() # Create automated email with source campaign (is_automated=True) source_campaign_1 = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign_1.id) ], ) # Create automated email without source campaign (is_automated=False) automated_email_2 = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=False, search=None, ) result = repository.find_by_criteria( criteria, order_by=["name.asc"], limit=10, offset=0 ) assert len(result) == 1 assert result[0].id == automated_email_2.id @pytest.mark.db def test_count_by_criteria_with_is_automated_true( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() # Create two automated emails with source campaigns source_campaign_1 = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign_1.id) ], ) source_campaign_2 = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign_2.id) ], ) # Create automated email without source campaign create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=True, search=None, ) count = repository.count_by_criteria(criteria) assert count == 2 @pytest.mark.db def test_count_by_criteria_with_is_automated_false( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() # Create automated email with source campaign source_campaign_1 = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign_1.id) ], ) # Create two automated emails without source campaigns create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=False, search=None, ) count = repository.count_by_criteria(criteria) assert count == 2 @pytest.mark.db def test_find_by_criteria_with_is_automated_none( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() # Create two automated emails create_model(AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id) create_model(AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id) criteria = AutomatedEmailCriteria( email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=None, search=None, ) result = repository.find_by_criteria( criteria, order_by=["name.asc"], limit=10, offset=0 ) # Should return both emails when is_automated is None assert len(result) == 2 @pytest.mark.db def test_find_by_criteria_order_by_type_asc( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() triggered = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, type=AutomatedEmailType.TRIGGERED, ) opt_in = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, type=AutomatedEmailType.OPT_IN, ) criteria = AutomatedEmailCriteria( search=None, email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=None, ) result = repository.find_by_criteria( criteria, order_by=["type.asc"], limit=10, offset=0 ) assert [r.id for r in result] == [opt_in.id, triggered.id] @pytest.mark.db def test_find_by_criteria_order_by_type_desc( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() triggered = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, type=AutomatedEmailType.TRIGGERED, ) opt_in = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, type=AutomatedEmailType.OPT_IN, ) criteria = AutomatedEmailCriteria( search=None, email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=None, ) result = repository.find_by_criteria( criteria, order_by=["type.desc"], limit=10, offset=0 ) assert [r.id for r in result] == [triggered.id, opt_in.id] @pytest.mark.db def test_find_by_criteria_order_by_is_automated_asc( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() source_campaign = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) automated = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign.id) ], ) not_automated = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( search=None, email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=None, ) result = repository.find_by_criteria( criteria, order_by=["isAutomated.asc"], limit=10, offset=0 ) assert [r.id for r in result] == [not_automated.id, automated.id] @pytest.mark.db def test_find_by_criteria_order_by_is_automated_desc( self, repository: AutomatedEmailRepository, create_model: CreateModel, faker: faker.Faker, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() source_campaign = create_model( SourceCampaign, vendor_id=vendor_id, subaccount_id=subaccount_id, ) automated = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, source_campaign_connections=[ AutomatedEmailTrigger(source_campaign_id=source_campaign.id) ], ) not_automated = create_model( AutomatedEmail, vendor_id=vendor_id, subaccount_id=subaccount_id, ) criteria = AutomatedEmailCriteria( search=None, email_ids=None, vendor_ids={vendor_id}, subaccount_ids={subaccount_id}, fandata_list_ids=None, is_automated=None, ) result = repository.find_by_criteria( criteria, order_by=["isAutomated.desc"], limit=10, offset=0 ) assert [r.id for r in result] == [automated.id, not_automated.id] @pytest.mark.db @pytest.mark.parametrize("order_by", get_args(AutomatedEmailOrderBy)) def test_find_by_criteria_order_by( self, order_by: AutomatedEmailOrderBy, repository: AutomatedEmailRepository ) -> None: repository.find_by_criteria( AutomatedEmailCriteria( search=None, email_ids=None, vendor_ids=None, subaccount_ids=None, fandata_list_ids=None, is_automated=False, ), order_by=[order_by], limit=10, offset=0, ) @pytest.mark.db def test_get_status_is_automated_true_when_trigger_exists( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: source_campaign = create_model(SourceCampaign) automated_email = create_model( AutomatedEmail, has_unapplied_changes=True, source_campaign_connections=[ AutomatedEmailTrigger( source_campaign_id=source_campaign.id, subscription_only=False, ), ], ) result = repository.get_status(automated_email.id) assert result is not None assert result.has_unapplied_changes is True assert result.is_automated is True assert result.vendor_id == automated_email.vendor_id assert result.subaccount_id == automated_email.subaccount_id @pytest.mark.db def test_get_status_is_automated_false_without_triggers( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: automated_email = create_model( AutomatedEmail, has_unapplied_changes=False, source_campaign_connections=[], ) result = repository.get_status(automated_email.id) assert result is not None assert result.has_unapplied_changes is False assert result.is_automated is False @pytest.mark.db def test_get_status_returns_none_for_deleted( self, repository: AutomatedEmailRepository, create_model: CreateModel, ) -> None: automated_email = create_model( AutomatedEmail, deleted_at=timezone.now(), ) result = repository.get_status(automated_email.id) assert result is None @pytest.mark.db def test_get_status_returns_none_for_missing( self, repository: AutomatedEmailRepository, ) -> None: result = repository.get_status("does-not-exist") assert result is None