@google-cloud/nodejs-common 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1337,10 +1337,13 @@ do_authentication(){
1337
1337
  do_oauth(){
1338
1338
  # Base url of Google OAuth service.
1339
1339
  OAUTH_BASE_URL="https://accounts.google.com/o/oauth2/"
1340
+ # Redirect uri.
1341
+ # Must be the same for requests of authorization code and refresh token.
1342
+ REDIRECT_URI="http%3A//127.0.0.1%3A8887"
1340
1343
  # Defaulat parameters of OAuth requests.
1341
1344
  OAUTH_PARAMETERS=(
1342
1345
  "access_type=offline"
1343
- "redirect_uri=urn:ietf:wg:oauth:2.0:oob"
1346
+ "redirect_uri=${REDIRECT_URI}"
1344
1347
  "response_type=code"
1345
1348
  )
1346
1349
  while [ ${#ENABLED_OAUTH_SCOPES[@]} -eq 0 ]; do
@@ -1409,18 +1412,26 @@ EOF
1409
1412
  printf '%s\n' "3. Open the link in browser and finish authentication: \
1410
1413
  ${auth_url}"
1411
1414
  cat <<EOF
1412
- Note: if the OAuth client is not for a native application, there will be an \
1415
+ Note:
1416
+ If the OAuth client is not for a native application, there will be an \
1413
1417
  "Error 400: redirect_uri_mismatch" shown up on the page. In this case, press \
1414
1418
  "Enter" to start again with a native application OAuth client ID.
1419
+ If there is no local web server serving at ${REDIRECT_URI}, the \
1420
+ succeeded OAuth flow will land the browser on an error page ("This site can't \
1421
+ be reached"). This is an expected behavior. Copy the whole URL and continue.
1422
+
1415
1423
  EOF
1416
- printf '%s' "4. Copy the authorization code from browser and paste here: "
1424
+ printf '%s' "4. Copy the authorization code or complete url from browser \
1425
+ and paste here: "
1417
1426
  read -r auth_code
1418
1427
  if [[ -z ${auth_code} ]]; then
1419
1428
  printf '%s\n\n' "No authorization code. Starting from beginning again..."
1420
1429
  continue
1421
1430
  fi
1431
+ auth_code=$(printf "%s" "${auth_code}" | sed 's/^.*code=//;s/&.*//')
1432
+ printf '%s\n' "Got authorization code: ${auth_code}"
1422
1433
  auth_response=$(curl -s -d "code=${auth_code}" -d "client_id=${client_id}" \
1423
- -d "grant_type=authorization_code" -d "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
1434
+ -d "grant_type=authorization_code" -d "redirect_uri=${REDIRECT_URI}" \
1424
1435
  -d "client_secret=${client_secret}" "${OAUTH_BASE_URL}token")
1425
1436
  auth_error=$(node -e "console.log(!!JSON.parse(process.argv[1]).error)" \
1426
1437
  "${auth_response}")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@google-cloud/nodejs-common",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A NodeJs common library for solutions based on Cloud Functions",
5
5
  "author": "Google Inc.",
6
6
  "license": "Apache-2.0",
@@ -80,6 +80,13 @@ const IDENTIFIERS = [
80
80
  'address_info',
81
81
  ];
82
82
 
83
+ /**
84
+ * Maximum number of user identifiers in single UserData.
85
+ * @see https://ads-developers.googleblog.com/2021/10/userdata-enforcement-in-google-ads-api.html
86
+ * @type {number}
87
+ */
88
+ const MAX_IDENTIFIERS_PER_USER = 20;
89
+
83
90
  /**
84
91
  * Configuration for uploading click conversions for Google Ads, includes:
85
92
  * gclid, conversion_action, conversion_date_time, conversion_value,
@@ -111,43 +118,34 @@ const IDENTIFIERS = [
111
118
  * order_id: (string|undefined),
112
119
  * user_identifier_source:(UserIdentifierSource|undefined),
113
120
  * custom_variable_tags:(!Array<string>|undefined),
114
- * customVariables:(!object<string,string>|undefined),
121
+ * customVariables:(!Object<string,string>|undefined),
115
122
  * }}
116
123
  */
117
124
  let ClickConversionConfig;
118
125
 
119
126
  /**
120
127
  * Configuration for uploading customer match to Google Ads, includes:
121
- * customer_id, login_customer_id, list_id, list_type and operation
122
- * list_type must be one of the following: hashed_email,
123
- * hashed_phone_number, mobile_id, third_party_user_id or address_info;
128
+ * customer_id, login_customer_id, list_id and operation.
124
129
  * operation must be one of the two: 'create' or 'remove';
125
130
  * @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserDataOperation
126
131
  * @typedef {{
127
132
  * customer_id: string,
128
133
  * login_customer_id: string,
129
134
  * list_id: string,
130
- * list_type: 'hashed_email'|'hashed_phone_number'|'mobile_id'|
131
- * 'third_party_user_id'|'address_info',
132
135
  * operation: 'create'|'remove',
133
136
  * }}
134
137
  */
135
138
  let CustomerMatchConfig;
136
139
 
137
140
  /**
138
- * Configuration for uploading customer match data for Google Ads, includes one of:
139
- * hashed_email, hashed_phone_number, mobile_id, third_party_user_id or address_info
141
+ * Configuration for uploading customer match data for Google Ads.
140
142
  * @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier
141
143
  * @typedef {{
142
- * hashed_email: string,
143
- * }|{
144
- * hashed_phone_number: string,
145
- * }|{
146
- * mobile_id: string,
147
- * }|{
148
- * third_party_user_id: string,
149
- * }|{
150
- * address_info: GoogleAdsApi.OfflineUserAddressInfo,
144
+ * hashed_email: (string|Array<string>|undefined),
145
+ * hashed_phone_number: (string|Array<string>|undefined),
146
+ * mobile_id: (string|Array<string>|undefined),
147
+ * third_party_user_id: (string|Array<string>|undefined),
148
+ * address_info: (GoogleAdsApi.OfflineUserAddressInfo|undefined),
151
149
  * }}
152
150
  */
153
151
  let CustomerMatchRecord;
@@ -530,18 +528,17 @@ class GoogleAds {
530
528
  const customerId = customerMatchConfig.customer_id.replace(/-/g, '');
531
529
  const loginCustomerId = customerMatchConfig.login_customer_id.replace(/-/g,
532
530
  '');
533
- const userListType = customerMatchConfig.list_type;
534
531
  const userListId = customerMatchConfig.list_id;
535
532
  const operation = customerMatchConfig.operation;
536
533
 
537
534
  const customer = this.getGoogleAdsApiCustomer_(loginCustomerId, customerId);
538
535
  const operationsList = this.buildOperationsList_(operation,
539
- customerMatchRecords, userListType);
536
+ customerMatchRecords);
540
537
  const metadata = this.buildCustomerMatchUserListMetadata_(customerId,
541
538
  userListId);
542
539
  const request = UploadUserDataRequest.create({
543
540
  customer_id: customerId,
544
- operations: [operationsList],
541
+ operations: operationsList,
545
542
  customer_match_user_list_metadata: metadata,
546
543
  });
547
544
  const response = await customer.userData.uploadUserData(request);
@@ -556,18 +553,36 @@ class GoogleAds {
556
553
  * @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserDataOperation
557
554
  * @param {string} operationType either 'create' or 'remove'
558
555
  * @param {Array<CustomerMatchRecord>} customerMatchRecords userIds
559
- * @param {string} userListType One of the following hashed_email, hashed_phone_number,
560
- * mobile_id, third_party_user_id or address_info
561
556
  * @return {Array<UserDataOperation>}
562
557
  * @private
563
558
  */
564
- buildOperationsList_(operationType, customerMatchRecords, userListType) {
565
- const userIdentifiers = customerMatchRecords.map((customerMatchRecord) => {
566
- return UserIdentifier.create(
567
- {[userListType]: customerMatchRecord[userListType]});
559
+ buildOperationsList_(operationType, customerMatchRecords) {
560
+ return customerMatchRecords.map((customerMatchRecord) => {
561
+ const userIdentifiers = [];
562
+ IDENTIFIERS.forEach((idType) => {
563
+ const idValue = customerMatchRecord[idType];
564
+ if (idValue) {
565
+ if (Array.isArray(idValue)) {
566
+ idValue.forEach((user) => {
567
+ userIdentifiers.push(UserIdentifier.create({[idType]: user}));
568
+ });
569
+ } else {
570
+ userIdentifiers.push(UserIdentifier.create({[idType]: idValue}));
571
+ }
572
+ }
573
+ });
574
+ let userData;
575
+ if (userIdentifiers.length <= MAX_IDENTIFIERS_PER_USER) {
576
+ userData = UserData.create({user_identifiers: userIdentifiers});
577
+ } else {
578
+ this.logger.warn(
579
+ `Too many user identifiers, will only send ${MAX_IDENTIFIERS_PER_USER}:`,
580
+ JSON.stringify(customerMatchRecord));
581
+ userData = UserData.create({user_identifiers: userIdentifiers}.slice(0,
582
+ MAX_IDENTIFIERS_PER_USER));
583
+ }
584
+ return UserDataOperation.create({[operationType]: userData});
568
585
  });
569
- const userData = UserData.create({user_identifiers: userIdentifiers});
570
- return UserDataOperation.create({[operationType]: userData});
571
586
  }
572
587
 
573
588
  /**