@google-cloud/nodejs-common 0.9.9-alpha → 1.0.3-alpha
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.
- package/bin/install_functions.sh +80 -21
- package/package.json +1 -1
- package/src/apis/google_ads.js +40 -20
- package/src/apis/index.js +1 -1
package/bin/install_functions.sh
CHANGED
|
@@ -443,7 +443,7 @@ select_functions_location() {
|
|
|
443
443
|
"name~${PROJECT_NAMESPACE}" --format="csv[no-heading](name,REGION)"))
|
|
444
444
|
if [[ ${#exist_functions[@]} -gt 0 ]]; then
|
|
445
445
|
local exist_region
|
|
446
|
-
exist_region=$(printf "${exist_functions[0]}" | cut -d
|
|
446
|
+
exist_region=$(printf "${exist_functions[0]}" | cut -d\, -f2 | uniq)
|
|
447
447
|
printf '%s\n' "Current application has already been installed in region: \
|
|
448
448
|
${exist_region}."
|
|
449
449
|
local i
|
|
@@ -466,9 +466,9 @@ Functions for that region. Do you want to continue? [N/y]: "
|
|
|
466
466
|
if [[ ${confirm_delete} == "Y" || ${confirm_delete} == "y" ]]; then
|
|
467
467
|
for i in "${!exist_functions[@]}"; do
|
|
468
468
|
local exist_function
|
|
469
|
-
exist_function=$(printf "${exist_functions[$i]}" | cut -d
|
|
469
|
+
exist_function=$(printf "${exist_functions[$i]}" | cut -d\, -f1)
|
|
470
470
|
local function_region
|
|
471
|
-
function_region=$(printf "${exist_functions[$i]}" | cut -d
|
|
471
|
+
function_region=$(printf "${exist_functions[$i]}" | cut -d\, -f2)
|
|
472
472
|
gcloud functions delete --region="${function_region}" \
|
|
473
473
|
"${exist_function}"
|
|
474
474
|
done
|
|
@@ -1818,31 +1818,66 @@ get_cloud_functions_service_account() {
|
|
|
1818
1818
|
}
|
|
1819
1819
|
|
|
1820
1820
|
#######################################
|
|
1821
|
-
# Make sure Firestore
|
|
1822
|
-
#
|
|
1823
|
-
#
|
|
1824
|
-
# datastore.locations.list - sample role: Cloud Datastore Owner
|
|
1825
|
-
# servicemanagement.services.bind - sample role: Editor
|
|
1821
|
+
# Make sure the Firestore database is in the current project. If there is no
|
|
1822
|
+
# Firestore datastore, it will help to create one.
|
|
1823
|
+
# To create the Firestore, the operator need to be the Owner.
|
|
1826
1824
|
# Globals:
|
|
1827
1825
|
# GCP_PROJECT
|
|
1828
1826
|
# Arguments:
|
|
1829
|
-
#
|
|
1827
|
+
# Firestore mode, 'native' or 'datastore'.
|
|
1828
|
+
# Firestore region, it's not the same list as Cloud Functions regions and it
|
|
1829
|
+
# will be bonded to this Cloud project after created.
|
|
1830
1830
|
#######################################
|
|
1831
1831
|
check_firestore_existence() {
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1832
|
+
local firestore mode appRegion
|
|
1833
|
+
mode="${1}"
|
|
1834
|
+
appRegion="${2}"
|
|
1835
|
+
firestore=$(gcloud app describe --format="csv[no-heading](databaseType)")
|
|
1836
|
+
if [[ -z "${firestore}" ]]; then
|
|
1837
|
+
printf '%s\n' "Firestore is not ready. Creating a new Firestore database\
|
|
1838
|
+
is an irreversible operation, so read carefully before continue:"
|
|
1839
|
+
printf '%s\n' " 1. You need to be the owner of ${GCP_PROJECT} to continue."
|
|
1840
|
+
printf '%s\n' " 2. Once you select the region and mode, you cannot change it."
|
|
1841
|
+
printf '%s\n' "Press any key to continue..."
|
|
1841
1842
|
local any
|
|
1842
1843
|
read -n1 -s any
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1844
|
+
if [[ -z "${mode}" ]]; then
|
|
1845
|
+
printf '%s\n' " For more information about mode, see \
|
|
1846
|
+
https://cloud.google.com/firestore/docs/firestore-or-datastore#choosing_a_database_mode"
|
|
1847
|
+
fi
|
|
1848
|
+
while [[ -z "${mode}" ]]; do
|
|
1849
|
+
printf '%s' " Enter the mode of your dataset [Native]: "
|
|
1850
|
+
local selectMode
|
|
1851
|
+
read -r selectMode
|
|
1852
|
+
selectMode=$(printf '%s' "${selectMode:-"Native"}" | \
|
|
1853
|
+
tr '[:upper:]' '[:lower:]')
|
|
1854
|
+
if [[ ${selectMode} == 'native' || ${selectMode} == 'datastore' ]]; then
|
|
1855
|
+
mode=${selectMode}
|
|
1856
|
+
fi
|
|
1857
|
+
done
|
|
1858
|
+
printf '%s\n' "Creating Firestore database in ${mode} mode..."
|
|
1859
|
+
gcloud app create --region=${appRegion}
|
|
1860
|
+
if [[ $? -eq 0 ]]; then
|
|
1861
|
+
if [[ "${mode}" == "native" ]]; then
|
|
1862
|
+
appRegion=$(gcloud app describe --format="csv[no-heading](locationId)")
|
|
1863
|
+
gcloud firestore databases create --region="${appRegion}"
|
|
1864
|
+
fi
|
|
1865
|
+
else
|
|
1866
|
+
return 1
|
|
1867
|
+
fi
|
|
1868
|
+
else
|
|
1869
|
+
printf '%s\n' "OK. Firestore is ready in mode ${firestore}."
|
|
1870
|
+
fi
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
#######################################
|
|
1874
|
+
# Installation step for confirming Firestore is ready.
|
|
1875
|
+
# See function check_firestore_existence.
|
|
1876
|
+
#######################################
|
|
1877
|
+
confirm_firestore() {
|
|
1878
|
+
(( STEP += 1 ))
|
|
1879
|
+
printf '%s\n' "Step ${STEP}: Checking the status of Firestore..."
|
|
1880
|
+
check_firestore_existence "$@"
|
|
1846
1881
|
}
|
|
1847
1882
|
|
|
1848
1883
|
#######################################
|
|
@@ -1875,3 +1910,27 @@ join_string_array() {
|
|
|
1875
1910
|
shift
|
|
1876
1911
|
printf %s "$first" "${@/#/$separator}"
|
|
1877
1912
|
}
|
|
1913
|
+
|
|
1914
|
+
#######################################
|
|
1915
|
+
# Creates or updates the BigQuery view.
|
|
1916
|
+
# Globals:
|
|
1917
|
+
# GCP_PROJECT
|
|
1918
|
+
# DATASET
|
|
1919
|
+
# Arguments:
|
|
1920
|
+
# The name of view.
|
|
1921
|
+
# The query of view.
|
|
1922
|
+
#######################################
|
|
1923
|
+
create_or_update_view() {
|
|
1924
|
+
local viewName viewQuery
|
|
1925
|
+
viewName="${1}"
|
|
1926
|
+
viewQuery="${2}"
|
|
1927
|
+
local action="mk"
|
|
1928
|
+
if [[ $(check_existence_in_bigquery "${DATASET}.${viewName}") -eq 0 ]]; then
|
|
1929
|
+
action="update"
|
|
1930
|
+
fi
|
|
1931
|
+
bq "${action}" \
|
|
1932
|
+
--use_legacy_sql=false \
|
|
1933
|
+
--view "${viewQuery}" \
|
|
1934
|
+
--project_id ${GCP_PROJECT} \
|
|
1935
|
+
"${DATASET}.${viewName}"
|
|
1936
|
+
}
|
package/package.json
CHANGED
package/src/apis/google_ads.js
CHANGED
|
@@ -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,
|
|
@@ -139,15 +146,11 @@ let CustomerMatchConfig;
|
|
|
139
146
|
* hashed_email, hashed_phone_number, mobile_id, third_party_user_id or address_info
|
|
140
147
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier
|
|
141
148
|
* @typedef {{
|
|
142
|
-
* hashed_email: string,
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* }|{
|
|
148
|
-
* third_party_user_id: string,
|
|
149
|
-
* }|{
|
|
150
|
-
* address_info: GoogleAdsApi.OfflineUserAddressInfo,
|
|
149
|
+
* hashed_email: (string|Array<string>|undefined),
|
|
150
|
+
* hashed_phone_number: (string|Array<string>|undefined),
|
|
151
|
+
* mobile_id: (string|Array<string>|undefined),
|
|
152
|
+
* third_party_user_id: (string|Array<string>|undefined),
|
|
153
|
+
* address_info: (GoogleAdsApi.OfflineUserAddressInfo|undefined),
|
|
151
154
|
* }}
|
|
152
155
|
*/
|
|
153
156
|
let CustomerMatchRecord;
|
|
@@ -530,18 +533,17 @@ class GoogleAds {
|
|
|
530
533
|
const customerId = customerMatchConfig.customer_id.replace(/-/g, '');
|
|
531
534
|
const loginCustomerId = customerMatchConfig.login_customer_id.replace(/-/g,
|
|
532
535
|
'');
|
|
533
|
-
const userListType = customerMatchConfig.list_type;
|
|
534
536
|
const userListId = customerMatchConfig.list_id;
|
|
535
537
|
const operation = customerMatchConfig.operation;
|
|
536
538
|
|
|
537
539
|
const customer = this.getGoogleAdsApiCustomer_(loginCustomerId, customerId);
|
|
538
540
|
const operationsList = this.buildOperationsList_(operation,
|
|
539
|
-
customerMatchRecords
|
|
541
|
+
customerMatchRecords);
|
|
540
542
|
const metadata = this.buildCustomerMatchUserListMetadata_(customerId,
|
|
541
543
|
userListId);
|
|
542
544
|
const request = UploadUserDataRequest.create({
|
|
543
545
|
customer_id: customerId,
|
|
544
|
-
operations:
|
|
546
|
+
operations: operationsList,
|
|
545
547
|
customer_match_user_list_metadata: metadata,
|
|
546
548
|
});
|
|
547
549
|
const response = await customer.userData.uploadUserData(request);
|
|
@@ -556,18 +558,36 @@ class GoogleAds {
|
|
|
556
558
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/UserDataOperation
|
|
557
559
|
* @param {string} operationType either 'create' or 'remove'
|
|
558
560
|
* @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
561
|
* @return {Array<UserDataOperation>}
|
|
562
562
|
* @private
|
|
563
563
|
*/
|
|
564
|
-
buildOperationsList_(operationType, customerMatchRecords
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
564
|
+
buildOperationsList_(operationType, customerMatchRecords) {
|
|
565
|
+
return customerMatchRecords.map((customerMatchRecord) => {
|
|
566
|
+
const userIdentifiers = [];
|
|
567
|
+
IDENTIFIERS.forEach((idType) => {
|
|
568
|
+
const idValue = customerMatchRecord[idType];
|
|
569
|
+
if (idValue) {
|
|
570
|
+
if (Array.isArray(idValue)) {
|
|
571
|
+
idValue.forEach((user) => {
|
|
572
|
+
userIdentifiers.push(UserIdentifier.create({[idType]: user}));
|
|
573
|
+
});
|
|
574
|
+
} else {
|
|
575
|
+
userIdentifiers.push(UserIdentifier.create({[idType]: idValue}));
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
let userData;
|
|
580
|
+
if (userIdentifiers.length <= MAX_IDENTIFIERS_PER_USER) {
|
|
581
|
+
userData = UserData.create({user_identifiers: userIdentifiers});
|
|
582
|
+
} else {
|
|
583
|
+
this.logger.warn(
|
|
584
|
+
`Too many user identifiers, will only send ${MAX_IDENTIFIERS_PER_USER}:`,
|
|
585
|
+
JSON.stringify(customerMatchRecord));
|
|
586
|
+
userData = UserData.create({user_identifiers: userIdentifiers}.slice(0,
|
|
587
|
+
MAX_IDENTIFIERS_PER_USER));
|
|
588
|
+
}
|
|
589
|
+
return UserDataOperation.create({[operationType]: userData});
|
|
568
590
|
});
|
|
569
|
-
const userData = UserData.create({user_identifiers: userIdentifiers});
|
|
570
|
-
return UserDataOperation.create({[operationType]: userData});
|
|
571
591
|
}
|
|
572
592
|
|
|
573
593
|
/**
|
package/src/apis/index.js
CHANGED
|
@@ -88,7 +88,7 @@ exports.bigquery = require('./bigquery.js');
|
|
|
88
88
|
* APIs integration class for Google Ads.
|
|
89
89
|
* @const {{
|
|
90
90
|
* GoogleAds:!GoogleAds,
|
|
91
|
-
*
|
|
91
|
+
* ConversionConfig:!ConversionConfig,
|
|
92
92
|
* CustomerMatchConfig: !CustomerMatchConfig,
|
|
93
93
|
* CustomerMatchRecord: !CustomerMatchRecord,
|
|
94
94
|
* ReportQueryConfig:!ReportQueryConfig,
|