@app-connect/core 0.0.3 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.test +5 -5
- package/README.md +434 -425
- package/adapter/mock.js +76 -76
- package/adapter/registry.js +247 -247
- package/handlers/admin.js +62 -60
- package/handlers/auth.js +205 -156
- package/handlers/contact.js +274 -274
- package/handlers/disposition.js +193 -193
- package/handlers/log.js +612 -586
- package/handlers/user.js +101 -101
- package/index.js +1302 -1202
- package/jest.config.js +56 -56
- package/lib/analytics.js +52 -52
- package/lib/callLogComposer.js +550 -451
- package/lib/constants.js +9 -0
- package/lib/encode.js +30 -30
- package/lib/generalErrorMessage.js +41 -41
- package/lib/jwt.js +16 -16
- package/lib/oauth.js +79 -29
- package/lib/util.js +43 -40
- package/models/adminConfigModel.js +17 -17
- package/models/cacheModel.js +23 -23
- package/models/callLogModel.js +27 -27
- package/models/dynamo/lockSchema.js +24 -24
- package/models/dynamo/noteCacheSchema.js +30 -0
- package/models/messageLogModel.js +25 -25
- package/models/sequelize.js +16 -16
- package/models/userModel.js +38 -38
- package/package.json +67 -64
- package/releaseNotes.json +701 -577
- package/test/adapter/registry.test.js +270 -270
- package/test/handlers/auth.test.js +230 -230
- package/test/lib/jwt.test.js +161 -161
- package/test/setup.js +176 -176
package/lib/constants.js
ADDED
package/lib/encode.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
const crypto = require('crypto');
|
|
2
|
-
|
|
3
|
-
function getCipherKey() {
|
|
4
|
-
if (!process.env.APP_SERVER_SECRET_KEY) {
|
|
5
|
-
throw new Error('APP_SERVER_SECRET_KEY is not defined');
|
|
6
|
-
}
|
|
7
|
-
if (process.env.APP_SERVER_SECRET_KEY.length < 32) {
|
|
8
|
-
// pad secret key with spaces if it is less than 32 bytes
|
|
9
|
-
return process.env.APP_SERVER_SECRET_KEY.padEnd(32, ' ');
|
|
10
|
-
}
|
|
11
|
-
if (process.env.APP_SERVER_SECRET_KEY.length > 32) {
|
|
12
|
-
// truncate secret key if it is more than 32 bytes
|
|
13
|
-
return process.env.APP_SERVER_SECRET_KEY.slice(0, 32);
|
|
14
|
-
}
|
|
15
|
-
return process.env.APP_SERVER_SECRET_KEY;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function encode(data) {
|
|
19
|
-
const cipher = crypto.createCipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0));
|
|
20
|
-
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function decoded(encryptedData) {
|
|
24
|
-
const decipher = crypto.createDecipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0));
|
|
25
|
-
return decipher.update(encryptedData, 'hex', 'utf8') + decipher.final('utf8');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
exports.encode = encode;
|
|
30
|
-
exports.decoded = decoded;
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
|
|
3
|
+
function getCipherKey() {
|
|
4
|
+
if (!process.env.APP_SERVER_SECRET_KEY) {
|
|
5
|
+
throw new Error('APP_SERVER_SECRET_KEY is not defined');
|
|
6
|
+
}
|
|
7
|
+
if (process.env.APP_SERVER_SECRET_KEY.length < 32) {
|
|
8
|
+
// pad secret key with spaces if it is less than 32 bytes
|
|
9
|
+
return process.env.APP_SERVER_SECRET_KEY.padEnd(32, ' ');
|
|
10
|
+
}
|
|
11
|
+
if (process.env.APP_SERVER_SECRET_KEY.length > 32) {
|
|
12
|
+
// truncate secret key if it is more than 32 bytes
|
|
13
|
+
return process.env.APP_SERVER_SECRET_KEY.slice(0, 32);
|
|
14
|
+
}
|
|
15
|
+
return process.env.APP_SERVER_SECRET_KEY;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function encode(data) {
|
|
19
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0));
|
|
20
|
+
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function decoded(encryptedData) {
|
|
24
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', getCipherKey(), Buffer.alloc(16, 0));
|
|
25
|
+
return decipher.update(encryptedData, 'hex', 'utf8') + decipher.final('utf8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
exports.encode = encode;
|
|
30
|
+
exports.decoded = decoded;
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
function rateLimitErrorMessage({ platform }) {
|
|
2
|
-
return {
|
|
3
|
-
message: `Rate limit exceeded`,
|
|
4
|
-
messageType: 'warning',
|
|
5
|
-
details: [
|
|
6
|
-
{
|
|
7
|
-
title: 'Details',
|
|
8
|
-
items: [
|
|
9
|
-
{
|
|
10
|
-
id: '1',
|
|
11
|
-
type: 'text',
|
|
12
|
-
text: `You have exceeded the maximum number of requests allowed by ${platform}. Please try again in the next minute. If the problem persists please contact support.`
|
|
13
|
-
}
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
],
|
|
17
|
-
ttl: 5000
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function authorizationErrorMessage({ platform }) {
|
|
22
|
-
return {
|
|
23
|
-
message: `Authorization error`,
|
|
24
|
-
messageType: 'warning',
|
|
25
|
-
details: [
|
|
26
|
-
{
|
|
27
|
-
title: 'Details',
|
|
28
|
-
items: [
|
|
29
|
-
{
|
|
30
|
-
id: '1',
|
|
31
|
-
type: 'text',
|
|
32
|
-
text: `It seems like there's something wrong with your authorization of ${platform}. Please Logout and then Connect your ${platform} account within this extension.`
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
ttl: 5000
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
exports.rateLimitErrorMessage = rateLimitErrorMessage;
|
|
1
|
+
function rateLimitErrorMessage({ platform }) {
|
|
2
|
+
return {
|
|
3
|
+
message: `Rate limit exceeded`,
|
|
4
|
+
messageType: 'warning',
|
|
5
|
+
details: [
|
|
6
|
+
{
|
|
7
|
+
title: 'Details',
|
|
8
|
+
items: [
|
|
9
|
+
{
|
|
10
|
+
id: '1',
|
|
11
|
+
type: 'text',
|
|
12
|
+
text: `You have exceeded the maximum number of requests allowed by ${platform}. Please try again in the next minute. If the problem persists please contact support.`
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
ttl: 5000
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function authorizationErrorMessage({ platform }) {
|
|
22
|
+
return {
|
|
23
|
+
message: `Authorization error`,
|
|
24
|
+
messageType: 'warning',
|
|
25
|
+
details: [
|
|
26
|
+
{
|
|
27
|
+
title: 'Details',
|
|
28
|
+
items: [
|
|
29
|
+
{
|
|
30
|
+
id: '1',
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: `It seems like there's something wrong with your authorization of ${platform}. Please Logout and then Connect your ${platform} account within this extension.`
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
ttl: 5000
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.rateLimitErrorMessage = rateLimitErrorMessage;
|
|
42
42
|
exports.authorizationErrorMessage = authorizationErrorMessage;
|
package/lib/jwt.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
const { sign, verify } = require('jsonwebtoken');
|
|
2
|
-
|
|
3
|
-
function generateJwt(data) {
|
|
4
|
-
return sign(data, process.env.APP_SERVER_SECRET_KEY, { expiresIn: '120y' })
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function decodeJwt(token) {
|
|
8
|
-
try {
|
|
9
|
-
return verify(token, process.env.APP_SERVER_SECRET_KEY);
|
|
10
|
-
} catch (e) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.generateJwt = generateJwt;
|
|
16
|
-
exports.decodeJwt = decodeJwt;
|
|
1
|
+
const { sign, verify } = require('jsonwebtoken');
|
|
2
|
+
|
|
3
|
+
function generateJwt(data) {
|
|
4
|
+
return sign(data, process.env.APP_SERVER_SECRET_KEY, { expiresIn: '120y' })
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function decodeJwt(token) {
|
|
8
|
+
try {
|
|
9
|
+
return verify(token, process.env.APP_SERVER_SECRET_KEY);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
exports.generateJwt = generateJwt;
|
|
16
|
+
exports.decodeJwt = decodeJwt;
|
package/lib/oauth.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
2
|
const ClientOAuth2 = require('client-oauth2');
|
|
3
|
-
const
|
|
3
|
+
const moment = require('moment');
|
|
4
4
|
const { UserModel } = require('../models/userModel');
|
|
5
5
|
const adapterRegistry = require('../adapter/registry');
|
|
6
|
+
const dynamoose = require('dynamoose');
|
|
6
7
|
|
|
7
8
|
// oauthApp strategy is default to 'code' which use credentials to get accessCode, then exchange for accessToken and refreshToken.
|
|
8
9
|
// To change to other strategies, please refer to: https://github.com/mulesoft-labs/js-client-oauth2
|
|
@@ -18,10 +19,10 @@ function getOAuthApp({ clientId, clientSecret, accessTokenUri, authorizationUri,
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
async function checkAndRefreshAccessToken(oauthApp, user, tokenLockTimeout =
|
|
22
|
-
const
|
|
23
|
-
const tokenExpiry =
|
|
24
|
-
const expiryBuffer =
|
|
22
|
+
async function checkAndRefreshAccessToken(oauthApp, user, tokenLockTimeout = 20) {
|
|
23
|
+
const now = moment();
|
|
24
|
+
const tokenExpiry = moment(user.tokenExpiry);
|
|
25
|
+
const expiryBuffer = 2; // 2 minutes
|
|
25
26
|
// Special case: Bullhorn
|
|
26
27
|
if (user.platform) {
|
|
27
28
|
const platformModule = adapterRegistry.getAdapter(user.platform);
|
|
@@ -29,52 +30,101 @@ async function checkAndRefreshAccessToken(oauthApp, user, tokenLockTimeout = 10)
|
|
|
29
30
|
return platformModule.checkAndRefreshAccessToken(oauthApp, user, tokenLockTimeout);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
// Other CRMs
|
|
33
|
-
if (user && user.accessToken && user.refreshToken && tokenExpiry.
|
|
33
|
+
// Other CRMs - check if token will expire within the buffer time
|
|
34
|
+
if (user && user.accessToken && user.refreshToken && tokenExpiry.isBefore(now.clone().add(expiryBuffer, 'minutes'))) {
|
|
34
35
|
// case: use dynamoDB to manage token refresh lock
|
|
35
|
-
if (
|
|
36
|
-
let lock = await Lock.get({ userId: user.id });
|
|
36
|
+
if (adapterRegistry.getManifest('default')?.platforms?.[user.platform]?.auth?.useTokenRefreshLock) {
|
|
37
37
|
let newLock;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
const { Lock } = require('../models/dynamo/lockSchema');
|
|
39
|
+
// Try to atomically create lock only if it doesn't exist
|
|
40
|
+
try {
|
|
41
|
+
newLock = await Lock.create(
|
|
42
|
+
{
|
|
43
|
+
userId: user.id,
|
|
44
|
+
ttl: now.unix() + 30
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
overwrite: false
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
console.log('lock created')
|
|
51
|
+
} catch (e) {
|
|
52
|
+
// If creation failed due to condition, a lock exists
|
|
53
|
+
if (e.name === 'ConditionalCheckFailedException' || e.__type === 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException') {
|
|
54
|
+
let lock = await Lock.get({ userId: user.id });
|
|
55
|
+
if (!!lock?.ttl && moment(lock.ttl).unix() < now.unix()) {
|
|
56
|
+
// Try to delete expired lock and create a new one atomically
|
|
57
|
+
try {
|
|
58
|
+
console.log('lock expired.')
|
|
59
|
+
await lock.delete();
|
|
60
|
+
newLock = await Lock.create(
|
|
61
|
+
{
|
|
62
|
+
userId: user.id,
|
|
63
|
+
ttl: now.unix() + 30
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
overwrite: false
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
} catch (e2) {
|
|
70
|
+
if (e2.name === 'ConditionalCheckFailedException' || e2.__type === 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException') {
|
|
71
|
+
// Another process created a lock between our delete and create
|
|
72
|
+
lock = await Lock.get({ userId: user.id });
|
|
73
|
+
} else {
|
|
74
|
+
throw e2;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (lock && !newLock) {
|
|
80
|
+
let processTime = 0;
|
|
81
|
+
let delay = 500; // Start with 500ms
|
|
82
|
+
const maxDelay = 8000; // Cap at 8 seconds
|
|
83
|
+
while (!!lock && processTime < tokenLockTimeout) {
|
|
84
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
85
|
+
processTime += delay / 1000; // Convert to seconds for comparison
|
|
86
|
+
delay = Math.min(delay * 2, maxDelay); // Exponential backoff with cap
|
|
87
|
+
lock = await Lock.get({ userId: user.id });
|
|
88
|
+
}
|
|
89
|
+
// Timeout -> let users try another time
|
|
90
|
+
if (processTime >= tokenLockTimeout) {
|
|
91
|
+
throw new Error('Token lock timeout');
|
|
92
|
+
}
|
|
93
|
+
user = await UserModel.findByPk(user.id);
|
|
94
|
+
console.log('locked. bypass')
|
|
95
|
+
return user;
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
throw e;
|
|
52
99
|
}
|
|
53
|
-
user = await UserModel.findByPk(user.id);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
newLock = await Lock.create({
|
|
57
|
-
userId: user.id
|
|
58
|
-
});
|
|
59
100
|
}
|
|
101
|
+
const startRefreshTime = moment();
|
|
60
102
|
const token = oauthApp.createToken(user.accessToken, user.refreshToken);
|
|
103
|
+
console.log('token refreshing...')
|
|
61
104
|
const { accessToken, refreshToken, expires } = await token.refresh();
|
|
62
105
|
user.accessToken = accessToken;
|
|
63
106
|
user.refreshToken = refreshToken;
|
|
64
107
|
user.tokenExpiry = expires;
|
|
65
108
|
await user.save();
|
|
66
109
|
if (newLock) {
|
|
110
|
+
const deletionStartTime = moment();
|
|
67
111
|
await newLock.delete();
|
|
112
|
+
const deletionEndTime = moment();
|
|
113
|
+
console.log(`lock deleted in ${deletionEndTime.diff(deletionStartTime)}ms`)
|
|
68
114
|
}
|
|
115
|
+
const endRefreshTime = moment();
|
|
116
|
+
console.log(`token refreshing finished in ${endRefreshTime.diff(startRefreshTime)}ms`)
|
|
69
117
|
}
|
|
70
118
|
// case: run withou token refresh lock
|
|
71
119
|
else {
|
|
120
|
+
console.log('token refreshing...')
|
|
72
121
|
const token = oauthApp.createToken(user.accessToken, user.refreshToken);
|
|
73
122
|
const { accessToken, refreshToken, expires } = await token.refresh();
|
|
74
123
|
user.accessToken = accessToken;
|
|
75
124
|
user.refreshToken = refreshToken;
|
|
76
125
|
user.tokenExpiry = expires;
|
|
77
126
|
await user.save();
|
|
127
|
+
console.log('token refreshing finished')
|
|
78
128
|
}
|
|
79
129
|
|
|
80
130
|
}
|
package/lib/util.js
CHANGED
|
@@ -1,40 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
const tzlookup = require('tz-lookup');
|
|
3
|
-
const { State } = require('country-state-city');
|
|
4
|
-
const crypto = require('crypto');
|
|
5
|
-
|
|
6
|
-
function getTimeZone(countryCode, stateCode) {
|
|
7
|
-
const state = State.getStateByCodeAndCountry(stateCode, countryCode);
|
|
8
|
-
if (!state) {
|
|
9
|
-
return 'Unknown timezone';
|
|
10
|
-
}
|
|
11
|
-
const timezone = tzlookup(state.latitude, state.longitude);
|
|
12
|
-
return timezone;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
function getHashValue(string, secretKey) {
|
|
17
|
-
return crypto.createHash('sha256').update(
|
|
18
|
-
`${string}:${secretKey}`
|
|
19
|
-
).digest('hex');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function secondsToHoursMinutesSeconds(seconds) {
|
|
23
|
-
// If not a number, return the input directly
|
|
24
|
-
if (isNaN(seconds)) {
|
|
25
|
-
return seconds;
|
|
26
|
-
}
|
|
27
|
-
const hours = Math.floor(seconds / 3600);
|
|
28
|
-
const hoursString = hours > 0 ? `${hours} ${hours > 1 ? 'hours' : 'hour'}` : '';
|
|
29
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
30
|
-
const minutesString = minutes > 0 ? `${minutes} ${minutes > 1 ? 'minutes' : 'minute'}` : '';
|
|
31
|
-
const remainingSeconds = seconds % 60;
|
|
32
|
-
const secondsString = remainingSeconds > 0 ? `${remainingSeconds} ${remainingSeconds > 1 ? 'seconds' : 'second'}` : '';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
|
|
2
|
+
const tzlookup = require('tz-lookup');
|
|
3
|
+
const { State } = require('country-state-city');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
|
|
6
|
+
function getTimeZone(countryCode, stateCode) {
|
|
7
|
+
const state = State.getStateByCodeAndCountry(stateCode, countryCode);
|
|
8
|
+
if (!state) {
|
|
9
|
+
return 'Unknown timezone';
|
|
10
|
+
}
|
|
11
|
+
const timezone = tzlookup(state.latitude, state.longitude);
|
|
12
|
+
return timezone;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function getHashValue(string, secretKey) {
|
|
17
|
+
return crypto.createHash('sha256').update(
|
|
18
|
+
`${string}:${secretKey}`
|
|
19
|
+
).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function secondsToHoursMinutesSeconds(seconds) {
|
|
23
|
+
// If not a number, return the input directly
|
|
24
|
+
if (isNaN(seconds)) {
|
|
25
|
+
return seconds;
|
|
26
|
+
}
|
|
27
|
+
const hours = Math.floor(seconds / 3600);
|
|
28
|
+
const hoursString = hours > 0 ? `${hours} ${hours > 1 ? 'hours' : 'hour'}` : '';
|
|
29
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
30
|
+
const minutesString = minutes > 0 ? `${minutes} ${minutes > 1 ? 'minutes' : 'minute'}` : '';
|
|
31
|
+
const remainingSeconds = seconds % 60;
|
|
32
|
+
const secondsString = remainingSeconds > 0 ? `${remainingSeconds} ${remainingSeconds > 1 ? 'seconds' : 'second'}` : '';
|
|
33
|
+
if (!hoursString && !minutesString && !secondsString) {
|
|
34
|
+
return '0 seconds';
|
|
35
|
+
}
|
|
36
|
+
const resultString = [hoursString, minutesString, secondsString].filter(Boolean).join(', ');
|
|
37
|
+
return resultString;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.getTimeZone = getTimeZone;
|
|
41
|
+
exports.getHashValue = getHashValue;
|
|
42
|
+
exports.secondsToHoursMinutesSeconds = secondsToHoursMinutesSeconds;
|
|
43
|
+
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const Sequelize = require('sequelize');
|
|
2
|
-
const { sequelize } = require('./sequelize');
|
|
3
|
-
|
|
4
|
-
// Model for User data
|
|
5
|
-
exports.AdminConfigModel = sequelize.define('adminConfigs', {
|
|
6
|
-
// hashed rc account ID
|
|
7
|
-
id: {
|
|
8
|
-
type: Sequelize.STRING,
|
|
9
|
-
primaryKey: true,
|
|
10
|
-
},
|
|
11
|
-
userSettings: {
|
|
12
|
-
type: Sequelize.JSON
|
|
13
|
-
},
|
|
14
|
-
customAdapter: {
|
|
15
|
-
type: Sequelize.JSON
|
|
16
|
-
}
|
|
17
|
-
});
|
|
1
|
+
const Sequelize = require('sequelize');
|
|
2
|
+
const { sequelize } = require('./sequelize');
|
|
3
|
+
|
|
4
|
+
// Model for User data
|
|
5
|
+
exports.AdminConfigModel = sequelize.define('adminConfigs', {
|
|
6
|
+
// hashed rc account ID
|
|
7
|
+
id: {
|
|
8
|
+
type: Sequelize.STRING,
|
|
9
|
+
primaryKey: true,
|
|
10
|
+
},
|
|
11
|
+
userSettings: {
|
|
12
|
+
type: Sequelize.JSON
|
|
13
|
+
},
|
|
14
|
+
customAdapter: {
|
|
15
|
+
type: Sequelize.JSON
|
|
16
|
+
}
|
|
17
|
+
});
|
package/models/cacheModel.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
const Sequelize = require('sequelize');
|
|
2
|
-
const { sequelize } = require('./sequelize');
|
|
3
|
-
|
|
4
|
-
// Model for cache data
|
|
5
|
-
exports.CacheModel = sequelize.define('cache', {
|
|
6
|
-
// id = {userId}-{cacheKey}
|
|
7
|
-
id: {
|
|
8
|
-
type: Sequelize.STRING,
|
|
9
|
-
primaryKey: true,
|
|
10
|
-
},
|
|
11
|
-
status: {
|
|
12
|
-
type: Sequelize.STRING,
|
|
13
|
-
},
|
|
14
|
-
userId: {
|
|
15
|
-
type: Sequelize.STRING,
|
|
16
|
-
},
|
|
17
|
-
cacheKey: {
|
|
18
|
-
type: Sequelize.STRING,
|
|
19
|
-
},
|
|
20
|
-
expiry: {
|
|
21
|
-
type: Sequelize.DATE
|
|
22
|
-
}
|
|
23
|
-
});
|
|
1
|
+
const Sequelize = require('sequelize');
|
|
2
|
+
const { sequelize } = require('./sequelize');
|
|
3
|
+
|
|
4
|
+
// Model for cache data
|
|
5
|
+
exports.CacheModel = sequelize.define('cache', {
|
|
6
|
+
// id = {userId}-{cacheKey}
|
|
7
|
+
id: {
|
|
8
|
+
type: Sequelize.STRING,
|
|
9
|
+
primaryKey: true,
|
|
10
|
+
},
|
|
11
|
+
status: {
|
|
12
|
+
type: Sequelize.STRING,
|
|
13
|
+
},
|
|
14
|
+
userId: {
|
|
15
|
+
type: Sequelize.STRING,
|
|
16
|
+
},
|
|
17
|
+
cacheKey: {
|
|
18
|
+
type: Sequelize.STRING,
|
|
19
|
+
},
|
|
20
|
+
expiry: {
|
|
21
|
+
type: Sequelize.DATE
|
|
22
|
+
}
|
|
23
|
+
});
|
package/models/callLogModel.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
const Sequelize = require('sequelize');
|
|
2
|
-
const { sequelize } = require('./sequelize');
|
|
3
|
-
|
|
4
|
-
// Model for User data
|
|
5
|
-
exports.CallLogModel = sequelize.define('callLogs', {
|
|
6
|
-
// callId
|
|
7
|
-
id: {
|
|
8
|
-
type: Sequelize.STRING,
|
|
9
|
-
primaryKey: true,
|
|
10
|
-
},
|
|
11
|
-
sessionId: {
|
|
12
|
-
type: Sequelize.STRING,
|
|
13
|
-
primaryKey: true,
|
|
14
|
-
},
|
|
15
|
-
platform: {
|
|
16
|
-
type: Sequelize.STRING,
|
|
17
|
-
},
|
|
18
|
-
thirdPartyLogId: {
|
|
19
|
-
type: Sequelize.STRING,
|
|
20
|
-
},
|
|
21
|
-
userId: {
|
|
22
|
-
type: Sequelize.STRING,
|
|
23
|
-
},
|
|
24
|
-
contactId: {
|
|
25
|
-
type: Sequelize.STRING,
|
|
26
|
-
}
|
|
27
|
-
});
|
|
1
|
+
const Sequelize = require('sequelize');
|
|
2
|
+
const { sequelize } = require('./sequelize');
|
|
3
|
+
|
|
4
|
+
// Model for User data
|
|
5
|
+
exports.CallLogModel = sequelize.define('callLogs', {
|
|
6
|
+
// callId
|
|
7
|
+
id: {
|
|
8
|
+
type: Sequelize.STRING,
|
|
9
|
+
primaryKey: true,
|
|
10
|
+
},
|
|
11
|
+
sessionId: {
|
|
12
|
+
type: Sequelize.STRING,
|
|
13
|
+
primaryKey: true,
|
|
14
|
+
},
|
|
15
|
+
platform: {
|
|
16
|
+
type: Sequelize.STRING,
|
|
17
|
+
},
|
|
18
|
+
thirdPartyLogId: {
|
|
19
|
+
type: Sequelize.STRING,
|
|
20
|
+
},
|
|
21
|
+
userId: {
|
|
22
|
+
type: Sequelize.STRING,
|
|
23
|
+
},
|
|
24
|
+
contactId: {
|
|
25
|
+
type: Sequelize.STRING,
|
|
26
|
+
}
|
|
27
|
+
});
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
const dynamoose = require('dynamoose');
|
|
2
|
-
|
|
3
|
-
const lockSchema = new dynamoose.Schema({
|
|
4
|
-
userId: {
|
|
5
|
-
type: String,
|
|
6
|
-
hashKey: true
|
|
7
|
-
},
|
|
8
|
-
ttl: {
|
|
9
|
-
type: Number
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const tableOptions = {
|
|
14
|
-
prefix: process.env.DYNAMODB_TABLE_PREFIX,
|
|
15
|
-
expires: 60 // 60 seconds
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
if (process.env.NODE_ENV === 'production') {
|
|
19
|
-
tableOptions.create = false;
|
|
20
|
-
tableOptions.waitForActive = false;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const Lock = dynamoose.model('-token-refresh-lock', lockSchema, tableOptions);
|
|
24
|
-
|
|
1
|
+
const dynamoose = require('dynamoose');
|
|
2
|
+
|
|
3
|
+
const lockSchema = new dynamoose.Schema({
|
|
4
|
+
userId: {
|
|
5
|
+
type: String,
|
|
6
|
+
hashKey: true
|
|
7
|
+
},
|
|
8
|
+
ttl: {
|
|
9
|
+
type: Number
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const tableOptions = {
|
|
14
|
+
prefix: process.env.DYNAMODB_TABLE_PREFIX,
|
|
15
|
+
expires: 60 // 60 seconds
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (process.env.NODE_ENV === 'production') {
|
|
19
|
+
tableOptions.create = false;
|
|
20
|
+
tableOptions.waitForActive = false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Lock = dynamoose.model('-token-refresh-lock', lockSchema, tableOptions);
|
|
24
|
+
|
|
25
25
|
exports.Lock = Lock;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const dynamoose = require('dynamoose');
|
|
2
|
+
|
|
3
|
+
const noteCacheSchema = new dynamoose.Schema({
|
|
4
|
+
sessionId: {
|
|
5
|
+
type: String,
|
|
6
|
+
hashKey: true,
|
|
7
|
+
},
|
|
8
|
+
note: {
|
|
9
|
+
type: String,
|
|
10
|
+
required: true,
|
|
11
|
+
},
|
|
12
|
+
ttl: {
|
|
13
|
+
type: Number,
|
|
14
|
+
required: true,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const tableOptions = {
|
|
19
|
+
prefix: process.env.DYNAMODB_TABLE_PREFIX,
|
|
20
|
+
expires: 60 // 60 seconds
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (process.env.NODE_ENV === 'production') {
|
|
24
|
+
tableOptions.create = false;
|
|
25
|
+
tableOptions.waitForActive = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const NoteCache = dynamoose.model('-note-cache', noteCacheSchema, tableOptions);
|
|
29
|
+
|
|
30
|
+
exports.NoteCache = NoteCache;
|