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.meta.client import FacebookClient from dmp.adapters.meta.models import AccessToken from dmp.core.types import PlainToken from dmp.meta.dtos import MetaUserConnectionResult from dmp.meta.exceptions import MetaUserConnectionError from dmp.meta.models import MetaUserConnection from dmp.meta.services import MetaAdAccountService, MetaUserConnectionService @dataclass class ConnectMetaUserRequest(AuthRequest): user_id: str access_token: PlainToken @singleton class ConnectMetaUserHandler: permission = Permission("ad_connection", "connect") def __init__( self, db: DefaultDB, auth_service: AuthService, facebook_client: FacebookClient, user_connection_service: MetaUserConnectionService, ad_account_service: MetaAdAccountService, ) -> None: self.db = db self.auth_service = auth_service self.facebook_client = facebook_client self.user_connection_service = user_connection_service self.ad_account_service = ad_account_service @transactional def handle(self, request: ConnectMetaUserRequest) -> MetaUserConnectionResult: self.auth_service.check_owned_resource( request.identity_id, permission=self.permission, resource_id=request.user_id, ) api_token = self.facebook_client.get_oauth_access_token(request.access_token) try: user = self.user_connection_service.get_user( request.user_id, access_token=api_token.access_token, ) except MetaUserConnectionError as exc: return MetaUserConnectionResult( user=exc.user, status=exc.status, required_scopes=exc.required_scopes, ad_accounts=[], ) user_connection = self._create_or_update_user_connection( identity_id=request.identity_id, user_id=request.user_id, api_token=api_token, ) # Update user info user_connection.user_name = user.name user_connection.user_picture = user.picture user_connection.is_valid = True api_ad_accounts = self.facebook_client.get_user_ad_accounts( user_id=request.user_id, user_access_token=api_token.access_token, ) ad_accounts = self.ad_account_service.get_ad_accounts_for_connection( user_connection, external_ad_accounts=api_ad_accounts, ) user_connection.ad_accounts = ad_accounts self.user_connection_service.save_user_connection(user_connection) return self.user_connection_service.make_connected_result( user_connection, user=user ) def _create_or_update_user_connection( self, *, identity_id: str, user_id: str, api_token: AccessToken, ) -> MetaUserConnection: """Create or update user connection.""" token = self.user_connection_service.encrypt_token(api_token.access_token) user_connection = self.user_connection_service.get_user_connection(identity_id) if not user_connection: user_connection = MetaUserConnection( identity_id=identity_id, user_id=user_id, token=token, ) else: user_connection.user_id = user_id # required for migration to a new app user_connection.token = token return user_connection