from dataclasses import dataclass from anydi import singleton from fansifter_common.auth.account import Account from fansifter_common.auth.identity import Identity from fansifter_common.auth.services import AuthService from fansifter_common.auth.types import Permission from dmp.adapters.db import DefaultDB, ReportingDB from dmp.adapters.features import AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE, Features from dmp.audiences.enums import AudienceTarget from dmp.audiences.exceptions import ( AudienceTargetNotSupportedError, ) from dmp.audiences.filters import AudienceFilters from dmp.audiences.models import Audience, AudienceFanDataList from dmp.audiences.services import AudienceService from dmp.audiences.types import FanDataListId from dmp.audiences.validators import AudienceValidator from dmp.rosters.exceptions import FanDataListIdIsRequiredError from dmp.rosters.services import GlobalFanDataAccessService from dmp.text_campaigns.repositories import ArtistPhoneNumberRepository @dataclass(kw_only=True) class CreateAudienceRequest: identity: Identity vendor_id: int subaccount_id: int name: str fandata_list_ids: list[FanDataListId] target: AudienceTarget filters: AudienceFilters @property def account(self) -> Account: return Account( vendor_id=self.vendor_id, subaccount_id=self.subaccount_id, ) @singleton class CreateAudienceHandler: ad_target_permission = Permission("audience", "create_ad_target") email_target_permission = Permission("audience", "create_email_target") text_target_permission = Permission("audience", "create_text_target") def __init__( self, db: DefaultDB, reporting_db: ReportingDB, auth_service: AuthService, audience_service: AudienceService, audience_validator: AudienceValidator, global_fandata_access_service: GlobalFanDataAccessService, artist_phone_number_repository: ArtistPhoneNumberRepository, features: Features, ) -> None: self.db = db self.reporting_db = reporting_db self.auth_service = auth_service self.audience_service = audience_service self.audience_validator = audience_validator self.global_fandata_access_service = global_fandata_access_service self.artist_phone_number_repository = artist_phone_number_repository self.features = features def handle(self, request: CreateAudienceRequest) -> Audience: if not request.fandata_list_ids: raise FanDataListIdIsRequiredError with self.db.transaction(), self.reporting_db.transaction(): match request.target: case AudienceTarget.EMAIL: self.auth_service.check_account_resource( request.identity.id, account=request.account, permission=self.email_target_permission, ) case AudienceTarget.ADS: self.auth_service.check_account_resource( request.identity.id, account=request.account, permission=self.ad_target_permission, ) case AudienceTarget.TEXT if self.features.is_on_for_identity( feature_flag_name=AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE, identity_id=request.identity.id, ): self.auth_service.check_account_resource( request.identity.id, account=request.account, permission=self.text_target_permission, ) case _: raise AudienceTargetNotSupportedError # Validate audience name under account self.audience_validator.validate_name( name=request.name, account=request.account ) # Validate fandata_list_ids self.audience_validator.validate_fandata_list( fandata_list_ids=request.fandata_list_ids, target=request.target, account=request.account, ) # Validate exclude_fandata_list_ids if request.filters.excluded_fan_data_lists: for fan_data_list in request.filters.excluded_fan_data_lists: self.audience_validator.validate_fandata_list( fandata_list_ids=[fan_data_list], target=request.target, account=request.account, ) # Validate TEXT audience if request.target == AudienceTarget.TEXT: self.audience_validator.validate_artist_has_phone_number( fandata_list_ids=request.fandata_list_ids ) fandata_lists = [ AudienceFanDataList( list_id=fandata_list.id, type=fandata_list.type, ) for fandata_list in request.fandata_list_ids ] audience = Audience( name=request.name, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, fandata_lists=fandata_lists, target=request.target, filters=request.filters, created_by=request.identity.id, updated_by=request.identity.id, ) global_fandata_list_enabled = ( self.global_fandata_access_service.is_enabled_for_any_vendor( vendor_ids=[request.vendor_id], ) ) self.audience_service.refresh_audience( audience, identity=request.identity, is_global=global_fandata_list_enabled, ) return audience