Skip to content

Commit

Permalink
Update google ads api to v15 (#556)
Browse files Browse the repository at this point in the history
* update google ads api to v15 with consent setting

* update google ads api to v15 yarn build

---------

Co-authored-by: phillipperalez <[email protected]>
  • Loading branch information
davidtamaki and phillipperalez authored Jun 20, 2024
1 parent e10b94b commit e85ad84
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 17 deletions.
2 changes: 2 additions & 0 deletions lib/actions/google/ads/lib/ads_executor.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export declare class GoogleAdsActionExecutor {
readonly targetCid: any;
readonly mobileAppId: any;
readonly uploadKeyType: string;
readonly consentAdUserData: any;
readonly consentAdPersonalization: any;
offlineUserDataJobResourceName: string;
targetUserListRN: string;
constructor(adsRequest: GoogleAdsActionRequest);
Expand Down
4 changes: 3 additions & 1 deletion lib/actions/google/ads/lib/ads_executor.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class GoogleAdsActionExecutor {
this.targetCid = this.adsRequest.targetCid;
this.mobileAppId = this.adsRequest.mobileAppId;
this.uploadKeyType = this.adsRequest.uploadKeyType;
this.consentAdUserData = this.adsRequest.consentAdUserData;
this.consentAdPersonalization = this.adsRequest.consentAdPersonalization;
this.offlineUserDataJobResourceName = ""; // will be updated later
this.targetUserListRN = adsRequest.formParams.targetUserListRN;
}
Expand All @@ -32,7 +34,7 @@ class GoogleAdsActionExecutor {
}
createDataJob() {
return __awaiter(this, void 0, void 0, function* () {
const createJobResp = yield this.apiClient.createDataJob(this.targetCid, this.targetUserListRN);
const createJobResp = yield this.apiClient.createDataJob(this.targetCid, this.targetUserListRN, this.consentAdUserData, this.consentAdPersonalization);
this.offlineUserDataJobResourceName = createJobResp.resourceName;
this.log("info", "Created data job:", this.offlineUserDataJobResourceName);
return createJobResp;
Expand Down
11 changes: 11 additions & 0 deletions lib/actions/google/ads/lib/ads_form_builder.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ export declare class GoogleAdsActionFormBuilder {
default: string;
required: boolean;
};
consentSetting(): {
name: string;
label: string;
type: "select";
options: {
name: string;
label: string;
}[];
default: string;
required: boolean;
}[];
private maybeSetLoginCustomer;
private maybeSetTargetCustomer;
private getLoginCidOptions;
Expand Down
46 changes: 41 additions & 5 deletions lib/actions/google/ads/lib/ads_form_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,24 @@ class GoogleAdsActionFormBuilder {
}
// 3) Branch 1: Show the fields for creating a new list (name & desc), plus hashing, and we're done
if (this.isCreate) {
form.fields.push(this.newListNameField());
form.fields.push(this.newListDescriptionField());
form.fields.push(this.doHashingFormField());
form.fields = [
...form.fields,
this.newListNameField(),
this.newListDescriptionField(),
this.doHashingFormField(),
...this.consentSetting(),
];
return form;
}
// 4) Branch 2: Select an existing list, but we need to check that there is at least one to choose...
const userListOptions = yield this.getUserListOptions();
if (userListOptions.length) {
form.fields.push(this.targetListField(userListOptions));
form.fields.push(this.doHashingFormField());
form.fields = [
...form.fields,
this.targetListField(userListOptions),
this.doHashingFormField(),
...this.consentSetting(),
];
}
else {
form.fields.push(this.noAvailableListsField());
Expand Down Expand Up @@ -250,6 +258,34 @@ class GoogleAdsActionFormBuilder {
required: true,
};
}
consentSetting() {
return [
{
name: "consentAdUserData",
label: "Step 5) The consent setting for consent for ad user data",
type: "select",
options: [
{ name: "UNSPECIFIED", label: "Unspecified" },
{ name: "GRANTED", label: "Granted" },
{ name: "DENIED", label: "Denied" },
],
default: "UNSPECIFIED",
required: true,
},
{
name: "consentAdPersonalization",
label: "The consent setting for consent for ad personalization",
type: "select",
options: [
{ name: "UNSPECIFIED", label: "Unspecified" },
{ name: "GRANTED", label: "Granted" },
{ name: "DENIED", label: "Denied" },
],
default: "UNSPECIFIED",
required: true,
},
];
}
maybeSetLoginCustomer() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.loginCid) {
Expand Down
2 changes: 2 additions & 0 deletions lib/actions/google/ads/lib/ads_request.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export declare class GoogleAdsActionRequest {
get isMobileDevice(): boolean;
get mobileAppId(): any;
get uploadKeyType(): "MOBILE_ADVERTISING_ID" | "CONTACT_INFO";
get consentAdUserData(): any;
get consentAdPersonalization(): any;
get developerToken(): string;
get doHashingBool(): boolean;
get isCreate(): boolean;
Expand Down
6 changes: 6 additions & 0 deletions lib/actions/google/ads/lib/ads_request.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ class GoogleAdsActionRequest {
get uploadKeyType() {
return this.isMobileDevice ? "MOBILE_ADVERTISING_ID" : "CONTACT_INFO";
}
get consentAdUserData() {
return this.formParams.consentAdUserData;
}
get consentAdPersonalization() {
return this.formParams.consentAdPersonalization;
}
get developerToken() {
return this.actionInstance.developerToken;
}
Expand Down
4 changes: 3 additions & 1 deletion lib/actions/google/ads/lib/api_client.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Logger } from "../../common/logger";
type ConsentType = "UNSPECIFIED" | "GRANTED" | "DENIED";
export declare class GoogleAdsApiClient {
readonly log: Logger;
readonly accessToken: string;
Expand All @@ -9,8 +10,9 @@ export declare class GoogleAdsApiClient {
searchOpenUserLists(clientCid: string, uploadKeyType: "MOBILE_ADVERTISING_ID" | "CONTACT_INFO"): Promise<any>;
searchClientCustomers(clientCid: string): Promise<any>;
createUserList(targetCid: string, newListName: string, newListDescription: string, uploadKeyType: "MOBILE_ADVERTISING_ID" | "CONTACT_INFO", mobileAppId?: string): Promise<any>;
createDataJob(targetCid: string, userListResourceName: string): Promise<any>;
createDataJob(targetCid: string, userListResourceName: string, consentAdUserData: ConsentType, consentAdPersonalization: ConsentType): Promise<any>;
addDataJobOperations(offlineUserDataJobResourceName: string, userIdentifiers: any[]): Promise<any>;
runJob(offlineUserDataJobResourceName: string): Promise<any>;
apiCall(method: "GET" | "POST", url: string, data?: any): Promise<any>;
}
export {};
9 changes: 7 additions & 2 deletions lib/actions/google/ads/lib/api_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,22 @@ class GoogleAdsApiClient {
return this.apiCall(method, path, body);
});
}
createDataJob(targetCid, userListResourceName) {
createDataJob(targetCid, userListResourceName, consentAdUserData, consentAdPersonalization) {
return __awaiter(this, void 0, void 0, function* () {
const method = "POST";
const path = `customers/${targetCid}/offlineUserDataJobs:create`;
const consent = {
ad_user_data: consentAdUserData,
ad_personalization: consentAdPersonalization,
};
const body = {
customer_id: targetCid,
job: {
external_id: Date.now(),
type: "CUSTOMER_MATCH_USER_LIST",
customer_match_user_list_metadata: {
user_list: userListResourceName,
consent,
},
},
};
Expand Down Expand Up @@ -143,7 +148,7 @@ class GoogleAdsApiClient {
url,
data,
headers,
baseURL: "https://googleads.googleapis.com/v14/",
baseURL: "https://googleads.googleapis.com/v15/",
});
if (process.env.ACTION_HUB_DEBUG) {
const apiResponse = lodash.cloneDeep(response);
Expand Down
9 changes: 8 additions & 1 deletion src/actions/google/ads/lib/ads_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export class GoogleAdsActionExecutor {
readonly targetCid = this.adsRequest.targetCid
readonly mobileAppId = this.adsRequest.mobileAppId
readonly uploadKeyType = this.adsRequest.uploadKeyType
readonly consentAdUserData = this.adsRequest.consentAdUserData
readonly consentAdPersonalization = this.adsRequest.consentAdPersonalization
offlineUserDataJobResourceName: string
targetUserListRN: string

Expand All @@ -25,7 +27,12 @@ export class GoogleAdsActionExecutor {
}

async createDataJob() {
const createJobResp = await this.apiClient.createDataJob(this.targetCid, this.targetUserListRN)
const createJobResp = await this.apiClient.createDataJob(
this.targetCid,
this.targetUserListRN,
this.consentAdUserData,
this.consentAdPersonalization,
)
this.offlineUserDataJobResourceName = createJobResp.resourceName
this.log("info", "Created data job:", this.offlineUserDataJobResourceName)
return createJobResp
Expand Down
47 changes: 42 additions & 5 deletions src/actions/google/ads/lib/ads_form_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,25 @@ export class GoogleAdsActionFormBuilder {

// 3) Branch 1: Show the fields for creating a new list (name & desc), plus hashing, and we're done
if (this.isCreate) {
form.fields.push(this.newListNameField())
form.fields.push(this.newListDescriptionField())
form.fields.push(this.doHashingFormField())
form.fields = [
...form.fields,
this.newListNameField(),
this.newListDescriptionField(),
this.doHashingFormField(),
...this.consentSetting(),
]
return form
}

// 4) Branch 2: Select an existing list, but we need to check that there is at least one to choose...
const userListOptions = await this.getUserListOptions()
if (userListOptions.length) {
form.fields.push(this.targetListField(userListOptions))
form.fields.push(this.doHashingFormField())
form.fields = [
...form.fields,
this.targetListField(userListOptions),
this.doHashingFormField(),
...this.consentSetting(),
]
} else {
form.fields.push(this.noAvailableListsField())
}
Expand Down Expand Up @@ -261,6 +269,35 @@ export class GoogleAdsActionFormBuilder {
}
}

consentSetting() {
return [
{
name: "consentAdUserData",
label: "Step 5) The consent setting for consent for ad user data",
type: "select" as "select",
options: [
{name: "UNSPECIFIED", label: "Unspecified"},
{name: "GRANTED", label: "Granted"},
{name: "DENIED", label: "Denied"},
],
default: "UNSPECIFIED",
required: true,
},
{
name: "consentAdPersonalization",
label: "The consent setting for consent for ad personalization",
type: "select" as "select",
options: [
{name: "UNSPECIFIED", label: "Unspecified"},
{name: "GRANTED", label: "Granted"},
{name: "DENIED", label: "Denied"},
],
default: "UNSPECIFIED",
required: true,
},
]
}

private async maybeSetLoginCustomer() {
if (!this.loginCid) {
return
Expand Down
8 changes: 8 additions & 0 deletions src/actions/google/ads/lib/ads_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ export class GoogleAdsActionRequest {
return this.isMobileDevice ? "MOBILE_ADVERTISING_ID" : "CONTACT_INFO"
}

get consentAdUserData() {
return this.formParams.consentAdUserData
}

get consentAdPersonalization() {
return this.formParams.consentAdPersonalization
}

get developerToken() {
return this.actionInstance.developerToken
}
Expand Down
20 changes: 18 additions & 2 deletions src/actions/google/ads/lib/api_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import * as lodash from "lodash"
import { sanitizeError as sanitize } from "../../common/error_utils"
import { Logger } from "../../common/logger"

type ConsentType = "UNSPECIFIED" | "GRANTED" | "DENIED"
interface Consent {
ad_user_data: ConsentType
ad_personalization: ConsentType
}

export class GoogleAdsApiClient {

constructor(readonly log: Logger, readonly accessToken: string
Expand Down Expand Up @@ -77,16 +83,26 @@ export class GoogleAdsApiClient {
return this.apiCall(method, path, body)
}

async createDataJob(targetCid: string, userListResourceName: string) {
async createDataJob(
targetCid: string,
userListResourceName: string,
consentAdUserData: ConsentType,
consentAdPersonalization: ConsentType,
) {
const method = "POST"
const path = `customers/${targetCid}/offlineUserDataJobs:create`
const consent: Consent = {
ad_user_data: consentAdUserData,
ad_personalization: consentAdPersonalization,
}
const body = {
customer_id: targetCid,
job: {
external_id: Date.now(), // must be an Int64 so not very useful
type: "CUSTOMER_MATCH_USER_LIST",
customer_match_user_list_metadata: {
user_list: userListResourceName,
consent,
},
},
}
Expand Down Expand Up @@ -129,7 +145,7 @@ export class GoogleAdsApiClient {
url,
data,
headers,
baseURL: "https://googleads.googleapis.com/v14/",
baseURL: "https://googleads.googleapis.com/v15/",
})

if (process.env.ACTION_HUB_DEBUG) {
Expand Down

0 comments on commit e85ad84

Please sign in to comment.