from typing import Any from urllib.parse import urljoin from fansifter_common.httpclient import HTTPClient from .exceptions import GoogleClientError from .types import OfflineJobOperation, UploadUsersResponse, UserDataOfflineJob class GoogleClient(HTTPClient): exception_class = GoogleClientError base_url = "https://googleads.googleapis.com" version = "v22" def __init__( self, developer_token: str, client_options: dict[str, Any] | None = None, ) -> None: client_options = client_options or {} client_options["base_url"] = urljoin(self.base_url, self.version) super().__init__(client_options=client_options) self.developer_token = developer_token def create_offline_user_data_job( self, access_token: str, customer_id: str, user_list_resource: str, login_customer_id: str | None, ) -> UserDataOfflineJob: headers = { "Authorization": f"Bearer {access_token}", "developer-token": self.developer_token, "Content-Type": "application/json", } if login_customer_id: headers["login-customer-id"] = login_customer_id return self.request( "POST", f"/customers/{customer_id}/offlineUserDataJobs:create", type=UserDataOfflineJob, headers=headers, json={ "job": { "type": "CUSTOMER_MATCH_USER_LIST", "customerMatchUserListMetadata": { "userList": user_list_resource, "consent": { "adUserData": "GRANTED", "adPersonalization": "GRANTED", }, }, } }, ) def add_to_offline_user_data_job( self, access_token: str, offline_job_resource: str, payload: list[list[str]], login_customer_id: str | None, ) -> UploadUsersResponse: operations = [] for email, phone in payload: identifiers = [] if email: identifiers.append({"hashedEmail": email}) if phone: identifiers.append({"hashedPhoneNumber": phone}) if identifiers: operations.append({"create": {"userIdentifiers": identifiers}}) headers = { "Authorization": f"Bearer {access_token}", "developer-token": self.developer_token, "Content-Type": "application/json", } if login_customer_id: headers["login-customer-id"] = login_customer_id return self.request( "POST", f"/{offline_job_resource}:addOperations", type=UploadUsersResponse, headers=headers, json={"operations": operations}, ) def start_offline_user_data_job( self, access_token: str, offline_job_resource: str, login_customer_id: str | None, ) -> OfflineJobOperation: headers = { "Authorization": f"Bearer {access_token}", "developer-token": self.developer_token, "Content-Type": "application/json", } if login_customer_id: headers["login-customer-id"] = login_customer_id return self.request( "POST", f"/{offline_job_resource}:run", type=OfflineJobOperation, headers=headers, json={"validateOnly": False}, )