from collections.abc import Sequence from anydi import singleton from fansifter_common.email import EmailType from fansifter_common.utils import timezone from email_campaigns.audiences.repositories import AudienceRepository from email_campaigns.campaigns.exceptions import EmailCampaignNotFoundError from email_campaigns.campaigns.models import EmailCampaign from email_campaigns.campaigns.repositories import EmailCampaignRepository from email_campaigns.campaigns.validators import CampaignValidator from email_campaigns.config import Settings from email_campaigns.emails.repositories import EmailAnalyticsRepository @singleton class EmailCampaignService: def __init__( self, campaign_validator: CampaignValidator, campaign_repository: EmailCampaignRepository, email_analytics_repository: EmailAnalyticsRepository, audience_repository: AudienceRepository, settings: Settings, ) -> None: self.campaign_validator = campaign_validator self.campaign_repository = campaign_repository self.email_analytics_repository = email_analytics_repository self.audience_repository = audience_repository self.settings = settings def get_campaign(self, campaign_id: str) -> EmailCampaign: email_campaign = self.campaign_repository.get(campaign_id) if email_campaign is None: raise EmailCampaignNotFoundError return email_campaign def save_campaign(self, campaign: EmailCampaign) -> None: self.campaign_repository.save(campaign) def delete_campaign( self, campaign: EmailCampaign, identity_id: str | None = None ) -> None: campaign.deleted_at = timezone.now() campaign.deleted_by = identity_id self.campaign_repository.save(campaign) def prefetch_audience( self, campaigns: Sequence[EmailCampaign] ) -> Sequence[EmailCampaign]: """Prefetch recipients count for draft campaigns.""" audience_ids = [ campaign.audience_id for campaign in campaigns if campaign.audience_id is not None ] audiences_by_id = { audience.id: audience for audience in self.audience_repository.find_by_ids(audience_ids) } for campaign in campaigns: if campaign.audience_id and campaign.audience_id in audiences_by_id: audience = audiences_by_id[campaign.audience_id] campaign.audience = audience return campaigns def prefetch_analytics( self, campaigns: Sequence[EmailCampaign] ) -> Sequence[EmailCampaign]: return self.email_analytics_repository.prefetch_analytics( campaigns, email_type=EmailType.CAMPAIGN, ) def should_enqueue_campaign(self, campaign: EmailCampaign) -> bool: return campaign.is_ready_for_queue( window_minutes=self.settings.campaign_schedule_in_queue_minutes, )