@app-connect/core 1.7.10 → 1.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/connector/developerPortal.js +43 -0
- package/connector/proxy/index.js +10 -3
- package/connector/registry.js +8 -6
- package/handlers/admin.js +135 -22
- package/handlers/auth.js +89 -67
- package/handlers/calldown.js +10 -4
- package/handlers/contact.js +4 -104
- package/handlers/disposition.js +7 -145
- package/handlers/log.js +174 -258
- package/handlers/user.js +19 -6
- package/index.js +280 -47
- package/lib/analytics.js +3 -1
- package/lib/authSession.js +68 -0
- package/lib/callLogComposer.js +498 -420
- package/lib/errorHandler.js +206 -0
- package/lib/jwt.js +2 -0
- package/lib/logger.js +190 -0
- package/lib/oauth.js +21 -10
- package/lib/ringcentral.js +2 -10
- package/lib/sharedSMSComposer.js +471 -0
- package/mcp/SupportedPlatforms.md +12 -0
- package/mcp/lib/validator.js +91 -0
- package/mcp/mcpHandler.js +166 -0
- package/mcp/tools/checkAuthStatus.js +110 -0
- package/mcp/tools/collectAuthInfo.js +91 -0
- package/mcp/tools/createCallLog.js +308 -0
- package/mcp/tools/createContact.js +117 -0
- package/mcp/tools/createMessageLog.js +283 -0
- package/mcp/tools/doAuth.js +190 -0
- package/mcp/tools/findContactByName.js +92 -0
- package/mcp/tools/findContactByPhone.js +101 -0
- package/mcp/tools/getCallLog.js +98 -0
- package/mcp/tools/getGoogleFilePicker.js +103 -0
- package/mcp/tools/getHelp.js +44 -0
- package/mcp/tools/getPublicConnectors.js +53 -0
- package/mcp/tools/index.js +64 -0
- package/mcp/tools/logout.js +68 -0
- package/mcp/tools/rcGetCallLogs.js +78 -0
- package/mcp/tools/setConnector.js +69 -0
- package/mcp/tools/updateCallLog.js +122 -0
- package/models/cacheModel.js +3 -0
- package/package.json +71 -70
- package/releaseNotes.json +24 -0
- package/test/handlers/log.test.js +11 -4
- package/test/lib/logger.test.js +206 -0
- package/test/lib/ringcentral.test.js +0 -6
- package/test/lib/sharedSMSComposer.test.js +1084 -0
- package/test/mcp/tools/collectAuthInfo.test.js +234 -0
- package/test/mcp/tools/createCallLog.test.js +425 -0
- package/test/mcp/tools/createMessageLog.test.js +580 -0
- package/test/mcp/tools/doAuth.test.js +376 -0
- package/test/mcp/tools/findContactByName.test.js +263 -0
- package/test/mcp/tools/findContactByPhone.test.js +284 -0
- package/test/mcp/tools/getCallLog.test.js +286 -0
- package/test/mcp/tools/getGoogleFilePicker.test.js +281 -0
- package/test/mcp/tools/getPublicConnectors.test.js +128 -0
- package/test/mcp/tools/logout.test.js +169 -0
- package/test/mcp/tools/setConnector.test.js +177 -0
- package/test/mcp/tools/updateCallLog.test.js +346 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const { logger } = require('../lib/logger');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async function getPublicConnectorList() {
|
|
6
|
+
try {
|
|
7
|
+
const response = await axios.get('https://appconnect.labs.ringcentral.com/public-api/connectors');
|
|
8
|
+
return response.data;
|
|
9
|
+
} catch (error) {
|
|
10
|
+
logger.error('Error getting public connector list:', error);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function getPrivateConnectorList() {
|
|
16
|
+
try {
|
|
17
|
+
const response = await axios.get(`https://appconnect.labs.ringcentral.com/public-api/connectors/internal?accountId=${process.env.RC_ACCOUNT_ID}`);
|
|
18
|
+
return response.data;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
logger.error('Error getting private connector list:', error);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function getConnectorManifest({connectorId, isPrivate = false}) {
|
|
26
|
+
try {
|
|
27
|
+
let response = null;
|
|
28
|
+
if(isPrivate) {
|
|
29
|
+
response = await axios.get(`https://appconnect.labs.ringcentral.com/public-api/connectors/${connectorId}/manifest?type=internal&accountId=${process.env.RC_ACCOUNT_ID}`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
response = await axios.get(`https://appconnect.labs.ringcentral.com/public-api/connectors/${connectorId}/manifest`);
|
|
33
|
+
}
|
|
34
|
+
return response.data;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.error('Error getting connector manifest:', error);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.getPublicConnectorList = getPublicConnectorList;
|
|
42
|
+
exports.getPrivateConnectorList = getPrivateConnectorList;
|
|
43
|
+
exports.getConnectorManifest = getConnectorManifest;
|
package/connector/proxy/index.js
CHANGED
|
@@ -10,6 +10,8 @@ const {
|
|
|
10
10
|
} = require('./engine');
|
|
11
11
|
const { Connector } = require('../../models/dynamo/connectorSchema');
|
|
12
12
|
const { UserModel } = require('../../models/userModel');
|
|
13
|
+
const logger = require('../../lib/logger');
|
|
14
|
+
const { handleDatabaseError } = require('../../lib/errorHandler');
|
|
13
15
|
|
|
14
16
|
async function loadPlatformConfig(proxyId) {
|
|
15
17
|
if (!proxyId) {
|
|
@@ -19,7 +21,7 @@ async function loadPlatformConfig(proxyId) {
|
|
|
19
21
|
const proxyConfig = await Connector.getProxyConfig(proxyId);
|
|
20
22
|
return proxyConfig;
|
|
21
23
|
} catch (error) {
|
|
22
|
-
|
|
24
|
+
logger.error('Error getting proxy config: ', { proxyId, stack: error.stack });
|
|
23
25
|
return null;
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -32,7 +34,7 @@ async function getAuthType({ proxyId, proxyConfig } = {}) {
|
|
|
32
34
|
return cfg.auth.type || 'apiKey';
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
async function getOauthInfo({ proxyId, proxyConfig, tokenUrl
|
|
37
|
+
async function getOauthInfo({ proxyId, proxyConfig, tokenUrl } = {}) {
|
|
36
38
|
const cfg = proxyConfig ? proxyConfig : (await loadPlatformConfig(proxyId));
|
|
37
39
|
if (!cfg) {
|
|
38
40
|
return {};
|
|
@@ -146,7 +148,12 @@ async function unAuthorize({ user }) {
|
|
|
146
148
|
}
|
|
147
149
|
user.accessToken = '';
|
|
148
150
|
user.refreshToken = '';
|
|
149
|
-
|
|
151
|
+
try {
|
|
152
|
+
await user.save();
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return handleDatabaseError(error, 'Error saving user');
|
|
156
|
+
}
|
|
150
157
|
return {
|
|
151
158
|
successful: true,
|
|
152
159
|
returnMessage: {
|
package/connector/registry.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// core/src/connector/registry.js
|
|
2
|
+
const logger = require('../lib/logger');
|
|
2
3
|
class ConnectorRegistry {
|
|
3
4
|
constructor() {
|
|
4
5
|
this.connectors = new Map();
|
|
@@ -29,7 +30,7 @@ class ConnectorRegistry {
|
|
|
29
30
|
const platformInterfaceMap = this.platformInterfaces.get(platformName);
|
|
30
31
|
platformInterfaceMap.set(interfaceName, interfaceFunction);
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
logger.info(`Registered interface function: ${platformName}.${interfaceName}`);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -61,7 +62,7 @@ class ConnectorRegistry {
|
|
|
61
62
|
const platformInterfaceMap = this.platformInterfaces.get(platformName);
|
|
62
63
|
if (platformInterfaceMap && platformInterfaceMap.has(interfaceName)) {
|
|
63
64
|
platformInterfaceMap.delete(interfaceName);
|
|
64
|
-
|
|
65
|
+
logger.info(`Unregistered interface function: ${platformName}.${interfaceName}`);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -80,7 +81,7 @@ class ConnectorRegistry {
|
|
|
80
81
|
this.manifests.set(platform, manifest);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
logger.info(`Registered connector: ${platform}`);
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
/**
|
|
@@ -109,7 +110,7 @@ class ConnectorRegistry {
|
|
|
109
110
|
composedConnector[interfaceName] = interfaceFunction;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
logger.info(`Returning interface-only connector for platform: ${platform}`);
|
|
113
114
|
return composedConnector;
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -203,14 +204,14 @@ class ConnectorRegistry {
|
|
|
203
204
|
this.connectors.delete(platform);
|
|
204
205
|
this.manifests.delete(platform);
|
|
205
206
|
this.platformInterfaces.delete(platform);
|
|
206
|
-
|
|
207
|
+
logger.info(`Unregistered connector: ${platform}`);
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
setReleaseNotes(releaseNotes) {
|
|
210
211
|
this.releaseNotes = releaseNotes;
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
getReleaseNotes(
|
|
214
|
+
getReleaseNotes() {
|
|
214
215
|
return this.releaseNotes;
|
|
215
216
|
}
|
|
216
217
|
|
|
@@ -237,6 +238,7 @@ class ConnectorRegistry {
|
|
|
237
238
|
try {
|
|
238
239
|
capabilities.authType = await originalConnector.getAuthType();
|
|
239
240
|
} catch (error) {
|
|
241
|
+
logger.error('Error getting auth type', { stack: error.stack });
|
|
240
242
|
capabilities.authType = 'unknown';
|
|
241
243
|
}
|
|
242
244
|
}
|
package/handlers/admin.js
CHANGED
|
@@ -4,6 +4,8 @@ const connectorRegistry = require('../connector/registry');
|
|
|
4
4
|
const oauth = require('../lib/oauth');
|
|
5
5
|
const { RingCentral } = require('../lib/ringcentral');
|
|
6
6
|
const { Connector } = require('../models/dynamo/connectorSchema');
|
|
7
|
+
const logger = require('../lib/logger');
|
|
8
|
+
const { handleDatabaseError } = require('../lib/errorHandler');
|
|
7
9
|
|
|
8
10
|
const CALL_AGGREGATION_GROUPS = ["Company", "CompanyNumbers", "Users", "Queues", "IVRs", "IVAs", "SharedLines", "UserGroups", "Sites", "Departments"]
|
|
9
11
|
|
|
@@ -136,7 +138,7 @@ async function getAdminReport({ rcAccountId, timezone, timeFrom, timeTo, groupBy
|
|
|
136
138
|
groupKeys: CALL_AGGREGATION_GROUPS
|
|
137
139
|
};
|
|
138
140
|
} catch (error) {
|
|
139
|
-
|
|
141
|
+
logger.error('Error getting admin report', { error });
|
|
140
142
|
return {
|
|
141
143
|
callLogStats: {}
|
|
142
144
|
};
|
|
@@ -206,13 +208,19 @@ async function getUserReport({ rcAccountId, rcExtensionId, timezone, timeFrom, t
|
|
|
206
208
|
};
|
|
207
209
|
return reportStats;
|
|
208
210
|
} catch (error) {
|
|
209
|
-
|
|
211
|
+
logger.error('Error getting user report', { error });
|
|
210
212
|
return null;
|
|
211
213
|
}
|
|
212
214
|
}
|
|
213
215
|
|
|
214
216
|
async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
215
|
-
|
|
217
|
+
let adminConfig = null;
|
|
218
|
+
try {
|
|
219
|
+
adminConfig = await getAdminSettings({ hashedRcAccountId });
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
return handleDatabaseError(error, 'Error getting user mapping');
|
|
223
|
+
}
|
|
216
224
|
const platformModule = connectorRegistry.getConnector(user.platform);
|
|
217
225
|
if (platformModule.getUserList) {
|
|
218
226
|
const proxyId = user.platformAdditionalInfo?.proxyId;
|
|
@@ -318,12 +326,17 @@ async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
|
318
326
|
});
|
|
319
327
|
}
|
|
320
328
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
329
|
+
try {
|
|
330
|
+
await upsertAdminSettings({
|
|
331
|
+
hashedRcAccountId,
|
|
332
|
+
adminSettings: {
|
|
333
|
+
userMappings: initialUserMappings
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
return handleDatabaseError(error, 'Error initializing user mapping');
|
|
339
|
+
}
|
|
327
340
|
}
|
|
328
341
|
// Incremental update
|
|
329
342
|
if (newUserMappings.length > 0) {
|
|
@@ -333,20 +346,30 @@ async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
|
333
346
|
...u,
|
|
334
347
|
rcExtensionId: [u.rcExtensionId]
|
|
335
348
|
}));
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
349
|
+
try {
|
|
350
|
+
await upsertAdminSettings({
|
|
351
|
+
hashedRcAccountId,
|
|
352
|
+
adminSettings: {
|
|
353
|
+
userMappings: [...adminConfig.userMappings, ...newUserMappings]
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
return handleDatabaseError(error, 'Error updating user mapping');
|
|
359
|
+
}
|
|
342
360
|
}
|
|
343
361
|
else {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
362
|
+
try {
|
|
363
|
+
await upsertAdminSettings({
|
|
364
|
+
hashedRcAccountId,
|
|
365
|
+
adminSettings: {
|
|
366
|
+
userMappings: [...newUserMappings]
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
return handleDatabaseError(error, 'Error updating user mapping');
|
|
372
|
+
}
|
|
350
373
|
}
|
|
351
374
|
}
|
|
352
375
|
return userMappingResult;
|
|
@@ -354,6 +377,95 @@ async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
|
354
377
|
return [];
|
|
355
378
|
}
|
|
356
379
|
|
|
380
|
+
async function reinitializeUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
381
|
+
const platformModule = connectorRegistry.getConnector(user.platform);
|
|
382
|
+
if (!platformModule.getUserList) {
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const proxyId = user.platformAdditionalInfo?.proxyId;
|
|
387
|
+
let proxyConfig = null;
|
|
388
|
+
if (proxyId) {
|
|
389
|
+
proxyConfig = await Connector.getProxyConfig(proxyId);
|
|
390
|
+
if (!proxyConfig?.operations?.getUserList) {
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const authType = await platformModule.getAuthType({ proxyId, proxyConfig });
|
|
396
|
+
let authHeader = '';
|
|
397
|
+
switch (authType) {
|
|
398
|
+
case 'oauth':
|
|
399
|
+
const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname, proxyId, proxyConfig })));
|
|
400
|
+
// eslint-disable-next-line no-param-reassign
|
|
401
|
+
user = await oauth.checkAndRefreshAccessToken(oauthApp, user);
|
|
402
|
+
authHeader = `Bearer ${user.accessToken}`;
|
|
403
|
+
break;
|
|
404
|
+
case 'apiKey':
|
|
405
|
+
const basicAuth = platformModule.getBasicAuth({ apiKey: user.accessToken });
|
|
406
|
+
authHeader = `Basic ${basicAuth}`;
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const crmUserList = await platformModule.getUserList({ user, authHeader, proxyConfig });
|
|
411
|
+
const userMappingResult = [];
|
|
412
|
+
const initialUserMappings = [];
|
|
413
|
+
|
|
414
|
+
// Auto-match CRM users with RC extensions by email or name
|
|
415
|
+
for (const crmUser of crmUserList) {
|
|
416
|
+
const rcExtensionForMapping = rcExtensionList.find(u =>
|
|
417
|
+
u.email === crmUser.email ||
|
|
418
|
+
u.name === crmUser.name ||
|
|
419
|
+
(`${u.firstName} ${u.lastName}` === crmUser.name)
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
if (rcExtensionForMapping) {
|
|
423
|
+
userMappingResult.push({
|
|
424
|
+
crmUser: {
|
|
425
|
+
id: crmUser.id,
|
|
426
|
+
name: crmUser.name ?? '',
|
|
427
|
+
email: crmUser.email ?? '',
|
|
428
|
+
},
|
|
429
|
+
rcUser: [{
|
|
430
|
+
extensionId: rcExtensionForMapping.id,
|
|
431
|
+
name: rcExtensionForMapping.name || `${rcExtensionForMapping.firstName} ${rcExtensionForMapping.lastName}`,
|
|
432
|
+
extensionNumber: rcExtensionForMapping?.extensionNumber ?? '',
|
|
433
|
+
email: rcExtensionForMapping?.email ?? ''
|
|
434
|
+
}]
|
|
435
|
+
});
|
|
436
|
+
initialUserMappings.push({
|
|
437
|
+
crmUserId: crmUser.id.toString(),
|
|
438
|
+
rcExtensionId: [rcExtensionForMapping.id.toString()]
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
userMappingResult.push({
|
|
443
|
+
crmUser: {
|
|
444
|
+
id: crmUser.id,
|
|
445
|
+
name: crmUser.name ?? '',
|
|
446
|
+
email: crmUser.email ?? '',
|
|
447
|
+
},
|
|
448
|
+
rcUser: []
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Overwrite existing mappings with fresh auto-matched mappings
|
|
454
|
+
try {
|
|
455
|
+
await upsertAdminSettings({
|
|
456
|
+
hashedRcAccountId,
|
|
457
|
+
adminSettings: {
|
|
458
|
+
userMappings: initialUserMappings
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
return handleDatabaseError(error, 'Error reinitializing user mapping');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return userMappingResult;
|
|
467
|
+
}
|
|
468
|
+
|
|
357
469
|
exports.validateAdminRole = validateAdminRole;
|
|
358
470
|
exports.upsertAdminSettings = upsertAdminSettings;
|
|
359
471
|
exports.getAdminSettings = getAdminSettings;
|
|
@@ -362,4 +474,5 @@ exports.getServerLoggingSettings = getServerLoggingSettings;
|
|
|
362
474
|
exports.updateServerLoggingSettings = updateServerLoggingSettings;
|
|
363
475
|
exports.getAdminReport = getAdminReport;
|
|
364
476
|
exports.getUserReport = getUserReport;
|
|
365
|
-
exports.getUserMapping = getUserMapping;
|
|
477
|
+
exports.getUserMapping = getUserMapping;
|
|
478
|
+
exports.reinitializeUserMapping = reinitializeUserMapping;
|
package/handlers/auth.js
CHANGED
|
@@ -5,8 +5,9 @@ const Op = require('sequelize').Op;
|
|
|
5
5
|
const { RingCentral } = require('../lib/ringcentral');
|
|
6
6
|
const adminCore = require('./admin');
|
|
7
7
|
const { Connector } = require('../models/dynamo/connectorSchema');
|
|
8
|
+
const { handleDatabaseError } = require('../lib/errorHandler');
|
|
8
9
|
|
|
9
|
-
async function onOAuthCallback({ platform, hostname, tokenUrl, query }) {
|
|
10
|
+
async function onOAuthCallback({ platform, hostname, tokenUrl, query, isFromMCP = false }) {
|
|
10
11
|
const callbackUri = query.callbackUri;
|
|
11
12
|
const apiUrl = query.apiUrl;
|
|
12
13
|
const username = query.username;
|
|
@@ -17,8 +18,7 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, query }) {
|
|
|
17
18
|
if (proxyId) {
|
|
18
19
|
proxyConfig = await Connector.getProxyConfig(proxyId);
|
|
19
20
|
}
|
|
20
|
-
const oauthInfo = await platformModule.getOauthInfo({ tokenUrl, hostname, rcAccountId: query.rcAccountId, proxyId, proxyConfig, userEmail });
|
|
21
|
-
|
|
21
|
+
const oauthInfo = await platformModule.getOauthInfo({ tokenUrl, hostname, rcAccountId: query.rcAccountId, proxyId, proxyConfig, userEmail, isFromMCP });
|
|
22
22
|
if (oauthInfo.failMessage) {
|
|
23
23
|
return {
|
|
24
24
|
userInfo: null,
|
|
@@ -41,19 +41,25 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, query }) {
|
|
|
41
41
|
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader, tokenUrl, apiUrl, hostname, platform, username, callbackUri, query, proxyId, proxyConfig, userEmail });
|
|
42
42
|
|
|
43
43
|
if (successful) {
|
|
44
|
-
let userInfo =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
let userInfo = null;
|
|
45
|
+
try {
|
|
46
|
+
userInfo = await saveUserInfo({
|
|
47
|
+
platformUserInfo,
|
|
48
|
+
platform,
|
|
49
|
+
tokenUrl,
|
|
50
|
+
apiUrl,
|
|
51
|
+
username,
|
|
52
|
+
hostname: platformUserInfo?.overridingHostname ? platformUserInfo.overridingHostname : hostname,
|
|
53
|
+
accessToken,
|
|
54
|
+
refreshToken,
|
|
55
|
+
tokenExpiry: isNaN(expires) ? null : expires,
|
|
56
|
+
rcAccountId: query?.rcAccountId,
|
|
57
|
+
proxyId
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
62
|
+
}
|
|
57
63
|
if (platformModule.postSaveUserInfo) {
|
|
58
64
|
userInfo = await platformModule.postSaveUserInfo({ userInfo, oauthApp });
|
|
59
65
|
}
|
|
@@ -75,13 +81,19 @@ async function onApiKeyLogin({ platform, hostname, apiKey, proxyId, additionalIn
|
|
|
75
81
|
const basicAuth = platformModule.getBasicAuth({ apiKey });
|
|
76
82
|
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader: `Basic ${basicAuth}`, hostname, platform, additionalInfo, apiKey, proxyId });
|
|
77
83
|
if (successful) {
|
|
78
|
-
let userInfo =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
let userInfo = null;
|
|
85
|
+
try {
|
|
86
|
+
userInfo = await saveUserInfo({
|
|
87
|
+
platformUserInfo,
|
|
88
|
+
platform,
|
|
89
|
+
hostname,
|
|
90
|
+
proxyId,
|
|
91
|
+
accessToken: platformUserInfo.overridingApiKey ?? apiKey
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
96
|
+
}
|
|
85
97
|
if (platformModule.postSaveUserInfo) {
|
|
86
98
|
userInfo = await platformModule.postSaveUserInfo({ userInfo });
|
|
87
99
|
}
|
|
@@ -107,43 +119,65 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
|
|
|
107
119
|
const platformAdditionalInfo = platformUserInfo.platformAdditionalInfo || {};
|
|
108
120
|
platformAdditionalInfo.proxyId = proxyId;
|
|
109
121
|
if (existingUser) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
timezoneName,
|
|
115
|
-
timezoneOffset,
|
|
116
|
-
accessToken,
|
|
117
|
-
refreshToken,
|
|
118
|
-
tokenExpiry,
|
|
119
|
-
rcAccountId,
|
|
120
|
-
platformAdditionalInfo: {
|
|
121
|
-
...existingUser.platformAdditionalInfo, // keep existing platformAdditionalInfo
|
|
122
|
-
...platformAdditionalInfo,
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
// TEMP: replace user with old ID
|
|
129
|
-
if (id.endsWith(`-${platform}`)) {
|
|
130
|
-
const oldID = id.split('-');
|
|
131
|
-
const userWithOldID = await UserModel.findByPk(oldID[0]);
|
|
132
|
-
if (userWithOldID) {
|
|
133
|
-
await UserModel.create({
|
|
134
|
-
id,
|
|
122
|
+
try {
|
|
123
|
+
await existingUser.update(
|
|
124
|
+
{
|
|
125
|
+
platform,
|
|
135
126
|
hostname,
|
|
136
127
|
timezoneName,
|
|
137
128
|
timezoneOffset,
|
|
138
|
-
platform,
|
|
139
129
|
accessToken,
|
|
140
130
|
refreshToken,
|
|
141
131
|
tokenExpiry,
|
|
142
132
|
rcAccountId,
|
|
143
|
-
platformAdditionalInfo
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
133
|
+
platformAdditionalInfo: {
|
|
134
|
+
...existingUser.platformAdditionalInfo, // keep existing platformAdditionalInfo
|
|
135
|
+
...platformAdditionalInfo,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
try {
|
|
146
|
+
// TEMP: replace user with old ID
|
|
147
|
+
if (id.endsWith(`-${platform}`)) {
|
|
148
|
+
const oldID = id.split('-');
|
|
149
|
+
const userWithOldID = await UserModel.findByPk(oldID[0]);
|
|
150
|
+
if (userWithOldID) {
|
|
151
|
+
await UserModel.create({
|
|
152
|
+
id,
|
|
153
|
+
hostname,
|
|
154
|
+
timezoneName,
|
|
155
|
+
timezoneOffset,
|
|
156
|
+
platform,
|
|
157
|
+
accessToken,
|
|
158
|
+
refreshToken,
|
|
159
|
+
tokenExpiry,
|
|
160
|
+
rcAccountId,
|
|
161
|
+
platformAdditionalInfo,
|
|
162
|
+
userSettings: userWithOldID.userSettings
|
|
163
|
+
});
|
|
164
|
+
await userWithOldID.destroy();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
await UserModel.create({
|
|
168
|
+
id,
|
|
169
|
+
hostname,
|
|
170
|
+
timezoneName,
|
|
171
|
+
timezoneOffset,
|
|
172
|
+
platform,
|
|
173
|
+
accessToken,
|
|
174
|
+
refreshToken,
|
|
175
|
+
tokenExpiry,
|
|
176
|
+
rcAccountId,
|
|
177
|
+
platformAdditionalInfo,
|
|
178
|
+
userSettings: {}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
147
181
|
}
|
|
148
182
|
else {
|
|
149
183
|
await UserModel.create({
|
|
@@ -161,20 +195,8 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
|
|
|
161
195
|
});
|
|
162
196
|
}
|
|
163
197
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
id,
|
|
167
|
-
hostname,
|
|
168
|
-
timezoneName,
|
|
169
|
-
timezoneOffset,
|
|
170
|
-
platform,
|
|
171
|
-
accessToken,
|
|
172
|
-
refreshToken,
|
|
173
|
-
tokenExpiry,
|
|
174
|
-
rcAccountId,
|
|
175
|
-
platformAdditionalInfo,
|
|
176
|
-
userSettings: {}
|
|
177
|
-
});
|
|
198
|
+
catch (error) {
|
|
199
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
178
200
|
}
|
|
179
201
|
}
|
|
180
202
|
return {
|
package/handlers/calldown.js
CHANGED
|
@@ -2,8 +2,9 @@ const { UserModel } = require('../models/userModel');
|
|
|
2
2
|
const { CallDownListModel } = require('../models/callDownListModel');
|
|
3
3
|
const { Op } = require('sequelize');
|
|
4
4
|
const jwt = require('../lib/jwt');
|
|
5
|
+
const { handleDatabaseError } = require('../lib/errorHandler');
|
|
5
6
|
|
|
6
|
-
async function schedule({ jwtToken,
|
|
7
|
+
async function schedule({ jwtToken, body }) {
|
|
7
8
|
const unAuthData = jwt.decodeJwt(jwtToken);
|
|
8
9
|
if (!unAuthData?.id) throw new Error('Unauthorized');
|
|
9
10
|
const user = await UserModel.findByPk(unAuthData.id);
|
|
@@ -48,9 +49,14 @@ async function markCalled({ jwtToken, id, lastCallAt }) {
|
|
|
48
49
|
const unAuthData = jwt.decodeJwt(jwtToken);
|
|
49
50
|
if (!unAuthData?.id) throw new Error('Unauthorized');
|
|
50
51
|
const when = lastCallAt ? new Date(lastCallAt) : new Date();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
try {
|
|
53
|
+
const [affected] = await CallDownListModel.update({ status: 'called', lastCallAt: when }, { where: { id, userId: unAuthData.id } });
|
|
54
|
+
if (!affected) throw new Error('Not found');
|
|
55
|
+
return { successful: true };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return handleDatabaseError(error, 'Error marking call as called', { id, userId: unAuthData.id });
|
|
59
|
+
}
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
async function update({ jwtToken, id, updateData }) {
|