@app-connect/core 1.7.8 → 1.7.11
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 +44 -21
- package/handlers/auth.js +97 -69
- package/handlers/calldown.js +10 -4
- package/handlers/contact.js +45 -112
- package/handlers/disposition.js +4 -142
- package/handlers/log.js +174 -259
- package/handlers/user.js +19 -6
- package/index.js +310 -122
- 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 -12
- 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 +90 -0
- package/mcp/tools/collectAuthInfo.js +86 -0
- package/mcp/tools/createCallLog.js +299 -0
- package/mcp/tools/createMessageLog.js +283 -0
- package/mcp/tools/doAuth.js +185 -0
- package/mcp/tools/findContactByName.js +87 -0
- package/mcp/tools/findContactByPhone.js +96 -0
- package/mcp/tools/getCallLog.js +98 -0
- package/mcp/tools/getHelp.js +39 -0
- package/mcp/tools/getPublicConnectors.js +46 -0
- package/mcp/tools/index.js +58 -0
- package/mcp/tools/logout.js +63 -0
- package/mcp/tools/rcGetCallLogs.js +73 -0
- package/mcp/tools/setConnector.js +64 -0
- package/mcp/tools/updateCallLog.js +122 -0
- package/models/accountDataModel.js +34 -0
- package/models/cacheModel.js +3 -0
- package/package.json +6 -4
- package/releaseNotes.json +36 -0
- package/test/connector/registry.test.js +145 -0
- package/test/handlers/admin.test.js +583 -0
- package/test/handlers/auth.test.js +355 -0
- package/test/handlers/contact.test.js +852 -0
- package/test/handlers/log.test.js +872 -0
- package/test/lib/callLogComposer.test.js +1231 -0
- package/test/lib/debugTracer.test.js +328 -0
- package/test/lib/logger.test.js +206 -0
- package/test/lib/oauth.test.js +359 -0
- package/test/lib/ringcentral.test.js +473 -0
- package/test/lib/sharedSMSComposer.test.js +1084 -0
- package/test/lib/util.test.js +282 -0
- package/test/mcp/tools/collectAuthInfo.test.js +192 -0
- package/test/mcp/tools/createCallLog.test.js +412 -0
- package/test/mcp/tools/createMessageLog.test.js +580 -0
- package/test/mcp/tools/doAuth.test.js +363 -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/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/test/models/accountDataModel.test.js +98 -0
- package/test/models/dynamo/connectorSchema.test.js +189 -0
- package/test/models/models.test.js +539 -0
- package/test/setup.js +176 -176
package/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const cors = require('cors')
|
|
3
3
|
const bodyParser = require('body-parser');
|
|
4
|
+
require('body-parser-xml')(bodyParser);
|
|
4
5
|
const dynamoose = require('dynamoose');
|
|
5
6
|
const axios = require('axios');
|
|
6
7
|
const { UserModel } = require('./models/userModel');
|
|
7
8
|
const { CallDownListModel } = require('./models/callDownListModel');
|
|
8
|
-
const { Op } = require('sequelize');
|
|
9
9
|
const { CallLogModel } = require('./models/callLogModel');
|
|
10
10
|
const { MessageLogModel } = require('./models/messageLogModel');
|
|
11
11
|
const { AdminConfigModel } = require('./models/adminConfigModel');
|
|
12
12
|
const { CacheModel } = require('./models/cacheModel');
|
|
13
|
+
const { AccountDataModel } = require('./models/accountDataModel');
|
|
13
14
|
const jwt = require('./lib/jwt');
|
|
14
15
|
const logCore = require('./handlers/log');
|
|
15
16
|
const contactCore = require('./handlers/contact');
|
|
@@ -24,14 +25,19 @@ const analytics = require('./lib/analytics');
|
|
|
24
25
|
const util = require('./lib/util');
|
|
25
26
|
const connectorRegistry = require('./connector/registry');
|
|
26
27
|
const calldown = require('./handlers/calldown');
|
|
28
|
+
const mcpHandler = require('./mcp/mcpHandler');
|
|
29
|
+
const logger = require('./lib/logger');
|
|
27
30
|
const { DebugTracer } = require('./lib/debugTracer');
|
|
28
31
|
const s3ErrorLogReport = require('./lib/s3ErrorLogReport');
|
|
32
|
+
const { handleDatabaseError } = require('./lib/errorHandler');
|
|
33
|
+
const { updateAuthSession } = require('./lib/authSession');
|
|
29
34
|
|
|
30
35
|
let packageJson = null;
|
|
31
36
|
try {
|
|
32
37
|
packageJson = require('./package.json');
|
|
33
38
|
}
|
|
34
39
|
catch (e) {
|
|
40
|
+
logger.error('Error loading package.json', { stack: e.stack });
|
|
35
41
|
packageJson = require('../package.json');
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -39,18 +45,25 @@ catch (e) {
|
|
|
39
45
|
if (process.env.DYNAMODB_LOCALHOST) {
|
|
40
46
|
dynamoose.aws.ddb.local(process.env.DYNAMODB_LOCALHOST);
|
|
41
47
|
}
|
|
42
|
-
|
|
48
|
+
// log axios requests
|
|
49
|
+
if (process.env.IS_PROD === 'false') {
|
|
50
|
+
axios.interceptors.request.use(request => {
|
|
51
|
+
console.log('Request:', `[${request.method}]`, request.url);
|
|
52
|
+
return request;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
43
55
|
axios.defaults.headers.common['Unified-CRM-Extension-Version'] = packageJson.version;
|
|
44
56
|
|
|
45
57
|
async function initDB() {
|
|
46
58
|
if (!process.env.DISABLE_SYNC_DB_TABLE) {
|
|
47
|
-
|
|
59
|
+
logger.info('creating db tables if not exist...');
|
|
48
60
|
await UserModel.sync();
|
|
49
61
|
await CallLogModel.sync();
|
|
50
62
|
await MessageLogModel.sync();
|
|
51
63
|
await AdminConfigModel.sync();
|
|
52
64
|
await CacheModel.sync();
|
|
53
65
|
await CallDownListModel.sync();
|
|
66
|
+
await AccountDataModel.sync();
|
|
54
67
|
}
|
|
55
68
|
}
|
|
56
69
|
|
|
@@ -120,6 +133,7 @@ function createCoreRouter() {
|
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
135
|
catch (e) {
|
|
136
|
+
logger.error('Error getting crm manifest', { stack: e.stack });
|
|
123
137
|
res.status(400).send('Platform not found');
|
|
124
138
|
}
|
|
125
139
|
});
|
|
@@ -159,11 +173,11 @@ function createCoreRouter() {
|
|
|
159
173
|
result.getLicenseStatus = !!platformModule.getLicenseStatus;
|
|
160
174
|
result.getLogFormatType = !!platformModule.getLogFormatType;
|
|
161
175
|
result.cacheCallNote = !!process.env.USE_CACHE;
|
|
162
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
176
|
+
res.status(200).send(tracer ? tracer.wrapResponse(result) : result);
|
|
163
177
|
}
|
|
164
178
|
else {
|
|
165
179
|
tracer?.trace('implementedInterfaces:noPlatform', {});
|
|
166
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
180
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please provide platform.') : 'Please provide platform.');
|
|
167
181
|
return;
|
|
168
182
|
}
|
|
169
183
|
}
|
|
@@ -187,11 +201,11 @@ function createCoreRouter() {
|
|
|
187
201
|
platformName = platform;
|
|
188
202
|
if (!userId) {
|
|
189
203
|
tracer?.trace('licenseStatus:noUserId', {});
|
|
190
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
204
|
+
res.status(400).send(tracer ? tracer.wrapResponse('No user ID') : 'No user ID');
|
|
191
205
|
success = true;
|
|
192
206
|
}
|
|
193
207
|
const licenseStatus = await authCore.getLicenseStatus({ userId, platform });
|
|
194
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
208
|
+
res.status(200).send(tracer ? tracer.wrapResponse(licenseStatus) : licenseStatus);
|
|
195
209
|
success = true;
|
|
196
210
|
}
|
|
197
211
|
else {
|
|
@@ -253,7 +267,7 @@ function createCoreRouter() {
|
|
|
253
267
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
254
268
|
if (!decodedToken) {
|
|
255
269
|
tracer?.trace('authValidation:invalidJwtToken', {});
|
|
256
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
270
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Invalid JWT token') : 'Invalid JWT token');
|
|
257
271
|
return;
|
|
258
272
|
}
|
|
259
273
|
const { id: userId, platform } = decodedToken;
|
|
@@ -267,12 +281,12 @@ function createCoreRouter() {
|
|
|
267
281
|
}
|
|
268
282
|
else {
|
|
269
283
|
tracer?.trace('authValidation:noToken', {});
|
|
270
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
284
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
271
285
|
success = false;
|
|
272
286
|
}
|
|
273
287
|
}
|
|
274
288
|
catch (e) {
|
|
275
|
-
|
|
289
|
+
logger.error('Auth validation failed', { platform: platformName, stack: e.stack });
|
|
276
290
|
tracer?.traceError('authValidation:error', e);
|
|
277
291
|
statusCode = e.response?.status ?? 'unknown';
|
|
278
292
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
@@ -314,17 +328,17 @@ function createCoreRouter() {
|
|
|
314
328
|
const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
|
|
315
329
|
if (isValidated) {
|
|
316
330
|
await adminCore.upsertAdminSettings({ hashedRcAccountId, adminSettings: req.body.adminSettings });
|
|
317
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
331
|
+
res.status(200).send(tracer ? tracer.wrapResponse('Admin settings updated') : 'Admin settings updated');
|
|
318
332
|
success = true;
|
|
319
333
|
}
|
|
320
334
|
else {
|
|
321
335
|
tracer?.trace('setAdminSettings:adminValidationFailed', {});
|
|
322
|
-
res.status(401).send(tracer ? tracer.wrapResponse(
|
|
336
|
+
res.status(401).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
|
|
323
337
|
success = false;
|
|
324
338
|
}
|
|
325
339
|
}
|
|
326
340
|
catch (e) {
|
|
327
|
-
|
|
341
|
+
logger.error('Set admin settings failed', { stack: e.stack });
|
|
328
342
|
tracer?.traceError('setAdminSettings:error', e);
|
|
329
343
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
330
344
|
success = false;
|
|
@@ -358,7 +372,7 @@ function createCoreRouter() {
|
|
|
358
372
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
359
373
|
if (!user) {
|
|
360
374
|
tracer?.trace('getAdminSettings:userNotFound', {});
|
|
361
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
375
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
362
376
|
return;
|
|
363
377
|
}
|
|
364
378
|
const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
|
|
@@ -366,7 +380,7 @@ function createCoreRouter() {
|
|
|
366
380
|
if (isValidated) {
|
|
367
381
|
const adminSettings = await adminCore.getAdminSettings({ hashedRcAccountId });
|
|
368
382
|
if (adminSettings) {
|
|
369
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
383
|
+
res.status(200).send(tracer ? tracer.wrapResponse(adminSettings) : adminSettings);
|
|
370
384
|
}
|
|
371
385
|
else {
|
|
372
386
|
res.status(200).send(tracer ? tracer.wrapResponse({
|
|
@@ -381,13 +395,13 @@ function createCoreRouter() {
|
|
|
381
395
|
}
|
|
382
396
|
else {
|
|
383
397
|
tracer?.trace('getAdminSettings:adminValidationFailed', {});
|
|
384
|
-
res.status(401).send(tracer ? tracer.wrapResponse(
|
|
398
|
+
res.status(401).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
|
|
385
399
|
success = true;
|
|
386
400
|
}
|
|
387
401
|
}
|
|
388
402
|
else {
|
|
389
403
|
tracer?.trace('getAdminSettings:noToken', {});
|
|
390
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
404
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
391
405
|
success = false;
|
|
392
406
|
}
|
|
393
407
|
}
|
|
@@ -426,30 +440,30 @@ function createCoreRouter() {
|
|
|
426
440
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
427
441
|
if (!user) {
|
|
428
442
|
tracer?.trace('getUserMapping:userNotFound', {});
|
|
429
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
443
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
430
444
|
return;
|
|
431
445
|
}
|
|
432
446
|
const { isValidated, rcAccountId } = await adminCore.validateAdminRole({ rcAccessToken: req.query.rcAccessToken });
|
|
433
447
|
const hashedRcAccountId = util.getHashValue(rcAccountId, process.env.HASH_KEY);
|
|
434
448
|
if (isValidated) {
|
|
435
449
|
const userMapping = await adminCore.getUserMapping({ user, hashedRcAccountId, rcExtensionList: req.body.rcExtensionList });
|
|
436
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
450
|
+
res.status(200).send(tracer ? tracer.wrapResponse(userMapping) : userMapping);
|
|
437
451
|
success = true;
|
|
438
452
|
}
|
|
439
453
|
else {
|
|
440
454
|
tracer?.trace('getUserMapping:adminValidationFailed', {});
|
|
441
|
-
res.status(401).send(tracer ? tracer.wrapResponse(
|
|
455
|
+
res.status(401).send(tracer ? tracer.wrapResponse('Admin validation failed') : 'Admin validation failed');
|
|
442
456
|
success = true;
|
|
443
457
|
}
|
|
444
458
|
}
|
|
445
459
|
else {
|
|
446
460
|
tracer?.trace('getUserMapping:noToken', {});
|
|
447
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
461
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
448
462
|
success = false;
|
|
449
463
|
}
|
|
450
464
|
}
|
|
451
465
|
catch (e) {
|
|
452
|
-
|
|
466
|
+
logger.error('Get user mapping failed', { stack: e.stack });
|
|
453
467
|
tracer?.traceError('getUserMapping:error', e);
|
|
454
468
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
455
469
|
}
|
|
@@ -477,7 +491,7 @@ function createCoreRouter() {
|
|
|
477
491
|
const jwtToken = req.query.jwtToken;
|
|
478
492
|
if (!jwtToken) {
|
|
479
493
|
tracer?.trace('getServerLoggingSettings:noToken', {});
|
|
480
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
494
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
481
495
|
return;
|
|
482
496
|
}
|
|
483
497
|
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
@@ -485,22 +499,22 @@ function createCoreRouter() {
|
|
|
485
499
|
const unAuthData = jwt.decodeJwt(jwtToken);
|
|
486
500
|
if (!unAuthData?.id) {
|
|
487
501
|
tracer?.trace('getServerLoggingSettings:noToken', {});
|
|
488
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
502
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
489
503
|
return;
|
|
490
504
|
}
|
|
491
505
|
platformName = unAuthData?.platform ?? 'Unknown';
|
|
492
506
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
493
507
|
if (!user) {
|
|
494
508
|
tracer?.trace('getServerLoggingSettings:userNotFound', {});
|
|
495
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
509
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
496
510
|
return;
|
|
497
511
|
}
|
|
498
512
|
const serverLoggingSettings = await adminCore.getServerLoggingSettings({ user });
|
|
499
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
513
|
+
res.status(200).send(tracer ? tracer.wrapResponse(serverLoggingSettings) : serverLoggingSettings);
|
|
500
514
|
success = true;
|
|
501
515
|
}
|
|
502
516
|
catch (e) {
|
|
503
|
-
|
|
517
|
+
logger.error('Get server logging settings failed', { stack: e.stack });
|
|
504
518
|
tracer?.traceError('getServerLoggingSettings:error', e);
|
|
505
519
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
506
520
|
}
|
|
@@ -528,12 +542,12 @@ function createCoreRouter() {
|
|
|
528
542
|
const jwtToken = req.query.jwtToken;
|
|
529
543
|
if (!jwtToken) {
|
|
530
544
|
tracer?.trace('setServerLoggingSettings:noToken', {});
|
|
531
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
545
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
532
546
|
return;
|
|
533
547
|
}
|
|
534
548
|
if (!req.body.additionalFieldValues) {
|
|
535
549
|
tracer?.trace('setServerLoggingSettings:missingAdditionalFieldValues', {});
|
|
536
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
550
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing additionalFieldValues') : 'Missing additionalFieldValues');
|
|
537
551
|
return;
|
|
538
552
|
}
|
|
539
553
|
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
@@ -541,14 +555,14 @@ function createCoreRouter() {
|
|
|
541
555
|
const unAuthData = jwt.decodeJwt(jwtToken);
|
|
542
556
|
if (!unAuthData?.id) {
|
|
543
557
|
tracer?.trace('setServerLoggingSettings:noToken', {});
|
|
544
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
558
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
545
559
|
return;
|
|
546
560
|
}
|
|
547
561
|
platformName = unAuthData?.platform ?? 'Unknown';
|
|
548
562
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
549
563
|
if (!user) {
|
|
550
564
|
tracer?.trace('setServerLoggingSettings:userNotFound', {});
|
|
551
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
565
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
552
566
|
return;
|
|
553
567
|
}
|
|
554
568
|
const { successful, returnMessage } = await adminCore.updateServerLoggingSettings({ user, additionalFieldValues: req.body.additionalFieldValues });
|
|
@@ -556,7 +570,7 @@ function createCoreRouter() {
|
|
|
556
570
|
success = true;
|
|
557
571
|
}
|
|
558
572
|
catch (e) {
|
|
559
|
-
|
|
573
|
+
logger.error('Set server logging settings failed', { stack: e.stack });
|
|
560
574
|
tracer?.traceError('setServerLoggingSettings:error', e);
|
|
561
575
|
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } }) : { successful: false, returnMessage: { messageType: 'warning', message: 'Server logging settings update failed', ttl: 5000 } });
|
|
562
576
|
success = false;
|
|
@@ -584,15 +598,15 @@ function createCoreRouter() {
|
|
|
584
598
|
const rcAccountId = req.query.rcAccountId;
|
|
585
599
|
if (rcAccessToken || rcAccountId) {
|
|
586
600
|
const userSettings = await userCore.getUserSettingsByAdmin({ rcAccessToken, rcAccountId });
|
|
587
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
601
|
+
res.status(200).send(tracer ? tracer.wrapResponse(userSettings) : userSettings);
|
|
588
602
|
}
|
|
589
603
|
else {
|
|
590
604
|
tracer?.trace('getUserSettingsByAdmin:noRcAccessTokenOrRcAccountId', {});
|
|
591
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
605
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Cannot find rc user login') : 'Cannot find rc user login');
|
|
592
606
|
}
|
|
593
607
|
}
|
|
594
608
|
catch (e) {
|
|
595
|
-
|
|
609
|
+
logger.error('Get user preload settings failed', { stack: e.stack });
|
|
596
610
|
tracer?.traceError('getUserSettingsByAdmin:error', e);
|
|
597
611
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
598
612
|
}
|
|
@@ -613,7 +627,7 @@ function createCoreRouter() {
|
|
|
613
627
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
614
628
|
if (!user) {
|
|
615
629
|
tracer?.trace('getUserSettings:userNotFound', {});
|
|
616
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
630
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
617
631
|
return;
|
|
618
632
|
}
|
|
619
633
|
else {
|
|
@@ -621,17 +635,17 @@ function createCoreRouter() {
|
|
|
621
635
|
const rcAccountId = req.query.rcAccountId;
|
|
622
636
|
const userSettings = await userCore.getUserSettings({ user, rcAccessToken, rcAccountId });
|
|
623
637
|
success = true;
|
|
624
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
638
|
+
res.status(200).send(tracer ? tracer.wrapResponse(userSettings) : userSettings);
|
|
625
639
|
}
|
|
626
640
|
}
|
|
627
641
|
else {
|
|
628
642
|
success = false;
|
|
629
643
|
tracer?.trace('getUserSettings:noToken', {});
|
|
630
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
644
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
631
645
|
}
|
|
632
646
|
}
|
|
633
647
|
catch (e) {
|
|
634
|
-
|
|
648
|
+
logger.error('Get user settings failed', { platform: platformName, stack: e.stack });
|
|
635
649
|
tracer?.traceError('getUserSettings:error', e, { platform: platformName });
|
|
636
650
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
637
651
|
}
|
|
@@ -664,13 +678,13 @@ function createCoreRouter() {
|
|
|
664
678
|
platformName = unAuthData?.platform;
|
|
665
679
|
if (!platformName) {
|
|
666
680
|
tracer?.trace('setUserSettings:unknownPlatform', {});
|
|
667
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
681
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Unknown platform') : 'Unknown platform');
|
|
668
682
|
return;
|
|
669
683
|
}
|
|
670
684
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
671
685
|
if (!user) {
|
|
672
686
|
tracer?.trace('setUserSettings:userNotFound', {});
|
|
673
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
687
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
674
688
|
return;
|
|
675
689
|
}
|
|
676
690
|
const { userSettings } = await userCore.updateUserSettings({ user, userSettings: req.body.userSettings, platformName });
|
|
@@ -679,12 +693,12 @@ function createCoreRouter() {
|
|
|
679
693
|
}
|
|
680
694
|
else {
|
|
681
695
|
tracer?.trace('setUserSettings:noToken', {});
|
|
682
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
696
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
683
697
|
success = false;
|
|
684
698
|
}
|
|
685
699
|
}
|
|
686
700
|
catch (e) {
|
|
687
|
-
|
|
701
|
+
logger.error('Set user settings failed', { platform: platformName, stack: e.stack });
|
|
688
702
|
tracer?.traceError('setUserSettings:error', e, { platform: platformName });
|
|
689
703
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
690
704
|
}
|
|
@@ -713,18 +727,18 @@ function createCoreRouter() {
|
|
|
713
727
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
714
728
|
if (!user) {
|
|
715
729
|
tracer?.trace('hostname:userNotFound', {});
|
|
716
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
730
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
717
731
|
return;
|
|
718
732
|
}
|
|
719
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
733
|
+
res.status(200).send(tracer ? tracer.wrapResponse(user.hostname) : user.hostname);
|
|
720
734
|
}
|
|
721
735
|
else {
|
|
722
736
|
tracer?.trace('hostname:noToken', {});
|
|
723
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
737
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
724
738
|
}
|
|
725
739
|
}
|
|
726
740
|
catch (e) {
|
|
727
|
-
|
|
741
|
+
logger.error('Get hostname failed', { stack: e.stack });
|
|
728
742
|
tracer?.traceError('hostname:error', e);
|
|
729
743
|
res.status(500).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
730
744
|
}
|
|
@@ -735,21 +749,32 @@ function createCoreRouter() {
|
|
|
735
749
|
tracer?.trace('oauth-callback:start', { query: req.query });
|
|
736
750
|
let platformName = null;
|
|
737
751
|
let success = false;
|
|
752
|
+
let sessionId = null;
|
|
738
753
|
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
739
754
|
try {
|
|
740
755
|
if (!req.query?.callbackUri || req.query.callbackUri === 'undefined') {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
756
|
+
// case: from mcp
|
|
757
|
+
if (req.query.code) {
|
|
758
|
+
// eslint-disable-next-line no-param-reassign
|
|
759
|
+
req.query.callbackUri = `${process.env.APP_SERVER}/oauth-callback?code=${req.query.code}`;
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
tracer?.trace('oauth-callback:missingCallbackUri', {});
|
|
763
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing callbackUri') : 'Missing callbackUri');
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
744
766
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
767
|
+
const state = new URL(req.query.callbackUri).searchParams.get('state') ?? req.query.state;
|
|
768
|
+
const stateParams = new URLSearchParams(state ? decodeURIComponent(state) : '');
|
|
769
|
+
platformName = stateParams.get('platform');
|
|
770
|
+
// Extract mcp auth sessionId if present
|
|
771
|
+
sessionId = stateParams?.get('sessionId');
|
|
772
|
+
const isFromMCP = !!sessionId;
|
|
773
|
+
const hostname = req.query.hostname ?? stateParams.get('hostname');
|
|
749
774
|
const tokenUrl = req.query.tokenUrl;
|
|
750
775
|
if (!platformName) {
|
|
751
776
|
tracer?.trace('oauth-callback:missingPlatformName', {});
|
|
752
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
777
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
|
|
753
778
|
return;
|
|
754
779
|
}
|
|
755
780
|
const hasAuthCodeInCallbackUri = req.query.callbackUri.includes('code=');
|
|
@@ -761,29 +786,53 @@ function createCoreRouter() {
|
|
|
761
786
|
platform: platformName,
|
|
762
787
|
hostname,
|
|
763
788
|
tokenUrl,
|
|
764
|
-
callbackUri: req.query.callbackUri,
|
|
765
|
-
apiUrl: req.query.apiUrl,
|
|
766
|
-
username: req.query.username,
|
|
767
789
|
query: req.query,
|
|
768
|
-
proxyId: req.query.proxyId
|
|
790
|
+
proxyId: req.query.proxyId,
|
|
791
|
+
isFromMCP
|
|
769
792
|
});
|
|
770
793
|
if (userInfo) {
|
|
771
794
|
const jwtToken = jwt.generateJwt({
|
|
772
795
|
id: userInfo.id.toString(),
|
|
773
796
|
platform: platformName
|
|
774
797
|
});
|
|
775
|
-
|
|
776
|
-
|
|
798
|
+
// Store in session if sessionId exists (MCP flow)
|
|
799
|
+
if (isFromMCP) {
|
|
800
|
+
await updateAuthSession(sessionId, {
|
|
801
|
+
status: 'completed',
|
|
802
|
+
jwtToken,
|
|
803
|
+
userInfo: {
|
|
804
|
+
id: userInfo.id,
|
|
805
|
+
name: userInfo.name
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
res.status(200).send("Authentication successful. Please go back to AI Agent and confirm it.");
|
|
809
|
+
success = true;
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
res.status(200).send(tracer ? tracer.wrapResponse({ jwtToken, name: userInfo.name, returnMessage }) : { jwtToken, name: userInfo.name, returnMessage });
|
|
813
|
+
success = true;
|
|
814
|
+
}
|
|
777
815
|
}
|
|
778
816
|
else {
|
|
779
817
|
res.status(200).send(tracer ? tracer.wrapResponse({ returnMessage }) : { returnMessage });
|
|
780
|
-
|
|
818
|
+
await updateAuthSession(sessionId, {
|
|
819
|
+
status: 'failed',
|
|
820
|
+
errorMessage: returnMessage?.message || 'Authentication failed'
|
|
821
|
+
});
|
|
781
822
|
}
|
|
823
|
+
success = false;
|
|
782
824
|
}
|
|
783
825
|
catch (e) {
|
|
784
|
-
|
|
826
|
+
logger.error('OAuth callback failed', { platform: platformName, stack: e.stack });
|
|
785
827
|
tracer?.traceError('oauth-callback:error', e, { platform: platformName });
|
|
786
828
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
829
|
+
if (sessionId) {
|
|
830
|
+
await updateAuthSession(sessionId, {
|
|
831
|
+
status: 'failed',
|
|
832
|
+
errorMessage: e.message || e.toString()
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
|
|
787
836
|
success = false;
|
|
788
837
|
}
|
|
789
838
|
const requestEndTime = new Date().getTime();
|
|
@@ -800,7 +849,7 @@ function createCoreRouter() {
|
|
|
800
849
|
author,
|
|
801
850
|
eventAddedVia
|
|
802
851
|
});
|
|
803
|
-
})
|
|
852
|
+
});
|
|
804
853
|
router.post('/apiKeyLogin', async function (req, res) {
|
|
805
854
|
const requestStartTime = new Date().getTime();
|
|
806
855
|
const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
|
|
@@ -817,12 +866,12 @@ function createCoreRouter() {
|
|
|
817
866
|
const additionalInfo = req.body.additionalInfo;
|
|
818
867
|
if (!platform) {
|
|
819
868
|
tracer?.trace('apiKeyLogin:missingPlatform', {});
|
|
820
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
869
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
|
|
821
870
|
return;
|
|
822
871
|
}
|
|
823
872
|
if (!apiKey) {
|
|
824
873
|
tracer?.trace('apiKeyLogin:missingApiKey', {});
|
|
825
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
874
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing api key') : 'Missing api key');
|
|
826
875
|
return;
|
|
827
876
|
}
|
|
828
877
|
const { userInfo, returnMessage } = await authCore.onApiKeyLogin({ platform, hostname, apiKey, proxyId, additionalInfo });
|
|
@@ -840,7 +889,7 @@ function createCoreRouter() {
|
|
|
840
889
|
}
|
|
841
890
|
}
|
|
842
891
|
catch (e) {
|
|
843
|
-
|
|
892
|
+
logger.error('API key login failed', { platform: platformName, stack: e.stack });
|
|
844
893
|
tracer?.traceError('apiKeyLogin:error', e, { platform: platformName });
|
|
845
894
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
846
895
|
success = false;
|
|
@@ -875,22 +924,22 @@ function createCoreRouter() {
|
|
|
875
924
|
const userToLogout = await UserModel.findByPk(unAuthData?.id);
|
|
876
925
|
if (!userToLogout) {
|
|
877
926
|
tracer?.trace('unAuthorize:userNotFound', {});
|
|
878
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
927
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
879
928
|
return;
|
|
880
929
|
}
|
|
881
930
|
const platformModule = connectorRegistry.getConnector(unAuthData?.platform ?? 'Unknown');
|
|
882
931
|
const { returnMessage } = await platformModule.unAuthorize({ user: userToLogout });
|
|
883
|
-
res.status(200).send(tracer ? tracer.wrapResponse(
|
|
932
|
+
res.status(200).send(tracer ? tracer.wrapResponse(returnMessage) : returnMessage);
|
|
884
933
|
success = true;
|
|
885
934
|
}
|
|
886
935
|
else {
|
|
887
936
|
tracer?.trace('unAuthorize:noToken', {});
|
|
888
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
937
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
889
938
|
success = false;
|
|
890
939
|
}
|
|
891
940
|
}
|
|
892
941
|
catch (e) {
|
|
893
|
-
|
|
942
|
+
logger.error('Unauthorize failed', { platform: platformName, stack: e.stack });
|
|
894
943
|
tracer?.traceError('unAuthorize:error', e, { platform: platformName });
|
|
895
944
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
896
945
|
success = false;
|
|
@@ -919,7 +968,7 @@ function createCoreRouter() {
|
|
|
919
968
|
res.status(200).send(tracer ? tracer.wrapResponse({ extensionId, accountId }) : { extensionId, accountId });
|
|
920
969
|
}
|
|
921
970
|
catch (e) {
|
|
922
|
-
|
|
971
|
+
logger.error('Get user info hash failed', { stack: e.stack });
|
|
923
972
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
924
973
|
tracer?.traceError('userInfoHash:error', e);
|
|
925
974
|
}
|
|
@@ -941,12 +990,20 @@ function createCoreRouter() {
|
|
|
941
990
|
tracer?.trace('findContact:jwtDecoded', { decodedToken });
|
|
942
991
|
if (!decodedToken) {
|
|
943
992
|
tracer?.trace('findContact:invalidToken', {});
|
|
944
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
993
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
945
994
|
return;
|
|
946
995
|
}
|
|
947
996
|
const { id: userId, platform } = decodedToken;
|
|
948
997
|
platformName = platform;
|
|
949
|
-
const { successful, returnMessage, contact, extraDataTracking } = await contactCore.findContact({
|
|
998
|
+
const { successful, returnMessage, contact, extraDataTracking } = await contactCore.findContact({
|
|
999
|
+
platform,
|
|
1000
|
+
userId,
|
|
1001
|
+
phoneNumber: req.query.phoneNumber.replace(' ', '+'),
|
|
1002
|
+
overridingFormat: req.query.overridingFormat,
|
|
1003
|
+
isExtension: req.query?.isExtension ?? false,
|
|
1004
|
+
tracer,
|
|
1005
|
+
isForceRefreshAccountData: req.query?.isForceRefreshAccountData === 'true'
|
|
1006
|
+
});
|
|
950
1007
|
tracer?.trace('findContact:result', { successful, returnMessage, contact });
|
|
951
1008
|
res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage, contact }) : { successful, returnMessage, contact });
|
|
952
1009
|
if (successful) {
|
|
@@ -960,12 +1017,12 @@ function createCoreRouter() {
|
|
|
960
1017
|
}
|
|
961
1018
|
else {
|
|
962
1019
|
tracer?.trace('findContact:noToken', {});
|
|
963
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1020
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
964
1021
|
success = false;
|
|
965
1022
|
}
|
|
966
1023
|
}
|
|
967
1024
|
catch (e) {
|
|
968
|
-
|
|
1025
|
+
logger.error('Find contact failed', { platform: platformName, stack: e.stack });
|
|
969
1026
|
tracer?.traceError('findContact:error', e, { platform: platformName });
|
|
970
1027
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
971
1028
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
@@ -1004,7 +1061,7 @@ function createCoreRouter() {
|
|
|
1004
1061
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1005
1062
|
if (!decodedToken) {
|
|
1006
1063
|
tracer?.trace('createContact:invalidToken', {});
|
|
1007
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1064
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1008
1065
|
return;
|
|
1009
1066
|
}
|
|
1010
1067
|
const { id: userId, platform } = decodedToken;
|
|
@@ -1018,12 +1075,12 @@ function createCoreRouter() {
|
|
|
1018
1075
|
}
|
|
1019
1076
|
else {
|
|
1020
1077
|
tracer?.trace('createContact:noToken', {});
|
|
1021
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1078
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1022
1079
|
success = false;
|
|
1023
1080
|
}
|
|
1024
1081
|
}
|
|
1025
1082
|
catch (e) {
|
|
1026
|
-
|
|
1083
|
+
logger.error('Create contact failed', { platform: platformName, stack: e.stack });
|
|
1027
1084
|
tracer?.traceError('createContact:error', e, { platform: platformName });
|
|
1028
1085
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1029
1086
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
@@ -1061,12 +1118,12 @@ function createCoreRouter() {
|
|
|
1061
1118
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1062
1119
|
if (!decodedToken) {
|
|
1063
1120
|
tracer?.trace('saveNoteCache:invalidToken', {});
|
|
1064
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1121
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1065
1122
|
return;
|
|
1066
1123
|
}
|
|
1067
1124
|
const { id: userId, platform } = decodedToken;
|
|
1068
1125
|
platformName = platform;
|
|
1069
|
-
const { successful, returnMessage, extraDataTracking } = await logCore.saveNoteCache({ sessionId: req.body.sessionId, note: req.body.note });
|
|
1126
|
+
const { successful, returnMessage, extraDataTracking } = await logCore.saveNoteCache({ platform, userId, sessionId: req.body.sessionId, note: req.body.note });
|
|
1070
1127
|
res.status(200).send(tracer ? tracer.wrapResponse({ successful, returnMessage }) : { successful, returnMessage });
|
|
1071
1128
|
success = true;
|
|
1072
1129
|
if (extraDataTracking) {
|
|
@@ -1074,7 +1131,7 @@ function createCoreRouter() {
|
|
|
1074
1131
|
}
|
|
1075
1132
|
}
|
|
1076
1133
|
} catch (e) {
|
|
1077
|
-
|
|
1134
|
+
logger.error('Save note cache failed', { platform: platformName, stack: e.stack });
|
|
1078
1135
|
tracer?.traceError('saveNoteCache:error', e, { platform: platformName });
|
|
1079
1136
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1080
1137
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
@@ -1088,6 +1145,14 @@ function createCoreRouter() {
|
|
|
1088
1145
|
accountId: hashedAccountId,
|
|
1089
1146
|
extensionId: hashedExtensionId,
|
|
1090
1147
|
success,
|
|
1148
|
+
requestDuration: (requestEndTime - requestStartTime) / 1000,
|
|
1149
|
+
userAgent,
|
|
1150
|
+
ip,
|
|
1151
|
+
author,
|
|
1152
|
+
eventAddedVia,
|
|
1153
|
+
extras: {
|
|
1154
|
+
...extraData
|
|
1155
|
+
}
|
|
1091
1156
|
});
|
|
1092
1157
|
})
|
|
1093
1158
|
router.get('/callLog', async function (req, res) {
|
|
@@ -1104,7 +1169,7 @@ function createCoreRouter() {
|
|
|
1104
1169
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1105
1170
|
if (!decodedToken) {
|
|
1106
1171
|
tracer?.trace('getCallLog:invalidToken', {});
|
|
1107
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1172
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1108
1173
|
return;
|
|
1109
1174
|
}
|
|
1110
1175
|
const { id: userId, platform } = decodedToken;
|
|
@@ -1119,12 +1184,12 @@ function createCoreRouter() {
|
|
|
1119
1184
|
}
|
|
1120
1185
|
else {
|
|
1121
1186
|
tracer?.trace('getCallLog:noToken', {});
|
|
1122
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1187
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1123
1188
|
success = false;
|
|
1124
1189
|
}
|
|
1125
1190
|
}
|
|
1126
1191
|
catch (e) {
|
|
1127
|
-
|
|
1192
|
+
logger.error('Get call log failed', { platform: platformName, stack: e.stack });
|
|
1128
1193
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1129
1194
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1130
1195
|
tracer?.traceError('getCallLog:error', e, { platform: platformName });
|
|
@@ -1162,7 +1227,7 @@ function createCoreRouter() {
|
|
|
1162
1227
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1163
1228
|
if (!decodedToken) {
|
|
1164
1229
|
tracer?.trace('createCallLog:invalidToken', {});
|
|
1165
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1230
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1166
1231
|
return;
|
|
1167
1232
|
}
|
|
1168
1233
|
const { id: userId, platform } = decodedToken;
|
|
@@ -1176,12 +1241,12 @@ function createCoreRouter() {
|
|
|
1176
1241
|
}
|
|
1177
1242
|
else {
|
|
1178
1243
|
tracer?.trace('createCallLog:noToken', {});
|
|
1179
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1244
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1180
1245
|
success = false;
|
|
1181
1246
|
}
|
|
1182
1247
|
}
|
|
1183
1248
|
catch (e) {
|
|
1184
|
-
|
|
1249
|
+
logger.error('Create call log failed', { platform: platformName, stack: e.stack });
|
|
1185
1250
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1186
1251
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1187
1252
|
tracer?.traceError('createCallLog:error', e, { platform: platformName });
|
|
@@ -1219,7 +1284,7 @@ function createCoreRouter() {
|
|
|
1219
1284
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1220
1285
|
if (!decodedToken) {
|
|
1221
1286
|
tracer?.trace('updateCallLog:invalidToken', {});
|
|
1222
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1287
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1223
1288
|
return;
|
|
1224
1289
|
}
|
|
1225
1290
|
const { id: userId, platform } = decodedToken;
|
|
@@ -1233,12 +1298,12 @@ function createCoreRouter() {
|
|
|
1233
1298
|
}
|
|
1234
1299
|
else {
|
|
1235
1300
|
tracer?.trace('updateCallLog:noToken', {});
|
|
1236
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1301
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1237
1302
|
success = false;
|
|
1238
1303
|
}
|
|
1239
1304
|
}
|
|
1240
1305
|
catch (e) {
|
|
1241
|
-
|
|
1306
|
+
logger.error('Update call log failed', { platform: platformName, stack: e.stack });
|
|
1242
1307
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1243
1308
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1244
1309
|
tracer?.traceError('updateCallLog:error', e, { platform: platformName });
|
|
@@ -1277,7 +1342,7 @@ function createCoreRouter() {
|
|
|
1277
1342
|
platformName = platform;
|
|
1278
1343
|
if (!userId) {
|
|
1279
1344
|
tracer?.trace('upsertCallDisposition:invalidToken', {});
|
|
1280
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1345
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1281
1346
|
return;
|
|
1282
1347
|
}
|
|
1283
1348
|
const { successful, returnMessage, extraDataTracking } = await dispositionCore.upsertCallDisposition({
|
|
@@ -1295,12 +1360,12 @@ function createCoreRouter() {
|
|
|
1295
1360
|
}
|
|
1296
1361
|
else {
|
|
1297
1362
|
tracer?.trace('upsertCallDisposition:noToken', {});
|
|
1298
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1363
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1299
1364
|
success = false;
|
|
1300
1365
|
}
|
|
1301
1366
|
}
|
|
1302
1367
|
catch (e) {
|
|
1303
|
-
|
|
1368
|
+
logger.error('Upsert call disposition failed', { platform: platformName, stack: e.stack });
|
|
1304
1369
|
extraData.statusCode = e.response?.status ?? 'unknown';
|
|
1305
1370
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1306
1371
|
tracer?.traceError('upsertCallDisposition:error', e, { platform: platformName });
|
|
@@ -1339,7 +1404,7 @@ function createCoreRouter() {
|
|
|
1339
1404
|
const decodedToken = jwt.decodeJwt(jwtToken);
|
|
1340
1405
|
if (!decodedToken) {
|
|
1341
1406
|
tracer?.trace('createMessageLog:invalidToken', {});
|
|
1342
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1407
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1343
1408
|
return;
|
|
1344
1409
|
}
|
|
1345
1410
|
const { id: userId, platform } = decodedToken;
|
|
@@ -1353,12 +1418,12 @@ function createCoreRouter() {
|
|
|
1353
1418
|
}
|
|
1354
1419
|
else {
|
|
1355
1420
|
tracer?.trace('createMessageLog:noToken', {});
|
|
1356
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1421
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1357
1422
|
success = false;
|
|
1358
1423
|
}
|
|
1359
1424
|
}
|
|
1360
1425
|
catch (e) {
|
|
1361
|
-
|
|
1426
|
+
logger.error('Create message log failed', { platform: platformName, stack: e.stack });
|
|
1362
1427
|
statusCode = e.response?.status ?? 'unknown';
|
|
1363
1428
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1364
1429
|
tracer?.traceError('createMessageLog:error', e, { platform: platformName });
|
|
@@ -1395,14 +1460,19 @@ function createCoreRouter() {
|
|
|
1395
1460
|
const jwtToken = req.query.jwtToken;
|
|
1396
1461
|
if (!jwtToken) {
|
|
1397
1462
|
tracer?.trace('scheduleCallDown:noToken', {});
|
|
1398
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1463
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1399
1464
|
return;
|
|
1400
1465
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1466
|
+
try {
|
|
1467
|
+
const { id } = await calldown.schedule({ jwtToken, rcAccessToken: req.query.rcAccessToken, body: req.body });
|
|
1468
|
+
success = true;
|
|
1469
|
+
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true, id }) : { successful: true, id });
|
|
1470
|
+
}
|
|
1471
|
+
catch (e) {
|
|
1472
|
+
return handleDatabaseError(e, 'Error scheduling call down');
|
|
1473
|
+
}
|
|
1404
1474
|
} catch (e) {
|
|
1405
|
-
|
|
1475
|
+
logger.error('Schedule call down failed', { platform: platformName, stack: e.stack });
|
|
1406
1476
|
statusCode = e.response?.status ?? 'unknown';
|
|
1407
1477
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1408
1478
|
tracer?.traceError('scheduleCallDown:error', e, { platform: platformName });
|
|
@@ -1438,14 +1508,14 @@ function createCoreRouter() {
|
|
|
1438
1508
|
const jwtToken = req.query.jwtToken;
|
|
1439
1509
|
if (!jwtToken) {
|
|
1440
1510
|
tracer?.trace('getCallDownList:noToken', {});
|
|
1441
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1511
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1442
1512
|
return;
|
|
1443
1513
|
}
|
|
1444
1514
|
const { items } = await calldown.list({ jwtToken, status: req.query.status });
|
|
1445
1515
|
success = true;
|
|
1446
1516
|
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true, items }) : { successful: true, items });
|
|
1447
1517
|
} catch (e) {
|
|
1448
|
-
|
|
1518
|
+
logger.error('Get call down list failed', { platform: platformName, stack: e.stack });
|
|
1449
1519
|
statusCode = e.response?.status ?? 'unknown';
|
|
1450
1520
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1451
1521
|
tracer?.traceError('getCallDownList:error', e, { platform: platformName });
|
|
@@ -1480,20 +1550,20 @@ function createCoreRouter() {
|
|
|
1480
1550
|
const id = req.query.id;
|
|
1481
1551
|
if (!jwtToken) {
|
|
1482
1552
|
tracer?.trace('deleteCallDownItem:noToken', {});
|
|
1483
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1553
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1484
1554
|
return;
|
|
1485
1555
|
}
|
|
1486
1556
|
const rid = req.params.id || id;
|
|
1487
1557
|
if (!rid) {
|
|
1488
1558
|
tracer?.trace('deleteCallDownItem:missingId', {});
|
|
1489
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1559
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing id') : 'Missing id');
|
|
1490
1560
|
return;
|
|
1491
1561
|
}
|
|
1492
1562
|
await calldown.remove({ jwtToken, id: rid });
|
|
1493
1563
|
success = true;
|
|
1494
1564
|
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
|
|
1495
1565
|
} catch (e) {
|
|
1496
|
-
|
|
1566
|
+
logger.error('Delete call down item failed', { platform: platformName, stack: e.stack });
|
|
1497
1567
|
statusCode = e.response?.status ?? 'unknown';
|
|
1498
1568
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1499
1569
|
tracer?.traceError('deleteCallDownItem:error', e, { platform: platformName });
|
|
@@ -1527,20 +1597,20 @@ function createCoreRouter() {
|
|
|
1527
1597
|
const jwtToken = req.query.jwtToken;
|
|
1528
1598
|
if (!jwtToken) {
|
|
1529
1599
|
tracer?.trace('markCallDownCalled:noToken', {});
|
|
1530
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1600
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1531
1601
|
return;
|
|
1532
1602
|
}
|
|
1533
1603
|
const id = req.params.id || req.body?.id;
|
|
1534
1604
|
if (!id) {
|
|
1535
1605
|
tracer?.trace('markCallDownCalled:missingId', {});
|
|
1536
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1606
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing id') : 'Missing id');
|
|
1537
1607
|
return;
|
|
1538
1608
|
}
|
|
1539
1609
|
await calldown.update({ jwtToken, id, updateData: req.body });
|
|
1540
1610
|
success = true;
|
|
1541
1611
|
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
|
|
1542
1612
|
} catch (e) {
|
|
1543
|
-
|
|
1613
|
+
logger.error('Mark call down called failed', { platform: platformName, stack: e.stack });
|
|
1544
1614
|
statusCode = e.response?.status ?? 'unknown';
|
|
1545
1615
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1546
1616
|
tracer?.traceError('markCallDownCalled:error', e, { platform: platformName });
|
|
@@ -1568,7 +1638,6 @@ function createCoreRouter() {
|
|
|
1568
1638
|
tracer?.trace('contactSearchByName:start', { query: req.query });
|
|
1569
1639
|
let platformName = null;
|
|
1570
1640
|
let success = false;
|
|
1571
|
-
let resultCount = 0;
|
|
1572
1641
|
let statusCode = 200;
|
|
1573
1642
|
const { hashedExtensionId, hashedAccountId, userAgent, ip, author } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
1574
1643
|
try {
|
|
@@ -1582,13 +1651,13 @@ function createCoreRouter() {
|
|
|
1582
1651
|
}
|
|
1583
1652
|
else {
|
|
1584
1653
|
tracer?.trace('contactSearchByName:noToken', {});
|
|
1585
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1654
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
1586
1655
|
success = false;
|
|
1587
1656
|
}
|
|
1588
1657
|
|
|
1589
1658
|
}
|
|
1590
1659
|
catch (e) {
|
|
1591
|
-
|
|
1660
|
+
logger.error('Contact search by name failed', { platform: platformName, stack: e.stack });
|
|
1592
1661
|
statusCode = e.response?.status ?? 'unknown';
|
|
1593
1662
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1594
1663
|
tracer?.traceError('contactSearchByName:error', e, { platform: platformName });
|
|
@@ -1625,7 +1694,7 @@ function createCoreRouter() {
|
|
|
1625
1694
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
1626
1695
|
if (!user) {
|
|
1627
1696
|
tracer?.trace('getAdminReport:userNotFound', {});
|
|
1628
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1697
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
1629
1698
|
return;
|
|
1630
1699
|
}
|
|
1631
1700
|
const report = await adminCore.getAdminReport({ rcAccountId: user.rcAccountId, timezone: req.query.timezone, timeFrom: req.query.timeFrom, timeTo: req.query.timeTo, groupBy: req.query.groupBy });
|
|
@@ -1634,11 +1703,11 @@ function createCoreRouter() {
|
|
|
1634
1703
|
return;
|
|
1635
1704
|
}
|
|
1636
1705
|
tracer?.trace('getAdminReport:invalidRequest', {});
|
|
1637
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1706
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
|
|
1638
1707
|
success = false;
|
|
1639
1708
|
}
|
|
1640
1709
|
catch (e) {
|
|
1641
|
-
|
|
1710
|
+
logger.error('Get admin report failed', { stack: e.stack });
|
|
1642
1711
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1643
1712
|
tracer?.traceError('getAdminReport:error', e, { platform: platformName });
|
|
1644
1713
|
}
|
|
@@ -1671,7 +1740,7 @@ function createCoreRouter() {
|
|
|
1671
1740
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
1672
1741
|
if (!user) {
|
|
1673
1742
|
tracer?.trace('getUserReport:userNotFound', {});
|
|
1674
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1743
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
1675
1744
|
return;
|
|
1676
1745
|
}
|
|
1677
1746
|
const report = await adminCore.getUserReport({ rcAccountId: user.rcAccountId, rcExtensionId: req.query.rcExtensionId, timezone: req.query.timezone, timeFrom: req.query.timeFrom, timeTo: req.query.timeTo });
|
|
@@ -1679,11 +1748,11 @@ function createCoreRouter() {
|
|
|
1679
1748
|
return;
|
|
1680
1749
|
}
|
|
1681
1750
|
tracer?.trace('getUserReport:invalidRequest', {});
|
|
1682
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1751
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
|
|
1683
1752
|
success = false;
|
|
1684
1753
|
}
|
|
1685
1754
|
catch (e) {
|
|
1686
|
-
|
|
1755
|
+
logger.error('Get user report failed', { stack: e.stack });
|
|
1687
1756
|
res.status(400).send(tracer ? tracer.wrapResponse({ error: e.message || e }) : { error: e.message || e });
|
|
1688
1757
|
tracer?.traceError('getUserReport:error', e, { platform: platformName });
|
|
1689
1758
|
}
|
|
@@ -1712,7 +1781,7 @@ function createCoreRouter() {
|
|
|
1712
1781
|
const user = await UserModel.findByPk(unAuthData?.id);
|
|
1713
1782
|
if (!user) {
|
|
1714
1783
|
tracer?.trace('onRingcentralOAuthCallback:userNotFound', {});
|
|
1715
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1784
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
1716
1785
|
return;
|
|
1717
1786
|
}
|
|
1718
1787
|
await authCore.onRingcentralOAuthCallback({ code, rcAccountId: user.rcAccountId });
|
|
@@ -1720,7 +1789,7 @@ function createCoreRouter() {
|
|
|
1720
1789
|
return;
|
|
1721
1790
|
}
|
|
1722
1791
|
tracer?.trace('onRingcentralOAuthCallback:invalidRequest', {});
|
|
1723
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1792
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
|
|
1724
1793
|
});
|
|
1725
1794
|
router.get('/debug/report/url', async function (req, res) {
|
|
1726
1795
|
const requestStartTime = new Date().getTime();
|
|
@@ -1738,7 +1807,7 @@ function createCoreRouter() {
|
|
|
1738
1807
|
}
|
|
1739
1808
|
else {
|
|
1740
1809
|
tracer?.trace('getErrorLogReportURL:invalidRequest', {});
|
|
1741
|
-
res.status(400).send(tracer ? tracer.wrapResponse(
|
|
1810
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Invalid request') : 'Invalid request');
|
|
1742
1811
|
success = false;
|
|
1743
1812
|
}
|
|
1744
1813
|
const requestEndTime = new Date().getTime();
|
|
@@ -1809,6 +1878,116 @@ function createCoreRouter() {
|
|
|
1809
1878
|
}
|
|
1810
1879
|
});
|
|
1811
1880
|
}
|
|
1881
|
+
// --- METADATA ENDPOINT 1: Resource Metadata ---
|
|
1882
|
+
// Tells the client "I am protected" and "Here is who protects me"
|
|
1883
|
+
router.get('/.well-known/oauth-protected-resource', (req, res) => {
|
|
1884
|
+
res.json({
|
|
1885
|
+
resource: process.env.APP_SERVER,
|
|
1886
|
+
// CHANGE THIS: Point to your own server so the client fetches YOUR metadata next
|
|
1887
|
+
authorization_servers: [process.env.APP_SERVER],
|
|
1888
|
+
scopes_supported: ["ReadAccounts"]
|
|
1889
|
+
});
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
// --- METADATA ENDPOINT 2: Auth Server Metadata ---
|
|
1893
|
+
// Usually, you can redirect to your provider's configuration.
|
|
1894
|
+
// If your provider supports OIDC discovery, this is often sufficient.
|
|
1895
|
+
router.get('/.well-known/oauth-authorization-server', (req, res) => {
|
|
1896
|
+
res.json({
|
|
1897
|
+
issuer: process.env.APP_SERVER,
|
|
1898
|
+
registration_endpoint: `${process.env.APP_SERVER}/oauth/register`,
|
|
1899
|
+
|
|
1900
|
+
// CHANGE THIS: Don't point to RingCentral. Point to your own Shim.
|
|
1901
|
+
authorization_endpoint: `${process.env.APP_SERVER}/oauth/authorize_shim`,
|
|
1902
|
+
|
|
1903
|
+
// Keep the token endpoint pointing to RingCentral (that usually works fine)
|
|
1904
|
+
token_endpoint: `${process.env.RINGCENTRAL_SERVER}/restapi/oauth/token`,
|
|
1905
|
+
token_endpoint_auth_methods_supported: ["client_secret_basic"],
|
|
1906
|
+
response_types_supported: ["code"]
|
|
1907
|
+
});
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
router.get('/oauth/authorize_shim', (req, res) => {
|
|
1911
|
+
// 1. Get the parameters ChatGPT sent us
|
|
1912
|
+
const { response_type, client_id, redirect_uri, state, scope } = req.query;
|
|
1913
|
+
|
|
1914
|
+
// 2. Rebuild the query string for RingCentral
|
|
1915
|
+
// We explicitly LEAVE OUT 'resource' and any other junk
|
|
1916
|
+
const params = new URLSearchParams({
|
|
1917
|
+
response_type,
|
|
1918
|
+
client_id, // This will be your RC Client ID (since ChatGPT got it from /register)
|
|
1919
|
+
redirect_uri,
|
|
1920
|
+
state,
|
|
1921
|
+
scope
|
|
1922
|
+
});
|
|
1923
|
+
|
|
1924
|
+
// 3. Redirect the user's browser to the REAL RingCentral URL
|
|
1925
|
+
const rcUrl = `${process.env.RINGCENTRAL_SERVER}/restapi/oauth/authorize?${params.toString()}`;
|
|
1926
|
+
|
|
1927
|
+
console.log("Proxying OAuth request to:", rcUrl); // Helpful for debugging
|
|
1928
|
+
res.redirect(rcUrl);
|
|
1929
|
+
});
|
|
1930
|
+
|
|
1931
|
+
router.post('/oauth/register', (req, res) => {
|
|
1932
|
+
// The MCP client calls this to get credentials.
|
|
1933
|
+
// We simply return our hardcoded RingCentral app credentials.
|
|
1934
|
+
res.json({
|
|
1935
|
+
client_id: process.env.RINGCENTRAL_CLIENT_ID,
|
|
1936
|
+
client_secret: process.env.RINGCENTRAL_CLIENT_SECRET
|
|
1937
|
+
});
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
router.use('/mcp', (req, res, next) => {// LOG EVERYTHING
|
|
1941
|
+
console.log(`[${req.method}] /mcp`);
|
|
1942
|
+
console.log("Headers:", JSON.stringify(req.headers['authorization'] ? "Auth Token Present" : "No Auth"));
|
|
1943
|
+
console.log("Body:", JSON.stringify(req.body));
|
|
1944
|
+
// return next();
|
|
1945
|
+
// Capture the response finish to see the status code
|
|
1946
|
+
res.on('finish', () => {
|
|
1947
|
+
console.log(`[Response] Status: ${res.statusCode}`);
|
|
1948
|
+
console.log(`[Response] data: ${JSON.stringify(res.data)}`);
|
|
1949
|
+
});
|
|
1950
|
+
|
|
1951
|
+
const authHeader = req.headers.authorization;
|
|
1952
|
+
const token = authHeader?.split(' ')[1]; // Remove "Bearer "
|
|
1953
|
+
// Allow the initial connection (GET) and CORS checks (OPTIONS) to pass freely.
|
|
1954
|
+
// We only want to block the actual commands (POST).
|
|
1955
|
+
if (req.method === 'GET' || req.method === 'OPTIONS') {
|
|
1956
|
+
return next();
|
|
1957
|
+
}
|
|
1958
|
+
// SCENARIO 1: No Token provided. Kick off the OAuth flow.
|
|
1959
|
+
if (!token) {
|
|
1960
|
+
res.setHeader('WWW-Authenticate', `Bearer realm="mcp", resource_metadata="${process.env.APP_SERVER}/.well-known/oauth-protected-resource"`);
|
|
1961
|
+
return res.status(401).send();
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
// SCENARIO 2: Token provided. Verify it.
|
|
1965
|
+
try {
|
|
1966
|
+
next();
|
|
1967
|
+
} catch (error) {
|
|
1968
|
+
console.error("Token validation failed:", error.message);
|
|
1969
|
+
// Token is invalid or expired
|
|
1970
|
+
res.setHeader('WWW-Authenticate', `Bearer realm="mcp", resource_metadata="${process.env.APP_SERVER}/.well-known/oauth-protected-resource"`);
|
|
1971
|
+
return res.status(401).send();
|
|
1972
|
+
}
|
|
1973
|
+
});
|
|
1974
|
+
// Handle OPTIONS for CORS preflight
|
|
1975
|
+
router.options('/mcp', (req, res) => {
|
|
1976
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
1977
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
1978
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept');
|
|
1979
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
1980
|
+
res.status(200).end();
|
|
1981
|
+
});
|
|
1982
|
+
|
|
1983
|
+
// Dedicated endpoint for all MCP traffic
|
|
1984
|
+
router.post('/mcp', async (req, res) => {
|
|
1985
|
+
// Set CORS headers
|
|
1986
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
1987
|
+
res.setHeader('Content-Type', 'application/json');
|
|
1988
|
+
|
|
1989
|
+
await mcpHandler.handleMcpRequest(req, res);
|
|
1990
|
+
});
|
|
1812
1991
|
|
|
1813
1992
|
return router;
|
|
1814
1993
|
}
|
|
@@ -1817,6 +1996,15 @@ function createCoreRouter() {
|
|
|
1817
1996
|
function createCoreMiddleware() {
|
|
1818
1997
|
return [
|
|
1819
1998
|
bodyParser.json(),
|
|
1999
|
+
bodyParser.xml({
|
|
2000
|
+
limit: '50mb',
|
|
2001
|
+
xmlParseOptions: {
|
|
2002
|
+
explicitArray: false,
|
|
2003
|
+
normalize: true,
|
|
2004
|
+
normalizeTags: false,
|
|
2005
|
+
trim: true
|
|
2006
|
+
}
|
|
2007
|
+
}),
|
|
1820
2008
|
cors({
|
|
1821
2009
|
methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE']
|
|
1822
2010
|
})
|