@app-connect/core 1.5.8 → 1.6.4
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/.env.test +5 -5
- package/README.md +434 -434
- package/adapter/mock.js +76 -76
- package/adapter/registry.js +247 -247
- package/handlers/admin.js +62 -60
- package/handlers/auth.js +205 -156
- package/handlers/contact.js +274 -274
- package/handlers/disposition.js +193 -193
- package/handlers/log.js +612 -587
- package/handlers/user.js +101 -101
- package/index.js +1302 -1204
- package/jest.config.js +56 -56
- package/lib/analytics.js +52 -52
- package/lib/callLogComposer.js +550 -485
- package/lib/constants.js +8 -8
- package/lib/encode.js +30 -30
- package/lib/generalErrorMessage.js +41 -41
- package/lib/jwt.js +16 -16
- package/lib/oauth.js +34 -21
- package/lib/util.js +43 -40
- package/models/adminConfigModel.js +17 -17
- package/models/cacheModel.js +23 -23
- package/models/callLogModel.js +27 -27
- package/models/dynamo/lockSchema.js +24 -24
- package/models/dynamo/noteCacheSchema.js +30 -0
- package/models/messageLogModel.js +25 -25
- package/models/sequelize.js +16 -16
- package/models/userModel.js +38 -38
- package/package.json +67 -64
- package/releaseNotes.json +701 -605
- package/test/adapter/registry.test.js +270 -270
- package/test/handlers/auth.test.js +230 -230
- package/test/lib/jwt.test.js +161 -161
- package/test/setup.js +176 -176
package/lib/callLogComposer.js
CHANGED
|
@@ -1,486 +1,551 @@
|
|
|
1
|
-
const moment = require('moment-timezone');
|
|
2
|
-
const { secondsToHoursMinutesSeconds } = require('./util');
|
|
3
|
-
const adapterRegistry = require('../adapter/registry');
|
|
4
|
-
const { LOG_DETAILS_FORMAT_TYPE } = require('./constants');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Centralized call log composition module
|
|
8
|
-
* Supports both plain text and HTML formats used across different CRM adapters
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Compose call log details based on user settings and format type
|
|
13
|
-
* @param {Object} params - Composition parameters
|
|
14
|
-
* @param {string} params.logFormat - logFormat type: 'plainText' or 'html'
|
|
15
|
-
* @param {string} params.existingBody - Existing log body (for updates)
|
|
16
|
-
* @param {Object} params.callLog - Call log information
|
|
17
|
-
* @param {Object} params.contactInfo - Contact information
|
|
18
|
-
* @param {Object} params.user - User information
|
|
19
|
-
* @param {string} params.note - User note
|
|
20
|
-
* @param {string} params.aiNote - AI generated note
|
|
21
|
-
* @param {string} params.transcript - Call transcript
|
|
22
|
-
* @param {string} params.recordingLink - Recording link
|
|
23
|
-
* @param {string} params.subject - Call subject
|
|
24
|
-
* @param {Date} params.startTime - Call start time
|
|
25
|
-
* @param {number} params.duration - Call duration in seconds
|
|
26
|
-
* @param {string} params.result - Call result
|
|
27
|
-
* @returns {Promise<string>} Composed log body
|
|
28
|
-
*/
|
|
29
|
-
async function composeCallLog(params) {
|
|
30
|
-
const {
|
|
31
|
-
logFormat = LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
32
|
-
existingBody = '',
|
|
33
|
-
callLog,
|
|
34
|
-
contactInfo,
|
|
35
|
-
user,
|
|
36
|
-
note,
|
|
37
|
-
aiNote,
|
|
38
|
-
transcript,
|
|
39
|
-
recordingLink,
|
|
40
|
-
subject,
|
|
41
|
-
startTime,
|
|
42
|
-
duration,
|
|
43
|
-
result,
|
|
44
|
-
platform
|
|
45
|
-
} = params;
|
|
46
|
-
|
|
47
|
-
let body = existingBody;
|
|
48
|
-
const userSettings = user.userSettings || {};
|
|
49
|
-
// Determine timezone handling
|
|
50
|
-
let resolvedStartTime = startTime || callLog?.startTime;
|
|
51
|
-
let timezoneOffset = user.timezoneOffset;
|
|
52
|
-
if (resolvedStartTime) {
|
|
53
|
-
resolvedStartTime = moment(resolvedStartTime);
|
|
54
|
-
}
|
|
55
|
-
// Apply upsert functions based on user settings
|
|
56
|
-
if (note && (userSettings?.addCallLogNote?.value ?? true)) {
|
|
57
|
-
body = upsertCallAgentNote({ body, note, logFormat });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (callLog?.sessionId && (userSettings?.addCallSessionId?.value ?? false)) {
|
|
61
|
-
body = upsertCallSessionId({ body, id: callLog.sessionId, logFormat });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
body =
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
body =
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
} else {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
result
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
result
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
result
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
result
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
1
|
+
const moment = require('moment-timezone');
|
|
2
|
+
const { secondsToHoursMinutesSeconds } = require('./util');
|
|
3
|
+
const adapterRegistry = require('../adapter/registry');
|
|
4
|
+
const { LOG_DETAILS_FORMAT_TYPE } = require('./constants');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Centralized call log composition module
|
|
8
|
+
* Supports both plain text and HTML formats used across different CRM adapters
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compose call log details based on user settings and format type
|
|
13
|
+
* @param {Object} params - Composition parameters
|
|
14
|
+
* @param {string} params.logFormat - logFormat type: 'plainText' or 'html'
|
|
15
|
+
* @param {string} params.existingBody - Existing log body (for updates)
|
|
16
|
+
* @param {Object} params.callLog - Call log information
|
|
17
|
+
* @param {Object} params.contactInfo - Contact information
|
|
18
|
+
* @param {Object} params.user - User information
|
|
19
|
+
* @param {string} params.note - User note
|
|
20
|
+
* @param {string} params.aiNote - AI generated note
|
|
21
|
+
* @param {string} params.transcript - Call transcript
|
|
22
|
+
* @param {string} params.recordingLink - Recording link
|
|
23
|
+
* @param {string} params.subject - Call subject
|
|
24
|
+
* @param {Date} params.startTime - Call start time
|
|
25
|
+
* @param {number} params.duration - Call duration in seconds
|
|
26
|
+
* @param {string} params.result - Call result
|
|
27
|
+
* @returns {Promise<string>} Composed log body
|
|
28
|
+
*/
|
|
29
|
+
async function composeCallLog(params) {
|
|
30
|
+
const {
|
|
31
|
+
logFormat = LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
32
|
+
existingBody = '',
|
|
33
|
+
callLog,
|
|
34
|
+
contactInfo,
|
|
35
|
+
user,
|
|
36
|
+
note,
|
|
37
|
+
aiNote,
|
|
38
|
+
transcript,
|
|
39
|
+
recordingLink,
|
|
40
|
+
subject,
|
|
41
|
+
startTime,
|
|
42
|
+
duration,
|
|
43
|
+
result,
|
|
44
|
+
platform
|
|
45
|
+
} = params;
|
|
46
|
+
|
|
47
|
+
let body = existingBody;
|
|
48
|
+
const userSettings = user.userSettings || {};
|
|
49
|
+
// Determine timezone handling
|
|
50
|
+
let resolvedStartTime = startTime || callLog?.startTime;
|
|
51
|
+
let timezoneOffset = user.timezoneOffset;
|
|
52
|
+
if (resolvedStartTime) {
|
|
53
|
+
resolvedStartTime = moment(resolvedStartTime);
|
|
54
|
+
}
|
|
55
|
+
// Apply upsert functions based on user settings
|
|
56
|
+
if (note && (userSettings?.addCallLogNote?.value ?? true)) {
|
|
57
|
+
body = upsertCallAgentNote({ body, note, logFormat });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (callLog?.sessionId && (userSettings?.addCallSessionId?.value ?? false)) {
|
|
61
|
+
body = upsertCallSessionId({ body, id: callLog.sessionId, logFormat });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const ringcentralUsername = callLog.direction === 'Inbound' ? callLog?.to?.name : callLog?.from?.name;
|
|
65
|
+
if (ringcentralUsername && (userSettings?.addRingCentralUserName?.value ?? false)) {
|
|
66
|
+
body = upsertRingCentralUserName({ body, userName: ringcentralUsername, logFormat });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const ringcentralNumber = callLog.direction === 'Inbound' ? callLog?.to?.phoneNumber : callLog?.from?.phoneNumber;
|
|
70
|
+
if (ringcentralNumber && (userSettings?.addRingCentralNumber?.value ?? false)) {
|
|
71
|
+
const ringcentralExtensionNumber = callLog.direction === 'Inbound' ? callLog?.from?.extensionNumber : callLog?.to?.extensionNumber;
|
|
72
|
+
body = upsertRingCentralNumberAndExtension({ body, number: ringcentralNumber, extension: ringcentralExtensionNumber ?? '', logFormat });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (subject && (userSettings?.addCallLogSubject?.value ?? true)) {
|
|
76
|
+
body = upsertCallSubject({ body, subject, logFormat });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (contactInfo?.phoneNumber && (userSettings?.addCallLogContactNumber?.value ?? false)) {
|
|
80
|
+
body = upsertContactPhoneNumber({
|
|
81
|
+
body,
|
|
82
|
+
phoneNumber: contactInfo.phoneNumber,
|
|
83
|
+
direction: callLog?.direction,
|
|
84
|
+
logFormat
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (resolvedStartTime && (userSettings?.addCallLogDateTime?.value ?? true)) {
|
|
89
|
+
body = upsertCallDateTime({
|
|
90
|
+
body,
|
|
91
|
+
startTime: resolvedStartTime,
|
|
92
|
+
timezoneOffset,
|
|
93
|
+
logDateFormat: userSettings?.logDateFormat?.value ?? 'YYYY-MM-DD hh:mm:ss A',
|
|
94
|
+
logFormat
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (typeof duration !== 'undefined' && (userSettings?.addCallLogDuration?.value ?? true)) {
|
|
99
|
+
body = upsertCallDuration({ body, duration, logFormat });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (result && (userSettings?.addCallLogResult?.value ?? true)) {
|
|
103
|
+
body = upsertCallResult({ body, result, logFormat });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (recordingLink && (userSettings?.addCallLogRecording?.value ?? true)) {
|
|
107
|
+
body = upsertCallRecording({ body, recordingLink, logFormat });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (aiNote && (userSettings?.addCallLogAINote?.value ?? true)) {
|
|
111
|
+
body = upsertAiNote({ body, aiNote, logFormat });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (transcript && (userSettings?.addCallLogTranscript?.value ?? true)) {
|
|
115
|
+
body = upsertTranscript({ body, transcript, logFormat });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return body;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Upsert functions for different log components
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
function upsertCallAgentNote({ body, note, logFormat }) {
|
|
126
|
+
if (!note) return body;
|
|
127
|
+
|
|
128
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
129
|
+
// HTML logFormat with proper Agent notes section handling
|
|
130
|
+
const noteRegex = RegExp('<b>Agent notes</b>([\\s\\S]+?)Call details</b>');
|
|
131
|
+
if (noteRegex.test(body)) {
|
|
132
|
+
return body.replace(noteRegex, `<b>Agent notes</b><br>${note}<br><br><b>Call details</b>`);
|
|
133
|
+
}
|
|
134
|
+
return `<b>Agent notes</b><br>${note}<br><br><b>Call details</b><br>` + body;
|
|
135
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
136
|
+
// Markdown logFormat with proper Agent notes section handling
|
|
137
|
+
const noteRegex = /## Agent notes\n([\s\S]*?)\n## Call details/;
|
|
138
|
+
if (noteRegex.test(body)) {
|
|
139
|
+
return body.replace(noteRegex, `## Agent notes\n${note}\n\n## Call details`);
|
|
140
|
+
}
|
|
141
|
+
if (body.startsWith('## Call details')) {
|
|
142
|
+
return `## Agent notes\n${note}\n\n` + body;
|
|
143
|
+
}
|
|
144
|
+
return `## Agent notes\n${note}\n\n## Call details\n` + body;
|
|
145
|
+
} else {
|
|
146
|
+
// Plain text logFormat - FIXED REGEX for multi-line notes with blank lines
|
|
147
|
+
const noteRegex = /- (?:Note|Agent notes): ([\s\S]*?)(?=\n- [A-Z][a-zA-Z\s/]*:|\n$|$)/;
|
|
148
|
+
if (noteRegex.test(body)) {
|
|
149
|
+
return body.replace(noteRegex, `- Note: ${note}`);
|
|
150
|
+
}
|
|
151
|
+
return `- Note: ${note}\n` + body;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function upsertCallSessionId({ body, id, logFormat }) {
|
|
156
|
+
if (!id) return body;
|
|
157
|
+
|
|
158
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
159
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
160
|
+
const idRegex = /(?:<li>)?<b>Session Id<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
161
|
+
if (idRegex.test(body)) {
|
|
162
|
+
return body.replace(idRegex, `<li><b>Session Id</b>: ${id}</li>`);
|
|
163
|
+
}
|
|
164
|
+
return body + `<li><b>Session Id</b>: ${id}</li>`;
|
|
165
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
166
|
+
// Markdown format: **Session Id**: value
|
|
167
|
+
const sessionIdRegex = /\*\*Session Id\*\*: [^\n]*\n*/;
|
|
168
|
+
if (sessionIdRegex.test(body)) {
|
|
169
|
+
return body.replace(sessionIdRegex, `**Session Id**: ${id}\n`);
|
|
170
|
+
}
|
|
171
|
+
return body + `**Session Id**: ${id}\n`;
|
|
172
|
+
} else {
|
|
173
|
+
// Match Session Id field and any trailing newlines, replace with single newline
|
|
174
|
+
const sessionIdRegex = /- Session Id: [^\n]*\n*/;
|
|
175
|
+
if (sessionIdRegex.test(body)) {
|
|
176
|
+
return body.replace(sessionIdRegex, `- Session Id: ${id}\n`);
|
|
177
|
+
}
|
|
178
|
+
return body + `- Session Id: ${id}\n`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function upsertRingCentralUserName({ body, userName, logFormat }) {
|
|
183
|
+
if (!userName) return body;
|
|
184
|
+
|
|
185
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
186
|
+
const userNameRegex = /(?:<li>)?<b>RingCentral user name<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
187
|
+
if (userNameRegex.test(body)) {
|
|
188
|
+
return body.replace(userNameRegex, `<li><b>RingCentral user name</b>: ${userName}</li>`);
|
|
189
|
+
} else {
|
|
190
|
+
return body + `<li><b>RingCentral user name</b>: ${userName}</li>`;
|
|
191
|
+
}
|
|
192
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
193
|
+
const userNameRegex = /\*\*RingCentral user name\*\*: [^\n]*\n*/i;
|
|
194
|
+
if (userNameRegex.test(body)) {
|
|
195
|
+
return body.replace(userNameRegex, `**RingCentral user name**: ${userName}\n`);
|
|
196
|
+
} else {
|
|
197
|
+
return body + `**RingCentral user name**: ${userName}\n`;
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
const userNameRegex = /- RingCentral user name: [^\n]*\n*/;
|
|
201
|
+
if (userNameRegex.test(body)) {
|
|
202
|
+
return body.replace(userNameRegex, `- RingCentral user name: ${userName}\n`);
|
|
203
|
+
} else {
|
|
204
|
+
return body + `- RingCentral user name: ${userName}\n`;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function upsertRingCentralNumberAndExtension({ body, number, extension, logFormat }) {
|
|
210
|
+
if (!number && !extension) return body;
|
|
211
|
+
|
|
212
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
213
|
+
const numberAndExtensionRegex = /(?:<li>)?<b>RingCentral number and extension<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
214
|
+
if (numberAndExtensionRegex.test(body)) {
|
|
215
|
+
return body.replace(numberAndExtensionRegex, `<li><b>RingCentral number and extension</b>: ${number} ${extension}</li>`);
|
|
216
|
+
}
|
|
217
|
+
return body + `<li><b>RingCentral number and extension</b>: ${number} ${extension}</li>`;
|
|
218
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
219
|
+
const numberAndExtensionRegex = /\*\*RingCentral number and extension\*\*: [^\n]*\n*/i;
|
|
220
|
+
if (numberAndExtensionRegex.test(body)) {
|
|
221
|
+
return body.replace(numberAndExtensionRegex, `**RingCentral number and extension**: ${number} ${extension}\n`);
|
|
222
|
+
}
|
|
223
|
+
return body + `**RingCentral number and extension**: ${number} ${extension}\n`;
|
|
224
|
+
} else {
|
|
225
|
+
const numberAndExtensionRegex = /- RingCentral number and extension: [^\n]*\n*/;
|
|
226
|
+
if (numberAndExtensionRegex.test(body)) {
|
|
227
|
+
return body.replace(numberAndExtensionRegex, `- RingCentral number and extension: ${number} ${extension}\n`);
|
|
228
|
+
}
|
|
229
|
+
return body + `- RingCentral number and extension: ${number} ${extension}\n`;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function upsertCallSubject({ body, subject, logFormat }) {
|
|
234
|
+
if (!subject) return body;
|
|
235
|
+
|
|
236
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
237
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
238
|
+
const subjectRegex = /(?:<li>)?<b>Summary<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
239
|
+
if (subjectRegex.test(body)) {
|
|
240
|
+
return body.replace(subjectRegex, `<li><b>Summary</b>: ${subject}</li>`);
|
|
241
|
+
}
|
|
242
|
+
return body + `<li><b>Summary</b>: ${subject}</li>`;
|
|
243
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
244
|
+
// Markdown format: **Summary**: value
|
|
245
|
+
const subjectRegex = /\*\*Summary\*\*: [^\n]*\n*/;
|
|
246
|
+
if (subjectRegex.test(body)) {
|
|
247
|
+
return body.replace(subjectRegex, `**Summary**: ${subject}\n`);
|
|
248
|
+
}
|
|
249
|
+
return body + `**Summary**: ${subject}\n`;
|
|
250
|
+
} else {
|
|
251
|
+
// Match Summary field and any trailing newlines, replace with single newline
|
|
252
|
+
const subjectRegex = /- Summary: [^\n]*\n*/;
|
|
253
|
+
if (subjectRegex.test(body)) {
|
|
254
|
+
return body.replace(subjectRegex, `- Summary: ${subject}\n`);
|
|
255
|
+
}
|
|
256
|
+
return body + `- Summary: ${subject}\n`;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function upsertContactPhoneNumber({ body, phoneNumber, direction, logFormat }) {
|
|
261
|
+
if (!phoneNumber) return body;
|
|
262
|
+
|
|
263
|
+
const label = direction === 'Outbound' ? 'Recipient' : 'Caller';
|
|
264
|
+
let result = body;
|
|
265
|
+
|
|
266
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
267
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
268
|
+
const phoneNumberRegex = new RegExp(`(?:<li>)?<b>${label} phone number</b>:\\s*([^<\\n]+)(?:</li>|(?=<|$))`, 'i');
|
|
269
|
+
if (phoneNumberRegex.test(result)) {
|
|
270
|
+
result = result.replace(phoneNumberRegex, `<li><b>${label} phone number</b>: ${phoneNumber}</li>`);
|
|
271
|
+
} else {
|
|
272
|
+
result += `<li><b>${label} phone number</b>: ${phoneNumber}</li>`;
|
|
273
|
+
}
|
|
274
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
275
|
+
// Markdown format: **Contact Number**: value
|
|
276
|
+
const phoneNumberRegex = /\*\*Contact Number\*\*: [^\n]*\n*/;
|
|
277
|
+
if (phoneNumberRegex.test(result)) {
|
|
278
|
+
result = result.replace(phoneNumberRegex, `**Contact Number**: ${phoneNumber}\n`);
|
|
279
|
+
} else {
|
|
280
|
+
result += `**Contact Number**: ${phoneNumber}\n`;
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
// More flexible regex that handles both with and without newlines
|
|
284
|
+
const phoneNumberRegex = /- Contact Number: ([^\n-]+)(?=\n-|\n|$)/;
|
|
285
|
+
if (phoneNumberRegex.test(result)) {
|
|
286
|
+
result = result.replace(phoneNumberRegex, `- Contact Number: ${phoneNumber}\n`);
|
|
287
|
+
} else {
|
|
288
|
+
result += `- Contact Number: ${phoneNumber}\n`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function upsertCallDateTime({ body, startTime, timezoneOffset, logFormat, logDateFormat }) {
|
|
295
|
+
if (!startTime) return body;
|
|
296
|
+
|
|
297
|
+
// Simple approach: convert to moment and apply timezone offset
|
|
298
|
+
let momentTime = moment(startTime);
|
|
299
|
+
if (timezoneOffset) {
|
|
300
|
+
// Handle both string offsets ('+05:30') and numeric offsets (330 minutes or 5.5 hours)
|
|
301
|
+
if (typeof timezoneOffset === 'string' && timezoneOffset.includes(':')) {
|
|
302
|
+
// String logFormat like '+05:30' or '-05:00'
|
|
303
|
+
momentTime = momentTime.utcOffset(timezoneOffset);
|
|
304
|
+
} else {
|
|
305
|
+
// Numeric logFormat (minutes or hours)
|
|
306
|
+
momentTime = momentTime.utcOffset(Number(timezoneOffset));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const formattedDateTime = momentTime.format(logDateFormat || 'YYYY-MM-DD hh:mm:ss A');
|
|
310
|
+
let result = body;
|
|
311
|
+
|
|
312
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
313
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
314
|
+
const dateTimeRegex = /(?:<li>)?<b>Date\/time<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
315
|
+
if (dateTimeRegex.test(result)) {
|
|
316
|
+
result = result.replace(dateTimeRegex, `<li><b>Date/time</b>: ${formattedDateTime}</li>`);
|
|
317
|
+
} else {
|
|
318
|
+
result += `<li><b>Date/time</b>: ${formattedDateTime}</li>`;
|
|
319
|
+
}
|
|
320
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
321
|
+
// Markdown format: **Date/Time**: value
|
|
322
|
+
const dateTimeRegex = /\*\*Date\/Time\*\*: [^\n]*\n*/;
|
|
323
|
+
if (dateTimeRegex.test(result)) {
|
|
324
|
+
result = result.replace(dateTimeRegex, `**Date/Time**: ${formattedDateTime}\n`);
|
|
325
|
+
} else {
|
|
326
|
+
result += `**Date/Time**: ${formattedDateTime}\n`;
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
// Handle duplicated Date/Time entries and match complete date/time values
|
|
330
|
+
const dateTimeRegex = /(?:- Date\/Time: [^-]*(?:-[^-]*)*)+/;
|
|
331
|
+
if (dateTimeRegex.test(result)) {
|
|
332
|
+
result = result.replace(dateTimeRegex, `- Date/Time: ${formattedDateTime}\n`);
|
|
333
|
+
} else {
|
|
334
|
+
result += `- Date/Time: ${formattedDateTime}\n`;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return result;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function upsertCallDuration({ body, duration, logFormat }) {
|
|
341
|
+
if (typeof duration === 'undefined') return body;
|
|
342
|
+
|
|
343
|
+
const formattedDuration = secondsToHoursMinutesSeconds(duration);
|
|
344
|
+
let result = body;
|
|
345
|
+
|
|
346
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
347
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
348
|
+
const durationRegex = /(?:<li>)?<b>Duration<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
349
|
+
if (durationRegex.test(result)) {
|
|
350
|
+
result = result.replace(durationRegex, `<li><b>Duration</b>: ${formattedDuration}</li>`);
|
|
351
|
+
} else {
|
|
352
|
+
result += `<li><b>Duration</b>: ${formattedDuration}</li>`;
|
|
353
|
+
}
|
|
354
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
355
|
+
// Markdown format: **Duration**: value
|
|
356
|
+
const durationRegex = /\*\*Duration\*\*: [^\n]*\n*/;
|
|
357
|
+
if (durationRegex.test(result)) {
|
|
358
|
+
result = result.replace(durationRegex, `**Duration**: ${formattedDuration}\n`);
|
|
359
|
+
} else {
|
|
360
|
+
result += `**Duration**: ${formattedDuration}\n`;
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
// More flexible regex that handles both with and without newlines
|
|
364
|
+
const durationRegex = /- Duration: ([^\n-]+)(?=\n-|\n|$)/;
|
|
365
|
+
if (durationRegex.test(result)) {
|
|
366
|
+
result = result.replace(durationRegex, `- Duration: ${formattedDuration}\n`);
|
|
367
|
+
} else {
|
|
368
|
+
result += `- Duration: ${formattedDuration}\n`;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function upsertCallResult({ body, result, logFormat }) {
|
|
375
|
+
if (!result) return body;
|
|
376
|
+
|
|
377
|
+
let bodyResult = body;
|
|
378
|
+
|
|
379
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
380
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
381
|
+
const resultRegex = /(?:<li>)?<b>Result<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
382
|
+
if (resultRegex.test(bodyResult)) {
|
|
383
|
+
bodyResult = bodyResult.replace(resultRegex, `<li><b>Result</b>: ${result}</li>`);
|
|
384
|
+
} else {
|
|
385
|
+
bodyResult += `<li><b>Result</b>: ${result}</li>`;
|
|
386
|
+
}
|
|
387
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
388
|
+
// Markdown format: **Result**: value
|
|
389
|
+
const resultRegex = /\*\*Result\*\*: [^\n]*\n*/;
|
|
390
|
+
if (resultRegex.test(bodyResult)) {
|
|
391
|
+
bodyResult = bodyResult.replace(resultRegex, `**Result**: ${result}\n`);
|
|
392
|
+
} else {
|
|
393
|
+
bodyResult += `**Result**: ${result}\n`;
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
// More flexible regex that handles both with and without newlines
|
|
397
|
+
const resultRegex = /- Result: ([^\n-]+)(?=\n-|\n|$)/;
|
|
398
|
+
if (resultRegex.test(bodyResult)) {
|
|
399
|
+
bodyResult = bodyResult.replace(resultRegex, `- Result: ${result}\n`);
|
|
400
|
+
} else {
|
|
401
|
+
bodyResult += `- Result: ${result}\n`;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return bodyResult;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function upsertCallRecording({ body, recordingLink, logFormat }) {
|
|
408
|
+
if (!recordingLink) return body;
|
|
409
|
+
|
|
410
|
+
let result = body;
|
|
411
|
+
|
|
412
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
413
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content
|
|
414
|
+
const recordingLinkRegex = /(?:<li>)?<b>Call recording link<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
415
|
+
if (recordingLink) {
|
|
416
|
+
if (recordingLinkRegex.test(result)) {
|
|
417
|
+
if (recordingLink.startsWith('http')) {
|
|
418
|
+
result = result.replace(recordingLinkRegex, `<li><b>Call recording link</b>: <a target="_blank" href="${recordingLink}">open</a></li>`);
|
|
419
|
+
} else {
|
|
420
|
+
result = result.replace(recordingLinkRegex, `<li><b>Call recording link</b>: (pending...)</li>`);
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
let text = '';
|
|
424
|
+
if (recordingLink.startsWith('http')) {
|
|
425
|
+
text = `<li><b>Call recording link</b>: <a target="_blank" href="${recordingLink}">open</a></li>`;
|
|
426
|
+
} else {
|
|
427
|
+
text = '<li><b>Call recording link</b>: (pending...)</li>';
|
|
428
|
+
}
|
|
429
|
+
if (result.indexOf('</ul>') === -1) {
|
|
430
|
+
result += text;
|
|
431
|
+
} else {
|
|
432
|
+
result = result.replace('</ul>', `${text}</ul>`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
437
|
+
// Markdown format: **Call recording link**: value
|
|
438
|
+
const recordingLinkRegex = /\*\*Call recording link\*\*: [^\n]*\n*/;
|
|
439
|
+
if (recordingLinkRegex.test(result)) {
|
|
440
|
+
result = result.replace(recordingLinkRegex, `**Call recording link**: ${recordingLink}\n`);
|
|
441
|
+
} else {
|
|
442
|
+
result += `**Call recording link**: ${recordingLink}\n`;
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
// Match recording link field and any trailing content, replace with single newline
|
|
446
|
+
const recordingLinkRegex = /- Call recording link: [^\n]*\n*/;
|
|
447
|
+
if (recordingLinkRegex.test(result)) {
|
|
448
|
+
result = result.replace(recordingLinkRegex, `- Call recording link: ${recordingLink}\n`);
|
|
449
|
+
} else {
|
|
450
|
+
if (result && !result.endsWith('\n')) {
|
|
451
|
+
result += '\n';
|
|
452
|
+
}
|
|
453
|
+
result += `- Call recording link: ${recordingLink}\n`;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return result;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function upsertAiNote({ body, aiNote, logFormat }) {
|
|
460
|
+
if (!aiNote) return body;
|
|
461
|
+
|
|
462
|
+
const clearedAiNote = aiNote.replace(/\n+$/, '');
|
|
463
|
+
let result = body;
|
|
464
|
+
|
|
465
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
466
|
+
const formattedAiNote = clearedAiNote.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
467
|
+
const aiNoteRegex = /<div><b>AI Note<\/b><br>(.+?)<\/div>/;
|
|
468
|
+
if (aiNoteRegex.test(result)) {
|
|
469
|
+
result = result.replace(aiNoteRegex, `<div><b>AI Note</b><br>${formattedAiNote}</div>`);
|
|
470
|
+
} else {
|
|
471
|
+
result += `<div><b>AI Note</b><br>${formattedAiNote}</div><br>`;
|
|
472
|
+
}
|
|
473
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
474
|
+
// Markdown format: ### AI Note
|
|
475
|
+
const aiNoteRegex = /### AI Note\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
476
|
+
if (aiNoteRegex.test(result)) {
|
|
477
|
+
result = result.replace(aiNoteRegex, `### AI Note\n${clearedAiNote}\n`);
|
|
478
|
+
} else {
|
|
479
|
+
result += `### AI Note\n${clearedAiNote}\n`;
|
|
480
|
+
}
|
|
481
|
+
} else {
|
|
482
|
+
const aiNoteRegex = /- AI Note:([\s\S]*?)--- END/;
|
|
483
|
+
if (aiNoteRegex.test(result)) {
|
|
484
|
+
result = result.replace(aiNoteRegex, `- AI Note:\n${clearedAiNote}\n--- END`);
|
|
485
|
+
} else {
|
|
486
|
+
result += `- AI Note:\n${clearedAiNote}\n--- END\n`;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function upsertTranscript({ body, transcript, logFormat }) {
|
|
493
|
+
if (!transcript) return body;
|
|
494
|
+
|
|
495
|
+
let result = body;
|
|
496
|
+
|
|
497
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
498
|
+
const formattedTranscript = transcript.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
499
|
+
const transcriptRegex = /<div><b>Transcript<\/b><br>(.+?)<\/div>/;
|
|
500
|
+
if (transcriptRegex.test(result)) {
|
|
501
|
+
result = result.replace(transcriptRegex, `<div><b>Transcript</b><br>${formattedTranscript}</div>`);
|
|
502
|
+
} else {
|
|
503
|
+
result += `<div><b>Transcript</b><br>${formattedTranscript}</div><br>`;
|
|
504
|
+
}
|
|
505
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
506
|
+
// Markdown format: ### Transcript
|
|
507
|
+
const transcriptRegex = /### Transcript\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
508
|
+
if (transcriptRegex.test(result)) {
|
|
509
|
+
result = result.replace(transcriptRegex, `### Transcript\n${transcript}\n`);
|
|
510
|
+
} else {
|
|
511
|
+
result += `### Transcript\n${transcript}\n`;
|
|
512
|
+
}
|
|
513
|
+
} else {
|
|
514
|
+
const transcriptRegex = /- Transcript:([\s\S]*?)--- END/;
|
|
515
|
+
if (transcriptRegex.test(result)) {
|
|
516
|
+
result = result.replace(transcriptRegex, `- Transcript:\n${transcript}\n--- END`);
|
|
517
|
+
} else {
|
|
518
|
+
result += `- Transcript:\n${transcript}\n--- END\n`;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Helper function to determine format type for a CRM platform
|
|
526
|
+
* @param {string} platform - CRM platform name
|
|
527
|
+
* @returns {string} Format type
|
|
528
|
+
*/
|
|
529
|
+
function getLogFormatType(platform) {
|
|
530
|
+
const manifest = adapterRegistry.getManifest(platform, true);
|
|
531
|
+
const platformConfig = manifest.platforms?.[platform];
|
|
532
|
+
return platformConfig?.logFormat;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
module.exports = {
|
|
536
|
+
composeCallLog,
|
|
537
|
+
getLogFormatType,
|
|
538
|
+
// Export individual upsert functions for backward compatibility
|
|
539
|
+
upsertCallAgentNote,
|
|
540
|
+
upsertCallSessionId,
|
|
541
|
+
upsertRingCentralUserName,
|
|
542
|
+
upsertRingCentralNumberAndExtension,
|
|
543
|
+
upsertCallSubject,
|
|
544
|
+
upsertContactPhoneNumber,
|
|
545
|
+
upsertCallDateTime,
|
|
546
|
+
upsertCallDuration,
|
|
547
|
+
upsertCallResult,
|
|
548
|
+
upsertCallRecording,
|
|
549
|
+
upsertAiNote,
|
|
550
|
+
upsertTranscript
|
|
486
551
|
};
|