@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
|
@@ -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;
|
package/handlers/auth.js
CHANGED
|
@@ -5,15 +5,20 @@ 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,
|
|
10
|
+
async function onOAuthCallback({ platform, hostname, tokenUrl, query, isFromMCP = false }) {
|
|
11
|
+
const callbackUri = query.callbackUri;
|
|
12
|
+
const apiUrl = query.apiUrl;
|
|
13
|
+
const username = query.username;
|
|
14
|
+
const proxyId = query.proxyId;
|
|
15
|
+
const userEmail = query.userEmail;
|
|
10
16
|
const platformModule = connectorRegistry.getConnector(platform);
|
|
11
17
|
let proxyConfig = null;
|
|
12
18
|
if (proxyId) {
|
|
13
19
|
proxyConfig = await Connector.getProxyConfig(proxyId);
|
|
14
20
|
}
|
|
15
|
-
const oauthInfo = await platformModule.getOauthInfo({ tokenUrl, hostname, rcAccountId: query.rcAccountId, proxyId, proxyConfig });
|
|
16
|
-
|
|
21
|
+
const oauthInfo = await platformModule.getOauthInfo({ tokenUrl, hostname, rcAccountId: query.rcAccountId, proxyId, proxyConfig, userEmail, isFromMCP });
|
|
17
22
|
if (oauthInfo.failMessage) {
|
|
18
23
|
return {
|
|
19
24
|
userInfo: null,
|
|
@@ -27,27 +32,34 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, callbackUri, apiU
|
|
|
27
32
|
// Some platforms require different oauth queries, this won't affect normal OAuth process unless CRM module implements getOverridingOAuthOption() method
|
|
28
33
|
let overridingOAuthOption = null;
|
|
29
34
|
if (platformModule.getOverridingOAuthOption != null) {
|
|
30
|
-
|
|
35
|
+
const code = new URL(callbackUri).searchParams.get('code');
|
|
36
|
+
overridingOAuthOption = platformModule.getOverridingOAuthOption({ code });
|
|
31
37
|
}
|
|
32
38
|
const oauthApp = oauth.getOAuthApp(oauthInfo);
|
|
33
39
|
const { accessToken, refreshToken, expires } = await oauthApp.code.getToken(callbackUri, overridingOAuthOption);
|
|
34
40
|
const authHeader = `Bearer ${accessToken}`;
|
|
35
|
-
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader, tokenUrl, apiUrl, hostname, platform, username, callbackUri, query, proxyId, proxyConfig });
|
|
41
|
+
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader, tokenUrl, apiUrl, hostname, platform, username, callbackUri, query, proxyId, proxyConfig, userEmail });
|
|
36
42
|
|
|
37
43
|
if (successful) {
|
|
38
|
-
let userInfo =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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: expires,
|
|
56
|
+
rcAccountId: query?.rcAccountId,
|
|
57
|
+
proxyId
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
62
|
+
}
|
|
51
63
|
if (platformModule.postSaveUserInfo) {
|
|
52
64
|
userInfo = await platformModule.postSaveUserInfo({ userInfo, oauthApp });
|
|
53
65
|
}
|
|
@@ -69,13 +81,19 @@ async function onApiKeyLogin({ platform, hostname, apiKey, proxyId, additionalIn
|
|
|
69
81
|
const basicAuth = platformModule.getBasicAuth({ apiKey });
|
|
70
82
|
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader: `Basic ${basicAuth}`, hostname, platform, additionalInfo, apiKey, proxyId });
|
|
71
83
|
if (successful) {
|
|
72
|
-
let userInfo =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
+
}
|
|
79
97
|
if (platformModule.postSaveUserInfo) {
|
|
80
98
|
userInfo = await platformModule.postSaveUserInfo({ userInfo });
|
|
81
99
|
}
|
|
@@ -101,43 +119,65 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
|
|
|
101
119
|
const platformAdditionalInfo = platformUserInfo.platformAdditionalInfo || {};
|
|
102
120
|
platformAdditionalInfo.proxyId = proxyId;
|
|
103
121
|
if (existingUser) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
timezoneName,
|
|
109
|
-
timezoneOffset,
|
|
110
|
-
accessToken,
|
|
111
|
-
refreshToken,
|
|
112
|
-
tokenExpiry,
|
|
113
|
-
rcAccountId,
|
|
114
|
-
platformAdditionalInfo: {
|
|
115
|
-
...existingUser.platformAdditionalInfo, // keep existing platformAdditionalInfo
|
|
116
|
-
...platformAdditionalInfo,
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// TEMP: replace user with old ID
|
|
123
|
-
if (id.endsWith(`-${platform}`)) {
|
|
124
|
-
const oldID = id.split('-');
|
|
125
|
-
const userWithOldID = await UserModel.findByPk(oldID[0]);
|
|
126
|
-
if (userWithOldID) {
|
|
127
|
-
await UserModel.create({
|
|
128
|
-
id,
|
|
122
|
+
try {
|
|
123
|
+
await existingUser.update(
|
|
124
|
+
{
|
|
125
|
+
platform,
|
|
129
126
|
hostname,
|
|
130
127
|
timezoneName,
|
|
131
128
|
timezoneOffset,
|
|
132
|
-
platform,
|
|
133
129
|
accessToken,
|
|
134
130
|
refreshToken,
|
|
135
131
|
tokenExpiry,
|
|
136
132
|
rcAccountId,
|
|
137
|
-
platformAdditionalInfo
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
+
}
|
|
141
181
|
}
|
|
142
182
|
else {
|
|
143
183
|
await UserModel.create({
|
|
@@ -155,20 +195,8 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
|
|
|
155
195
|
});
|
|
156
196
|
}
|
|
157
197
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
id,
|
|
161
|
-
hostname,
|
|
162
|
-
timezoneName,
|
|
163
|
-
timezoneOffset,
|
|
164
|
-
platform,
|
|
165
|
-
accessToken,
|
|
166
|
-
refreshToken,
|
|
167
|
-
tokenExpiry,
|
|
168
|
-
rcAccountId,
|
|
169
|
-
platformAdditionalInfo,
|
|
170
|
-
userSettings: {}
|
|
171
|
-
});
|
|
198
|
+
catch (error) {
|
|
199
|
+
return handleDatabaseError(error, 'Error saving user info');
|
|
172
200
|
}
|
|
173
201
|
}
|
|
174
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 }) {
|