@meltwater/conversations-api-services 1.0.0 → 1.0.2
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/package.json +1 -1
- package/src/data-access/http/facebookApi.client.js +63 -28
- package/src/data-access/http/instagramApi.client.js +84 -32
- package/src/data-access/http/linkedInApi.client.js +90 -65
- package/src/data-access/index.js +0 -2
- package/.github/workflows/release.yml +0 -42
- package/src/data-access/http/tiktokApi.client.js +0 -477
package/package.json
CHANGED
|
@@ -107,7 +107,7 @@ export class FacebookApiClient {
|
|
|
107
107
|
);
|
|
108
108
|
logger.info(
|
|
109
109
|
`Native Facebook API Publish Comment Response for documentId ${documentId}`,
|
|
110
|
-
{
|
|
110
|
+
{ responseBody: response.body }
|
|
111
111
|
);
|
|
112
112
|
return response.body;
|
|
113
113
|
}
|
|
@@ -147,7 +147,7 @@ export class FacebookApiClient {
|
|
|
147
147
|
);
|
|
148
148
|
logger.info(
|
|
149
149
|
`Native Facebook API Publish Private Message Response for documentId ${documentId}`,
|
|
150
|
-
{
|
|
150
|
+
{ responseBody: response.body }
|
|
151
151
|
);
|
|
152
152
|
return response.body;
|
|
153
153
|
}
|
|
@@ -162,21 +162,23 @@ export class FacebookApiClient {
|
|
|
162
162
|
.query({ access_token: accessToken, ...queryParams })
|
|
163
163
|
.send(payload);
|
|
164
164
|
} catch (err) {
|
|
165
|
-
let errorText = '';
|
|
166
165
|
if (
|
|
167
166
|
err &&
|
|
168
167
|
err.response &&
|
|
169
168
|
err.response.body &&
|
|
170
169
|
err.response.body.error
|
|
171
170
|
) {
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
logger.error(
|
|
172
|
+
`Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
|
|
173
|
+
);
|
|
174
174
|
} else {
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
logger.error(
|
|
176
|
+
`Failed to call facebook api for documentId ${documentId}`,
|
|
177
|
+
err
|
|
178
|
+
);
|
|
177
179
|
}
|
|
178
180
|
|
|
179
|
-
throw
|
|
181
|
+
throw err;
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
if (response.status !== 200) {
|
|
@@ -204,21 +206,23 @@ export class FacebookApiClient {
|
|
|
204
206
|
.query({ access_token: accessToken })
|
|
205
207
|
.send(payload);
|
|
206
208
|
} catch (err) {
|
|
207
|
-
let errorText = '';
|
|
208
209
|
if (
|
|
209
210
|
err &&
|
|
210
211
|
err.response &&
|
|
211
212
|
err.response.body &&
|
|
212
213
|
err.response.body.error
|
|
213
214
|
) {
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
logger.error(
|
|
216
|
+
`Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
|
|
217
|
+
);
|
|
216
218
|
} else {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
logger.error(
|
|
220
|
+
`Failed to call facebook api for documentId ${documentId}`,
|
|
221
|
+
err
|
|
222
|
+
);
|
|
219
223
|
}
|
|
220
224
|
|
|
221
|
-
throw
|
|
225
|
+
throw err;
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
if (response.status !== 200) {
|
|
@@ -246,21 +250,23 @@ export class FacebookApiClient {
|
|
|
246
250
|
.query({ access_token: accessToken })
|
|
247
251
|
.send(payload);
|
|
248
252
|
} catch (err) {
|
|
249
|
-
let errorText = '';
|
|
250
253
|
if (
|
|
251
254
|
err &&
|
|
252
255
|
err.response &&
|
|
253
256
|
err.response.body &&
|
|
254
257
|
err.response.body.error
|
|
255
258
|
) {
|
|
256
|
-
|
|
257
|
-
|
|
259
|
+
logger.error(
|
|
260
|
+
`Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
|
|
261
|
+
);
|
|
258
262
|
} else {
|
|
259
|
-
|
|
260
|
-
|
|
263
|
+
logger.error(
|
|
264
|
+
`Failed to call facebook api for documentId ${documentId}`,
|
|
265
|
+
err
|
|
266
|
+
);
|
|
261
267
|
}
|
|
262
268
|
|
|
263
|
-
throw
|
|
269
|
+
throw err;
|
|
264
270
|
}
|
|
265
271
|
|
|
266
272
|
if (response.status !== 200) {
|
|
@@ -374,6 +380,13 @@ export class FacebookApiClient {
|
|
|
374
380
|
);
|
|
375
381
|
}
|
|
376
382
|
|
|
383
|
+
//sendNotification -> needs to wait for temp document to reach user
|
|
384
|
+
setTimeout(() => {
|
|
385
|
+
PushRepository.publish(
|
|
386
|
+
`${companyId}-${documentId}`,
|
|
387
|
+
updatedDocument
|
|
388
|
+
);
|
|
389
|
+
}, 5000);
|
|
377
390
|
return apiResponse;
|
|
378
391
|
}
|
|
379
392
|
|
|
@@ -381,7 +394,7 @@ export class FacebookApiClient {
|
|
|
381
394
|
const {
|
|
382
395
|
documentId,
|
|
383
396
|
appData: { hidden: hiddenOnNative },
|
|
384
|
-
metaData: { externalId },
|
|
397
|
+
metaData: { externalId: externalId },
|
|
385
398
|
systemData: {
|
|
386
399
|
connectionsCredential: credentialId,
|
|
387
400
|
policies: { storage: { privateTo: companyId } = {} } = {},
|
|
@@ -445,6 +458,7 @@ export class FacebookApiClient {
|
|
|
445
458
|
} = document;
|
|
446
459
|
|
|
447
460
|
let banResponse;
|
|
461
|
+
let notificationPayload = document;
|
|
448
462
|
let authorId = authors[0].authorInfo.externalId;
|
|
449
463
|
|
|
450
464
|
try {
|
|
@@ -477,9 +491,30 @@ export class FacebookApiClient {
|
|
|
477
491
|
`finished banning in facebook for ${authorId} on company ${companyId} `,
|
|
478
492
|
{ banResponse }
|
|
479
493
|
);
|
|
494
|
+
|
|
495
|
+
notificationPayload.banStatus = {
|
|
496
|
+
code: banResponse.success === true ? 200 : 500,
|
|
497
|
+
message:
|
|
498
|
+
banResponse.success === true ? 'Success' : 'Failed to Ban',
|
|
499
|
+
};
|
|
500
|
+
logger.debug(
|
|
501
|
+
`Notification payload for ${authorId} on company ${companyId} `,
|
|
502
|
+
notificationPayload
|
|
503
|
+
);
|
|
480
504
|
} catch (error) {
|
|
481
505
|
logger.error(`${authorId} - error recieved - ${error.code}`, error);
|
|
506
|
+
// message failed ot send, mark as such
|
|
507
|
+
notificationPayload.banStatus = {
|
|
508
|
+
code: 405,
|
|
509
|
+
message: 'Exception Occurred',
|
|
510
|
+
};
|
|
482
511
|
}
|
|
512
|
+
setTimeout(() => {
|
|
513
|
+
PushRepository.publish(
|
|
514
|
+
`${companyId}-${authorId}`,
|
|
515
|
+
notificationPayload
|
|
516
|
+
);
|
|
517
|
+
}, 5000);
|
|
483
518
|
}
|
|
484
519
|
|
|
485
520
|
async toggleLike(document) {
|
|
@@ -544,7 +579,7 @@ export class FacebookApiClient {
|
|
|
544
579
|
|
|
545
580
|
logger.info(
|
|
546
581
|
`Native Facebook API Like Response for documentId ${documentId}`,
|
|
547
|
-
{
|
|
582
|
+
{ responseBody: response.body }
|
|
548
583
|
);
|
|
549
584
|
return response.body;
|
|
550
585
|
}
|
|
@@ -566,7 +601,7 @@ export class FacebookApiClient {
|
|
|
566
601
|
|
|
567
602
|
logger.info(
|
|
568
603
|
`Native Facebook API Unlike Response for documentId ${documentId}`,
|
|
569
|
-
{
|
|
604
|
+
{ responseBody: response.body }
|
|
570
605
|
);
|
|
571
606
|
return response.body;
|
|
572
607
|
}
|
|
@@ -589,7 +624,7 @@ export class FacebookApiClient {
|
|
|
589
624
|
|
|
590
625
|
logger.info(
|
|
591
626
|
`Native Facebook API Hide Response for documentId ${documentId}`,
|
|
592
|
-
{
|
|
627
|
+
{ responseBody: response.body }
|
|
593
628
|
);
|
|
594
629
|
return response.body;
|
|
595
630
|
}
|
|
@@ -612,7 +647,7 @@ export class FacebookApiClient {
|
|
|
612
647
|
|
|
613
648
|
logger.info(
|
|
614
649
|
`Native Facebook API Unhide Response for documentId ${documentId}`,
|
|
615
|
-
{
|
|
650
|
+
{ responseBody: response.body }
|
|
616
651
|
);
|
|
617
652
|
return response.body;
|
|
618
653
|
}
|
|
@@ -648,7 +683,7 @@ export class FacebookApiClient {
|
|
|
648
683
|
}
|
|
649
684
|
logger.info(
|
|
650
685
|
`Native Facebook API is User Banned Response was invalid for userId ${userId} ${credentialId}`,
|
|
651
|
-
{
|
|
686
|
+
{ responseBody: response }
|
|
652
687
|
);
|
|
653
688
|
return false;
|
|
654
689
|
}
|
|
@@ -671,7 +706,7 @@ export class FacebookApiClient {
|
|
|
671
706
|
|
|
672
707
|
logger.info(
|
|
673
708
|
`Native Facebook API Hide Response for externalAuthorId ${authorId}`,
|
|
674
|
-
{
|
|
709
|
+
{ responseBody: response.body }
|
|
675
710
|
);
|
|
676
711
|
return response.body;
|
|
677
712
|
}
|
|
@@ -694,7 +729,7 @@ export class FacebookApiClient {
|
|
|
694
729
|
|
|
695
730
|
logger.info(
|
|
696
731
|
`Native Facebook API Unban Response for externalAuthorId ${authorId}`,
|
|
697
|
-
{
|
|
732
|
+
{ responseBody: response.body }
|
|
698
733
|
);
|
|
699
734
|
return response.body;
|
|
700
735
|
}
|
|
@@ -3,6 +3,9 @@ import logger from '../../lib/logger.js';
|
|
|
3
3
|
import { removePrefix } from '../../lib/externalId.helpers.js';
|
|
4
4
|
import assert from 'assert';
|
|
5
5
|
import { CredentialsApiClient } from '../http/credentialsApi.client.js';
|
|
6
|
+
// import { messagesRepository } from '@data-access/mongo/repository/messages.js';
|
|
7
|
+
// import PushRepository from '@data-access/redis/repository/push.repository.js';
|
|
8
|
+
// import { DOCUMENT_STATUS } from '@data-access/mongo/query.helpers.js';
|
|
6
9
|
|
|
7
10
|
const INSTAGRAM_URL = 'https://graph.facebook.com';
|
|
8
11
|
export class InstagramApiClient {
|
|
@@ -44,22 +47,22 @@ export class InstagramApiClient {
|
|
|
44
47
|
.query(queryStringArgs)
|
|
45
48
|
.send(data);
|
|
46
49
|
} catch (err) {
|
|
47
|
-
let errorText = '';
|
|
48
50
|
if (
|
|
49
51
|
err &&
|
|
50
52
|
err.response &&
|
|
51
53
|
err.response.body &&
|
|
52
54
|
err.response.body.error
|
|
53
55
|
) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
logger.error(
|
|
57
|
+
`Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`
|
|
58
|
+
);
|
|
57
59
|
} else {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
logger.error(
|
|
61
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
62
|
+
err
|
|
63
|
+
);
|
|
61
64
|
}
|
|
62
|
-
throw
|
|
65
|
+
throw err;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
if (response.status !== 200) {
|
|
@@ -97,7 +100,7 @@ export class InstagramApiClient {
|
|
|
97
100
|
|
|
98
101
|
logger.info(
|
|
99
102
|
`Native Instagram API getPost Response for documentId ${documentId}`,
|
|
100
|
-
{
|
|
103
|
+
{ responseBody: response.body }
|
|
101
104
|
);
|
|
102
105
|
return response.body;
|
|
103
106
|
} catch (err) {
|
|
@@ -124,20 +127,22 @@ export class InstagramApiClient {
|
|
|
124
127
|
.query({ message: text })
|
|
125
128
|
.send();
|
|
126
129
|
} catch (err) {
|
|
127
|
-
let errorText = '';
|
|
128
130
|
if (
|
|
129
131
|
err &&
|
|
130
132
|
err.response &&
|
|
131
133
|
err.response.body &&
|
|
132
134
|
err.response.body.error
|
|
133
135
|
) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
logger.error(
|
|
137
|
+
`Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`
|
|
138
|
+
);
|
|
136
139
|
} else {
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
logger.error(
|
|
141
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
142
|
+
err
|
|
143
|
+
);
|
|
139
144
|
}
|
|
140
|
-
throw
|
|
145
|
+
throw err;
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
if (response.status !== 200) {
|
|
@@ -168,15 +173,18 @@ export class InstagramApiClient {
|
|
|
168
173
|
.query({ hide: hideStatus })
|
|
169
174
|
.send();
|
|
170
175
|
} catch (err) {
|
|
171
|
-
let errorText = '';
|
|
172
176
|
if (err && err.response && err.response.body) {
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
logger.error(
|
|
178
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
179
|
+
err.response.body.error
|
|
180
|
+
);
|
|
175
181
|
} else {
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
logger.error(
|
|
183
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
184
|
+
err
|
|
185
|
+
);
|
|
178
186
|
}
|
|
179
|
-
throw
|
|
187
|
+
throw err;
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
if (response.status !== 200) {
|
|
@@ -207,15 +215,18 @@ export class InstagramApiClient {
|
|
|
207
215
|
.query({ fields: fields })
|
|
208
216
|
.send();
|
|
209
217
|
} catch (err) {
|
|
210
|
-
let errorText = '';
|
|
211
218
|
if (err && err.response && err.response.body) {
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
logger.error(
|
|
220
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
221
|
+
err.response.body.error
|
|
222
|
+
);
|
|
214
223
|
} else {
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
logger.error(
|
|
225
|
+
`Failed to call instagram api for documentId ${documentId}`,
|
|
226
|
+
err
|
|
227
|
+
);
|
|
217
228
|
}
|
|
218
|
-
throw
|
|
229
|
+
throw err;
|
|
219
230
|
}
|
|
220
231
|
|
|
221
232
|
if (response.status !== 200) {
|
|
@@ -267,7 +278,7 @@ export class InstagramApiClient {
|
|
|
267
278
|
|
|
268
279
|
logger.info(
|
|
269
280
|
`Native Intagram API Publish Comment Response for documentId ${documentId}`,
|
|
270
|
-
{
|
|
281
|
+
{ responseBody: response.body }
|
|
271
282
|
);
|
|
272
283
|
return response.body;
|
|
273
284
|
}
|
|
@@ -316,7 +327,7 @@ export class InstagramApiClient {
|
|
|
316
327
|
|
|
317
328
|
logger.info(
|
|
318
329
|
`Native Instagram API Publish Reply Response for documentId ${documentId}`,
|
|
319
|
-
{
|
|
330
|
+
{ responseBody: response.body }
|
|
320
331
|
);
|
|
321
332
|
return response.body;
|
|
322
333
|
}
|
|
@@ -402,10 +413,51 @@ export class InstagramApiClient {
|
|
|
402
413
|
default:
|
|
403
414
|
throw new Error('Unsupported discussion type');
|
|
404
415
|
}
|
|
416
|
+
|
|
417
|
+
if (apiResponse) {
|
|
418
|
+
let findQuery = { documentId };
|
|
419
|
+
findQuery['systemData.policies.storage.privateTo'] = companyId;
|
|
420
|
+
let updateObj = {};
|
|
421
|
+
updateObj['systemData.status'] = DOCUMENT_STATUS.SUCCESS;
|
|
422
|
+
// update with the new id from instagram reply/comment or direct message
|
|
423
|
+
updateObj['metaData.externalId'] =
|
|
424
|
+
apiResponse.id || `${apiResponse.message_id}`;
|
|
425
|
+
updateObj.documentId = Buffer.from(
|
|
426
|
+
`${updateObj['metaData.externalId']}`
|
|
427
|
+
).toString('base64');
|
|
428
|
+
updatedDocument = await messagesRepository.updateOne(
|
|
429
|
+
findQuery,
|
|
430
|
+
updateObj
|
|
431
|
+
);
|
|
432
|
+
} else {
|
|
433
|
+
throw new Error(
|
|
434
|
+
'Invalid response from instagram publish endpoints'
|
|
435
|
+
);
|
|
436
|
+
}
|
|
405
437
|
} catch (err) {
|
|
406
438
|
logger.error(documentId + ' - exception details ' + err, err);
|
|
439
|
+
let findQuery = { documentId };
|
|
440
|
+
findQuery['systemData.policies.storage.privateTo'] = companyId;
|
|
441
|
+
|
|
442
|
+
let updateQuery = {};
|
|
443
|
+
updateQuery['systemData.status'] = DOCUMENT_STATUS.FAILED;
|
|
444
|
+
updateQuery['systemData.error'] =
|
|
445
|
+
err && err.response && err.response.error
|
|
446
|
+
? err.response.error
|
|
447
|
+
: err;
|
|
448
|
+
updatedDocument = await messagesRepository.updateOne(
|
|
449
|
+
findQuery,
|
|
450
|
+
updateQuery
|
|
451
|
+
);
|
|
407
452
|
}
|
|
408
453
|
|
|
454
|
+
//sendNotification -> needs to wait for temp document to reach user
|
|
455
|
+
setTimeout(() => {
|
|
456
|
+
PushRepository.publish(
|
|
457
|
+
`${companyId}-${documentId}`,
|
|
458
|
+
updatedDocument
|
|
459
|
+
);
|
|
460
|
+
}, 5000);
|
|
409
461
|
return apiResponse;
|
|
410
462
|
}
|
|
411
463
|
|
|
@@ -427,7 +479,7 @@ export class InstagramApiClient {
|
|
|
427
479
|
|
|
428
480
|
logger.info(
|
|
429
481
|
`Native Instagram API Hide Response for documentId ${documentId}`,
|
|
430
|
-
{
|
|
482
|
+
{ responseBody: response.body }
|
|
431
483
|
);
|
|
432
484
|
return response.body;
|
|
433
485
|
}
|
|
@@ -450,7 +502,7 @@ export class InstagramApiClient {
|
|
|
450
502
|
|
|
451
503
|
logger.info(
|
|
452
504
|
`Native Instagram API Unhide Response for documentId ${documentId}`,
|
|
453
|
-
{
|
|
505
|
+
{ responseBody: response.body }
|
|
454
506
|
);
|
|
455
507
|
return response.body;
|
|
456
508
|
}
|
|
@@ -489,7 +541,7 @@ export class InstagramApiClient {
|
|
|
489
541
|
|
|
490
542
|
logger.info(
|
|
491
543
|
`Native Instagram API Publish Private Message Response for documentId ${documentId}`,
|
|
492
|
-
{
|
|
544
|
+
{ responseBody: response.body }
|
|
493
545
|
);
|
|
494
546
|
return response.body;
|
|
495
547
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import superagentfrom from 'superagent';
|
|
2
|
+
import configurationfrom from '../../lib/configuration.js';
|
|
3
|
+
// import { DOCUMENT_STATUS } from '@data-access/mongo/query.helpers.js';
|
|
4
|
+
// import { messagesRepository } from '@data-access/mongo/repository/messages.js';
|
|
5
|
+
// import PushRepositoryfrom from '@data-access/redis/repository/push.repository.js';
|
|
5
6
|
|
|
6
7
|
export class LinkedInApiClient {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.
|
|
8
|
+
constructor({ services }) {
|
|
9
|
+
this.tokenService = services.token;
|
|
10
|
+
this.logger = services.logger;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
async likeMessage(document) {
|
|
@@ -41,12 +43,12 @@ export class LinkedInApiClient {
|
|
|
41
43
|
)}?actor=${fixedEncodeURIComponent(payload.actor)}`;
|
|
42
44
|
|
|
43
45
|
try {
|
|
44
|
-
let credential = await this.
|
|
46
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
45
47
|
credentialId,
|
|
46
48
|
companyId
|
|
47
49
|
);
|
|
48
50
|
if (!likedByUser) {
|
|
49
|
-
logger.debug(`${documentId} - trying Delete `, {
|
|
51
|
+
this.logger.debug(`${documentId} - trying Delete `, {
|
|
50
52
|
query,
|
|
51
53
|
payload,
|
|
52
54
|
});
|
|
@@ -61,7 +63,7 @@ export class LinkedInApiClient {
|
|
|
61
63
|
'LinkedIn-Version': '202305',
|
|
62
64
|
});
|
|
63
65
|
} else {
|
|
64
|
-
logger.debug(`${documentId} - sending to linkedin `, {
|
|
66
|
+
this.logger.debug(`${documentId} - sending to linkedin `, {
|
|
65
67
|
query,
|
|
66
68
|
payload,
|
|
67
69
|
});
|
|
@@ -78,17 +80,12 @@ export class LinkedInApiClient {
|
|
|
78
80
|
.send(payload);
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
logger.info(
|
|
83
|
+
this.logger.info(
|
|
82
84
|
`Native Linkedin API Like Comment Response for documentId ${documentId}`,
|
|
83
|
-
{
|
|
84
|
-
ok: response.ok,
|
|
85
|
-
status: response.status,
|
|
86
|
-
message: JSON.parse(response.text),
|
|
87
|
-
likedByUser,
|
|
88
|
-
}
|
|
85
|
+
{ response, likedByUser }
|
|
89
86
|
);
|
|
90
87
|
} catch (err) {
|
|
91
|
-
logger.error(documentId + ' - exception details', {
|
|
88
|
+
this.logger.error(documentId + ' - exception details', {
|
|
92
89
|
err,
|
|
93
90
|
});
|
|
94
91
|
throw err;
|
|
@@ -107,28 +104,22 @@ export class LinkedInApiClient {
|
|
|
107
104
|
},
|
|
108
105
|
metaData: {
|
|
109
106
|
externalId,
|
|
110
|
-
|
|
111
|
-
inReplyTo: { id: inReplyToId },
|
|
107
|
+
inReplyTo: { id: inReplyToId},
|
|
112
108
|
},
|
|
113
109
|
} = document;
|
|
114
110
|
|
|
115
|
-
const [, comment] = externalId.split(',');
|
|
116
|
-
const commentId = comment.split(')')[0];
|
|
117
|
-
|
|
118
111
|
let response;
|
|
119
112
|
let query = `${configuration.get(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
inReplyToId
|
|
123
|
-
)}/comments/${commentId}?actor=${fixedEncodeURIComponent(actorURN)}`;
|
|
113
|
+
'LINKEDIN_API'
|
|
114
|
+
)}/socialActions/${fixedEncodeURIComponent(inReplyToId)}/comments/${fixedEncodeURIComponent(externalId)}`;
|
|
124
115
|
|
|
125
116
|
try {
|
|
126
|
-
let credential = await this.
|
|
117
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
127
118
|
credentialId,
|
|
128
119
|
companyId
|
|
129
120
|
);
|
|
130
|
-
|
|
131
|
-
logger.debug(`${documentId} - trying Delete `, {
|
|
121
|
+
|
|
122
|
+
this.logger.debug(`${documentId} - trying Delete `, {
|
|
132
123
|
query,
|
|
133
124
|
});
|
|
134
125
|
response = await superagent
|
|
@@ -139,25 +130,18 @@ export class LinkedInApiClient {
|
|
|
139
130
|
'X-RestLi-Protocol-Version': configuration.get(
|
|
140
131
|
'LINKEDIN_API_VERSION'
|
|
141
132
|
),
|
|
142
|
-
'LinkedIn-Version': '
|
|
133
|
+
'LinkedIn-Version': '202401',
|
|
143
134
|
});
|
|
144
135
|
|
|
145
|
-
logger.info(
|
|
136
|
+
this.logger.info(
|
|
146
137
|
`Native Linkedin API Delete Comment Response for documentId ${documentId}`,
|
|
147
|
-
{
|
|
138
|
+
{ response }
|
|
148
139
|
);
|
|
149
140
|
} catch (err) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
message: JSON.parse(err.response.text),
|
|
155
|
-
});
|
|
156
|
-
} else {
|
|
157
|
-
errorText = `Call to linkedin api with documentId ${documentId} failed`;
|
|
158
|
-
logger.error(errorText, err);
|
|
159
|
-
}
|
|
160
|
-
throw new Error(errorText);
|
|
141
|
+
this.logger.error(documentId + ' - exception details', {
|
|
142
|
+
err,
|
|
143
|
+
});
|
|
144
|
+
throw err;
|
|
161
145
|
}
|
|
162
146
|
return response;
|
|
163
147
|
}
|
|
@@ -219,7 +203,7 @@ export class LinkedInApiClient {
|
|
|
219
203
|
// data-listener -> linkedin_api.client sendComment
|
|
220
204
|
let response, updatedDocument;
|
|
221
205
|
try {
|
|
222
|
-
let credential = await this.
|
|
206
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
223
207
|
credentialId,
|
|
224
208
|
companyId
|
|
225
209
|
);
|
|
@@ -241,13 +225,52 @@ export class LinkedInApiClient {
|
|
|
241
225
|
status: 200,
|
|
242
226
|
message: JSON.parse(response.text),
|
|
243
227
|
};
|
|
228
|
+
|
|
229
|
+
//markMessageAsSuccess
|
|
230
|
+
let findQuery = { documentId };
|
|
231
|
+
findQuery['systemData.policies.storage.privateTo'] = companyId;
|
|
232
|
+
let updateQuery = {};
|
|
233
|
+
const { $URN: externalId, actor } = response.message;
|
|
234
|
+
|
|
235
|
+
updateQuery['systemData.status'] = DOCUMENT_STATUS.SUCCESS;
|
|
236
|
+
updateQuery['authors[0].authorInfo.externalId'] = actor;
|
|
237
|
+
updateQuery['metaData.externalId'] = externalId;
|
|
238
|
+
updateQuery.documentId = Buffer.from(`${externalId}`).toString(
|
|
239
|
+
'base64'
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
updatedDocument = await messagesRepository.updateOne(
|
|
243
|
+
findQuery,
|
|
244
|
+
updateQuery
|
|
245
|
+
);
|
|
244
246
|
} catch (err) {
|
|
245
|
-
logger.error(
|
|
247
|
+
this.logger.error(
|
|
246
248
|
documentId + ' - exception linkedin publish ' + err,
|
|
247
249
|
err
|
|
248
250
|
);
|
|
251
|
+
|
|
252
|
+
let findQuery = { documentId };
|
|
253
|
+
findQuery['systemData.policies.storage.privateTo'] = companyId;
|
|
254
|
+
let updateQuery = {};
|
|
255
|
+
updateQuery['systemData.status'] = DOCUMENT_STATUS.FAILED;
|
|
256
|
+
updateQuery['systemData.error'] =
|
|
257
|
+
err && err.response && err.response.error
|
|
258
|
+
? err.response.error
|
|
259
|
+
: err;
|
|
260
|
+
updatedDocument = await messagesRepository.updateOne(
|
|
261
|
+
findQuery,
|
|
262
|
+
updateQuery
|
|
263
|
+
);
|
|
249
264
|
}
|
|
250
265
|
|
|
266
|
+
//sendNotification -> needs to wait for temp document to reach user
|
|
267
|
+
setTimeout(() => {
|
|
268
|
+
PushRepository.publish(
|
|
269
|
+
`${companyId}-${documentId}`,
|
|
270
|
+
updatedDocument
|
|
271
|
+
);
|
|
272
|
+
}, 5000);
|
|
273
|
+
|
|
251
274
|
return response;
|
|
252
275
|
}
|
|
253
276
|
|
|
@@ -268,7 +291,7 @@ export class LinkedInApiClient {
|
|
|
268
291
|
|
|
269
292
|
let response;
|
|
270
293
|
try {
|
|
271
|
-
let credential = await this.
|
|
294
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
272
295
|
credentialId,
|
|
273
296
|
companyId
|
|
274
297
|
);
|
|
@@ -292,7 +315,7 @@ export class LinkedInApiClient {
|
|
|
292
315
|
};
|
|
293
316
|
return response;
|
|
294
317
|
} catch (err) {
|
|
295
|
-
logger.error(
|
|
318
|
+
this.logger.error(
|
|
296
319
|
documentId + ' - exception linkedin media register ' + err,
|
|
297
320
|
err
|
|
298
321
|
);
|
|
@@ -320,14 +343,16 @@ export class LinkedInApiClient {
|
|
|
320
343
|
})
|
|
321
344
|
.then((result) => result.body);
|
|
322
345
|
} catch (error) {
|
|
323
|
-
logger.error(
|
|
346
|
+
this.logger.error(
|
|
324
347
|
`Failed requesting LinkedIn API for profileId ${urn}`,
|
|
325
348
|
error
|
|
326
349
|
);
|
|
327
350
|
return;
|
|
328
351
|
}
|
|
329
352
|
|
|
330
|
-
logger.info(
|
|
353
|
+
this.logger.info(
|
|
354
|
+
`Finished requesting LinkedIn API for profileId ${urn}`
|
|
355
|
+
);
|
|
331
356
|
|
|
332
357
|
return profile;
|
|
333
358
|
}
|
|
@@ -353,13 +378,13 @@ export class LinkedInApiClient {
|
|
|
353
378
|
})
|
|
354
379
|
.then((result) => result.body);
|
|
355
380
|
} catch (error) {
|
|
356
|
-
logger.error(
|
|
381
|
+
this.logger.error(
|
|
357
382
|
`Failed requesting LinkedIn API for organizationId ${urn}`,
|
|
358
383
|
error
|
|
359
384
|
);
|
|
360
385
|
}
|
|
361
386
|
|
|
362
|
-
logger.info(
|
|
387
|
+
this.logger.info(
|
|
363
388
|
`Finished requesting LinkedIn API for organizationId ${urn}`
|
|
364
389
|
);
|
|
365
390
|
|
|
@@ -385,14 +410,14 @@ export class LinkedInApiClient {
|
|
|
385
410
|
'LinkedIn-Version': '202305',
|
|
386
411
|
});
|
|
387
412
|
} catch (error) {
|
|
388
|
-
logger.error('Error in getAllStats ' + error, error);
|
|
413
|
+
this.logger.error('Error in getAllStats ' + error, error);
|
|
389
414
|
}
|
|
390
415
|
|
|
391
416
|
let { commentSummary, reactionSummaries } = response.body || {};
|
|
392
417
|
if (commentSummary && reactionSummaries) {
|
|
393
418
|
return { commentSummary, reactionSummaries };
|
|
394
419
|
} else {
|
|
395
|
-
logger.error(
|
|
420
|
+
this.logger.error(
|
|
396
421
|
`Invalid response getting all Linkedin Stats for externalId = ${externalId} ` +
|
|
397
422
|
response,
|
|
398
423
|
response
|
|
@@ -413,14 +438,14 @@ export class LinkedInApiClient {
|
|
|
413
438
|
reactionSummaries,
|
|
414
439
|
};
|
|
415
440
|
} catch (error) {
|
|
416
|
-
logger.error('Error in getSocialStats: ' + error, error);
|
|
441
|
+
this.logger.error('Error in getSocialStats: ' + error, error);
|
|
417
442
|
}
|
|
418
443
|
}
|
|
419
444
|
|
|
420
445
|
async getImageMedia(mediaId, credentialId, companyId) {
|
|
421
446
|
let response = {};
|
|
422
447
|
|
|
423
|
-
let credential = await this.
|
|
448
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
424
449
|
credentialId,
|
|
425
450
|
companyId
|
|
426
451
|
);
|
|
@@ -448,14 +473,14 @@ export class LinkedInApiClient {
|
|
|
448
473
|
'LinkedIn-Version': '202305',
|
|
449
474
|
});
|
|
450
475
|
} catch (error) {
|
|
451
|
-
logger.error('Error in getImageMedia ' + error, error);
|
|
476
|
+
this.logger.error('Error in getImageMedia ' + error, error);
|
|
452
477
|
}
|
|
453
478
|
|
|
454
479
|
let { downloadUrl } = response.body || {};
|
|
455
480
|
if (downloadUrl) {
|
|
456
481
|
return { downloadUrl };
|
|
457
482
|
} else {
|
|
458
|
-
logger.error(
|
|
483
|
+
this.logger.error(
|
|
459
484
|
`Invalid response getting Linkedin media for mediaId = ${mediaId} ` +
|
|
460
485
|
response,
|
|
461
486
|
response
|
|
@@ -468,7 +493,7 @@ export class LinkedInApiClient {
|
|
|
468
493
|
let response = {};
|
|
469
494
|
let tempValue;
|
|
470
495
|
|
|
471
|
-
let credential = await this.
|
|
496
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
472
497
|
credentialId,
|
|
473
498
|
companyId
|
|
474
499
|
);
|
|
@@ -504,14 +529,14 @@ export class LinkedInApiClient {
|
|
|
504
529
|
'LinkedIn-Version': '202305',
|
|
505
530
|
});
|
|
506
531
|
} catch (error) {
|
|
507
|
-
logger.error('Error in getVideoMedia ' + error, error);
|
|
532
|
+
this.logger.error('Error in getVideoMedia ' + error, error);
|
|
508
533
|
}
|
|
509
534
|
|
|
510
535
|
let { thumbnail, downloadUrl } = response.body || {};
|
|
511
536
|
if (downloadUrl) {
|
|
512
537
|
return { thumbnail, downloadUrl };
|
|
513
538
|
} else {
|
|
514
|
-
logger.error(
|
|
539
|
+
this.logger.error(
|
|
515
540
|
`Invalid response getting Linkedin media for mediaId = ${mediaId} ` +
|
|
516
541
|
response,
|
|
517
542
|
response
|
|
@@ -552,7 +577,7 @@ export class LinkedInApiClient {
|
|
|
552
577
|
|
|
553
578
|
return {};
|
|
554
579
|
} catch (error) {
|
|
555
|
-
logger.error('Error in getMedia: ' + error, error);
|
|
580
|
+
this.logger.error('Error in getMedia: ' + error, error);
|
|
556
581
|
}
|
|
557
582
|
}
|
|
558
583
|
|
|
@@ -564,7 +589,7 @@ export class LinkedInApiClient {
|
|
|
564
589
|
) {
|
|
565
590
|
let result;
|
|
566
591
|
try {
|
|
567
|
-
let credential = await this.
|
|
592
|
+
let credential = await this.tokenService.getByCredentialId(
|
|
568
593
|
credentialId,
|
|
569
594
|
companyId
|
|
570
595
|
);
|
|
@@ -586,7 +611,7 @@ export class LinkedInApiClient {
|
|
|
586
611
|
})
|
|
587
612
|
.then((result) => result.body);
|
|
588
613
|
} catch (error) {
|
|
589
|
-
logger.error('Error in getLikesByUser: ' + error, error);
|
|
614
|
+
this.logger.error('Error in getLikesByUser: ' + error, error);
|
|
590
615
|
return false;
|
|
591
616
|
}
|
|
592
617
|
return true;
|
|
@@ -595,7 +620,7 @@ export class LinkedInApiClient {
|
|
|
595
620
|
async uploadMedia(query) {
|
|
596
621
|
const { socialAccountId, url, token, data } = query;
|
|
597
622
|
|
|
598
|
-
logger.info(
|
|
623
|
+
this.logger.info(
|
|
599
624
|
`Starting to upload media to linkedin for ${socialAccountId}`,
|
|
600
625
|
{ url: query.url }
|
|
601
626
|
);
|
|
@@ -613,7 +638,7 @@ export class LinkedInApiClient {
|
|
|
613
638
|
})
|
|
614
639
|
.send(data)
|
|
615
640
|
.catch((err) => {
|
|
616
|
-
logger.error(err);
|
|
641
|
+
this.logger.error(err);
|
|
617
642
|
throw err;
|
|
618
643
|
});
|
|
619
644
|
}
|
package/src/data-access/index.js
CHANGED
|
@@ -10,7 +10,6 @@ import { InstagramApiClient } from './http/instagramApi.client.js';
|
|
|
10
10
|
import { InstagramVideoClient } from './http/InstagramVideoClient.js';
|
|
11
11
|
import { IRClient } from './http/ir.client.js';
|
|
12
12
|
import { LinkedInApiClient } from './http/linkedInApi.client.js';
|
|
13
|
-
import { TikTokApiClient } from './http/tiktokApi.client.js';
|
|
14
13
|
import { MasfClient } from './http/masf.client.js';
|
|
15
14
|
import { WarpZoneApiClient } from './http/WarpZoneApi.client.js';
|
|
16
15
|
|
|
@@ -27,7 +26,6 @@ export {
|
|
|
27
26
|
InstagramVideoClient,
|
|
28
27
|
IRClient,
|
|
29
28
|
LinkedInApiClient,
|
|
30
|
-
TikTokApiClient,
|
|
31
29
|
MasfClient,
|
|
32
30
|
WarpZoneApiClient,
|
|
33
31
|
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read # for checkout
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
release:
|
|
12
|
-
name: Release
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
permissions:
|
|
15
|
-
contents: write # to be able to publish a GitHub release
|
|
16
|
-
issues: write # to be able to comment on released issues
|
|
17
|
-
pull-requests: write # to be able to comment on released pull requests
|
|
18
|
-
id-token: write # to enable use of OIDC for npm provenance
|
|
19
|
-
steps:
|
|
20
|
-
- name: Checkout
|
|
21
|
-
uses: actions/checkout@v3
|
|
22
|
-
with:
|
|
23
|
-
fetch-depth: 0
|
|
24
|
-
persist-credential: false
|
|
25
|
-
token: ${{ secrets.GH_TOKEN }}
|
|
26
|
-
- name: Setup Node.js
|
|
27
|
-
uses: actions/setup-node@v3
|
|
28
|
-
with:
|
|
29
|
-
node-version: "lts/*"
|
|
30
|
-
- name: NPM Auth Setup
|
|
31
|
-
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
|
|
32
|
-
- name: NPM whoami
|
|
33
|
-
run: npm whoami
|
|
34
|
-
- name: Install dependencies
|
|
35
|
-
run: npm clean-install
|
|
36
|
-
- name: Verify signatures
|
|
37
|
-
run: npm audit signatures
|
|
38
|
-
- name: Release
|
|
39
|
-
env:
|
|
40
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
41
|
-
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
42
|
-
run: npx semantic-release
|
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
import superagent from 'superagent';
|
|
2
|
-
import configuration from '../../lib/configuration.js';
|
|
3
|
-
import logger from '../../lib/logger.js';
|
|
4
|
-
import { removePrefix } from '../../lib/externalId.helpers.js';
|
|
5
|
-
import { CredentialsApiClient } from '../http/credentialsApi.client.js';
|
|
6
|
-
|
|
7
|
-
export class TikTokApiClient {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.tiktokURL = configuration.get('TIKTOK_API_URL');
|
|
10
|
-
this.credentialsAPI = new CredentialsApiClient();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async getAuthorization(document) {
|
|
14
|
-
const {
|
|
15
|
-
documentId,
|
|
16
|
-
systemData: {
|
|
17
|
-
connectionsCredential: credentialId,
|
|
18
|
-
policies: { storage: { privateTo: companyId } = {} } = {},
|
|
19
|
-
} = {},
|
|
20
|
-
} = document;
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const credential = await this.credentialsAPI.getToken(
|
|
24
|
-
credentialId,
|
|
25
|
-
companyId
|
|
26
|
-
);
|
|
27
|
-
return `${credential.token}`;
|
|
28
|
-
} catch (error) {
|
|
29
|
-
logger.error(
|
|
30
|
-
`${documentId} - error getting tiktok token - ${error.code}`,
|
|
31
|
-
error
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async sendPost({
|
|
37
|
-
paramString = '',
|
|
38
|
-
headers = {},
|
|
39
|
-
document,
|
|
40
|
-
postData = undefined,
|
|
41
|
-
}) {
|
|
42
|
-
let response = {};
|
|
43
|
-
try {
|
|
44
|
-
response = await superagent
|
|
45
|
-
.post(this.tiktokURL + paramString)
|
|
46
|
-
.set('Accept', 'application/json')
|
|
47
|
-
.set('Content-Type', 'application/json')
|
|
48
|
-
.set('Access-Token', await this.getAuthorization(document))
|
|
49
|
-
.send(postData);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
let errorText = '';
|
|
52
|
-
if (
|
|
53
|
-
err &&
|
|
54
|
-
err.response &&
|
|
55
|
-
err.response.body &&
|
|
56
|
-
err.response.body.error
|
|
57
|
-
) {
|
|
58
|
-
errorText = `Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`;
|
|
59
|
-
logger.error(errorText);
|
|
60
|
-
} else {
|
|
61
|
-
errorText = `Failed to call tiktok api for paramString ${paramString}`;
|
|
62
|
-
logger.error(errorText, err);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
throw new Error(errorText);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return response;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// assumes batch calls are using the same credential
|
|
72
|
-
async sendRequest({ paramString = '', headers = {}, document }) {
|
|
73
|
-
let response = {};
|
|
74
|
-
try {
|
|
75
|
-
response = await superagent
|
|
76
|
-
.get(this.tiktokURL + paramString)
|
|
77
|
-
.set('Accept', 'application/json')
|
|
78
|
-
.set('Content-Type', 'application/json')
|
|
79
|
-
.set('Access-Token', await this.getAuthorization(document))
|
|
80
|
-
.send();
|
|
81
|
-
} catch (err) {
|
|
82
|
-
let errorText = '';
|
|
83
|
-
if (
|
|
84
|
-
err &&
|
|
85
|
-
err.response &&
|
|
86
|
-
err.response.body &&
|
|
87
|
-
err.response.body.error
|
|
88
|
-
) {
|
|
89
|
-
errorText = `Failed to call tiktok api for paramString ${paramString}: ${err.response.body.error.message}`;
|
|
90
|
-
logger.error(errorText);
|
|
91
|
-
} else {
|
|
92
|
-
errorText = `Failed to call tiktok api for paramString ${paramString}`;
|
|
93
|
-
logger.error(errorText, err);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
throw new Error(errorText);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (response.status !== 200) {
|
|
100
|
-
logger.error(
|
|
101
|
-
`Failed to call tiktok api for documentId ${documentId}`,
|
|
102
|
-
response.body
|
|
103
|
-
);
|
|
104
|
-
let error = new Error(
|
|
105
|
-
`Failed to call tiktok api for documentId ${documentId}`
|
|
106
|
-
);
|
|
107
|
-
error.code = response.status;
|
|
108
|
-
throw error;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return response.body;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async getChannelInfoForDocuments(documents) {
|
|
115
|
-
const channelInfo = await this.getStatsForDocuments(
|
|
116
|
-
documents,
|
|
117
|
-
'metaData.authors.0.authorInfo.externalId',
|
|
118
|
-
{
|
|
119
|
-
og: ['video/list/'],
|
|
120
|
-
}
|
|
121
|
-
);
|
|
122
|
-
return channelInfo;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async getStatsForDocuments(
|
|
126
|
-
documents,
|
|
127
|
-
externalIdFrom = 'metaData.externalId',
|
|
128
|
-
paramsByType = {
|
|
129
|
-
og: ['video/list/'],
|
|
130
|
-
}
|
|
131
|
-
) {
|
|
132
|
-
// for batching separate og and comment/reply requests per credential
|
|
133
|
-
const documentsByTypeAndCredentials = documents.reduce(
|
|
134
|
-
(retObj, document, index) => {
|
|
135
|
-
const paramArray =
|
|
136
|
-
paramsByType[document.metaData.discussionType];
|
|
137
|
-
if (paramArray) {
|
|
138
|
-
paramArray.forEach((paramString) => {
|
|
139
|
-
let discussionTypeBucket =
|
|
140
|
-
retObj[
|
|
141
|
-
`${paramString}${document.systemData.connectionsCredential}`
|
|
142
|
-
];
|
|
143
|
-
if (!discussionTypeBucket) {
|
|
144
|
-
discussionTypeBucket = {
|
|
145
|
-
paramString,
|
|
146
|
-
document,
|
|
147
|
-
externalIds: [],
|
|
148
|
-
externalIdToDocumentIndex: {},
|
|
149
|
-
};
|
|
150
|
-
retObj[
|
|
151
|
-
`${paramString}${document.systemData.connectionsCredential}`
|
|
152
|
-
] = discussionTypeBucket;
|
|
153
|
-
}
|
|
154
|
-
const externalIdTrimmed = removePrefix(
|
|
155
|
-
// javascript weirdness to get around '.' notation
|
|
156
|
-
externalIdFrom
|
|
157
|
-
.split('.')
|
|
158
|
-
.reduce((a, b) => a[b], document)
|
|
159
|
-
);
|
|
160
|
-
discussionTypeBucket.externalIds.push(
|
|
161
|
-
externalIdTrimmed
|
|
162
|
-
);
|
|
163
|
-
discussionTypeBucket.externalIdToDocumentIndex[
|
|
164
|
-
externalIdTrimmed
|
|
165
|
-
] = index;
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
return retObj;
|
|
169
|
-
},
|
|
170
|
-
{}
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const sortedResults = Array(documents.length).fill();
|
|
174
|
-
await Promise.all(
|
|
175
|
-
Object.values(documentsByTypeAndCredentials).map(
|
|
176
|
-
async (documentsByTypeAndCredential) => {
|
|
177
|
-
if (documentsByTypeAndCredential.externalIds.length) {
|
|
178
|
-
const {
|
|
179
|
-
metaData: {
|
|
180
|
-
inReplyTo: { profileId: business_id },
|
|
181
|
-
},
|
|
182
|
-
} = documentsByTypeAndCredential.document;
|
|
183
|
-
const trimmedBusinessId = removePrefix(business_id);
|
|
184
|
-
const requestResult = await this.sendRequest({
|
|
185
|
-
paramString: `${
|
|
186
|
-
documentsByTypeAndCredential.paramString
|
|
187
|
-
}?business_id=${trimmedBusinessId}&fields=["item_id","create_time","thumbnail_url","share_url","embed_url","caption","video_views","likes","comments","shares"]&filters=${JSON.stringify(
|
|
188
|
-
{
|
|
189
|
-
video_ids:
|
|
190
|
-
documentsByTypeAndCredential.externalIds,
|
|
191
|
-
}
|
|
192
|
-
)}`,
|
|
193
|
-
document: documentsByTypeAndCredential.document,
|
|
194
|
-
});
|
|
195
|
-
requestResult.data.videos.forEach(
|
|
196
|
-
({
|
|
197
|
-
item_id,
|
|
198
|
-
create_time,
|
|
199
|
-
thumbnail_url,
|
|
200
|
-
share_url,
|
|
201
|
-
embed_url,
|
|
202
|
-
caption,
|
|
203
|
-
video_views,
|
|
204
|
-
likes,
|
|
205
|
-
comments,
|
|
206
|
-
shares,
|
|
207
|
-
...args
|
|
208
|
-
}) => {
|
|
209
|
-
const documentIndex =
|
|
210
|
-
documentsByTypeAndCredential
|
|
211
|
-
.externalIdToDocumentIndex[item_id];
|
|
212
|
-
sortedResults[documentIndex] = {
|
|
213
|
-
...sortedResults[documentIndex],
|
|
214
|
-
item_id,
|
|
215
|
-
create_time,
|
|
216
|
-
thumbnail_url,
|
|
217
|
-
externalId:
|
|
218
|
-
documents[documentIndex].metaData
|
|
219
|
-
.externalId,
|
|
220
|
-
share_url,
|
|
221
|
-
embed_url,
|
|
222
|
-
caption,
|
|
223
|
-
video_views,
|
|
224
|
-
likes,
|
|
225
|
-
comments,
|
|
226
|
-
shares,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
)
|
|
233
|
-
);
|
|
234
|
-
return sortedResults;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async publish(message, videoId, markMessageAsCompleteDocumentId) {
|
|
238
|
-
const {
|
|
239
|
-
metaData: { discussionType },
|
|
240
|
-
} = message;
|
|
241
|
-
let publishedMessage;
|
|
242
|
-
|
|
243
|
-
switch (discussionType) {
|
|
244
|
-
case 'qt':
|
|
245
|
-
publishedMessage = await this.insertComment(message);
|
|
246
|
-
break;
|
|
247
|
-
case 're':
|
|
248
|
-
publishedMessage = await this.insertReply(
|
|
249
|
-
videoId,
|
|
250
|
-
message,
|
|
251
|
-
markMessageAsCompleteDocumentId
|
|
252
|
-
);
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return publishedMessage;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
async insertComment(document) {
|
|
260
|
-
const {
|
|
261
|
-
body: {
|
|
262
|
-
content: { text: text },
|
|
263
|
-
},
|
|
264
|
-
metaData: {
|
|
265
|
-
source: { id: business_id },
|
|
266
|
-
inReplyTo: { id: video_id },
|
|
267
|
-
},
|
|
268
|
-
} = document;
|
|
269
|
-
const { body: publishedMessage } =
|
|
270
|
-
(await this.sendPost({
|
|
271
|
-
paramString: 'comment/create/',
|
|
272
|
-
postData: {
|
|
273
|
-
business_id,
|
|
274
|
-
video_id,
|
|
275
|
-
text,
|
|
276
|
-
},
|
|
277
|
-
document,
|
|
278
|
-
})) || {};
|
|
279
|
-
return publishedMessage;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async insertReply(videoId, document, markMessageAsCompleteDocumentId) {
|
|
283
|
-
const {
|
|
284
|
-
body: {
|
|
285
|
-
content: { text: text },
|
|
286
|
-
},
|
|
287
|
-
metaData: {
|
|
288
|
-
inReplyTo: { id: comment_id, profileId: business_id },
|
|
289
|
-
},
|
|
290
|
-
} = document;
|
|
291
|
-
|
|
292
|
-
const { body: publishedMessage } =
|
|
293
|
-
(await this.sendPost({
|
|
294
|
-
paramString: 'comment/reply/create/',
|
|
295
|
-
postData: {
|
|
296
|
-
business_id: document.metaData.source.id,
|
|
297
|
-
comment_id: markMessageAsCompleteDocumentId || comment_id,
|
|
298
|
-
video_id: removePrefix(videoId),
|
|
299
|
-
text,
|
|
300
|
-
},
|
|
301
|
-
document,
|
|
302
|
-
})) || {};
|
|
303
|
-
|
|
304
|
-
return publishedMessage;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async toggleLike(document) {
|
|
308
|
-
const {
|
|
309
|
-
enrichments: {
|
|
310
|
-
socialScores: { tt_liked_by_user: likedByUser },
|
|
311
|
-
},
|
|
312
|
-
} = document;
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
let likeResponse = await (!likedByUser
|
|
316
|
-
? this.like(document)
|
|
317
|
-
: this.unlike(document));
|
|
318
|
-
return likeResponse;
|
|
319
|
-
} catch (error) {
|
|
320
|
-
logger.error(`${document} - error recieved - ${error.code}`, error);
|
|
321
|
-
throw error;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
async toggleHide(document) {
|
|
326
|
-
const {
|
|
327
|
-
documentId,
|
|
328
|
-
appData: { hidden: hiddenOnNative },
|
|
329
|
-
} = document;
|
|
330
|
-
|
|
331
|
-
let response;
|
|
332
|
-
try {
|
|
333
|
-
if (hiddenOnNative) {
|
|
334
|
-
response = await this.hide(document);
|
|
335
|
-
} else {
|
|
336
|
-
response = await this.unhide(document);
|
|
337
|
-
}
|
|
338
|
-
logger.info(
|
|
339
|
-
`Native Tiktok API Hide Response for documentId ${documentId}`,
|
|
340
|
-
{ status: response.status, ok: response.ok }
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
if (response.message === 'OK') {
|
|
344
|
-
return response;
|
|
345
|
-
}
|
|
346
|
-
} catch (error) {
|
|
347
|
-
logger.error(
|
|
348
|
-
`${documentId} - error recieved - ${error.code}`,
|
|
349
|
-
error
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async like(document) {
|
|
355
|
-
const {
|
|
356
|
-
metaData: {
|
|
357
|
-
externalId: comment_id,
|
|
358
|
-
source: { id: sourceId },
|
|
359
|
-
},
|
|
360
|
-
} = document;
|
|
361
|
-
const { body: publishedMessage } =
|
|
362
|
-
(await this.sendPost({
|
|
363
|
-
paramString: 'comment/like/',
|
|
364
|
-
postData: {
|
|
365
|
-
business_id: removePrefix(sourceId),
|
|
366
|
-
comment_id: removePrefix(comment_id),
|
|
367
|
-
action: 'LIKE',
|
|
368
|
-
},
|
|
369
|
-
document,
|
|
370
|
-
})) || {};
|
|
371
|
-
return publishedMessage;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
async unlike(document) {
|
|
375
|
-
const {
|
|
376
|
-
metaData: {
|
|
377
|
-
inReplyTo: { id: comment_id },
|
|
378
|
-
source: { id: sourceId },
|
|
379
|
-
},
|
|
380
|
-
} = document;
|
|
381
|
-
const { body: publishedMessage } =
|
|
382
|
-
(await this.sendPost({
|
|
383
|
-
paramString: 'comment/like/',
|
|
384
|
-
postData: {
|
|
385
|
-
business_id: removePrefix(sourceId),
|
|
386
|
-
comment_id: removePrefix(comment_id),
|
|
387
|
-
action: 'unlike',
|
|
388
|
-
},
|
|
389
|
-
document,
|
|
390
|
-
})) || {};
|
|
391
|
-
return publishedMessage;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
async hide(document) {
|
|
395
|
-
const {
|
|
396
|
-
metaData: {
|
|
397
|
-
externalId: comment_id,
|
|
398
|
-
source: { id: sourceId },
|
|
399
|
-
inReplyTo: { id: video_id },
|
|
400
|
-
},
|
|
401
|
-
} = document;
|
|
402
|
-
const { body: publishedMessage } =
|
|
403
|
-
(await this.sendPost({
|
|
404
|
-
paramString: 'comment/hide/',
|
|
405
|
-
postData: {
|
|
406
|
-
business_id: removePrefix(sourceId),
|
|
407
|
-
comment_id: removePrefix(comment_id),
|
|
408
|
-
video_id: removePrefix(video_id),
|
|
409
|
-
action: 'HIDE',
|
|
410
|
-
},
|
|
411
|
-
document,
|
|
412
|
-
})) || {};
|
|
413
|
-
return publishedMessage;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
async unhide(document) {
|
|
417
|
-
const {
|
|
418
|
-
metaData: {
|
|
419
|
-
externalId: comment_id,
|
|
420
|
-
source: { id: sourceId },
|
|
421
|
-
inReplyTo: { id: video_id },
|
|
422
|
-
},
|
|
423
|
-
} = document;
|
|
424
|
-
const { body: publishedMessage } =
|
|
425
|
-
(await this.sendPost({
|
|
426
|
-
paramString: 'comment/hide/',
|
|
427
|
-
postData: {
|
|
428
|
-
business_id: removePrefix(sourceId),
|
|
429
|
-
comment_id: removePrefix(comment_id),
|
|
430
|
-
video_id: removePrefix(video_id),
|
|
431
|
-
action: 'UNHIDE',
|
|
432
|
-
},
|
|
433
|
-
document,
|
|
434
|
-
})) || {};
|
|
435
|
-
return publishedMessage;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async deleteComment(document) {
|
|
439
|
-
const {
|
|
440
|
-
metaData: {
|
|
441
|
-
inReplyTo: { id: comment_id, profileId: business_id },
|
|
442
|
-
},
|
|
443
|
-
} = document;
|
|
444
|
-
const { body: publishedMessage } =
|
|
445
|
-
(await this.sendPost({
|
|
446
|
-
paramString: 'comment/delete/',
|
|
447
|
-
postData: {
|
|
448
|
-
business_id,
|
|
449
|
-
comment_id,
|
|
450
|
-
},
|
|
451
|
-
document,
|
|
452
|
-
})) || {};
|
|
453
|
-
return publishedMessage;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
async getProfile(business_id, document) {
|
|
457
|
-
const fields = '["username", "display_name", "profile_image"]';
|
|
458
|
-
const profile =
|
|
459
|
-
(await this.sendRequest({
|
|
460
|
-
paramString: `get/?business_id=${business_id}&fields=${fields}`,
|
|
461
|
-
document,
|
|
462
|
-
})) || {};
|
|
463
|
-
return profile;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
async getPostData(business_id, video_id, document) {
|
|
467
|
-
const fields =
|
|
468
|
-
'["item_id", "thumbnail_url", "create_time", "username", "display_name", "profile_image"]';
|
|
469
|
-
const video_ids = `["${video_id}"]`;
|
|
470
|
-
const profile =
|
|
471
|
-
(await this.sendRequest({
|
|
472
|
-
paramString: `video/list?business_id=${business_id}&fields=${fields}&filters={"video_ids":${video_ids}}`,
|
|
473
|
-
document,
|
|
474
|
-
})) || {};
|
|
475
|
-
return profile;
|
|
476
|
-
}
|
|
477
|
-
}
|