@app-connect/core 1.7.10 → 1.7.12
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/connector/developerPortal.js +43 -0
- package/connector/proxy/index.js +10 -3
- package/connector/registry.js +8 -6
- package/handlers/admin.js +135 -22
- package/handlers/auth.js +89 -67
- package/handlers/calldown.js +10 -4
- package/handlers/contact.js +4 -104
- package/handlers/disposition.js +7 -145
- package/handlers/log.js +174 -258
- package/handlers/user.js +19 -6
- package/index.js +280 -47
- package/lib/analytics.js +3 -1
- package/lib/authSession.js +68 -0
- package/lib/callLogComposer.js +498 -420
- package/lib/errorHandler.js +206 -0
- package/lib/jwt.js +2 -0
- package/lib/logger.js +190 -0
- package/lib/oauth.js +21 -10
- package/lib/ringcentral.js +2 -10
- package/lib/sharedSMSComposer.js +471 -0
- package/mcp/SupportedPlatforms.md +12 -0
- package/mcp/lib/validator.js +91 -0
- package/mcp/mcpHandler.js +166 -0
- package/mcp/tools/checkAuthStatus.js +110 -0
- package/mcp/tools/collectAuthInfo.js +91 -0
- package/mcp/tools/createCallLog.js +308 -0
- package/mcp/tools/createContact.js +117 -0
- package/mcp/tools/createMessageLog.js +283 -0
- package/mcp/tools/doAuth.js +190 -0
- package/mcp/tools/findContactByName.js +92 -0
- package/mcp/tools/findContactByPhone.js +101 -0
- package/mcp/tools/getCallLog.js +98 -0
- package/mcp/tools/getGoogleFilePicker.js +103 -0
- package/mcp/tools/getHelp.js +44 -0
- package/mcp/tools/getPublicConnectors.js +53 -0
- package/mcp/tools/index.js +64 -0
- package/mcp/tools/logout.js +68 -0
- package/mcp/tools/rcGetCallLogs.js +78 -0
- package/mcp/tools/setConnector.js +69 -0
- package/mcp/tools/updateCallLog.js +122 -0
- package/models/cacheModel.js +3 -0
- package/package.json +71 -70
- package/releaseNotes.json +24 -0
- package/test/handlers/log.test.js +11 -4
- package/test/lib/logger.test.js +206 -0
- package/test/lib/ringcentral.test.js +0 -6
- package/test/lib/sharedSMSComposer.test.js +1084 -0
- package/test/mcp/tools/collectAuthInfo.test.js +234 -0
- package/test/mcp/tools/createCallLog.test.js +425 -0
- package/test/mcp/tools/createMessageLog.test.js +580 -0
- package/test/mcp/tools/doAuth.test.js +376 -0
- package/test/mcp/tools/findContactByName.test.js +263 -0
- package/test/mcp/tools/findContactByPhone.test.js +284 -0
- package/test/mcp/tools/getCallLog.test.js +286 -0
- package/test/mcp/tools/getGoogleFilePicker.test.js +281 -0
- package/test/mcp/tools/getPublicConnectors.test.js +128 -0
- package/test/mcp/tools/logout.test.js +169 -0
- package/test/mcp/tools/setConnector.test.js +177 -0
- package/test/mcp/tools/updateCallLog.test.js +346 -0
package/handlers/log.js
CHANGED
|
@@ -3,22 +3,30 @@ const { CallLogModel } = require('../models/callLogModel');
|
|
|
3
3
|
const { MessageLogModel } = require('../models/messageLogModel');
|
|
4
4
|
const { UserModel } = require('../models/userModel');
|
|
5
5
|
const oauth = require('../lib/oauth');
|
|
6
|
-
const errorMessage = require('../lib/generalErrorMessage');
|
|
7
6
|
const { composeCallLog } = require('../lib/callLogComposer');
|
|
7
|
+
const { composeSharedSMSLog } = require('../lib/sharedSMSComposer');
|
|
8
8
|
const connectorRegistry = require('../connector/registry');
|
|
9
9
|
const { LOG_DETAILS_FORMAT_TYPE } = require('../lib/constants');
|
|
10
10
|
const { NoteCache } = require('../models/dynamo/noteCacheSchema');
|
|
11
11
|
const { Connector } = require('../models/dynamo/connectorSchema');
|
|
12
12
|
const moment = require('moment');
|
|
13
13
|
const { getMediaReaderLinkByPlatformMediaLink } = require('../lib/util');
|
|
14
|
+
const logger = require('../lib/logger');
|
|
15
|
+
const { handleApiError, handleDatabaseError } = require('../lib/errorHandler');
|
|
14
16
|
|
|
15
17
|
async function createCallLog({ platform, userId, incomingData, hashedAccountId, isFromSSCL }) {
|
|
16
18
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
let existingCallLog = null;
|
|
20
|
+
try {
|
|
21
|
+
existingCallLog = await CallLogModel.findOne({
|
|
22
|
+
where: {
|
|
23
|
+
sessionId: incomingData.logInfo.sessionId
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return handleDatabaseError(error, 'Error finding existing call log');
|
|
29
|
+
}
|
|
22
30
|
if (existingCallLog) {
|
|
23
31
|
return {
|
|
24
32
|
successful: false,
|
|
@@ -29,7 +37,13 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
}
|
|
32
|
-
let user =
|
|
40
|
+
let user = null;
|
|
41
|
+
try {
|
|
42
|
+
user = await UserModel.findByPk(userId);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return handleDatabaseError(error, 'Error finding user');
|
|
46
|
+
}
|
|
33
47
|
if (!user || !user.accessToken) {
|
|
34
48
|
return {
|
|
35
49
|
successful: false,
|
|
@@ -88,12 +102,12 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
88
102
|
type: incomingData.contactType ?? "",
|
|
89
103
|
name: incomingData.contactName ?? ""
|
|
90
104
|
};
|
|
91
|
-
|
|
105
|
+
|
|
92
106
|
// Compose call log details centrally
|
|
93
107
|
const logFormat = platformModule.getLogFormatType ? platformModule.getLogFormatType(platform, proxyConfig) : LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT;
|
|
94
108
|
let composedLogDetails = '';
|
|
95
109
|
if (logFormat === LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT || logFormat === LOG_DETAILS_FORMAT_TYPE.HTML || logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
96
|
-
composedLogDetails =
|
|
110
|
+
composedLogDetails = composeCallLog({
|
|
97
111
|
logFormat,
|
|
98
112
|
callLog,
|
|
99
113
|
contactInfo,
|
|
@@ -135,54 +149,23 @@ async function createCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
135
149
|
proxyConfig,
|
|
136
150
|
});
|
|
137
151
|
if (logId) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
try {
|
|
153
|
+
await CallLogModel.create({
|
|
154
|
+
id: incomingData.logInfo.telephonySessionId || incomingData.logInfo.id,
|
|
155
|
+
sessionId: incomingData.logInfo.sessionId,
|
|
156
|
+
platform,
|
|
157
|
+
thirdPartyLogId: logId,
|
|
158
|
+
userId,
|
|
159
|
+
contactId
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return handleDatabaseError(error, 'Error creating call log');
|
|
164
|
+
}
|
|
146
165
|
}
|
|
147
166
|
return { successful: !!logId, logId, returnMessage, extraDataTracking };
|
|
148
167
|
} catch (e) {
|
|
149
|
-
|
|
150
|
-
if (e.response?.status === 429) {
|
|
151
|
-
return {
|
|
152
|
-
successful: false,
|
|
153
|
-
returnMessage: errorMessage.rateLimitErrorMessage({ platform })
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
else if (e.response?.status >= 400 && e.response?.status < 410) {
|
|
157
|
-
return {
|
|
158
|
-
successful: false,
|
|
159
|
-
returnMessage: errorMessage.authorizationErrorMessage({ platform }),
|
|
160
|
-
extraDataTracking: {
|
|
161
|
-
statusCode: e.response?.status,
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
successful: false,
|
|
167
|
-
returnMessage:
|
|
168
|
-
{
|
|
169
|
-
message: `Error creating call log`,
|
|
170
|
-
messageType: 'warning',
|
|
171
|
-
details: [
|
|
172
|
-
{
|
|
173
|
-
title: 'Details',
|
|
174
|
-
items: [
|
|
175
|
-
{
|
|
176
|
-
id: '1',
|
|
177
|
-
type: 'text',
|
|
178
|
-
text: `Please check if your account has permission to CREATE logs.`
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
}
|
|
182
|
-
],
|
|
183
|
-
ttl: 5000
|
|
184
|
-
}
|
|
185
|
-
};
|
|
168
|
+
return handleApiError(e, platform, 'createCallLog', { userId });
|
|
186
169
|
}
|
|
187
170
|
}
|
|
188
171
|
|
|
@@ -233,8 +216,7 @@ async function getCallLog({ userId, sessionIds, platform, requireDetails }) {
|
|
|
233
216
|
}
|
|
234
217
|
});
|
|
235
218
|
for (const sId of sessionIdsArray) {
|
|
236
|
-
if(sId == 0)
|
|
237
|
-
{
|
|
219
|
+
if (sId == 0) {
|
|
238
220
|
logs.push({ sessionId: sId, matched: false });
|
|
239
221
|
continue;
|
|
240
222
|
}
|
|
@@ -243,7 +225,7 @@ async function getCallLog({ userId, sessionIds, platform, requireDetails }) {
|
|
|
243
225
|
logs.push({ sessionId: sId, matched: false });
|
|
244
226
|
}
|
|
245
227
|
else {
|
|
246
|
-
const getCallLogResult = await platformModule.getCallLog({ user, callLogId: callLog.thirdPartyLogId, contactId: callLog.contactId, authHeader, proxyConfig });
|
|
228
|
+
const getCallLogResult = await platformModule.getCallLog({ user, telephonySessionId: callLog.id, callLogId: callLog.thirdPartyLogId, contactId: callLog.contactId, authHeader, proxyConfig });
|
|
247
229
|
returnMessage = getCallLogResult.returnMessage;
|
|
248
230
|
extraDataTracking = getCallLogResult.extraDataTracking;
|
|
249
231
|
logs.push({ sessionId: callLog.sessionId, matched: true, logId: callLog.thirdPartyLogId, logData: getCallLogResult.callLogInfo });
|
|
@@ -271,59 +253,23 @@ async function getCallLog({ userId, sessionIds, platform, requireDetails }) {
|
|
|
271
253
|
return { successful: true, logs, returnMessage, extraDataTracking };
|
|
272
254
|
}
|
|
273
255
|
catch (e) {
|
|
274
|
-
|
|
275
|
-
if (e.response?.status === 429) {
|
|
276
|
-
return {
|
|
277
|
-
successful: false,
|
|
278
|
-
returnMessage: errorMessage.rateLimitErrorMessage({ platform }),
|
|
279
|
-
extraDataTracking: {
|
|
280
|
-
statusCode: e.response?.status,
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
else if (e.response?.status >= 400 && e.response?.status < 410) {
|
|
285
|
-
return {
|
|
286
|
-
successful: false,
|
|
287
|
-
returnMessage: errorMessage.authorizationErrorMessage({ platform }),
|
|
288
|
-
extraDataTracking: {
|
|
289
|
-
statusCode: e.response?.status,
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
successful: false,
|
|
295
|
-
returnMessage:
|
|
296
|
-
{
|
|
297
|
-
message: `Error getting call log`,
|
|
298
|
-
messageType: 'warning',
|
|
299
|
-
details: [
|
|
300
|
-
{
|
|
301
|
-
title: 'Details',
|
|
302
|
-
items: [
|
|
303
|
-
{
|
|
304
|
-
id: '1',
|
|
305
|
-
type: 'text',
|
|
306
|
-
text: `Please check if your account has permission to READ logs.`
|
|
307
|
-
}
|
|
308
|
-
]
|
|
309
|
-
}
|
|
310
|
-
],
|
|
311
|
-
ttl: 5000
|
|
312
|
-
},
|
|
313
|
-
extraDataTracking: {
|
|
314
|
-
statusCode: e.response?.status,
|
|
315
|
-
}
|
|
316
|
-
};
|
|
256
|
+
return handleApiError(e, platform, 'getCallLog', { userId, sessionIds, requireDetails });
|
|
317
257
|
}
|
|
318
258
|
}
|
|
319
259
|
|
|
320
260
|
async function updateCallLog({ platform, userId, incomingData, hashedAccountId, isFromSSCL }) {
|
|
321
261
|
try {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
262
|
+
let existingCallLog = null;
|
|
263
|
+
try {
|
|
264
|
+
existingCallLog = await CallLogModel.findOne({
|
|
265
|
+
where: {
|
|
266
|
+
sessionId: incomingData.sessionId
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
return handleDatabaseError(error, 'Error finding existing call log');
|
|
272
|
+
}
|
|
327
273
|
if (existingCallLog) {
|
|
328
274
|
const platformModule = connectorRegistry.getConnector(platform);
|
|
329
275
|
let user = await UserModel.findByPk(userId);
|
|
@@ -358,6 +304,7 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
358
304
|
try {
|
|
359
305
|
const getLogResult = await platformModule.getCallLog({
|
|
360
306
|
user,
|
|
307
|
+
telephonySessionId: existingCallLog.id,
|
|
361
308
|
callLogId: existingCallLog.thirdPartyLogId,
|
|
362
309
|
contactId: existingCallLog.contactId,
|
|
363
310
|
authHeader,
|
|
@@ -371,9 +318,9 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
371
318
|
existingBody = getLogResult.callLogInfo.note;
|
|
372
319
|
}
|
|
373
320
|
} catch (error) {
|
|
374
|
-
|
|
321
|
+
logger.error('Error getting existing log details, proceeding with empty body', { stack: error.stack });
|
|
375
322
|
}
|
|
376
|
-
composedLogDetails =
|
|
323
|
+
composedLogDetails = composeCallLog({
|
|
377
324
|
logFormat,
|
|
378
325
|
existingBody,
|
|
379
326
|
callLog: {
|
|
@@ -434,49 +381,7 @@ async function updateCallLog({ platform, userId, incomingData, hashedAccountId,
|
|
|
434
381
|
}
|
|
435
382
|
return { successful: false };
|
|
436
383
|
} catch (e) {
|
|
437
|
-
|
|
438
|
-
if (e.response?.status === 429) {
|
|
439
|
-
return {
|
|
440
|
-
successful: false,
|
|
441
|
-
returnMessage: errorMessage.rateLimitErrorMessage({ platform }),
|
|
442
|
-
extraDataTracking: {
|
|
443
|
-
statusCode: e.response?.status,
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
else if (e.response?.status >= 400 && e.response?.status < 410) {
|
|
448
|
-
return {
|
|
449
|
-
successful: false,
|
|
450
|
-
returnMessage: errorMessage.authorizationErrorMessage({ platform }),
|
|
451
|
-
extraDataTracking: {
|
|
452
|
-
statusCode: e.response?.status,
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
successful: false,
|
|
458
|
-
returnMessage:
|
|
459
|
-
{
|
|
460
|
-
message: `Error updating call log`,
|
|
461
|
-
messageType: 'warning',
|
|
462
|
-
details: [
|
|
463
|
-
{
|
|
464
|
-
title: 'Details',
|
|
465
|
-
items: [
|
|
466
|
-
{
|
|
467
|
-
id: '1',
|
|
468
|
-
type: 'text',
|
|
469
|
-
text: `Please check if the log entity still exist on ${platform} and your account has permission to EDIT logs.`
|
|
470
|
-
}
|
|
471
|
-
]
|
|
472
|
-
}
|
|
473
|
-
],
|
|
474
|
-
ttl: 5000
|
|
475
|
-
},
|
|
476
|
-
extraDataTracking: {
|
|
477
|
-
statusCode: e.response?.status,
|
|
478
|
-
}
|
|
479
|
-
};
|
|
384
|
+
return handleApiError(e, platform, 'updateCallLog', { userId });
|
|
480
385
|
}
|
|
481
386
|
}
|
|
482
387
|
|
|
@@ -498,7 +403,13 @@ async function createMessageLog({ platform, userId, incomingData }) {
|
|
|
498
403
|
const platformModule = connectorRegistry.getConnector(platform);
|
|
499
404
|
const contactNumber = incomingData.logInfo.correspondents[0].phoneNumber;
|
|
500
405
|
const additionalSubmission = incomingData.additionalSubmission;
|
|
501
|
-
let user =
|
|
406
|
+
let user = null;
|
|
407
|
+
try {
|
|
408
|
+
user = await UserModel.findByPk(userId);
|
|
409
|
+
}
|
|
410
|
+
catch (error) {
|
|
411
|
+
return handleDatabaseError(error, 'Error finding user');
|
|
412
|
+
}
|
|
502
413
|
if (!user || !user.accessToken) {
|
|
503
414
|
return {
|
|
504
415
|
successful: false,
|
|
@@ -546,139 +457,144 @@ async function createMessageLog({ platform, userId, incomingData }) {
|
|
|
546
457
|
type: incomingData.contactType ?? "",
|
|
547
458
|
name: incomingData.contactName ?? ""
|
|
548
459
|
};
|
|
460
|
+
// For shared SMS
|
|
461
|
+
const assigneeName = incomingData.logInfo.assignee?.name;
|
|
462
|
+
const ownerName = incomingData.logInfo.owner?.name;
|
|
463
|
+
const isSharedSMS = !!ownerName;
|
|
464
|
+
|
|
549
465
|
const messageIds = incomingData.logInfo.messages.map(m => { return { id: m.id.toString() }; });
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
466
|
+
let existingMessages = null;
|
|
467
|
+
try {
|
|
468
|
+
existingMessages = await MessageLogModel.findAll({
|
|
469
|
+
where: {
|
|
470
|
+
[Op.or]: messageIds
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
return handleDatabaseError(error, 'Error finding existing messages');
|
|
476
|
+
}
|
|
555
477
|
const existingIds = existingMessages.map(m => m.id);
|
|
556
478
|
const logIds = [];
|
|
557
|
-
//
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
if (existingIds.includes(message.id.toString())) {
|
|
561
|
-
continue;
|
|
562
|
-
}
|
|
563
|
-
let recordingLink = null;
|
|
564
|
-
if (message.attachments && message.attachments.some(a => a.type === 'AudioRecording')) {
|
|
565
|
-
recordingLink = message.attachments.find(a => a.type === 'AudioRecording').link;
|
|
566
|
-
}
|
|
567
|
-
let faxDocLink = null;
|
|
568
|
-
let faxDownloadLink = null;
|
|
569
|
-
if (message.attachments && message.attachments.some(a => a.type === 'RenderedDocument')) {
|
|
570
|
-
faxDocLink = message.attachments.find(a => a.type === 'RenderedDocument').link;
|
|
571
|
-
faxDownloadLink = message.attachments.find(a => a.type === 'RenderedDocument').uri + `?access_token=${incomingData.logInfo.rcAccessToken}`
|
|
572
|
-
}
|
|
573
|
-
let imageLink = null;
|
|
574
|
-
let imageDownloadLink = null;
|
|
575
|
-
let imageContentType = null;
|
|
576
|
-
if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'))) {
|
|
577
|
-
const imageAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'));
|
|
578
|
-
if (imageAttachment) {
|
|
579
|
-
imageLink = getMediaReaderLinkByPlatformMediaLink(imageAttachment?.uri);
|
|
580
|
-
imageDownloadLink = imageAttachment?.uri + `?access_token=${incomingData.logInfo.rcAccessToken}`;
|
|
581
|
-
imageContentType = imageAttachment?.contentType;
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
let videoLink = null;
|
|
585
|
-
if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment')) {
|
|
586
|
-
const imageAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'));
|
|
587
|
-
if (imageAttachment) {
|
|
588
|
-
imageLink = getMediaReaderLinkByPlatformMediaLink(imageAttachment?.uri);
|
|
589
|
-
}
|
|
590
|
-
const videoAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('video/'));
|
|
591
|
-
if (videoAttachment) {
|
|
592
|
-
videoLink = getMediaReaderLinkByPlatformMediaLink(videoAttachment?.uri);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
const existingSameDateMessageLog = await MessageLogModel.findOne({
|
|
479
|
+
// Case: Shared SMS
|
|
480
|
+
if (isSharedSMS) {
|
|
481
|
+
const existingMessageLog = await MessageLogModel.findOne({
|
|
596
482
|
where: {
|
|
597
483
|
conversationLogId: incomingData.logInfo.conversationLogId
|
|
598
484
|
}
|
|
599
485
|
});
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
486
|
+
const entities = incomingData.logInfo.entities;
|
|
487
|
+
const sharedSMSLogContent = composeSharedSMSLog({ logFormat: platformModule.getLogFormatType(platform, proxyConfig), conversation: incomingData.logInfo, contactName: contactInfo.name, timezoneOffset: user.timezoneOffset });
|
|
488
|
+
if (existingMessageLog) {
|
|
489
|
+
const updateMessageResult = await platformModule.updateMessageLog({ user, contactInfo, sharedSMSLogContent, existingMessageLog: existingMessageLog, authHeader, additionalSubmission, proxyConfig });
|
|
604
490
|
returnMessage = updateMessageResult?.returnMessage;
|
|
605
491
|
}
|
|
606
492
|
else {
|
|
607
|
-
const createMessageLogResult = await platformModule.createMessageLog({ user, contactInfo,
|
|
608
|
-
crmLogId = createMessageLogResult.logId;
|
|
493
|
+
const createMessageLogResult = await platformModule.createMessageLog({ user, contactInfo, sharedSMSLogContent, authHeader, additionalSubmission, proxyConfig });
|
|
494
|
+
const crmLogId = createMessageLogResult.logId;
|
|
609
495
|
returnMessage = createMessageLogResult?.returnMessage;
|
|
610
496
|
extraDataTracking = createMessageLogResult.extraDataTracking;
|
|
497
|
+
if (createMessageLogResult.logId) {
|
|
498
|
+
const createdMessageLog =
|
|
499
|
+
await MessageLogModel.create({
|
|
500
|
+
id: incomingData.logInfo.conversationLogId,
|
|
501
|
+
platform,
|
|
502
|
+
conversationId: incomingData.logInfo.conversationId,
|
|
503
|
+
thirdPartyLogId: createMessageLogResult.logId,
|
|
504
|
+
userId,
|
|
505
|
+
conversationLogId: incomingData.logInfo.conversationLogId
|
|
506
|
+
});
|
|
507
|
+
logIds.push(createdMessageLog.id);
|
|
508
|
+
}
|
|
611
509
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
510
|
+
}
|
|
511
|
+
// Case: normal SMS
|
|
512
|
+
else {
|
|
513
|
+
// reverse the order of messages to log the oldest message first
|
|
514
|
+
const reversedMessages = incomingData.logInfo.messages.reverse();
|
|
515
|
+
for (const message of reversedMessages) {
|
|
516
|
+
if (existingIds.includes(message.id.toString())) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
let recordingLink = null;
|
|
520
|
+
if (message.attachments && message.attachments.some(a => a.type === 'AudioRecording')) {
|
|
521
|
+
recordingLink = message.attachments.find(a => a.type === 'AudioRecording').link;
|
|
522
|
+
}
|
|
523
|
+
let faxDocLink = null;
|
|
524
|
+
let faxDownloadLink = null;
|
|
525
|
+
if (message.attachments && message.attachments.some(a => a.type === 'RenderedDocument')) {
|
|
526
|
+
faxDocLink = message.attachments.find(a => a.type === 'RenderedDocument').link;
|
|
527
|
+
faxDownloadLink = message.attachments.find(a => a.type === 'RenderedDocument').uri + `?access_token=${incomingData.logInfo.rcAccessToken}`
|
|
528
|
+
}
|
|
529
|
+
let imageLink = null;
|
|
530
|
+
let imageDownloadLink = null;
|
|
531
|
+
let imageContentType = null;
|
|
532
|
+
if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'))) {
|
|
533
|
+
const imageAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'));
|
|
534
|
+
if (imageAttachment) {
|
|
535
|
+
imageLink = getMediaReaderLinkByPlatformMediaLink(imageAttachment?.uri);
|
|
536
|
+
imageDownloadLink = imageAttachment?.uri + `?access_token=${incomingData.logInfo.rcAccessToken}`;
|
|
537
|
+
imageContentType = imageAttachment?.contentType;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
let videoLink = null;
|
|
541
|
+
if (message.attachments && message.attachments.some(a => a.type === 'MmsAttachment')) {
|
|
542
|
+
const imageAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('image/'));
|
|
543
|
+
if (imageAttachment) {
|
|
544
|
+
imageLink = getMediaReaderLinkByPlatformMediaLink(imageAttachment?.uri);
|
|
545
|
+
}
|
|
546
|
+
const videoAttachment = message.attachments.find(a => a.type === 'MmsAttachment' && a.contentType.startsWith('video/'));
|
|
547
|
+
if (videoAttachment) {
|
|
548
|
+
videoLink = getMediaReaderLinkByPlatformMediaLink(videoAttachment?.uri);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
const existingSameDateMessageLog = await MessageLogModel.findOne({
|
|
552
|
+
where: {
|
|
620
553
|
conversationLogId: incomingData.logInfo.conversationLogId
|
|
621
|
-
}
|
|
622
|
-
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
if (existingSameDateMessageLog) {
|
|
557
|
+
const updateMessageResult = await platformModule.updateMessageLog({ user, contactInfo, assigneeName, ownerName, existingMessageLog: existingSameDateMessageLog, message, authHeader, additionalSubmission, imageLink, videoLink, proxyConfig });
|
|
558
|
+
returnMessage = updateMessageResult?.returnMessage;
|
|
559
|
+
}
|
|
560
|
+
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
|
+
}
|
|
579
|
+
returnMessage = createMessageLogResult?.returnMessage;
|
|
580
|
+
extraDataTracking = createMessageLogResult.extraDataTracking;
|
|
581
|
+
}
|
|
623
582
|
}
|
|
624
583
|
}
|
|
625
584
|
return { successful: true, logIds, returnMessage, extraDataTracking };
|
|
626
585
|
}
|
|
627
586
|
catch (e) {
|
|
628
|
-
|
|
629
|
-
if (e.response?.status === 429) {
|
|
630
|
-
return {
|
|
631
|
-
successful: false,
|
|
632
|
-
returnMessage: errorMessage.rateLimitErrorMessage({ platform }),
|
|
633
|
-
extraDataTracking: {
|
|
634
|
-
statusCode: e.response?.status,
|
|
635
|
-
}
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
else if (e.response?.status >= 400 && e.response?.status < 410) {
|
|
639
|
-
return {
|
|
640
|
-
successful: false,
|
|
641
|
-
returnMessage: errorMessage.authorizationErrorMessage({ platform }),
|
|
642
|
-
extraDataTracking: {
|
|
643
|
-
statusCode: e.response?.status,
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
return {
|
|
648
|
-
successful: false,
|
|
649
|
-
returnMessage:
|
|
650
|
-
{
|
|
651
|
-
message: `Error creating message log`,
|
|
652
|
-
messageType: 'warning',
|
|
653
|
-
details: [
|
|
654
|
-
{
|
|
655
|
-
title: 'Details',
|
|
656
|
-
items: [
|
|
657
|
-
{
|
|
658
|
-
id: '1',
|
|
659
|
-
type: 'text',
|
|
660
|
-
text: `Please check if your account has permission to CREATE logs.`
|
|
661
|
-
}
|
|
662
|
-
]
|
|
663
|
-
}
|
|
664
|
-
],
|
|
665
|
-
ttl: 5000
|
|
666
|
-
},
|
|
667
|
-
extraDataTracking: {
|
|
668
|
-
statusCode: e.response?.status,
|
|
669
|
-
}
|
|
670
|
-
};
|
|
587
|
+
return handleApiError(e, platform, 'createMessageLog', { userId });
|
|
671
588
|
}
|
|
672
589
|
}
|
|
673
590
|
|
|
674
|
-
async function saveNoteCache({ sessionId, note }) {
|
|
591
|
+
async function saveNoteCache({ platform, userId, sessionId, note }) {
|
|
675
592
|
try {
|
|
676
593
|
const now = moment();
|
|
677
|
-
|
|
594
|
+
await NoteCache.create({ sessionId, note, ttl: now.unix() + 3600 });
|
|
678
595
|
return { successful: true, returnMessage: 'Note cache saved' };
|
|
679
596
|
} catch (e) {
|
|
680
|
-
|
|
681
|
-
return { successful: false, returnMessage: 'Error saving note cache' };
|
|
597
|
+
return handleApiError(e, platform, 'saveNoteCache', { userId, sessionId, note });
|
|
682
598
|
}
|
|
683
599
|
}
|
|
684
600
|
|
package/handlers/user.js
CHANGED
|
@@ -2,6 +2,8 @@ const axios = require('axios');
|
|
|
2
2
|
const { AdminConfigModel } = require('../models/adminConfigModel');
|
|
3
3
|
const { getHashValue } = require('../lib/util');
|
|
4
4
|
const connectorRegistry = require('../connector/registry');
|
|
5
|
+
const logger = require('../lib/logger');
|
|
6
|
+
const { handleDatabaseError } = require('../lib/errorHandler');
|
|
5
7
|
|
|
6
8
|
async function getUserSettingsByAdmin({ rcAccessToken, rcAccountId }) {
|
|
7
9
|
let hashedRcAccountId = null;
|
|
@@ -31,6 +33,7 @@ async function getUserSettings({ user, rcAccessToken, rcAccountId }) {
|
|
|
31
33
|
userSettingsByAdmin = await getUserSettingsByAdmin({ rcAccessToken, rcAccountId });
|
|
32
34
|
}
|
|
33
35
|
catch (e) {
|
|
36
|
+
logger.error('Error getting user settings by admin', { stack: e.stack });
|
|
34
37
|
userSettingsByAdmin = [];
|
|
35
38
|
}
|
|
36
39
|
}
|
|
@@ -77,9 +80,14 @@ async function updateUserSettings({ user, userSettings, platformName }) {
|
|
|
77
80
|
if (platformModule.onUpdateUserSettings) {
|
|
78
81
|
const { successful, returnMessage } = await platformModule.onUpdateUserSettings({ user, userSettings, updatedSettings });
|
|
79
82
|
if (successful) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
try {
|
|
84
|
+
await user.update({
|
|
85
|
+
userSettings: updatedSettings
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return handleDatabaseError(error, 'Error updating user settings');
|
|
90
|
+
}
|
|
83
91
|
}
|
|
84
92
|
return {
|
|
85
93
|
successful,
|
|
@@ -87,9 +95,14 @@ async function updateUserSettings({ user, userSettings, platformName }) {
|
|
|
87
95
|
};
|
|
88
96
|
}
|
|
89
97
|
else {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
try {
|
|
99
|
+
await user.update({
|
|
100
|
+
userSettings: updatedSettings
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
return handleDatabaseError(error, 'Error updating user settings');
|
|
105
|
+
}
|
|
93
106
|
}
|
|
94
107
|
return {
|
|
95
108
|
userSettings: user.userSettings
|