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.fivetran import FivetranClient from dmp.adapters.fivetran.models import ConnectCard from dmp.config import Settings from dmp.google.exceptions import GoogleUserConnectionNotFoundError from dmp.google.models import GoogleAdReportingConnection from dmp.google.repositories import GoogleAdReportingConnectionRepository from dmp.google.services import GoogleUserConnectionService @dataclass class ConnectGoogleAdReportingRequest(AuthRequest): redirect_uri: str user_id: str @singleton class ConnectGoogleAdReportingHandler: permission = Permission("ad_connection", "connect") def __init__( self, db: DefaultDB, auth_service: AuthService, ad_reporting_connection_repository: GoogleAdReportingConnectionRepository, user_connection_service: GoogleUserConnectionService, fivetran_client: FivetranClient, settings: Settings, ) -> None: self.db = db self.auth_service = auth_service self.ad_reporting_connection_repository = ad_reporting_connection_repository self.user_connection_service = user_connection_service self.fivetran_client = fivetran_client self.settings = settings @transactional def handle( self, request: ConnectGoogleAdReportingRequest ) -> tuple[GoogleAdReportingConnection, ConnectCard]: self.auth_service.check_owned_resource( request.identity_id, permission=self.permission ) user_connection = self.user_connection_service.get_user_connection( request.identity_id, request.user_id, ) if user_connection: ad_account_external_ids = [ connection_ad_account.ad_account.external_id for connection_ad_account in user_connection.connection_ad_accounts ] else: raise GoogleUserConnectionNotFoundError ad_reporting_connection = self.ad_reporting_connection_repository.get_connection_by_identity_id_and_user_id( identity_id=request.identity_id, user_id=request.user_id ) if ad_reporting_connection: self.auth_service.check_owned_resource( request.identity_id, permission=self.permission, resource_id=ad_reporting_connection.id, ) ad_reporting_connection.initial_email_sent = False connect_card = self.fivetran_client.get_connect_card( connection_id=ad_reporting_connection.fivetran_connector_id, redirect_uri=request.redirect_uri, ) else: fivetran_schema = self._generate_fivetran_schema( request.identity_id, request.user_id ) connection = self.fivetran_client.create_google_ads_connection( group_id=self.settings.fivetran_reporting_group_id, schema=fivetran_schema, redirect_uri=request.redirect_uri, accounts=ad_account_external_ids, ) ad_reporting_connection = GoogleAdReportingConnection( fivetran_connector_id=connection.id, fivetran_schema=fivetran_schema, identity_id=request.identity_id, user_id=request.user_id, ) connect_card = connection.connect_card self.ad_reporting_connection_repository.add(ad_reporting_connection) return ad_reporting_connection, connect_card def _generate_fivetran_schema(self, identity_id: str, user_id: str) -> str: user_slug = identity_id.replace("-", "_").lower() fivetran_schema = f"google_{user_slug}_{user_id}" if self.settings.fivetran_schema_prefix: return f"{self.settings.fivetran_schema_prefix.lower()}_{fivetran_schema}" return fivetran_schema