from dataclasses import dataclass from anydi import singleton from fansifter_common.auth.requests import AuthRequest from fansifter_common.auth.services import AuthService from fansifter_common.auth.types import Permission from dmp.adapters.db import DefaultDB, transactional from dmp.adapters.tiktok import TikTokClient from dmp.config import Settings from dmp.core.types import PlainToken from dmp.tiktok.dtos import TikTokUserConnectionResponse from dmp.tiktok.exceptions import ( TikTokUserConnectionScopesError, ) from dmp.tiktok.models import TikTokAdAccount from dmp.tiktok.services import TikTokAdAccountService, TikTokUserConnectionService @dataclass class ConnectTikTokUserRequest(AuthRequest): access_token: PlainToken @singleton class ConnectTikTokUserHandler: permission = Permission("ad_connection", "connect") def __init__( self, db: DefaultDB, auth_service: AuthService, tiktok_client: TikTokClient, user_connection_service: TikTokUserConnectionService, ad_account_service: TikTokAdAccountService, settings: Settings, ) -> None: self.db = db self.auth_service = auth_service self.tiktok_client = tiktok_client self.user_connection_service = user_connection_service self.ad_account_service = ad_account_service self.settings = settings @transactional def handle(self, request: ConnectTikTokUserRequest) -> TikTokUserConnectionResponse: self.auth_service.check_owned_resource( request.identity_id, permission=self.permission, ) api_token = self.tiktok_client.get_oauth_access_token( tmp_token=request.access_token ) if not api_token.scopes_sufficient(self.settings.tiktok_user_required_scopes): raise TikTokUserConnectionScopesError access_token = api_token.access_token user_connection = self.user_connection_service.create_or_update_user_connection( identity_id=request.identity_id, access_token=access_token ) api_ad_accounts = self.tiktok_client.get_ad_accounts_details( access_token, api_token.advertiser_ids ) ad_accounts = self.ad_account_service.get_ad_accounts_for_connection( user_connection, api_ad_accounts ) self._fill_ad_accounts_missing_data(ad_accounts, access_token) user_connection.ad_accounts = ad_accounts self.user_connection_service.save_user_connection(user_connection) return self.user_connection_service.make_connected_response(user_connection) def _fill_ad_accounts_missing_data( self, ad_accounts: list[TikTokAdAccount], access_token: PlainToken ) -> None: for ad_account in ad_accounts: if ad_account.business_center_id: business_center = self.tiktok_client.get_business_center_details( access_token=access_token, business_center_id=ad_account.business_center_id, ) if business_center: ad_account.business_center_name = business_center.name ad_account.campaigns_count = ( self.tiktok_client.get_ad_account_campaigns_count( access_token=access_token, advertiser_id=ad_account.external_id ) )