@google-cloud/nodejs-common 2.1.0 → 2.2.0
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 +1 -0
- package/package.json +14 -14
- package/src/apis/analytics.js +17 -21
- package/src/apis/base/ads_api_common.js +2 -19
- package/src/apis/base/google_api_client.js +55 -0
- package/src/apis/dfa_reporting.js +17 -33
- package/src/apis/display_video.js +11 -42
- package/src/apis/doubleclick_bidmanager.js +34 -42
- package/src/apis/doubleclick_search.js +17 -33
- package/src/apis/google_ads_api.js +2 -2
- package/src/apis/index.js +0 -1
- package/src/apis/search_ads.js +23 -23
- package/src/apis/spreadsheets.js +16 -23
- package/src/apis/youtube.js +18 -26
- package/src/components/firestore/datastore_mode_access.js +4 -3
- package/src/components/utils.js +22 -4
package/bin/install_functions.sh
CHANGED
|
@@ -1560,6 +1560,7 @@ set_cloud_functions_default_settings() {
|
|
|
1560
1560
|
default_cf_flag+=(--set-env-vars=DEBUG="${DEBUG}")
|
|
1561
1561
|
default_cf_flag+=(--set-env-vars=IN_GCP="${IN_GCP}")
|
|
1562
1562
|
default_cf_flag+=(--set-env-vars=DATABASE_ID="${DATABASE_ID}")
|
|
1563
|
+
default_cf_flag+=(--set-env-vars=DATABASE_MODE="${DATABASE_MODE}")
|
|
1563
1564
|
}
|
|
1564
1565
|
|
|
1565
1566
|
#######################################
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@google-cloud/nodejs-common",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "A NodeJs common library for solutions based on Cloud Functions",
|
|
5
5
|
"author": "Google Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -16,24 +16,24 @@
|
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://github.com/GoogleCloudPlatform/cloud-for-marketing/blob/master/marketing-analytics/activation/common-libs/nodejs-common/README.md",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@google-cloud/aiplatform": "^3.
|
|
19
|
+
"@google-cloud/aiplatform": "^3.17.0",
|
|
20
20
|
"@google-cloud/automl": "^4.0.1",
|
|
21
|
-
"@google-cloud/bigquery": "^7.
|
|
22
|
-
"@google-cloud/datastore": "^8.
|
|
23
|
-
"@google-cloud/firestore": "^7.
|
|
21
|
+
"@google-cloud/bigquery": "^7.5.2",
|
|
22
|
+
"@google-cloud/datastore": "^8.6.0",
|
|
23
|
+
"@google-cloud/firestore": "^7.5.0",
|
|
24
24
|
"@google-cloud/logging-winston": "^6.0.0",
|
|
25
|
-
"@google-cloud/pubsub": "^4.
|
|
26
|
-
"@google-cloud/storage": "^7.
|
|
27
|
-
"@google-cloud/scheduler": "^4.0
|
|
28
|
-
"@google-cloud/secret-manager": "^5.0
|
|
29
|
-
"gaxios": "^6.
|
|
25
|
+
"@google-cloud/pubsub": "^4.3.3",
|
|
26
|
+
"@google-cloud/storage": "^7.9.0",
|
|
27
|
+
"@google-cloud/scheduler": "^4.1.0",
|
|
28
|
+
"@google-cloud/secret-manager": "^5.2.0",
|
|
29
|
+
"gaxios": "^6.3.0",
|
|
30
30
|
"google-ads-nodejs-client": "16.0.0",
|
|
31
31
|
"google-ads-api": "^14.1.0",
|
|
32
32
|
"google-ads-node": "^12.0.2",
|
|
33
|
-
"google-auth-library": "^9.
|
|
34
|
-
"googleapis": "^
|
|
35
|
-
"winston": "^3.
|
|
36
|
-
"@grpc/grpc-js": "1.
|
|
33
|
+
"google-auth-library": "^9.7.0",
|
|
34
|
+
"googleapis": "^134.0.0",
|
|
35
|
+
"winston": "^3.13.0",
|
|
36
|
+
"@grpc/grpc-js": "^1.10.5",
|
|
37
37
|
"lodash": "^4.17.21"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
package/src/apis/analytics.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
const stream = require('stream');
|
|
23
23
|
const {google} = require('googleapis');
|
|
24
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
24
25
|
const {Schema$Upload} = google.analytics;
|
|
25
26
|
const AuthClient = require('./auth_client.js');
|
|
26
27
|
const {wait, getLogger, BatchResult} = require('../components/utils.js');
|
|
@@ -55,31 +56,26 @@ let DataImportClearConfig;
|
|
|
55
56
|
/**
|
|
56
57
|
* Google Analytics API v3 stub.
|
|
57
58
|
*/
|
|
58
|
-
class Analytics {
|
|
59
|
+
class Analytics extends GoogleApiClient {
|
|
59
60
|
/**
|
|
60
61
|
* @constructor
|
|
61
62
|
* @param {!Object<string,string>=} env The environment object to hold env
|
|
62
63
|
* variables.
|
|
63
64
|
*/
|
|
64
65
|
constructor(env = process.env) {
|
|
65
|
-
|
|
66
|
+
super(env);
|
|
67
|
+
this.googleApi = 'analytics';
|
|
66
68
|
this.logger = getLogger('API.GA');
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
78
|
-
this.analytics = google.analytics({
|
|
79
|
-
version: API_VERSION,
|
|
80
|
-
auth: this.authClient.getDefaultAuth(),
|
|
81
|
-
});
|
|
82
|
-
return this.analytics;
|
|
71
|
+
/** @override */
|
|
72
|
+
getScope() {
|
|
73
|
+
return API_SCOPES;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @override */
|
|
77
|
+
getVersion() {
|
|
78
|
+
return API_VERSION;
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
/**
|
|
@@ -102,7 +98,7 @@ class Analytics {
|
|
|
102
98
|
},
|
|
103
99
|
config);
|
|
104
100
|
|
|
105
|
-
const analytics = await this.
|
|
101
|
+
const analytics = await this.getApiClient();
|
|
106
102
|
const response = await analytics.management.uploads.uploadData(
|
|
107
103
|
uploadConfig);
|
|
108
104
|
this.logger.debug('Configuration: ', config);
|
|
@@ -151,7 +147,7 @@ class Analytics {
|
|
|
151
147
|
* @return {!Promise<!Schema$Upload>} Updated data import Job status.
|
|
152
148
|
*/
|
|
153
149
|
async checkJobStatus(jobConfig) {
|
|
154
|
-
const analytics = await this.
|
|
150
|
+
const analytics = await this.getApiClient();
|
|
155
151
|
const { data: job } = await analytics.management.uploads.get(jobConfig);
|
|
156
152
|
if (job.status !== 'PENDING') return job;
|
|
157
153
|
this.logger.debug(
|
|
@@ -169,7 +165,7 @@ class Analytics {
|
|
|
169
165
|
* @return {!Promise<!Array<string>>}
|
|
170
166
|
*/
|
|
171
167
|
async listAccounts() {
|
|
172
|
-
const analytics = await this.
|
|
168
|
+
const analytics = await this.getApiClient();
|
|
173
169
|
const response = await analytics.management.accounts.list();
|
|
174
170
|
return response.data.items.map(
|
|
175
171
|
(account) => `Account id: ${account.name}[${account.id}]`
|
|
@@ -182,7 +178,7 @@ class Analytics {
|
|
|
182
178
|
* @return {!Promise<!Array<Object>>}
|
|
183
179
|
*/
|
|
184
180
|
async listUploads(config) {
|
|
185
|
-
const analytics = await this.
|
|
181
|
+
const analytics = await this.getApiClient();
|
|
186
182
|
const response = await analytics.management.uploads.list(config);
|
|
187
183
|
return response.data.items;
|
|
188
184
|
}
|
|
@@ -203,7 +199,7 @@ class Analytics {
|
|
|
203
199
|
const request = Object.assign({}, config, {
|
|
204
200
|
resource: {customDataImportUids},
|
|
205
201
|
});
|
|
206
|
-
const analytics = await this.
|
|
202
|
+
const analytics = await this.getApiClient();
|
|
207
203
|
await analytics.management.uploads.deleteUploadData(request);
|
|
208
204
|
this.logger.debug('Delete uploads: ', customDataImportUids);
|
|
209
205
|
}
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
const { Transform } = require('stream');
|
|
21
21
|
const {
|
|
22
|
-
|
|
23
|
-
changeObjectNamingFromLowerCamelToSnake,
|
|
22
|
+
getFilterAndStringifyFn,
|
|
24
23
|
getLogger,
|
|
25
24
|
} = require('../../components/utils.js');
|
|
26
25
|
|
|
@@ -37,22 +36,6 @@ const START_TAG = '"results":';
|
|
|
37
36
|
const FIELD_MASK_TAG = '"fieldMask"';
|
|
38
37
|
const END_TAG = '"requestId"';
|
|
39
38
|
|
|
40
|
-
/**
|
|
41
|
-
* Generates a function that can convert a given JSON object to a JSON string
|
|
42
|
-
* with only specified fields(fieldMask), in specified naming convention.
|
|
43
|
-
* @param {string} fieldMask The 'fieldMask' string from response.
|
|
44
|
-
* @param {boolean=} snakeCase Whether or not output JSON in snake naming.
|
|
45
|
-
*/
|
|
46
|
-
function generateProcessFn(fieldMask, snakeCase = false) {
|
|
47
|
-
const extractor = extractObject(fieldMask.split(','));
|
|
48
|
-
return (originalObject) => {
|
|
49
|
-
const extracted = extractor(originalObject);
|
|
50
|
-
const generatedObject = snakeCase
|
|
51
|
-
? changeObjectNamingFromLowerCamelToSnake(extracted) : extracted;
|
|
52
|
-
return JSON.stringify(generatedObject);
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
39
|
/**
|
|
57
40
|
* A stream.Transform that can extract properties and convert naming of the
|
|
58
41
|
* reponse of Google/Search Ads report from REST interface.
|
|
@@ -85,7 +68,7 @@ class RestSearchStreamTransform extends Transform {
|
|
|
85
68
|
.substring(maskIndex + FIELD_MASK_TAG.length, rawString.indexOf(END_TAG))
|
|
86
69
|
.split('"')[1];
|
|
87
70
|
this.logger.debug(`Got fieldMask: ${fieldMask}`);
|
|
88
|
-
this.processFn =
|
|
71
|
+
this.processFn = getFilterAndStringifyFn(fieldMask, this.snakeCase);
|
|
89
72
|
}
|
|
90
73
|
const resultsWithTailing = rawString.substring(startIndex, maskIndex);
|
|
91
74
|
const results = resultsWithTailing.substring(
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Copyright 2023 Google Inc.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @fileoverview A base class for Google Api client library class.
|
|
17
|
+
*/
|
|
18
|
+
const { google } = require('googleapis');
|
|
19
|
+
const { getLogger, getObjectByPath } = require('../../components/utils.js');
|
|
20
|
+
const { AuthRestfulApi } = require('./auth_restful_api.js');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A Google Api client library class.
|
|
24
|
+
*/
|
|
25
|
+
class GoogleApiClient extends AuthRestfulApi {
|
|
26
|
+
|
|
27
|
+
/** @constructor */
|
|
28
|
+
constructor(env = process.env, options = {}) {
|
|
29
|
+
super(env, options);
|
|
30
|
+
this.logger = getLogger('API.default');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns the Api version of the Api in the current library.
|
|
35
|
+
* @return {string}
|
|
36
|
+
* @abstract
|
|
37
|
+
*/
|
|
38
|
+
getVersion() { }
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns the Api instance.
|
|
42
|
+
* @return {!Promise<object>} The Api instance.
|
|
43
|
+
*/
|
|
44
|
+
async getApiClient() {
|
|
45
|
+
if (this.apiClient) return this.apiClient;
|
|
46
|
+
this.logger.info(`Initialized ${this.constructor.name} instance.`);
|
|
47
|
+
this.apiClient = google[this.googleApi]({
|
|
48
|
+
version: this.getVersion(),
|
|
49
|
+
auth: await this.getAuth(),
|
|
50
|
+
});
|
|
51
|
+
return this.apiClient;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = { GoogleApiClient };
|
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
const {
|
|
23
|
-
const {
|
|
24
|
-
const AuthClient = require('./auth_client.js');
|
|
22
|
+
const { request } = require('gaxios');
|
|
23
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
25
24
|
const {
|
|
26
25
|
getLogger,
|
|
27
26
|
getFilterFunction,
|
|
@@ -94,7 +93,7 @@ const MAX_IDENTIFIERS_PER_USER = 5;
|
|
|
94
93
|
* Google DfaReport API v3.0 stub.
|
|
95
94
|
* see https://developers.google.com/doubleclick-advertisers/service_accounts
|
|
96
95
|
*/
|
|
97
|
-
class DfaReporting {
|
|
96
|
+
class DfaReporting extends GoogleApiClient {
|
|
98
97
|
|
|
99
98
|
/**
|
|
100
99
|
* @constructor
|
|
@@ -102,34 +101,19 @@ class DfaReporting {
|
|
|
102
101
|
* variables.
|
|
103
102
|
*/
|
|
104
103
|
constructor(env = process.env) {
|
|
105
|
-
|
|
104
|
+
super(env);
|
|
105
|
+
this.googleApi = 'dfareporting';
|
|
106
106
|
this.logger = getLogger('API.CM');
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* @private
|
|
113
|
-
*/
|
|
114
|
-
async getApiClient_() {
|
|
115
|
-
if (this.dfareporting) return this.dfareporting;
|
|
116
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
117
|
-
this.dfareporting = google.dfareporting({
|
|
118
|
-
version: API_VERSION,
|
|
119
|
-
auth: await this.getAuth_(),
|
|
120
|
-
});
|
|
121
|
-
return this.dfareporting;
|
|
109
|
+
/** @override */
|
|
110
|
+
getScope() {
|
|
111
|
+
return API_SCOPES;
|
|
122
112
|
}
|
|
123
113
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*/
|
|
128
|
-
async getAuth_() {
|
|
129
|
-
if (this.auth) return this.auth;
|
|
130
|
-
await this.authClient.prepareCredentials();
|
|
131
|
-
this.auth = this.authClient.getDefaultAuth();
|
|
132
|
-
return this.auth;
|
|
114
|
+
/** @override */
|
|
115
|
+
getVersion() {
|
|
116
|
+
return API_VERSION;
|
|
133
117
|
}
|
|
134
118
|
|
|
135
119
|
/**
|
|
@@ -140,7 +124,7 @@ class DfaReporting {
|
|
|
140
124
|
* @return {!Promise<string>}
|
|
141
125
|
*/
|
|
142
126
|
async getProfileId(accountId) {
|
|
143
|
-
const dfareporting = await this.
|
|
127
|
+
const dfareporting = await this.getApiClient();
|
|
144
128
|
const { data: { items } } = await dfareporting.userProfiles.list();
|
|
145
129
|
const profiles = items.filter(
|
|
146
130
|
(profile) => profile.accountId === accountId
|
|
@@ -237,7 +221,7 @@ class DfaReporting {
|
|
|
237
221
|
numberOfLines: lines.length,
|
|
238
222
|
};
|
|
239
223
|
try {
|
|
240
|
-
const dfareporting = await this.
|
|
224
|
+
const dfareporting = await this.getApiClient();
|
|
241
225
|
const response = await dfareporting.conversions[operation]({
|
|
242
226
|
profileId: config.profileId,
|
|
243
227
|
requestBody: requestBody,
|
|
@@ -304,7 +288,7 @@ class DfaReporting {
|
|
|
304
288
|
* @return {!Promise<!Array<string>>}
|
|
305
289
|
*/
|
|
306
290
|
async listUserProfiles() {
|
|
307
|
-
const dfareporting = await this.
|
|
291
|
+
const dfareporting = await this.getApiClient();
|
|
308
292
|
const { data: { items } } = await dfareporting.userProfiles.list();
|
|
309
293
|
return items.map(({profileId, userName, accountId, accountName}) => {
|
|
310
294
|
return `Profile: ${profileId}[${userName}] `
|
|
@@ -349,7 +333,7 @@ class DfaReporting {
|
|
|
349
333
|
*/
|
|
350
334
|
async runReport(config) {
|
|
351
335
|
const profileId = await this.getProfileForOperation_(config);
|
|
352
|
-
const dfareporting = await this.
|
|
336
|
+
const dfareporting = await this.getApiClient();
|
|
353
337
|
const { startDate, endDate } = config;
|
|
354
338
|
if (startDate && endDate) {
|
|
355
339
|
const { data: report } = await dfareporting.reports.get({
|
|
@@ -392,7 +376,7 @@ class DfaReporting {
|
|
|
392
376
|
*/
|
|
393
377
|
async getReportFileUrl(config) {
|
|
394
378
|
const profileId = await this.getProfileForOperation_(config);
|
|
395
|
-
const dfareporting = await this.
|
|
379
|
+
const dfareporting = await this.getApiClient();
|
|
396
380
|
const response = await dfareporting.reports.files.get({
|
|
397
381
|
profileId,
|
|
398
382
|
reportId: config.reportId,
|
|
@@ -410,7 +394,7 @@ class DfaReporting {
|
|
|
410
394
|
* @return {!Promise<stream>}
|
|
411
395
|
*/
|
|
412
396
|
async getReportFileStream(url) {
|
|
413
|
-
const auth = await this.
|
|
397
|
+
const auth = await this.getAuth();
|
|
414
398
|
const headers = await auth.getRequestHeaders();
|
|
415
399
|
const response = await request({
|
|
416
400
|
method: 'GET',
|
|
@@ -19,14 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
const {
|
|
23
|
-
const
|
|
24
|
-
const {
|
|
25
|
-
getLogger,
|
|
26
|
-
getObjectByPath,
|
|
27
|
-
SendSingleBatch,
|
|
28
|
-
BatchResult,
|
|
29
|
-
} = require('../components/utils.js');
|
|
22
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
23
|
+
const { getLogger } = require('../components/utils.js');
|
|
30
24
|
|
|
31
25
|
const API_SCOPES = Object.freeze([
|
|
32
26
|
'https://www.googleapis.com/auth/display-video',
|
|
@@ -40,7 +34,7 @@ const API_VERSION = 'v3';
|
|
|
40
34
|
* Bid Manager API.
|
|
41
35
|
* @see https://developers.google.com/bid-manager/reference/rest
|
|
42
36
|
*/
|
|
43
|
-
class DisplayVideo {
|
|
37
|
+
class DisplayVideo extends GoogleApiClient {
|
|
44
38
|
|
|
45
39
|
/**
|
|
46
40
|
* @constructor
|
|
@@ -48,44 +42,19 @@ class DisplayVideo {
|
|
|
48
42
|
* variables.
|
|
49
43
|
*/
|
|
50
44
|
constructor(env = process.env) {
|
|
51
|
-
|
|
45
|
+
super(env);
|
|
46
|
+
this.googleApi = 'displayvideo';
|
|
52
47
|
this.logger = getLogger('API.DV3API');
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* @private
|
|
59
|
-
*/
|
|
60
|
-
async getApiClient_() {
|
|
61
|
-
if (this.displayvideo) return this.displayvideo;
|
|
62
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
63
|
-
this.displayvideo = google.displayvideo({
|
|
64
|
-
version: API_VERSION,
|
|
65
|
-
auth: await this.getAuth_(),
|
|
66
|
-
});
|
|
67
|
-
return this.displayvideo;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Gets the auth object.
|
|
72
|
-
* @return {!Promise<{!OAuth2Client|!JWT|!Compute}>}
|
|
73
|
-
*/
|
|
74
|
-
async getAuth_() {
|
|
75
|
-
if (this.auth) return this.auth;
|
|
76
|
-
await this.authClient.prepareCredentials();
|
|
77
|
-
this.auth = this.authClient.getDefaultAuth();
|
|
78
|
-
return this.auth;
|
|
50
|
+
/** @override */
|
|
51
|
+
getScope() {
|
|
52
|
+
return API_SCOPES;
|
|
79
53
|
}
|
|
80
54
|
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
* @return {Object}
|
|
85
|
-
*/
|
|
86
|
-
async getFunctionObject(path) {
|
|
87
|
-
const instance = await this.getApiClient_();
|
|
88
|
-
return getObjectByPath(instance, path);
|
|
55
|
+
/** @override */
|
|
56
|
+
getVersion() {
|
|
57
|
+
return API_VERSION;
|
|
89
58
|
}
|
|
90
59
|
|
|
91
60
|
}
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
const {
|
|
23
|
-
const AuthClient = require('./auth_client.js');
|
|
22
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
24
23
|
const { getLogger } = require('../components/utils.js');
|
|
25
24
|
|
|
26
25
|
const API_SCOPES = Object.freeze([
|
|
@@ -28,25 +27,24 @@ const API_SCOPES = Object.freeze([
|
|
|
28
27
|
]);
|
|
29
28
|
const API_VERSION = 'v2';
|
|
30
29
|
|
|
31
|
-
/**
|
|
32
|
-
* The returned information of get a query.
|
|
33
|
-
* @typedef {{
|
|
34
|
-
* running:boolean,
|
|
35
|
-
* latestReportRunTimeMs:string,
|
|
36
|
-
* googleCloudStoragePathForLatestReport:string,
|
|
37
|
-
* }}
|
|
38
|
-
*/
|
|
39
|
-
let QueryResource;
|
|
40
|
-
|
|
41
30
|
/**
|
|
42
31
|
* RequestBody controls the data range of reports.
|
|
43
32
|
* see:
|
|
44
|
-
* https://developers.google.com/bid-manager/
|
|
33
|
+
* https://developers.google.com/bid-manager/reference/rest/v2/queries/run#RunQueryRequest
|
|
45
34
|
* @typedef {{
|
|
46
|
-
* dataRange:
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
35
|
+
* dataRange: {
|
|
36
|
+
* range: Range,
|
|
37
|
+
* customStartDate: {
|
|
38
|
+
* year: integer,
|
|
39
|
+
* month: integer,
|
|
40
|
+
* day: integer,
|
|
41
|
+
* },
|
|
42
|
+
* customEndDate: {
|
|
43
|
+
* year: integer,
|
|
44
|
+
* month: integer,
|
|
45
|
+
* day: integer,
|
|
46
|
+
* },
|
|
47
|
+
* }
|
|
50
48
|
* }}
|
|
51
49
|
*/
|
|
52
50
|
let RequestBody;
|
|
@@ -56,31 +54,26 @@ let RequestBody;
|
|
|
56
54
|
* Note: DV360 report API only support OAuth 2.0, see:
|
|
57
55
|
* https://developers.google.com/bid-manager/how-tos/authorizing
|
|
58
56
|
*/
|
|
59
|
-
class DoubleClickBidManager {
|
|
57
|
+
class DoubleClickBidManager extends GoogleApiClient {
|
|
60
58
|
/**
|
|
61
59
|
* @constructor
|
|
62
60
|
* @param {!Object<string,string>=} env The environment object to hold env
|
|
63
61
|
* variables.
|
|
64
62
|
*/
|
|
65
63
|
constructor(env = process.env) {
|
|
66
|
-
|
|
64
|
+
super(env);
|
|
65
|
+
this.googleApi = 'doubleclickbidmanager';
|
|
67
66
|
this.logger = getLogger('API.DV3');
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
79
|
-
this.doubleclickbidmanager = google.doubleclickbidmanager({
|
|
80
|
-
version: API_VERSION,
|
|
81
|
-
auth: this.authClient.getDefaultAuth(),
|
|
82
|
-
});
|
|
83
|
-
return this.doubleclickbidmanager;
|
|
69
|
+
/** @override */
|
|
70
|
+
getScope() {
|
|
71
|
+
return API_SCOPES;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @override */
|
|
75
|
+
getVersion() {
|
|
76
|
+
return API_VERSION;
|
|
84
77
|
}
|
|
85
78
|
|
|
86
79
|
/**
|
|
@@ -91,21 +84,21 @@ class DoubleClickBidManager {
|
|
|
91
84
|
* @return {!Promise<number>} Report Id.
|
|
92
85
|
*/
|
|
93
86
|
async runQuery(queryId, requestBody = undefined) {
|
|
94
|
-
const doubleclickbidmanager = await this.
|
|
87
|
+
const doubleclickbidmanager = await this.getApiClient();
|
|
95
88
|
const response = await doubleclickbidmanager.queries.run(
|
|
96
89
|
{queryId, requestBody});
|
|
97
90
|
return response.data.key.reportId;
|
|
98
91
|
}
|
|
99
92
|
|
|
100
93
|
/**
|
|
101
|
-
* Gets a query
|
|
94
|
+
* Gets a query metadata.
|
|
102
95
|
* See https://developers.google.com/bid-manager/reference/rest/v2/queries/get
|
|
103
96
|
* @param {number} queryId Id of the query.
|
|
104
|
-
* @return {!Promise<!
|
|
105
|
-
* https://developers.google.com/bid-manager/reference/rest/v2/queries#
|
|
97
|
+
* @return {!Promise<!QueryMetadata>} Query metadata, see
|
|
98
|
+
* https://developers.google.com/bid-manager/reference/rest/v2/queries#QueryMetadata
|
|
106
99
|
*/
|
|
107
100
|
async getQuery(queryId) {
|
|
108
|
-
const doubleclickbidmanager = await this.
|
|
101
|
+
const doubleclickbidmanager = await this.getApiClient();
|
|
109
102
|
const response = await doubleclickbidmanager.queries.get({ queryId });
|
|
110
103
|
return response.data.metadata;
|
|
111
104
|
}
|
|
@@ -117,14 +110,14 @@ class DoubleClickBidManager {
|
|
|
117
110
|
* @return {!Promise<number>} Id of created query.
|
|
118
111
|
*/
|
|
119
112
|
async createQuery(query) {
|
|
120
|
-
const doubleclickbidmanager = await this.
|
|
113
|
+
const doubleclickbidmanager = await this.getApiClient();
|
|
121
114
|
const response = await doubleclickbidmanager.queries.create(
|
|
122
115
|
{requestBody: query});
|
|
123
116
|
return response.data.queryId;
|
|
124
117
|
}
|
|
125
118
|
|
|
126
119
|
async getQueryReport(queryId, reportId) {
|
|
127
|
-
const doubleclickbidmanager = await this.
|
|
120
|
+
const doubleclickbidmanager = await this.getApiClient();
|
|
128
121
|
const response = await doubleclickbidmanager.queries.reports.get(
|
|
129
122
|
{ queryId, reportId });
|
|
130
123
|
return response.data.metadata;
|
|
@@ -136,7 +129,7 @@ class DoubleClickBidManager {
|
|
|
136
129
|
* @return {!Promise<boolean>} Whether the query was deleted.
|
|
137
130
|
*/
|
|
138
131
|
async deleteQuery(queryId) {
|
|
139
|
-
const doubleclickbidmanager = await this.
|
|
132
|
+
const doubleclickbidmanager = await this.getApiClient();
|
|
140
133
|
try {
|
|
141
134
|
const { status } = await doubleclickbidmanager.queries.delete({ queryId });
|
|
142
135
|
return status === 200;
|
|
@@ -148,7 +141,6 @@ class DoubleClickBidManager {
|
|
|
148
141
|
}
|
|
149
142
|
|
|
150
143
|
module.exports = {
|
|
151
|
-
QueryResource,
|
|
152
144
|
RequestBody,
|
|
153
145
|
DoubleClickBidManager,
|
|
154
146
|
};
|
|
@@ -19,9 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict';
|
|
21
21
|
|
|
22
|
-
const {google} = require('googleapis');
|
|
23
22
|
const {request} = require('gaxios');
|
|
24
|
-
const
|
|
23
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
25
24
|
const {
|
|
26
25
|
getLogger,
|
|
27
26
|
SendSingleBatch,
|
|
@@ -118,7 +117,7 @@ let ReportRequest;
|
|
|
118
117
|
* Quota limits, see:
|
|
119
118
|
* https://support.google.com/adsihc/answer/6346075?hl=en
|
|
120
119
|
*/
|
|
121
|
-
class DoubleClickSearch {
|
|
120
|
+
class DoubleClickSearch extends GoogleApiClient {
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
123
|
* @constructor
|
|
@@ -126,34 +125,19 @@ class DoubleClickSearch {
|
|
|
126
125
|
* variables.
|
|
127
126
|
*/
|
|
128
127
|
constructor(env = process.env) {
|
|
129
|
-
|
|
128
|
+
super(env);
|
|
129
|
+
this.googleApi = 'doubleclicksearch';
|
|
130
130
|
this.logger = getLogger('API.DS');
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
/**
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
* @private
|
|
137
|
-
*/
|
|
138
|
-
async getApiClient_() {
|
|
139
|
-
if (this.doubleclicksearch) return this.doubleclicksearch;
|
|
140
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
141
|
-
this.doubleclicksearch = google.doubleclicksearch({
|
|
142
|
-
version: API_VERSION,
|
|
143
|
-
auth: await this.getAuth_(),
|
|
144
|
-
});
|
|
145
|
-
return this.doubleclicksearch;
|
|
133
|
+
/** @override */
|
|
134
|
+
getScope() {
|
|
135
|
+
return API_SCOPES;
|
|
146
136
|
}
|
|
147
137
|
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
*/
|
|
152
|
-
async getAuth_() {
|
|
153
|
-
if (this.auth) return this.auth;
|
|
154
|
-
await this.authClient.prepareCredentials();
|
|
155
|
-
this.auth = this.authClient.getDefaultAuth();
|
|
156
|
-
return this.auth;
|
|
138
|
+
/** @override */
|
|
139
|
+
getVersion() {
|
|
140
|
+
return API_VERSION;
|
|
157
141
|
}
|
|
158
142
|
|
|
159
143
|
/**
|
|
@@ -172,7 +156,7 @@ class DoubleClickSearch {
|
|
|
172
156
|
});
|
|
173
157
|
this.logger.debug('Sending out availabilities', availabilities);
|
|
174
158
|
try {
|
|
175
|
-
const doubleclicksearch = await this.
|
|
159
|
+
const doubleclicksearch = await this.getApiClient();
|
|
176
160
|
const response = await doubleclicksearch.conversion.updateAvailability(
|
|
177
161
|
{requestBody: {availabilities}});
|
|
178
162
|
this.logger.debug('Get response: ', response);
|
|
@@ -221,7 +205,7 @@ class DoubleClickSearch {
|
|
|
221
205
|
numberOfLines: lines.length,
|
|
222
206
|
};
|
|
223
207
|
try {
|
|
224
|
-
const doubleclicksearch = await this.
|
|
208
|
+
const doubleclicksearch = await this.getApiClient();
|
|
225
209
|
const response = await doubleclicksearch.conversion.insert(
|
|
226
210
|
{requestBody: {conversion: conversions}}
|
|
227
211
|
);
|
|
@@ -322,7 +306,7 @@ class DoubleClickSearch {
|
|
|
322
306
|
* @return {!Promise<string>}
|
|
323
307
|
*/
|
|
324
308
|
async requestReports(requestBody) {
|
|
325
|
-
const doubleclicksearch = await this.
|
|
309
|
+
const doubleclicksearch = await this.getApiClient();
|
|
326
310
|
const { status, data } = await doubleclicksearch.reports.request({ requestBody });
|
|
327
311
|
if (status >= 200 && status < 300) {
|
|
328
312
|
return data.id;
|
|
@@ -341,7 +325,7 @@ class DoubleClickSearch {
|
|
|
341
325
|
* }>>}
|
|
342
326
|
*/
|
|
343
327
|
async getReportUrls(reportId) {
|
|
344
|
-
const doubleclicksearch = await this.
|
|
328
|
+
const doubleclicksearch = await this.getApiClient();
|
|
345
329
|
const { status, data } = await doubleclicksearch.reports.get({ reportId });
|
|
346
330
|
switch (status) {
|
|
347
331
|
case 200:
|
|
@@ -367,11 +351,11 @@ class DoubleClickSearch {
|
|
|
367
351
|
* @return {!Promise<string>}
|
|
368
352
|
*/
|
|
369
353
|
async getReportFile(reportId, reportFragment) {
|
|
370
|
-
const doubleclicksearch = await this.
|
|
354
|
+
const doubleclicksearch = await this.getApiClient();
|
|
371
355
|
const response = await doubleclicksearch.reports.getFile(
|
|
372
356
|
{reportId, reportFragment});
|
|
373
357
|
if (response.status === 200) {
|
|
374
|
-
return
|
|
358
|
+
return response.data;
|
|
375
359
|
}
|
|
376
360
|
const errorMsg =
|
|
377
361
|
`Error in get file from reports: ${reportFragment}@${reportId}`;
|
|
@@ -387,7 +371,7 @@ class DoubleClickSearch {
|
|
|
387
371
|
* @return {!Promise<ReadableStream>}
|
|
388
372
|
*/
|
|
389
373
|
async getReportFileStream(url) {
|
|
390
|
-
const auth = await this.
|
|
374
|
+
const auth = await this.getAuth();
|
|
391
375
|
const headers = await auth.getRequestHeaders();
|
|
392
376
|
const response = await request({
|
|
393
377
|
method: 'GET',
|
|
@@ -1100,7 +1100,7 @@ class GoogleAdsApi {
|
|
|
1100
1100
|
*/
|
|
1101
1101
|
buildCustomerMatchUserListMetadata_(config) {
|
|
1102
1102
|
const { customerId, listId, customerMatchUserListMetadata } = config;
|
|
1103
|
-
const resourceName = `customers/${customerId}/userLists/${listId}`;
|
|
1103
|
+
const resourceName = `customers/${getCleanCid(customerId)}/userLists/${listId}`;
|
|
1104
1104
|
return new CustomerMatchUserListMetadata(Object.assign({
|
|
1105
1105
|
userList: resourceName,
|
|
1106
1106
|
}, customerMatchUserListMetadata));
|
|
@@ -1521,7 +1521,7 @@ const buildConversionJsonList = (lines, config, conversionFields,
|
|
|
1521
1521
|
conversion.customVariables = variables.map((variable) => {
|
|
1522
1522
|
return new CustomVariable({
|
|
1523
1523
|
conversionCustomVariable:
|
|
1524
|
-
`customers/${customerId}/conversionCustomVariables/${customVariables[variable]}`,
|
|
1524
|
+
`customers/${getCleanCid(customerId)}/conversionCustomVariables/${customVariables[variable]}`,
|
|
1525
1525
|
value: record[variable],
|
|
1526
1526
|
});
|
|
1527
1527
|
});
|
package/src/apis/index.js
CHANGED
package/src/apis/search_ads.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
const { request: gaxiosRequest } = require('gaxios');
|
|
22
22
|
const { google } = require('googleapis');
|
|
23
|
-
const
|
|
23
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
24
24
|
const { getLogger } = require('../components/utils.js');
|
|
25
25
|
const { getCleanCid, RestSearchStreamTransform }
|
|
26
26
|
= require('./base/ads_api_common.js');
|
|
@@ -35,7 +35,7 @@ const API_VERSION = 'v0';
|
|
|
35
35
|
* Search Ads 360 Reporting API stub.
|
|
36
36
|
* See: https://developers.google.com/search-ads/reporting/api/reference/release-notes
|
|
37
37
|
*/
|
|
38
|
-
class SearchAds {
|
|
38
|
+
class SearchAds extends GoogleApiClient {
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* @constructor
|
|
@@ -43,10 +43,21 @@ class SearchAds {
|
|
|
43
43
|
* variables.
|
|
44
44
|
*/
|
|
45
45
|
constructor(env = process.env) {
|
|
46
|
-
|
|
46
|
+
super(env);
|
|
47
|
+
this.googleApi = 'searchads360';
|
|
47
48
|
this.logger = getLogger('API.SA');
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
/** @override */
|
|
52
|
+
getScope() {
|
|
53
|
+
return API_SCOPES;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @override */
|
|
57
|
+
getVersion() {
|
|
58
|
+
return API_VERSION;
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
/**
|
|
51
62
|
* Prepares the Search Ads 360 Reporting API instance.
|
|
52
63
|
* OAuth 2.0 application credentials is required for calling this API.
|
|
@@ -59,11 +70,11 @@ class SearchAds {
|
|
|
59
70
|
* @return {!google.searchads360}
|
|
60
71
|
* @private
|
|
61
72
|
*/
|
|
62
|
-
async
|
|
73
|
+
async getApiClient(loginCustomerId) {
|
|
63
74
|
this.logger.debug(`Initialized SA reporting for ${loginCustomerId}`);
|
|
64
75
|
const options = {
|
|
65
|
-
version:
|
|
66
|
-
auth: await this.
|
|
76
|
+
version: this.getVersion(),
|
|
77
|
+
auth: await this.getAuth(),
|
|
67
78
|
};
|
|
68
79
|
if (loginCustomerId) {
|
|
69
80
|
options.headers = { 'login-customer-id': getCleanCid(loginCustomerId) };
|
|
@@ -71,17 +82,6 @@ class SearchAds {
|
|
|
71
82
|
return google.searchads360(options);
|
|
72
83
|
}
|
|
73
84
|
|
|
74
|
-
/**
|
|
75
|
-
* Gets the auth object.
|
|
76
|
-
* @return {!Promise<{!OAuth2Client|!JWT|!Compute}>}
|
|
77
|
-
*/
|
|
78
|
-
async getAuth_() {
|
|
79
|
-
if (this.auth) return this.auth;
|
|
80
|
-
await this.authClient.prepareCredentials();
|
|
81
|
-
this.auth = this.authClient.getDefaultAuth();
|
|
82
|
-
return this.auth;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
85
|
/**
|
|
86
86
|
* Gets a report synchronously from a given Customer account.
|
|
87
87
|
* If there is a `nextPageToken` in the response, it means the report is not
|
|
@@ -96,7 +96,7 @@ class SearchAds {
|
|
|
96
96
|
* @see https://developers.google.com/search-ads/reporting/api/reference/rpc/google.ads.searchads360.v0.services#searchsearchads360response
|
|
97
97
|
*/
|
|
98
98
|
async getPaginatedReport(customerId, loginCustomerId, query, options = {}) {
|
|
99
|
-
const searchads = await this.
|
|
99
|
+
const searchads = await this.getApiClient(loginCustomerId);
|
|
100
100
|
const requestBody = Object.assign({
|
|
101
101
|
query,
|
|
102
102
|
pageSize: 10000,
|
|
@@ -120,7 +120,7 @@ class SearchAds {
|
|
|
120
120
|
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/search
|
|
121
121
|
*/
|
|
122
122
|
async restStreamReport(customerId, loginCustomerId, query) {
|
|
123
|
-
const auth = await this.
|
|
123
|
+
const auth = await this.getAuth();
|
|
124
124
|
const headers = Object.assign(
|
|
125
125
|
await auth.getRequestHeaders(), {
|
|
126
126
|
'login-customer-id': getCleanCid(loginCustomerId),
|
|
@@ -166,7 +166,7 @@ class SearchAds {
|
|
|
166
166
|
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/searchAds360Fields#SearchAds360Field
|
|
167
167
|
*/
|
|
168
168
|
async getReportField(fieldName) {
|
|
169
|
-
const searchads = await this.
|
|
169
|
+
const searchads = await this.getApiClient();
|
|
170
170
|
const resourceName = `searchAds360Fields/${fieldName}`;
|
|
171
171
|
const response =
|
|
172
172
|
await searchads.searchAds360Fields.get({ resourceName });
|
|
@@ -185,7 +185,7 @@ class SearchAds {
|
|
|
185
185
|
*/
|
|
186
186
|
async searchReportField(adFields,
|
|
187
187
|
metadata = ['name', 'data_type', 'is_repeated', 'type_url',]) {
|
|
188
|
-
const searchads = await this.
|
|
188
|
+
const searchads = await this.getApiClient();
|
|
189
189
|
const selectClause = metadata.join(',');
|
|
190
190
|
const fields = adFields.join('","');
|
|
191
191
|
const query = `SELECT ${selectClause} WHERE name IN ("${fields}")`;
|
|
@@ -203,7 +203,7 @@ class SearchAds {
|
|
|
203
203
|
* @see https://developers.google.com/search-ads/reporting/api/reference/rest/v0/customers.customColumns#CustomColumn
|
|
204
204
|
*/
|
|
205
205
|
async listCustomColumns(customerId, loginCustomerId) {
|
|
206
|
-
const searchads = await this.
|
|
206
|
+
const searchads = await this.getApiClient(loginCustomerId);
|
|
207
207
|
const response = await searchads.customers.customColumns.list({ customerId });
|
|
208
208
|
return response.data.customColumns;
|
|
209
209
|
}
|
|
@@ -219,7 +219,7 @@ class SearchAds {
|
|
|
219
219
|
*/
|
|
220
220
|
async getCustomColumn(columnId, customerId, loginCustomerId) {
|
|
221
221
|
const resourceName = `customers/${customerId}/customColumns/${columnId}`;
|
|
222
|
-
const searchads = await this.
|
|
222
|
+
const searchads = await this.getApiClient(loginCustomerId);
|
|
223
223
|
const response = await searchads.customers.customColumns.get({ resourceName });
|
|
224
224
|
return response.data;
|
|
225
225
|
}
|
package/src/apis/spreadsheets.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
21
|
const {google} = require('googleapis');
|
|
22
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
22
23
|
const {Params$Resource$Spreadsheets$Get} = google.sheets;
|
|
23
24
|
const AuthClient = require('./auth_client.js');
|
|
24
25
|
const {getLogger, BatchResult} = require('../components/utils.js');
|
|
@@ -63,7 +64,7 @@ let DimensionRange;
|
|
|
63
64
|
/**
|
|
64
65
|
* Google Spreadsheets API v4 stub.
|
|
65
66
|
*/
|
|
66
|
-
class Spreadsheets {
|
|
67
|
+
class Spreadsheets extends GoogleApiClient {
|
|
67
68
|
/**
|
|
68
69
|
* Init Spreadsheets API client.
|
|
69
70
|
* @param {string} spreadsheetId
|
|
@@ -71,29 +72,21 @@ class Spreadsheets {
|
|
|
71
72
|
* variables.
|
|
72
73
|
*/
|
|
73
74
|
constructor(spreadsheetId, env = process.env) {
|
|
75
|
+
super(env);
|
|
76
|
+
this.googleApi = 'sheets';
|
|
74
77
|
/** @const {string} */
|
|
75
78
|
this.spreadsheetId = spreadsheetId;
|
|
76
|
-
this.authClient = new AuthClient(API_SCOPES, env);
|
|
77
|
-
/**
|
|
78
|
-
* Logger object from 'log4js' package where this type is not exported.
|
|
79
|
-
*/
|
|
80
79
|
this.logger = getLogger('API.GS');
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
92
|
-
this.sheets = google.sheets({
|
|
93
|
-
version: API_VERSION,
|
|
94
|
-
auth: this.authClient.getDefaultAuth(),
|
|
95
|
-
});
|
|
96
|
-
return this.sheets;
|
|
82
|
+
/** @override */
|
|
83
|
+
getScope() {
|
|
84
|
+
return API_SCOPES;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** @override */
|
|
88
|
+
getVersion() {
|
|
89
|
+
return API_VERSION;
|
|
97
90
|
}
|
|
98
91
|
|
|
99
92
|
/**
|
|
@@ -108,7 +101,7 @@ class Spreadsheets {
|
|
|
108
101
|
spreadsheetId: this.spreadsheetId,
|
|
109
102
|
ranges: sheetName,
|
|
110
103
|
};
|
|
111
|
-
const sheets = await this.
|
|
104
|
+
const sheets = await this.getApiClient();
|
|
112
105
|
const response = await sheets.spreadsheets.get(request);
|
|
113
106
|
const sheet = response.data.sheets[0];
|
|
114
107
|
this.logger.debug(`Get sheet[${sheetName}]: `, sheet);
|
|
@@ -127,7 +120,7 @@ class Spreadsheets {
|
|
|
127
120
|
range: sheetName,
|
|
128
121
|
};
|
|
129
122
|
try {
|
|
130
|
-
const sheets = await this.
|
|
123
|
+
const sheets = await this.getApiClient();
|
|
131
124
|
const response = await sheets.spreadsheets.values.clear(request);
|
|
132
125
|
const data = response.data;
|
|
133
126
|
this.logger.debug(`Clear sheet[${sheetName}}]: `, data);
|
|
@@ -180,7 +173,7 @@ class Spreadsheets {
|
|
|
180
173
|
ranges: sheetName,
|
|
181
174
|
};
|
|
182
175
|
try {
|
|
183
|
-
const sheets = await this.
|
|
176
|
+
const sheets = await this.getApiClient();
|
|
184
177
|
const response = await sheets.spreadsheets.get(request);
|
|
185
178
|
const sheet = response.data.sheets[0];
|
|
186
179
|
const sheetId = sheet.properties.sheetId;
|
|
@@ -232,7 +225,7 @@ class Spreadsheets {
|
|
|
232
225
|
numberOfLines: data.trim().split('\n').length,
|
|
233
226
|
};
|
|
234
227
|
try {
|
|
235
|
-
const sheets = await this.
|
|
228
|
+
const sheets = await this.getApiClient();
|
|
236
229
|
const response = await sheets.spreadsheets.batchUpdate(request);
|
|
237
230
|
const data = response.data;
|
|
238
231
|
this.logger.debug(`Batch[${batchId}] uploaded: `, data);
|
package/src/apis/youtube.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
21
|
const {google} = require('googleapis');
|
|
22
|
+
const { GoogleApiClient } = require('./base/google_api_client.js');
|
|
22
23
|
const {
|
|
23
24
|
Schema$Channel,
|
|
24
25
|
Schema$Video,
|
|
@@ -26,8 +27,7 @@ const {
|
|
|
26
27
|
Schema$Playlist,
|
|
27
28
|
Schema$Search,
|
|
28
29
|
} = google.youtube;
|
|
29
|
-
const
|
|
30
|
-
const {getLogger} = require('../components/utils.js');
|
|
30
|
+
const { getLogger } = require('../components/utils.js');
|
|
31
31
|
|
|
32
32
|
const API_SCOPES = Object.freeze([
|
|
33
33
|
'https://www.googleapis.com/auth/youtube.force-ssl'
|
|
@@ -159,34 +159,26 @@ let ListSearchConfig;
|
|
|
159
159
|
* Search list type definition, see:
|
|
160
160
|
* https://developers.google.com/youtube/v3/docs/search/list
|
|
161
161
|
*/
|
|
162
|
-
class YouTube {
|
|
162
|
+
class YouTube extends GoogleApiClient {
|
|
163
163
|
/**
|
|
164
164
|
* @constructor
|
|
165
165
|
* @param {!Object<string,string>=} env The environment object to hold env
|
|
166
166
|
* variables.
|
|
167
167
|
*/
|
|
168
168
|
constructor(env = process.env) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
* Logger object from 'log4js' package where this type is not exported.
|
|
172
|
-
*/
|
|
169
|
+
super(env);
|
|
170
|
+
this.googleApi = 'youtube';
|
|
173
171
|
this.logger = getLogger('API.YT');
|
|
174
172
|
}
|
|
175
173
|
|
|
176
|
-
/**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.logger.debug(`Initialized ${this.constructor.name} instance.`);
|
|
185
|
-
this.youtube = google.youtube({
|
|
186
|
-
version: API_VERSION,
|
|
187
|
-
auth: this.authClient.getDefaultAuth(),
|
|
188
|
-
});
|
|
189
|
-
return this.youtube;
|
|
174
|
+
/** @override */
|
|
175
|
+
getScope() {
|
|
176
|
+
return API_SCOPES;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** @override */
|
|
180
|
+
getVersion() {
|
|
181
|
+
return API_VERSION;
|
|
190
182
|
}
|
|
191
183
|
|
|
192
184
|
/**
|
|
@@ -200,7 +192,7 @@ class YouTube {
|
|
|
200
192
|
const channelListRequest = Object.assign({}, config);
|
|
201
193
|
channelListRequest.part = channelListRequest.part.join(',')
|
|
202
194
|
try {
|
|
203
|
-
const youtube = await this.
|
|
195
|
+
const youtube = await this.getApiClient();
|
|
204
196
|
const response = await youtube.channels.list(channelListRequest);
|
|
205
197
|
this.logger.debug('Response: ', response);
|
|
206
198
|
return response.data.items;
|
|
@@ -223,7 +215,7 @@ class YouTube {
|
|
|
223
215
|
const videoListRequest = Object.assign({}, config);
|
|
224
216
|
videoListRequest.part = videoListRequest.part.join(',')
|
|
225
217
|
try {
|
|
226
|
-
const youtube = await this.
|
|
218
|
+
const youtube = await this.getApiClient();
|
|
227
219
|
const response = await youtube.videos.list(videoListRequest);
|
|
228
220
|
this.logger.debug('Response: ', response);
|
|
229
221
|
return response.data.items;
|
|
@@ -247,7 +239,7 @@ class YouTube {
|
|
|
247
239
|
const commentThreadsRequest = Object.assign({}, config);
|
|
248
240
|
commentThreadsRequest.part = commentThreadsRequest.part.join(',')
|
|
249
241
|
try {
|
|
250
|
-
const youtube = await this.
|
|
242
|
+
const youtube = await this.getApiClient();
|
|
251
243
|
const response = await youtube.commentThreads.list(commentThreadsRequest);
|
|
252
244
|
this.logger.debug('Response: ', response.data);
|
|
253
245
|
return response.data.items;
|
|
@@ -282,7 +274,7 @@ class YouTube {
|
|
|
282
274
|
}
|
|
283
275
|
|
|
284
276
|
try {
|
|
285
|
-
const youtube = await this.
|
|
277
|
+
const youtube = await this.getApiClient();
|
|
286
278
|
const response = await youtube.playlists.list(playlistsRequest);
|
|
287
279
|
this.logger.debug('Response: ', response.data);
|
|
288
280
|
if (response.data.nextPageToken) {
|
|
@@ -324,7 +316,7 @@ class YouTube {
|
|
|
324
316
|
}
|
|
325
317
|
|
|
326
318
|
try {
|
|
327
|
-
const youtube = await this.
|
|
319
|
+
const youtube = await this.getApiClient();
|
|
328
320
|
const response = await youtube.search.list(searchRequest);
|
|
329
321
|
this.logger.debug('Response: ', response.data);
|
|
330
322
|
if (response.data.nextPageToken) {
|
|
@@ -75,7 +75,7 @@ class DatastoreModeAccess {
|
|
|
75
75
|
*/
|
|
76
76
|
getKey(id) {
|
|
77
77
|
const keyPath = [this.kind];
|
|
78
|
-
if (id) keyPath.push(isNaN(id) ? id :
|
|
78
|
+
if (id) keyPath.push(isNaN(id) ? id : this.datastore.int(id));
|
|
79
79
|
return this.datastore.key({
|
|
80
80
|
namespace: this.namespace,
|
|
81
81
|
path: keyPath,
|
|
@@ -116,10 +116,11 @@ class DatastoreModeAccess {
|
|
|
116
116
|
const key = this.getKey(id);
|
|
117
117
|
const apiResponse =
|
|
118
118
|
await this.datastore.save({ key, data, excludeLargeProperties: true });
|
|
119
|
-
// Default key in Datastore is
|
|
119
|
+
// Default key in Datastore is an int as string in response. It could be
|
|
120
|
+
// larger than JavaScript max safe integer, so keep it as string here.
|
|
120
121
|
// With a given id, the key in response is null.
|
|
121
122
|
const updatedId = id !== undefined ? id
|
|
122
|
-
:
|
|
123
|
+
: apiResponse[0].mutationResults[0].key.path[0].id;
|
|
123
124
|
this.logger.debug(`Result of saving ${updatedId}@${this.kind}: `,
|
|
124
125
|
JSON.stringify(apiResponse));
|
|
125
126
|
// Datastore has a delay to write entity. This method only returns id
|
package/src/components/utils.js
CHANGED
|
@@ -487,7 +487,7 @@ const extractObject = (paths) => {
|
|
|
487
487
|
return (sourceObject) => {
|
|
488
488
|
const output = {};
|
|
489
489
|
paths.forEach((path) => {
|
|
490
|
-
const [value, owner, property] = path.split('.')
|
|
490
|
+
const [value, owner, property] = path.trim().split('.')
|
|
491
491
|
.reduce(transcribe, [sourceObject, output, undefined]);
|
|
492
492
|
if (typeof value !== 'undefined') {
|
|
493
493
|
owner[property] = value;
|
|
@@ -509,7 +509,7 @@ const getObjectByPath = (obj, paths) => {
|
|
|
509
509
|
paths.split('.').filter((key) => !!key).forEach((key) => {
|
|
510
510
|
instance = instance[key];
|
|
511
511
|
if (!instance) {
|
|
512
|
-
console.error('Fail to get
|
|
512
|
+
console.error('Fail to get element from path:', paths);
|
|
513
513
|
return instance;
|
|
514
514
|
}
|
|
515
515
|
});
|
|
@@ -591,7 +591,24 @@ const changeObjectNamingFromLowerCamelToSnake = (obj) => {
|
|
|
591
591
|
} else {
|
|
592
592
|
return obj;
|
|
593
593
|
}
|
|
594
|
-
}
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Generates a function that can convert a given JSON object to a JSON string
|
|
598
|
+
* with only specified fields(fieldMask), in specified naming convention.
|
|
599
|
+
* @param {string} fieldMask The 'fieldMask' string from response.
|
|
600
|
+
* @param {boolean=} snakeCase Whether or not output JSON in snake naming.
|
|
601
|
+
*/
|
|
602
|
+
const getFilterAndStringifyFn = (fieldMask, snakeCase = false) => {
|
|
603
|
+
const extractor = extractObject(
|
|
604
|
+
Array.isArray(fieldMask) ? fieldMask : fieldMask.split(','));
|
|
605
|
+
return (originalObject) => {
|
|
606
|
+
const extracted = extractor(originalObject);
|
|
607
|
+
const generatedObject = snakeCase
|
|
608
|
+
? changeObjectNamingFromLowerCamelToSnake(extracted) : extracted;
|
|
609
|
+
return JSON.stringify(generatedObject);
|
|
610
|
+
};
|
|
611
|
+
};
|
|
595
612
|
|
|
596
613
|
/**
|
|
597
614
|
* Returns the response data for a HTTP request. It will retry the specific
|
|
@@ -619,7 +636,7 @@ const requestWithRetry = async (options, logger = console, retryTimes = 3) => {
|
|
|
619
636
|
logger.error(`Request ${JSON.stringify(options)}`, error);
|
|
620
637
|
}
|
|
621
638
|
} while (processedTimes <= retryTimes)
|
|
622
|
-
}
|
|
639
|
+
};
|
|
623
640
|
|
|
624
641
|
// noinspection JSUnusedAssignment
|
|
625
642
|
module.exports = {
|
|
@@ -641,5 +658,6 @@ module.exports = {
|
|
|
641
658
|
changeNamingFromLowerCamelToSnake,
|
|
642
659
|
changeObjectNamingFromSnakeToLowerCamel,
|
|
643
660
|
changeObjectNamingFromLowerCamelToSnake,
|
|
661
|
+
getFilterAndStringifyFn,
|
|
644
662
|
requestWithRetry,
|
|
645
663
|
};
|