@app-connect/core 1.7.22 → 1.7.23
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/docs/libraries.md +1 -1
- package/handlers/auth.js +10 -4
- package/handlers/log.js +217 -109
- package/handlers/plugin.js +183 -1
- package/handlers/user.js +1 -1
- package/index.js +152 -7
- package/lib/callLogComposer.js +36 -36
- package/lib/util.js +0 -18
- package/package.json +1 -1
- package/releaseNotes.json +8 -0
- package/test/handlers/admin.test.js +1 -2
- package/test/handlers/log.test.js +60 -0
- package/test/handlers/plugin.test.js +93 -0
- package/test/lib/callLogComposer.test.js +21 -21
- package/test/lib/util.test.js +1 -332
- package/test/routes/managedAuthRoutes.test.js +0 -3
package/handlers/plugin.js
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
const { CacheModel } = require('../models/cacheModel');
|
|
2
2
|
const { Op } = require('sequelize');
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
const { AccountDataModel } = require('../models/accountDataModel');
|
|
5
|
+
const logger = require('../lib/logger');
|
|
6
|
+
|
|
7
|
+
const PUBLIC_MANIFEST_BASE = 'https://appconnect.labs.ringcentral.com/public-api/connectors';
|
|
8
|
+
|
|
9
|
+
async function getPluginsFromRcAccountId({ rcAccountId }) {
|
|
10
|
+
const accountData = await AccountDataModel.findAll({
|
|
11
|
+
where: {
|
|
12
|
+
rcAccountId,
|
|
13
|
+
dataKey: 'pluginData',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const workingPlugins = accountData.map(data => ({
|
|
17
|
+
id: data.platformName,
|
|
18
|
+
data: data.data,
|
|
19
|
+
}));
|
|
20
|
+
return workingPlugins;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getPluginConfigFromUserSettings({ userSettings, pluginId }) {
|
|
24
|
+
if (!userSettings) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const targetPluginSettings = userSettings[`plugin_${pluginId}`];
|
|
28
|
+
if (!targetPluginSettings?.value?.config) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return targetPluginSettings.value.config;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function getPluginLicenseStatus({ rcAccountId, pluginId }) {
|
|
35
|
+
const accountData = await AccountDataModel.findOne({
|
|
36
|
+
where: {
|
|
37
|
+
rcAccountId,
|
|
38
|
+
platformName: pluginId,
|
|
39
|
+
dataKey: 'pluginData',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
if (!accountData) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const licenseStatusUrl = accountData.data.licenseStatusUrl;
|
|
46
|
+
const licenseStatusResponse = await axios.get(licenseStatusUrl, {
|
|
47
|
+
headers: {
|
|
48
|
+
'Authorization': `Bearer ${accountData.data.jwtToken}`
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return licenseStatusResponse.data;
|
|
52
|
+
}
|
|
3
53
|
|
|
4
54
|
async function getPluginAsyncTasks({ asyncTaskIds }) {
|
|
5
55
|
const caches = await CacheModel.findAll({
|
|
@@ -24,4 +74,136 @@ async function getPluginAsyncTasks({ asyncTaskIds }) {
|
|
|
24
74
|
return result;
|
|
25
75
|
}
|
|
26
76
|
|
|
27
|
-
|
|
77
|
+
function getRefreshedJwtTokenFromHeaders({ headers }) {
|
|
78
|
+
if (!headers) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return headers['x-refreshed-jwt-token'] || headers['X-Refreshed-Jwt-Token'] || null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function resolvePluginManifest({ pluginId, pluginAccess, rcAccountId, pluginName }) {
|
|
85
|
+
const manifestFetchers = [];
|
|
86
|
+
if (pluginAccess === 'public') {
|
|
87
|
+
manifestFetchers.push(`${PUBLIC_MANIFEST_BASE}/${pluginId}/manifest?type=plugin`);
|
|
88
|
+
} else if (pluginAccess === 'private' || pluginAccess === 'shared') {
|
|
89
|
+
manifestFetchers.push(`${PUBLIC_MANIFEST_BASE}/${pluginId}/manifest?access=internal&type=plugin&accountId=${rcAccountId}`);
|
|
90
|
+
} else {
|
|
91
|
+
manifestFetchers.push(`${PUBLIC_MANIFEST_BASE}/${pluginId}/manifest?type=plugin`);
|
|
92
|
+
manifestFetchers.push(`${PUBLIC_MANIFEST_BASE}/${pluginId}/manifest?access=internal&type=plugin&accountId=${rcAccountId}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let pluginData = null;
|
|
96
|
+
let lastError = null;
|
|
97
|
+
for (const url of manifestFetchers) {
|
|
98
|
+
try {
|
|
99
|
+
const pluginDataResponse = await axios.get(url);
|
|
100
|
+
pluginData = pluginDataResponse.data;
|
|
101
|
+
break;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
lastError = error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!pluginData) {
|
|
108
|
+
throw lastError || new Error(`Unable to resolve manifest for plugin ${pluginId}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const platformKey = pluginName || Object.keys(pluginData.platforms || {})[0];
|
|
112
|
+
if (!platformKey || !pluginData.platforms?.[platformKey]) {
|
|
113
|
+
throw new Error(`Unable to resolve platform manifest for plugin ${pluginId}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
pluginData,
|
|
118
|
+
pluginManifest: pluginData.platforms[platformKey],
|
|
119
|
+
platformKey,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function persistPluginData({ rcAccountId, pluginId, jwtToken, pluginData = {} }) {
|
|
124
|
+
try {
|
|
125
|
+
const accountData = await AccountDataModel.findOne({
|
|
126
|
+
where: {
|
|
127
|
+
rcAccountId,
|
|
128
|
+
platformName: pluginId
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
if (!accountData) {
|
|
132
|
+
await AccountDataModel.create({
|
|
133
|
+
rcAccountId,
|
|
134
|
+
platformName: pluginId,
|
|
135
|
+
dataKey: 'pluginData',
|
|
136
|
+
data: {
|
|
137
|
+
jwtToken,
|
|
138
|
+
...pluginData,
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
await accountData.update({
|
|
143
|
+
data: {
|
|
144
|
+
jwtToken,
|
|
145
|
+
...pluginData,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
logger.error('Failed to persist plugin data', {
|
|
151
|
+
pluginId,
|
|
152
|
+
rcAccountId,
|
|
153
|
+
message: error.message,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function registerPluginAccount({ pluginId, rcAccessToken, rcAccountId, pluginAccess, pluginName }) {
|
|
159
|
+
const { pluginManifest } = await resolvePluginManifest({ pluginId, pluginAccess, rcAccountId, pluginName });
|
|
160
|
+
if (!pluginManifest?.endpointUrl) {
|
|
161
|
+
throw new Error(`Plugin endpoint URL not found for ${pluginId}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const registerUrl = pluginManifest.userRegisterEndpointUrl;
|
|
165
|
+
const registerResponse = await axios.post(registerUrl, {
|
|
166
|
+
rcAccessToken,
|
|
167
|
+
rcAccountId: rcAccountId?.toString(),
|
|
168
|
+
});
|
|
169
|
+
const pluginJwtToken = registerResponse.data?.jwtToken;
|
|
170
|
+
if (!pluginJwtToken) {
|
|
171
|
+
throw new Error('Plugin register API did not return jwtToken');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await persistPluginData({
|
|
175
|
+
rcAccountId: rcAccountId?.toString(),
|
|
176
|
+
pluginId,
|
|
177
|
+
jwtToken: pluginJwtToken,
|
|
178
|
+
pluginData: pluginManifest,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
successful: true,
|
|
183
|
+
registerUrl,
|
|
184
|
+
jwtToken: pluginJwtToken,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function unregisterPluginAccount({ pluginId, rcAccountId }) {
|
|
189
|
+
const accountData = await AccountDataModel.findOne({
|
|
190
|
+
where: {
|
|
191
|
+
rcAccountId,
|
|
192
|
+
platformName: pluginId,
|
|
193
|
+
dataKey: 'pluginData'
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
if (accountData) {
|
|
197
|
+
await accountData.destroy();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
exports.getPluginsFromRcAccountId = getPluginsFromRcAccountId;
|
|
202
|
+
exports.getPluginConfigFromUserSettings = getPluginConfigFromUserSettings;
|
|
203
|
+
exports.getPluginLicenseStatus = getPluginLicenseStatus;
|
|
204
|
+
exports.getPluginAsyncTasks = getPluginAsyncTasks;
|
|
205
|
+
exports.getRefreshedJwtTokenFromHeaders = getRefreshedJwtTokenFromHeaders;
|
|
206
|
+
exports.resolvePluginManifest = resolvePluginManifest;
|
|
207
|
+
exports.persistPluginData = persistPluginData;
|
|
208
|
+
exports.registerPluginAccount = registerPluginAccount;
|
|
209
|
+
exports.unregisterPluginAccount = unregisterPluginAccount;
|
package/handlers/user.js
CHANGED
|
@@ -71,7 +71,7 @@ async function getUserSettings({ user, rcAccessToken, rcAccountId }) {
|
|
|
71
71
|
config[k] = configFromadminSettings[k];
|
|
72
72
|
}
|
|
73
73
|
else {
|
|
74
|
-
config[k].customizable = configFromadminSettings[k]
|
|
74
|
+
config[k].customizable = configFromadminSettings[k]?.customizable ?? true;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
result[key].value.config = config;
|
package/index.js
CHANGED
|
@@ -1165,13 +1165,13 @@ function createCoreRouter() {
|
|
|
1165
1165
|
res.status(400).send(tracer ? tracer.wrapResponse('Missing platform name') : 'Missing platform name');
|
|
1166
1166
|
return;
|
|
1167
1167
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const rcUserTokenResult = await adminCore.validateRcUserToken({ rcAccessToken });
|
|
1172
|
-
rcAccountId = rcUserTokenResult.rcAccountId;
|
|
1173
|
-
rcExtensionId = rcUserTokenResult.rcExtensionId;
|
|
1168
|
+
if (!rcAccessToken) {
|
|
1169
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Missing RingCentral access token') : 'Missing RingCentral access token');
|
|
1170
|
+
return;
|
|
1174
1171
|
}
|
|
1172
|
+
const rcUserTokenResult = await adminCore.validateRcUserToken({ rcAccessToken });
|
|
1173
|
+
const rcAccountId = rcUserTokenResult.rcAccountId;
|
|
1174
|
+
const rcExtensionId = rcUserTokenResult.rcExtensionId;
|
|
1175
1175
|
const { userInfo, returnMessage } = await authCore.onApiKeyLogin({
|
|
1176
1176
|
platform,
|
|
1177
1177
|
hostname,
|
|
@@ -2197,7 +2197,7 @@ function createCoreRouter() {
|
|
|
2197
2197
|
let platformName = null;
|
|
2198
2198
|
let success = false;
|
|
2199
2199
|
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
2200
|
-
const
|
|
2200
|
+
const jwtToken = req.jwtToken || req.query.jwtToken;
|
|
2201
2201
|
try {
|
|
2202
2202
|
if (!jwtToken) {
|
|
2203
2203
|
tracer?.trace('pluginAsyncTask:noToken', {});
|
|
@@ -2239,6 +2239,151 @@ function createCoreRouter() {
|
|
|
2239
2239
|
});
|
|
2240
2240
|
});
|
|
2241
2241
|
|
|
2242
|
+
router.post('/plugin/register', async function (req, res) {
|
|
2243
|
+
const requestStartTime = new Date().getTime();
|
|
2244
|
+
const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
|
|
2245
|
+
tracer?.trace('pluginRegister:start', { body: req.body });
|
|
2246
|
+
let success = false;
|
|
2247
|
+
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
2248
|
+
try {
|
|
2249
|
+
const { pluginId, rcAccountId, pluginAccess, pluginName } = req.body || {};
|
|
2250
|
+
const rcAccessToken = req.query?.rcAccessToken;
|
|
2251
|
+
if (!pluginId || !rcAccountId) {
|
|
2252
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'pluginId and rcAccountId are required' }) : { successful: false, returnMessage: 'pluginId and rcAccountId are required' });
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
if (!rcAccessToken) {
|
|
2256
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Missing RingCentral access token' }) : { successful: false, returnMessage: 'Missing RingCentral access token' });
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
const { isValidated, rcAccountId: validatedRcAccountId } = await adminCore.validateAdminRole({ rcAccessToken });
|
|
2260
|
+
if (!isValidated) {
|
|
2261
|
+
res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Admin validation failed' }) : { successful: false, returnMessage: 'Admin validation failed' });
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
if (validatedRcAccountId?.toString() !== rcAccountId?.toString()) {
|
|
2265
|
+
res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'rcAccountId mismatch' }) : { successful: false, returnMessage: 'rcAccountId mismatch' });
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
await pluginCore.registerPluginAccount({
|
|
2270
|
+
pluginId,
|
|
2271
|
+
rcAccessToken,
|
|
2272
|
+
rcAccountId: rcAccountId?.toString(),
|
|
2273
|
+
pluginAccess,
|
|
2274
|
+
pluginName,
|
|
2275
|
+
});
|
|
2276
|
+
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
|
|
2277
|
+
success = true;
|
|
2278
|
+
} catch (e) {
|
|
2279
|
+
logger.error('Plugin register failed', { stack: e.stack });
|
|
2280
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: e.message || e }) : { successful: false, returnMessage: e.message || e });
|
|
2281
|
+
tracer?.traceError('pluginRegister:error', e);
|
|
2282
|
+
success = false;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
const requestEndTime = new Date().getTime();
|
|
2286
|
+
analytics.track({
|
|
2287
|
+
eventName: 'Plugin Register',
|
|
2288
|
+
interfaceName: 'pluginRegister',
|
|
2289
|
+
accountId: hashedAccountId,
|
|
2290
|
+
extensionId: hashedExtensionId,
|
|
2291
|
+
success,
|
|
2292
|
+
requestDuration: (requestEndTime - requestStartTime) / 1000,
|
|
2293
|
+
userAgent,
|
|
2294
|
+
ip,
|
|
2295
|
+
author,
|
|
2296
|
+
eventAddedVia
|
|
2297
|
+
});
|
|
2298
|
+
});
|
|
2299
|
+
|
|
2300
|
+
router.delete('/plugin/unregister', async function (req, res) {
|
|
2301
|
+
const requestStartTime = new Date().getTime();
|
|
2302
|
+
const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
|
|
2303
|
+
tracer?.trace('pluginUnregister:start', { query: req.query });
|
|
2304
|
+
let success = false;
|
|
2305
|
+
const { hashedExtensionId, hashedAccountId, userAgent, ip, author, eventAddedVia } = getAnalyticsVariablesInReqHeaders({ headers: req.headers })
|
|
2306
|
+
try {
|
|
2307
|
+
const { pluginId, rcAccountId, pluginName } = req.query || {};
|
|
2308
|
+
const rcAccessToken = req.query?.rcAccessToken;
|
|
2309
|
+
if (!pluginId || !rcAccountId) {
|
|
2310
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'pluginId and rcAccountId are required' }) : { successful: false, returnMessage: 'pluginId and rcAccountId are required' });
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
if (!rcAccessToken) {
|
|
2314
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Missing RingCentral access token' }) : { successful: false, returnMessage: 'Missing RingCentral access token' });
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
const { isValidated, rcAccountId: validatedRcAccountId } = await adminCore.validateAdminRole({ rcAccessToken });
|
|
2318
|
+
if (!isValidated) {
|
|
2319
|
+
res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'Admin validation failed' }) : { successful: false, returnMessage: 'Admin validation failed' });
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
if (validatedRcAccountId?.toString() !== rcAccountId?.toString()) {
|
|
2323
|
+
res.status(403).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: 'rcAccountId mismatch' }) : { successful: false, returnMessage: 'rcAccountId mismatch' });
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
await pluginCore.unregisterPluginAccount({
|
|
2328
|
+
pluginId,
|
|
2329
|
+
rcAccountId: rcAccountId?.toString(),
|
|
2330
|
+
pluginName,
|
|
2331
|
+
});
|
|
2332
|
+
res.status(200).send(tracer ? tracer.wrapResponse({ successful: true }) : { successful: true });
|
|
2333
|
+
success = true;
|
|
2334
|
+
} catch (e) {
|
|
2335
|
+
logger.error('Plugin unregister failed', { stack: e.stack });
|
|
2336
|
+
res.status(400).send(tracer ? tracer.wrapResponse({ successful: false, returnMessage: e.message || e }) : { successful: false, returnMessage: e.message || e });
|
|
2337
|
+
tracer?.traceError('pluginUnregister:error', e);
|
|
2338
|
+
success = false;
|
|
2339
|
+
}
|
|
2340
|
+
const requestEndTime = new Date().getTime();
|
|
2341
|
+
analytics.track({
|
|
2342
|
+
eventName: 'Plugin Unregister',
|
|
2343
|
+
interfaceName: 'pluginUnregister',
|
|
2344
|
+
accountId: hashedAccountId,
|
|
2345
|
+
extensionId: hashedExtensionId,
|
|
2346
|
+
success,
|
|
2347
|
+
requestDuration: (requestEndTime - requestStartTime) / 1000,
|
|
2348
|
+
userAgent,
|
|
2349
|
+
ip,
|
|
2350
|
+
author,
|
|
2351
|
+
eventAddedVia
|
|
2352
|
+
});
|
|
2353
|
+
});
|
|
2354
|
+
|
|
2355
|
+
router.get('/plugin/licenseStatus', async function (req, res) {
|
|
2356
|
+
const tracer = req.headers['is-debug'] === 'true' ? DebugTracer.fromRequest(req) : null;
|
|
2357
|
+
tracer?.trace('getPluginLicenseStatus:start', { query: req.query });
|
|
2358
|
+
try {
|
|
2359
|
+
const jwtToken = req.jwtToken || req.query.jwtToken;
|
|
2360
|
+
if (!jwtToken) {
|
|
2361
|
+
tracer?.trace('getPluginLicenseStatus:noToken', {});
|
|
2362
|
+
res.status(400).send(tracer ? tracer.wrapResponse('Please go to Settings and authorize CRM platform') : 'Please go to Settings and authorize CRM platform');
|
|
2363
|
+
return;
|
|
2364
|
+
}
|
|
2365
|
+
const unAuthData = jwt.decodeJwt(jwtToken);
|
|
2366
|
+
const user = await UserModel.findByPk(unAuthData?.id);
|
|
2367
|
+
if (!user) {
|
|
2368
|
+
tracer?.trace('getPluginLicenseStatus:userNotFound', {});
|
|
2369
|
+
res.status(400).send(tracer ? tracer.wrapResponse('User not found') : 'User not found');
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2372
|
+
const { rcAccountId, pluginId } = req.query;
|
|
2373
|
+
if (!rcAccountId || !pluginId) {
|
|
2374
|
+
res.status(400).send(tracer ? tracer.wrapResponse('rcAccountId and pluginId are required') : 'rcAccountId and pluginId are required');
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2377
|
+
const licenseStatus = await pluginCore.getPluginLicenseStatus({ rcAccountId, pluginId });
|
|
2378
|
+
res.status(200).send(tracer ? tracer.wrapResponse(licenseStatus) : licenseStatus);
|
|
2379
|
+
}
|
|
2380
|
+
catch (e) {
|
|
2381
|
+
logger.error('Get plugin license status failed', { stack: e.stack });
|
|
2382
|
+
res.status(200).send(tracer ? tracer.wrapResponse({ licenseStatus: false, licenseStatusDescription: e.message || e }) : { licenseStatus: false, licenseStatusDescription: e.message || e });
|
|
2383
|
+
tracer?.traceError('getPluginLicenseStatus:error', e);
|
|
2384
|
+
}
|
|
2385
|
+
});
|
|
2386
|
+
|
|
2242
2387
|
if (process.env.IS_PROD === 'false') {
|
|
2243
2388
|
router.post('/registerMockUser', async function (req, res) {
|
|
2244
2389
|
const secretKey = req.query.secretKey;
|
package/lib/callLogComposer.js
CHANGED
|
@@ -702,27 +702,27 @@ function upsertRingSenseTranscript({ body, transcript, logFormat }) {
|
|
|
702
702
|
switch (logFormat) {
|
|
703
703
|
case LOG_DETAILS_FORMAT_TYPE.HTML:
|
|
704
704
|
const formattedTranscript = clearedTranscript.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
705
|
-
transcriptRegex = /<div><b>
|
|
705
|
+
transcriptRegex = /<div><b>ACE transcript<\/b><br>(.+?)<\/div>/;
|
|
706
706
|
if (transcriptRegex.test(result)) {
|
|
707
|
-
result = result.replace(transcriptRegex, `<div><b>
|
|
707
|
+
result = result.replace(transcriptRegex, `<div><b>ACE transcript</b><br>${formattedTranscript}</div>`);
|
|
708
708
|
} else {
|
|
709
|
-
result += `<div><b>
|
|
709
|
+
result += `<div><b>ACE transcript</b><br>${formattedTranscript}</div>`;
|
|
710
710
|
}
|
|
711
711
|
break;
|
|
712
712
|
case LOG_DETAILS_FORMAT_TYPE.MARKDOWN:
|
|
713
|
-
transcriptRegex = /###
|
|
713
|
+
transcriptRegex = /### ACE transcript\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
714
714
|
if (transcriptRegex.test(result)) {
|
|
715
|
-
result = result.replace(transcriptRegex, `###
|
|
715
|
+
result = result.replace(transcriptRegex, `### ACE transcript\n${clearedTranscript}\n`);
|
|
716
716
|
} else {
|
|
717
|
-
result += `###
|
|
717
|
+
result += `### ACE transcript\n${clearedTranscript}\n`;
|
|
718
718
|
}
|
|
719
719
|
break;
|
|
720
720
|
case LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT:
|
|
721
|
-
transcriptRegex = /-
|
|
721
|
+
transcriptRegex = /- ACE transcript:([\s\S]*?)--- END/;
|
|
722
722
|
if (transcriptRegex.test(result)) {
|
|
723
|
-
result = result.replace(transcriptRegex, `-
|
|
723
|
+
result = result.replace(transcriptRegex, `- ACE transcript:\n${clearedTranscript}\n--- END`);
|
|
724
724
|
} else {
|
|
725
|
-
result += `\n-
|
|
725
|
+
result += `\n- ACE transcript:\n${clearedTranscript}\n--- END\n`;
|
|
726
726
|
}
|
|
727
727
|
break;
|
|
728
728
|
}
|
|
@@ -739,28 +739,28 @@ function upsertRingSenseSummary({ body, summary, logFormat }) {
|
|
|
739
739
|
|
|
740
740
|
switch (logFormat) {
|
|
741
741
|
case LOG_DETAILS_FORMAT_TYPE.HTML:
|
|
742
|
-
summaryRegex = /<div><b>
|
|
742
|
+
summaryRegex = /<div><b>ACE summary<\/b><br>(.+?)<\/div>/;
|
|
743
743
|
const formattedSummary = clearedSummary.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
744
744
|
if (summaryRegex.test(result)) {
|
|
745
|
-
result = result.replace(summaryRegex, `<div><b>
|
|
745
|
+
result = result.replace(summaryRegex, `<div><b>ACE summary</b><br>${formattedSummary}</div>`);
|
|
746
746
|
} else {
|
|
747
|
-
result += `<div><b>
|
|
747
|
+
result += `<div><b>ACE summary</b><br>${formattedSummary}</div>`;
|
|
748
748
|
}
|
|
749
749
|
break;
|
|
750
750
|
case LOG_DETAILS_FORMAT_TYPE.MARKDOWN:
|
|
751
|
-
summaryRegex = /###
|
|
751
|
+
summaryRegex = /### ACE summary\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
752
752
|
if (summaryRegex.test(result)) {
|
|
753
|
-
result = result.replace(summaryRegex, `###
|
|
753
|
+
result = result.replace(summaryRegex, `### ACE summary\n${summary}\n`);
|
|
754
754
|
} else {
|
|
755
|
-
result += `###
|
|
755
|
+
result += `### ACE summary\n${summary}\n`;
|
|
756
756
|
}
|
|
757
757
|
break;
|
|
758
758
|
case LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT:
|
|
759
|
-
summaryRegex = /-
|
|
759
|
+
summaryRegex = /- ACE summary:([\s\S]*?)--- END/;
|
|
760
760
|
if (summaryRegex.test(result)) {
|
|
761
|
-
result = result.replace(summaryRegex, `-
|
|
761
|
+
result = result.replace(summaryRegex, `- ACE summary:\n${summary}\n--- END`);
|
|
762
762
|
} else {
|
|
763
|
-
result += `\n-
|
|
763
|
+
result += `\n- ACE summary:\n${summary}\n--- END\n`;
|
|
764
764
|
}
|
|
765
765
|
break;
|
|
766
766
|
}
|
|
@@ -811,28 +811,28 @@ function upsertRingSenseBulletedSummary({ body, summary, logFormat }) {
|
|
|
811
811
|
|
|
812
812
|
switch (logFormat) {
|
|
813
813
|
case LOG_DETAILS_FORMAT_TYPE.HTML:
|
|
814
|
-
summaryRegex = /<div><b>
|
|
814
|
+
summaryRegex = /<div><b>ACE bulleted summary<\/b><br>(.+?)<\/div>/;
|
|
815
815
|
const formattedSummary = clearedSummary.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
816
816
|
if (summaryRegex.test(result)) {
|
|
817
|
-
result = result.replace(summaryRegex, `<div><b>
|
|
817
|
+
result = result.replace(summaryRegex, `<div><b>ACE bulleted summary</b><br>${formattedSummary}</div>`);
|
|
818
818
|
} else {
|
|
819
|
-
result += `<div><b>
|
|
819
|
+
result += `<div><b>ACE bulleted summary</b><br>${formattedSummary}</div>`;
|
|
820
820
|
}
|
|
821
821
|
break;
|
|
822
822
|
case LOG_DETAILS_FORMAT_TYPE.MARKDOWN:
|
|
823
|
-
summaryRegex = /###
|
|
823
|
+
summaryRegex = /### ACE bulleted summary\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
824
824
|
if (summaryRegex.test(result)) {
|
|
825
|
-
result = result.replace(summaryRegex, `###
|
|
825
|
+
result = result.replace(summaryRegex, `### ACE bulleted summary\n${summary}\n`);
|
|
826
826
|
} else {
|
|
827
|
-
result += `###
|
|
827
|
+
result += `### ACE bulleted summary\n${summary}\n`;
|
|
828
828
|
}
|
|
829
829
|
break;
|
|
830
830
|
case LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT:
|
|
831
|
-
summaryRegex = /-
|
|
831
|
+
summaryRegex = /- ACE bulleted summary:\s*([^<\n]+)(?=\n|$)/i;
|
|
832
832
|
if (summaryRegex.test(result)) {
|
|
833
|
-
result = result.replace(summaryRegex, `-
|
|
833
|
+
result = result.replace(summaryRegex, `- ACE bulleted summary:\n${summary}\n--- END`);
|
|
834
834
|
} else {
|
|
835
|
-
result += `\n-
|
|
835
|
+
result += `\n- ACE bulleted summary:\n${summary}\n--- END\n`;
|
|
836
836
|
}
|
|
837
837
|
break;
|
|
838
838
|
}
|
|
@@ -847,27 +847,27 @@ function upsertRingSenseLink({ body, link, logFormat }) {
|
|
|
847
847
|
|
|
848
848
|
switch (logFormat) {
|
|
849
849
|
case LOG_DETAILS_FORMAT_TYPE.HTML:
|
|
850
|
-
linkRegex = /(?:<li>)?<b>
|
|
850
|
+
linkRegex = /(?:<li>)?<b>ACE recording link<\/b>:\s*(?:<a[^>]*>[^<]*<\/a>|[^<]+)(?:<\/li>|(?=<|$))/i;
|
|
851
851
|
if (linkRegex.test(result)) {
|
|
852
|
-
result = result.replace(linkRegex, `<li><b>
|
|
852
|
+
result = result.replace(linkRegex, `<li><b>ACE recording link</b>: <a target="_blank" href="${link}">open</a></li>`);
|
|
853
853
|
} else {
|
|
854
|
-
result += `<li><b>
|
|
854
|
+
result += `<li><b>ACE recording link</b>: <a target="_blank" href="${link}">open</a></li>`;
|
|
855
855
|
}
|
|
856
856
|
break;
|
|
857
857
|
case LOG_DETAILS_FORMAT_TYPE.MARKDOWN:
|
|
858
|
-
linkRegex = /\*\*
|
|
858
|
+
linkRegex = /\*\*ACE recording link\*\*:\s*([^<\n]+)(?=\n|$)/i;
|
|
859
859
|
if (linkRegex.test(result)) {
|
|
860
|
-
result = result.replace(linkRegex, `**
|
|
860
|
+
result = result.replace(linkRegex, `**ACE recording link**: ${link}\n`);
|
|
861
861
|
} else {
|
|
862
|
-
result += `**
|
|
862
|
+
result += `**ACE recording link**: ${link}\n`;
|
|
863
863
|
}
|
|
864
864
|
break;
|
|
865
865
|
case LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT:
|
|
866
|
-
linkRegex = /-
|
|
866
|
+
linkRegex = /- ACE recording link:\s*([^<\n]+)(?=\n|$)/i;
|
|
867
867
|
if (linkRegex.test(result)) {
|
|
868
|
-
result = result.replace(linkRegex, `-
|
|
868
|
+
result = result.replace(linkRegex, `- ACE recording link: ${link}`);
|
|
869
869
|
} else {
|
|
870
|
-
result += `-
|
|
870
|
+
result += `- ACE recording link: ${link}\n`;
|
|
871
871
|
}
|
|
872
872
|
break;
|
|
873
873
|
}
|
package/lib/util.js
CHANGED
|
@@ -60,26 +60,8 @@ function getMediaReaderLinkByPlatformMediaLink(platformMediaLink) {
|
|
|
60
60
|
return `https://ringcentral.github.io/ringcentral-media-reader/?media=${encodedPlatformMediaLink}`;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
function getPluginsFromUserSettings({ userSettings, logType }) {
|
|
64
|
-
const result = [];
|
|
65
|
-
if (!userSettings) {
|
|
66
|
-
return result;
|
|
67
|
-
}
|
|
68
|
-
for (const userSettingKey in userSettings) {
|
|
69
|
-
if (!userSettingKey.startsWith('plugin_')) {
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
const pluginUserSetting = userSettings[userSettingKey];
|
|
73
|
-
if (pluginUserSetting.value.logTypes.includes(logType)) {
|
|
74
|
-
result.push({ id: userSettingKey.replace('plugin_', ''), value: pluginUserSetting.value });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
63
|
exports.getTimeZone = getTimeZone;
|
|
81
64
|
exports.getHashValue = getHashValue;
|
|
82
65
|
exports.secondsToHoursMinutesSeconds = secondsToHoursMinutesSeconds;
|
|
83
66
|
exports.getMostRecentDate = getMostRecentDate;
|
|
84
67
|
exports.getMediaReaderLinkByPlatformMediaLink = getMediaReaderLinkByPlatformMediaLink;
|
|
85
|
-
exports.getPluginsFromUserSettings = getPluginsFromUserSettings;
|
package/package.json
CHANGED
package/releaseNotes.json
CHANGED
|
@@ -142,8 +142,7 @@ describe('Admin Handler', () => {
|
|
|
142
142
|
|
|
143
143
|
expect(result).toEqual({
|
|
144
144
|
rcAccountId: 'rc-account-789',
|
|
145
|
-
rcExtensionId: 'extension-789'
|
|
146
|
-
rcUserName: 'Alex Johnson'
|
|
145
|
+
rcExtensionId: 'extension-789'
|
|
147
146
|
});
|
|
148
147
|
expect(axios.get).toHaveBeenCalledWith(
|
|
149
148
|
'https://platform.ringcentral.com/restapi/v1.0/account/~/extension/~',
|