@meltwater/conversations-api-services 1.0.0 → 1.0.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltwater/conversations-api-services",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Repository to contain all conversations api services shared across our services",
5
5
  "type": "module",
6
6
  "main": "src/data-access/index.js",
@@ -0,0 +1,164 @@
1
+ import superagent from 'superagent';
2
+ import logger from '../../lib/logger.js';
3
+ import { generateToken } from '../../lib/auth.helpers.js';
4
+
5
+ class AssetManagerClient {
6
+ apiKey;
7
+ constructor() {
8
+ const { GRAPHQL_GATEWAY_URL } = process.env;
9
+ this.gatewayURL = GRAPHQL_GATEWAY_URL;
10
+ this.request = superagent;
11
+ }
12
+
13
+ /**
14
+ *
15
+ * @param {*} assetQuery
16
+ * @param {*} assetQuery.assetId
17
+ * @param {*} assetQuery.userId
18
+ * @param {*} assetQuery.companyId
19
+ * @returns
20
+ */
21
+ async getURL({ assetId, userId, companyId }) {
22
+ try {
23
+ const response = await this.request
24
+ .post(`${this.gatewayURL}`)
25
+ .set('apollographql-client-name', 'phoenix-conversations')
26
+ .set('Authorization', await generateToken(userId, companyId))
27
+ .send({
28
+ query: `
29
+ query getAssetUrlForPublishing(
30
+ $filter: AssetFilterInput
31
+ ) {
32
+ assets(filter: $filter) {
33
+ edges {
34
+ node {
35
+ url
36
+ }
37
+ }
38
+ }
39
+ }
40
+ `,
41
+ operationName: 'getAssetUrlForPublishing',
42
+ variables: {
43
+ filter: {
44
+ ids: [assetId],
45
+ uploadPath: [
46
+ 'ASSET_MANAGER',
47
+ 'ENGAGE_CONVERSATIONS',
48
+ ],
49
+ },
50
+ },
51
+ });
52
+ return response.body;
53
+ } catch (exception) {
54
+ // How would you prefer to handle this
55
+ logger.error('Error getting asset url', {
56
+ assetId,
57
+ userId,
58
+ companyId,
59
+ exception,
60
+ });
61
+ throw exception;
62
+ }
63
+ }
64
+
65
+ async getAssetUrlAndSize({ assetId, userId, companyId }) {
66
+ try {
67
+ const response = await this.request
68
+ .post(`${this.gatewayURL}`)
69
+ .set('apollographql-client-name', 'grimoire-publisher')
70
+ .set('Authorization', await generateToken(userId, companyId))
71
+ .send({
72
+ query: `
73
+ query getAssetUrlAndSizeForPublishing(
74
+ $filter: AssetFilterInput
75
+ ) {
76
+ assets(filter: $filter) {
77
+ edges {
78
+ node {
79
+ url
80
+ size {
81
+ bytes
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ `,
88
+ operationName: 'getAssetUrlAndSizeForPublishing',
89
+ variables: {
90
+ filter: {
91
+ ids: [assetId],
92
+ uploadPath: [
93
+ 'ASSET_MANAGER',
94
+ 'ENGAGE_CONVERSATIONS',
95
+ ],
96
+ },
97
+ },
98
+ });
99
+ return response.body;
100
+ } catch (exception) {
101
+ // How would you prefer to handle this
102
+ logger.error('Error getting asset', {
103
+ assetId,
104
+ userId,
105
+ companyId,
106
+ exception,
107
+ });
108
+ throw exception;
109
+ }
110
+ }
111
+
112
+ async getAsset({ assetId, userId, companyId }) {
113
+ try {
114
+ const response = await this.request
115
+ .post(`${this.gatewayURL}`)
116
+ .set('apollographql-client-name', 'grimoire-publisher')
117
+ .set('Authorization', await generateToken(userId, companyId))
118
+ .send({
119
+ query: `
120
+ query getAssetUrlAndSizeForPublishing(
121
+ $filter: AssetFilterInput
122
+ ) {
123
+ assets(filter: $filter) {
124
+ edges {
125
+ node {
126
+ fileName
127
+ url
128
+ size {
129
+ bytes
130
+ }
131
+ path
132
+ type
133
+ mimeType
134
+ }
135
+ }
136
+ }
137
+ }
138
+ `,
139
+ operationName: 'getAssetUrlAndSizeForPublishing',
140
+ variables: {
141
+ filter: {
142
+ ids: [assetId],
143
+ uploadPath: [
144
+ 'ASSET_MANAGER',
145
+ 'ENGAGE_CONVERSATIONS',
146
+ ],
147
+ },
148
+ },
149
+ });
150
+ return response.body;
151
+ } catch (exception) {
152
+ // How would you prefer to handle this
153
+ logger.error('Error getting asset', {
154
+ assetId,
155
+ userId,
156
+ companyId,
157
+ exception,
158
+ });
159
+ throw exception;
160
+ }
161
+ }
162
+ }
163
+
164
+ export const assetManagerClient = new AssetManagerClient();
@@ -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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- errorText = `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`;
173
- logger.error(errorText);
171
+ logger.error(
172
+ `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
173
+ );
174
174
  } else {
175
- errorText = `Failed to call facebook api for documentId ${documentId}`;
176
- logger.error(errorText, err);
175
+ logger.error(
176
+ `Failed to call facebook api for documentId ${documentId}`,
177
+ err
178
+ );
177
179
  }
178
180
 
179
- throw new Error(errorText);
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
- errorText = `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`;
215
- logger.error(errorText);
215
+ logger.error(
216
+ `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
217
+ );
216
218
  } else {
217
- errorText = `Failed to call facebook api for documentId ${documentId}`;
218
- logger.error(errorText, err);
219
+ logger.error(
220
+ `Failed to call facebook api for documentId ${documentId}`,
221
+ err
222
+ );
219
223
  }
220
224
 
221
- throw new Error(errorText);
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
- errorText = `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`;
257
- logger.error(errorText);
259
+ logger.error(
260
+ `Failed to call facebook api for documentId ${documentId}: ${err.response.body.error.message}`
261
+ );
258
262
  } else {
259
- errorText = `Failed to call facebook api for documentId ${documentId}`;
260
- logger.error(errorText, err);
263
+ logger.error(
264
+ `Failed to call facebook api for documentId ${documentId}`,
265
+ err
266
+ );
261
267
  }
262
268
 
263
- throw new Error(errorText);
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- errorText =
55
- 'Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}';
56
- logger.error(errorText);
56
+ logger.error(
57
+ `Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`
58
+ );
57
59
  } else {
58
- errorText =
59
- 'Failed to call instagram api for documentId ${documentId}';
60
- logger.error(errorText, err);
60
+ logger.error(
61
+ `Failed to call instagram api for documentId ${documentId}`,
62
+ err
63
+ );
61
64
  }
62
- throw new Error(errorText);
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
- { status: response.status, ok: response.ok }
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
- errorText = `Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`;
135
- logger.error(errorText);
136
+ logger.error(
137
+ `Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`
138
+ );
136
139
  } else {
137
- errorText = `Failed to call instagram api for documentId ${documentId}`;
138
- logger.error(errorText, err);
140
+ logger.error(
141
+ `Failed to call instagram api for documentId ${documentId}`,
142
+ err
143
+ );
139
144
  }
140
- throw new Error(errorText);
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
- errorText = `Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`;
174
- logger.error(errorText, err.response.body.error);
177
+ logger.error(
178
+ `Failed to call instagram api for documentId ${documentId}`,
179
+ err.response.body.error
180
+ );
175
181
  } else {
176
- errorText = `Failed to call instagram api for documentId ${documentId}`;
177
- logger.error(errorText, err);
182
+ logger.error(
183
+ `Failed to call instagram api for documentId ${documentId}`,
184
+ err
185
+ );
178
186
  }
179
- throw new Error(errorText);
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
- errorText = `Failed to call instagram api for documentId ${documentId}: ${err.response.body.error.message}`;
213
- logger.error(errorText, err.response.body.error);
219
+ logger.error(
220
+ `Failed to call instagram api for documentId ${documentId}`,
221
+ err.response.body.error
222
+ );
214
223
  } else {
215
- errorText = `Failed to call instagram api for documentId ${documentId}`;
216
- logger.error(errorText, err);
224
+ logger.error(
225
+ `Failed to call instagram api for documentId ${documentId}`,
226
+ err
227
+ );
217
228
  }
218
- throw new Error(errorText);
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
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
- { status: response.status, ok: response.ok }
544
+ { responseBody: response.body }
493
545
  );
494
546
  return response.body;
495
547
  }
@@ -1,6 +1,7 @@
1
1
  import { v4 } from 'uuid';
2
2
  import superagent from 'superagent';
3
3
  import logger from '../../lib/logger.js';
4
+ import { awsSecrets } from './secrets.js';
4
5
  import configuration from '../../lib/configuration.js';
5
6
  import { metricN } from '../../lib/metrics.helper.js';
6
7
 
@@ -15,19 +16,21 @@ export class IRClient {
15
16
  }
16
17
 
17
18
  async init() {
18
- let irApiKey = configuration.get('IR_API_KEY');
19
+ let irApiKey = process.env.IR_API_KEY
20
+ ? { IR_API_KEY: process.env.IR_API_KEY }
21
+ : await awsSecrets.getSecret('IR_API_KEY');
19
22
 
20
23
  this.searchServicesUrl = configuration.get('SEARCH_SERVICE_URL');
21
- this.searchServicesKey = irApiKey;
24
+ this.searchServicesKey = irApiKey.IR_API_KEY;
22
25
 
23
26
  this.documentRevisionsServiceUrl = configuration.get(
24
27
  'DOCUMENT_REVISIONS_SERVICE_URL'
25
28
  );
26
29
  this.documentServiceUrl = configuration.get('DOCUMENT_SERVICE_URL');
27
- this.documentServiceKey = irApiKey;
30
+ this.documentServiceKey = irApiKey.IR_API_KEY;
28
31
 
29
32
  this.exportApiUrl = configuration.get('EXPORT_API_URL');
30
- this.exportApiKey = irApiKey;
33
+ this.exportApiKey = irApiKey.IR_API_KEY;
31
34
  }
32
35
 
33
36
  async addRevisionsToDocuments(operations) {