@app-connect/core 1.7.15 → 1.7.17

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/handlers/admin.js CHANGED
@@ -109,7 +109,7 @@ async function getAdminReport({ rcAccountId, timezone, timeFrom, timeTo, groupBy
109
109
  var callLogStats = [];
110
110
  var itemKeys = [];
111
111
  for (const record of callsAggregationData.data.records) {
112
- if(!record?.info?.name){
112
+ if (!record?.info?.name) {
113
113
  continue;
114
114
  }
115
115
  itemKeys.push(record.info.name);
@@ -238,6 +238,17 @@ async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
238
238
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
239
239
  // eslint-disable-next-line no-param-reassign
240
240
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
241
+ if (!user) {
242
+ return {
243
+ successful: false,
244
+ returnMessage: {
245
+ message: `User session expired. Please connect again.`,
246
+ messageType: 'warning',
247
+ ttl: 5000
248
+ },
249
+ isRevokeUserSession: true
250
+ }
251
+ }
241
252
  authHeader = `Bearer ${user.accessToken}`;
242
253
  break;
243
254
  case 'apiKey':
@@ -399,6 +410,17 @@ async function reinitializeUserMapping({ user, hashedRcAccountId, rcExtensionLis
399
410
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
400
411
  // eslint-disable-next-line no-param-reassign
401
412
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
413
+ if (!user) {
414
+ return {
415
+ successful: false,
416
+ returnMessage: {
417
+ message: `User session expired. Please connect again.`,
418
+ messageType: 'warning',
419
+ ttl: 5000
420
+ },
421
+ isRevokeUserSession: true
422
+ }
423
+ }
402
424
  authHeader = `Bearer ${user.accessToken}`;
403
425
  break;
404
426
  case 'apiKey':
@@ -38,7 +38,7 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
38
38
  if (!isForceRefreshAccountData) {
39
39
  if (existingMatchedContactInfo) {
40
40
  console.log('found existing matched contact info in account data');
41
- return { successful: true, returnMessage: null, contact: existingMatchedContactInfo.data, extraDataTracking: null };
41
+ return { successful: true, returnMessage: null, contact: existingMatchedContactInfo.data, extraDataTracking: { isCached: true } };
42
42
  }
43
43
  }
44
44
  const proxyId = user.platformAdditionalInfo?.proxyId;
@@ -56,6 +56,17 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
56
56
  case 'oauth':
57
57
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
58
58
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
59
+ if (!user) {
60
+ return {
61
+ successful: false,
62
+ returnMessage: {
63
+ message: `User session expired. Please connect again.`,
64
+ messageType: 'warning',
65
+ ttl: 5000
66
+ },
67
+ isRevokeUserSession: true
68
+ }
69
+ }
59
70
  authHeader = `Bearer ${user.accessToken}`;
60
71
  tracer?.trace('handler.findContact:oauthAuth', { authHeader });
61
72
  break;
@@ -74,13 +85,12 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
74
85
  // save in org data
75
86
  // Danger: it does NOT support one RC account mapping to multiple CRM platforms, because contacts will be shared
76
87
  if (user.rcAccountId) {
77
- if(existingMatchedContactInfo)
78
- {
88
+ if (existingMatchedContactInfo) {
79
89
  await existingMatchedContactInfo.update({
80
90
  data: matchedContactInfo
81
91
  });
82
92
  }
83
- else{
93
+ else {
84
94
  await AccountDataModel.create({
85
95
  rcAccountId: user.rcAccountId,
86
96
  platformName: platform,
@@ -154,6 +164,17 @@ async function createContact({ platform, userId, phoneNumber, newContactName, ne
154
164
  case 'oauth':
155
165
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
156
166
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
167
+ if (!user) {
168
+ return {
169
+ successful: false,
170
+ returnMessage: {
171
+ message: `User session expired. Please connect again.`,
172
+ messageType: 'warning',
173
+ ttl: 5000
174
+ },
175
+ isRevokeUserSession: true
176
+ }
177
+ }
157
178
  authHeader = `Bearer ${user.accessToken}`;
158
179
  break;
159
180
  case 'apiKey':
@@ -203,6 +224,17 @@ async function findContactWithName({ platform, userId, name }) {
203
224
  case 'oauth':
204
225
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
205
226
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
227
+ if (!user) {
228
+ return {
229
+ successful: false,
230
+ returnMessage: {
231
+ message: `User session expired. Please connect again.`,
232
+ messageType: 'warning',
233
+ ttl: 5000
234
+ },
235
+ isRevokeUserSession: true
236
+ }
237
+ }
206
238
  authHeader = `Bearer ${user.accessToken}`;
207
239
  break;
208
240
  case 'apiKey':
@@ -45,6 +45,17 @@ async function upsertCallDisposition({ platform, userId, sessionId, dispositions
45
45
  case 'oauth':
46
46
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
47
47
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
48
+ if (!user) {
49
+ return {
50
+ successful: false,
51
+ returnMessage: {
52
+ message: `User session expired. Please connect again.`,
53
+ messageType: 'warning',
54
+ ttl: 5000
55
+ },
56
+ isRevokeUserSession: true
57
+ }
58
+ }
48
59
  authHeader = `Bearer ${user.accessToken}`;
49
60
  break;
50
61
  case 'apiKey':
package/handlers/log.js CHANGED
@@ -13,6 +13,7 @@ const moment = require('moment');
13
13
  const { getMediaReaderLinkByPlatformMediaLink } = require('../lib/util');
14
14
  const logger = require('../lib/logger');
15
15
  const { handleApiError, handleDatabaseError } = require('../lib/errorHandler');
16
+ const { AccountDataModel } = require('../models/accountDataModel');
16
17
 
17
18
  async function createCallLog({ platform, userId, incomingData, hashedAccountId, isFromSSCL }) {
18
19
  try {
@@ -77,6 +78,17 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
77
78
  case 'oauth':
78
79
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
79
80
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
81
+ if (!user) {
82
+ return {
83
+ successful: false,
84
+ returnMessage: {
85
+ message: `User session expired. Please connect again.`,
86
+ messageType: 'warning',
87
+ ttl: 5000
88
+ },
89
+ isRevokeUserSession: true
90
+ }
91
+ }
80
92
  authHeader = `Bearer ${user.accessToken}`;
81
93
  break;
82
94
  case 'apiKey':
@@ -129,7 +141,7 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
129
141
  });
130
142
  }
131
143
 
132
- const { logId, returnMessage, extraDataTracking } = await platformModule.createCallLog({
144
+ let { logId, returnMessage, extraDataTracking } = await platformModule.createCallLog({
133
145
  user,
134
146
  contactInfo,
135
147
  authHeader,
@@ -148,6 +160,11 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
148
160
  isFromSSCL,
149
161
  proxyConfig,
150
162
  });
163
+ if (!extraDataTracking) {
164
+ extraDataTracking = {};
165
+ }
166
+ extraDataTracking.withSmartNoteLog = !!aiNote;
167
+ extraDataTracking.withTranscript = !!transcript;
151
168
  if (logId) {
152
169
  try {
153
170
  await CallLogModel.create({
@@ -201,6 +218,17 @@ async function getCallLog({ userId, sessionIds, platform, requireDetails }) {
201
218
  case 'oauth':
202
219
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
203
220
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
221
+ if (!user) {
222
+ return {
223
+ successful: false,
224
+ returnMessage: {
225
+ message: `User session expired. Please connect again.`,
226
+ messageType: 'warning',
227
+ ttl: 5000
228
+ },
229
+ isRevokeUserSession: true
230
+ }
231
+ }
204
232
  authHeader = `Bearer ${user.accessToken}`;
205
233
  break;
206
234
  case 'apiKey':
@@ -287,6 +315,17 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
287
315
  case 'oauth':
288
316
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
289
317
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
318
+ if (!user) {
319
+ return {
320
+ successful: false,
321
+ returnMessage: {
322
+ message: `User session expired. Please connect again.`,
323
+ messageType: 'warning',
324
+ ttl: 5000
325
+ },
326
+ isRevokeUserSession: true
327
+ }
328
+ }
290
329
  authHeader = `Bearer ${user.accessToken}`;
291
330
  break;
292
331
  case 'apiKey':
@@ -351,7 +390,7 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
351
390
  });
352
391
  }
353
392
 
354
- const { updatedNote, returnMessage, extraDataTracking } = await platformModule.updateCallLog({
393
+ let { updatedNote, returnMessage, extraDataTracking } = await platformModule.updateCallLog({
355
394
  user,
356
395
  existingCallLog,
357
396
  authHeader,
@@ -377,6 +416,11 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
377
416
  isFromSSCL,
378
417
  proxyConfig,
379
418
  });
419
+ if (!extraDataTracking) {
420
+ extraDataTracking = {};
421
+ }
422
+ extraDataTracking.withSmartNoteLog = !!incomingData.aiNote;
423
+ extraDataTracking.withTranscript = !!incomingData.transcript;
380
424
  return { successful: true, logId: existingCallLog.thirdPartyLogId, updatedNote, returnMessage, extraDataTracking };
381
425
  }
382
426
  return { successful: false };
@@ -432,6 +476,17 @@ async function createMessageLog({ platform, userId, incomingData }) {
432
476
  case 'oauth':
433
477
  const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
434
478
  user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
479
+ if (!user) {
480
+ return {
481
+ successful: false,
482
+ returnMessage: {
483
+ message: `User session expired. Please connect again.`,
484
+ messageType: 'warning',
485
+ ttl: 5000
486
+ },
487
+ isRevokeUserSession: true
488
+ }
489
+ }
435
490
  authHeader = `Bearer ${user.accessToken}`;
436
491
  break;
437
492
  case 'apiKey':
@@ -457,12 +512,33 @@ async function createMessageLog({ platform, userId, incomingData }) {
457
512
  type: incomingData.contactType ?? "",
458
513
  name: incomingData.contactName ?? ""
459
514
  };
515
+ const isGroupSMS = incomingData.logInfo.correspondents.length > 1;
460
516
  // For shared SMS
461
517
  const assigneeName = incomingData.logInfo.assignee?.name;
462
518
  const ownerName = incomingData.logInfo.owner?.name;
463
519
  const isSharedSMS = !!ownerName;
464
520
 
465
- const messageIds = incomingData.logInfo.messages.map(m => { return { id: m.id.toString() }; });
521
+ let messageIds = [];
522
+ const correspondents = [];
523
+ if (isGroupSMS) {
524
+ messageIds = incomingData.logInfo.messages.map(m => { return { id: m.id.toString() + `-${incomingData.contactId}` }; });
525
+ for (var i = 0; i < incomingData.logInfo.correspondents.length; i++) {
526
+ // find cached contact by composite key; findByPk expects raw PK values, so use where clause
527
+ const correspondentContactInfo = await AccountDataModel.findOne({
528
+ where: {
529
+ rcAccountId: user.rcAccountId,
530
+ platformName: platform,
531
+ dataKey: `contact-${incomingData.logInfo.correspondents[i].phoneNumber}`
532
+ }
533
+ })
534
+ if (correspondentContactInfo && correspondentContactInfo.data[0]?.name != incomingData.contactName) {
535
+ correspondents.push(correspondentContactInfo.data);
536
+ }
537
+ }
538
+ }
539
+ else {
540
+ messageIds = incomingData.logInfo.messages.map(m => { return { id: m.id.toString() }; });
541
+ }
466
542
  let existingMessages = null;
467
543
  try {
468
544
  existingMessages = await MessageLogModel.findAll({
@@ -510,9 +586,18 @@ async function createMessageLog({ platform, userId, incomingData }) {
510
586
  }
511
587
  // Case: normal SMS
512
588
  else {
589
+ if (isGroupSMS) {
590
+ // eslint-disable-next-line no-param-reassign
591
+ incomingData.logInfo.conversationLogId = incomingData.logInfo.conversationLogId + `-${incomingData.contactId}`;
592
+ // eslint-disable-next-line no-param-reassign
593
+ incomingData.logInfo.conversationId = incomingData.logInfo.conversationId + `-${incomingData.contactId}`;
594
+ }
513
595
  // reverse the order of messages to log the oldest message first
514
596
  const reversedMessages = incomingData.logInfo.messages.reverse();
515
597
  for (const message of reversedMessages) {
598
+ if (isGroupSMS) {
599
+ message.id = message.id.toString() + `-${incomingData.contactId}`;
600
+ }
516
601
  if (existingIds.includes(message.id.toString())) {
517
602
  continue;
518
603
  }
@@ -522,14 +607,14 @@ async function createMessageLog({ platform, userId, incomingData }) {
522
607
  }
523
608
  let faxDocLink = null;
524
609
  let faxDownloadLink = null;
525
- if (message.attachments && message.attachments.some(a => a.type === 'RenderedDocument')) {
610
+ if (message.attachments && message.attachments.some(a => a.type === 'RenderedDocument') && incomingData.logInfo.rcAccessToken) {
526
611
  faxDocLink = message.attachments.find(a => a.type === 'RenderedDocument').link;
527
612
  faxDownloadLink = message.attachments.find(a => a.type === 'RenderedDocument').uri + `?access_token=${incomingData.logInfo.rcAccessToken}`
528
613
  }
529
614
  let imageLink = null;
530
615
  let imageDownloadLink = null;
531
616
  let imageContentType = null;
532
- if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'))) {
617
+ if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/')) && incomingData.logInfo.rcAccessToken) {
533
618
  const imageAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'));
534
619
  if (imageAttachment) {
535
620
  imageLink = getMediaReaderLinkByPlatformMediaLink(imageAttachment?.uri);
@@ -553,32 +638,35 @@ async function createMessageLog({ platform, userId, incomingData }) {
553
638
  conversationLogId: incomingData.logInfo.conversationLogId
554
639
  }
555
640
  });
641
+ let crmLogId = ''
556
642
  if (existingSameDateMessageLog) {
557
- const updateMessageResult = await platformModule.updateMessageLog({ user, contactInfo, assigneeName, ownerName, existingMessageLog: existingSameDateMessageLog, message, authHeader, additionalSubmission, imageLink, videoLink, proxyConfig });
643
+ const updateMessageResult = await platformModule.updateMessageLog({ user, contactInfo, assigneeName, ownerName, existingMessageLog: existingSameDateMessageLog, message, authHeader, additionalSubmission, imageLink, imageDownloadLink, imageContentType, videoLink, proxyConfig });
644
+ crmLogId = existingSameDateMessageLog.thirdPartyLogId;
558
645
  returnMessage = updateMessageResult?.returnMessage;
646
+ extraDataTracking = updateMessageResult.extraDataTracking;
559
647
  }
560
648
  else {
561
- const createMessageLogResult = await platformModule.createMessageLog({ user, contactInfo, assigneeName, ownerName, authHeader, message, additionalSubmission, recordingLink, faxDocLink, faxDownloadLink, imageLink, imageDownloadLink, imageContentType, videoLink, proxyConfig });
562
- const crmLogId = createMessageLogResult.logId;
563
- if (crmLogId) {
564
- try {
565
- const createdMessageLog =
566
- await MessageLogModel.create({
567
- id: message.id.toString(),
568
- platform,
569
- conversationId: incomingData.logInfo.conversationId,
570
- thirdPartyLogId: crmLogId,
571
- userId,
572
- conversationLogId: incomingData.logInfo.conversationLogId
573
- });
574
- logIds.push(createdMessageLog.id);
575
- } catch (error) {
576
- return handleDatabaseError(error, 'Error creating message log');
577
- }
578
- }
649
+ const createMessageLogResult = await platformModule.createMessageLog({ user, contactInfo, correspondents, assigneeName, ownerName, authHeader, message, additionalSubmission, recordingLink, faxDocLink, faxDownloadLink, imageLink, imageDownloadLink, imageContentType, videoLink, proxyConfig });
650
+ crmLogId = createMessageLogResult.logId;
579
651
  returnMessage = createMessageLogResult?.returnMessage;
580
652
  extraDataTracking = createMessageLogResult.extraDataTracking;
581
653
  }
654
+ if (crmLogId) {
655
+ try {
656
+ const createdMessageLog =
657
+ await MessageLogModel.create({
658
+ id: message.id.toString(),
659
+ platform,
660
+ conversationId: incomingData.logInfo.conversationId,
661
+ thirdPartyLogId: crmLogId,
662
+ userId,
663
+ conversationLogId: incomingData.logInfo.conversationLogId
664
+ });
665
+ logIds.push(createdMessageLog.id);
666
+ } catch (error) {
667
+ return handleDatabaseError(error, 'Error creating message log');
668
+ }
669
+ }
582
670
  }
583
671
  }
584
672
  return { successful: true, logIds, returnMessage, extraDataTracking };