@app-connect/core 1.7.16 → 1.7.18
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/handlers/admin.js +23 -1
- package/handlers/contact.js +33 -0
- package/handlers/disposition.js +11 -0
- package/handlers/log.js +82 -7
- package/index.js +108 -55
- package/lib/oauth.js +22 -15
- package/package.json +72 -72
- package/releaseNotes.json +16 -0
- package/test/handlers/log.test.js +225 -0
- package/test/setup.js +176 -176
package/lib/oauth.js
CHANGED
|
@@ -101,41 +101,48 @@ async function checkAndRefreshAccessToken(oauthApp, user, tokenLockTimeout = 20)
|
|
|
101
101
|
try {
|
|
102
102
|
const startRefreshTime = moment();
|
|
103
103
|
const token = oauthApp.createToken(user.accessToken, user.refreshToken);
|
|
104
|
-
|
|
104
|
+
logger.info('token refreshing...')
|
|
105
105
|
const { accessToken, refreshToken, expires } = await token.refresh();
|
|
106
106
|
user.accessToken = accessToken;
|
|
107
107
|
user.refreshToken = refreshToken;
|
|
108
108
|
user.tokenExpiry = expires;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
try {
|
|
110
|
+
await user.save();
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
return handleDatabaseError(error, 'Error saving user');
|
|
114
|
+
}
|
|
115
115
|
if (newLock) {
|
|
116
116
|
const deletionStartTime = moment();
|
|
117
117
|
await newLock.delete();
|
|
118
118
|
const deletionEndTime = moment();
|
|
119
|
-
|
|
119
|
+
logger.info(`lock deleted in ${deletionEndTime.diff(deletionStartTime)}ms`)
|
|
120
120
|
}
|
|
121
121
|
const endRefreshTime = moment();
|
|
122
|
-
|
|
122
|
+
logger.info(`token refreshing finished in ${endRefreshTime.diff(startRefreshTime)}ms`)
|
|
123
123
|
}
|
|
124
124
|
catch (e) {
|
|
125
125
|
console.log('token refreshing failed', e.stack)
|
|
126
126
|
if (newLock) {
|
|
127
127
|
await newLock.delete();
|
|
128
128
|
}
|
|
129
|
+
return null;
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
// case: run withou token refresh lock
|
|
132
133
|
else {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
try {
|
|
135
|
+
logger.info('token refreshing...')
|
|
136
|
+
const token = oauthApp.createToken(user.accessToken, user.refreshToken);
|
|
137
|
+
const { accessToken, refreshToken, expires } = await token.refresh();
|
|
138
|
+
user.accessToken = accessToken;
|
|
139
|
+
user.refreshToken = refreshToken;
|
|
140
|
+
user.tokenExpiry = expires;
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
console.log('token refreshing failed', e.stack)
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
139
146
|
try {
|
|
140
147
|
await user.save();
|
|
141
148
|
}
|
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@app-connect/core",
|
|
3
|
-
"version": "1.7.
|
|
4
|
-
"description": "RingCentral App Connect Core",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/ringcentral/rc-unified-crm-extension.git"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"RingCentral",
|
|
12
|
-
"App Connect"
|
|
13
|
-
],
|
|
14
|
-
"author": "RingCentral Labs",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"peerDependencies": {
|
|
17
|
-
"axios": "^1.12.2",
|
|
18
|
-
"express": "^4.22.1",
|
|
19
|
-
"moment": "^2.29.4",
|
|
20
|
-
"moment-timezone": "^0.5.39",
|
|
21
|
-
"pg": "^8.8.0",
|
|
22
|
-
"sequelize": "^6.29.0"
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"@aws-sdk/client-dynamodb": "^3.751.0",
|
|
26
|
-
"@aws-sdk/client-s3": "^3.947.0",
|
|
27
|
-
"@aws-sdk/s3-request-presigner": "^3.947.0",
|
|
28
|
-
"@modelcontextprotocol/sdk": "^1.21.1",
|
|
29
|
-
"awesome-phonenumber": "^5.6.0",
|
|
30
|
-
"body-parser": "^1.20.4",
|
|
31
|
-
"body-parser-xml": "^2.0.5",
|
|
32
|
-
"client-oauth2": "^4.3.3",
|
|
33
|
-
"cors": "^2.8.5",
|
|
34
|
-
"country-state-city": "^3.2.1",
|
|
35
|
-
"dotenv": "^16.0.3",
|
|
36
|
-
"dynamoose": "^4.0.3",
|
|
37
|
-
"jsonwebtoken": "^9.0.0",
|
|
38
|
-
"mixpanel": "^0.18.0",
|
|
39
|
-
"shortid": "^2.2.17",
|
|
40
|
-
"tz-lookup": "^6.1.25",
|
|
41
|
-
"ua-parser-js": "^1.0.38"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"test": "jest",
|
|
45
|
-
"test:watch": "jest --watch",
|
|
46
|
-
"test:coverage": "jest --coverage",
|
|
47
|
-
"test:ci": "jest --ci --coverage --watchAll=false"
|
|
48
|
-
},
|
|
49
|
-
"devDependencies": {
|
|
50
|
-
"@eslint/js": "^9.22.0",
|
|
51
|
-
"@octokit/rest": "^19.0.5",
|
|
52
|
-
"axios": "^1.12.2",
|
|
53
|
-
"eslint": "^9.22.0",
|
|
54
|
-
"express": "^4.22.1",
|
|
55
|
-
"globals": "^16.0.0",
|
|
56
|
-
"jest": "^29.3.1",
|
|
57
|
-
"moment": "^2.29.4",
|
|
58
|
-
"moment-timezone": "^0.5.39",
|
|
59
|
-
"nock": "^13.2.9",
|
|
60
|
-
"pg": "^8.8.0",
|
|
61
|
-
"sequelize": "^6.29.0",
|
|
62
|
-
"sqlite3": "^5.1.2",
|
|
63
|
-
"supertest": "^6.3.1"
|
|
64
|
-
},
|
|
65
|
-
"overrides": {
|
|
66
|
-
"js-object-utilities": "2.2.1"
|
|
67
|
-
},
|
|
68
|
-
"bugs": {
|
|
69
|
-
"url": "https://github.com/ringcentral/rc-unified-crm-extension/issues"
|
|
70
|
-
},
|
|
71
|
-
"homepage": "https://github.com/ringcentral/rc-unified-crm-extension#readme"
|
|
72
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@app-connect/core",
|
|
3
|
+
"version": "1.7.18",
|
|
4
|
+
"description": "RingCentral App Connect Core",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ringcentral/rc-unified-crm-extension.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"RingCentral",
|
|
12
|
+
"App Connect"
|
|
13
|
+
],
|
|
14
|
+
"author": "RingCentral Labs",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"axios": "^1.12.2",
|
|
18
|
+
"express": "^4.22.1",
|
|
19
|
+
"moment": "^2.29.4",
|
|
20
|
+
"moment-timezone": "^0.5.39",
|
|
21
|
+
"pg": "^8.8.0",
|
|
22
|
+
"sequelize": "^6.29.0"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@aws-sdk/client-dynamodb": "^3.751.0",
|
|
26
|
+
"@aws-sdk/client-s3": "^3.947.0",
|
|
27
|
+
"@aws-sdk/s3-request-presigner": "^3.947.0",
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.21.1",
|
|
29
|
+
"awesome-phonenumber": "^5.6.0",
|
|
30
|
+
"body-parser": "^1.20.4",
|
|
31
|
+
"body-parser-xml": "^2.0.5",
|
|
32
|
+
"client-oauth2": "^4.3.3",
|
|
33
|
+
"cors": "^2.8.5",
|
|
34
|
+
"country-state-city": "^3.2.1",
|
|
35
|
+
"dotenv": "^16.0.3",
|
|
36
|
+
"dynamoose": "^4.0.3",
|
|
37
|
+
"jsonwebtoken": "^9.0.0",
|
|
38
|
+
"mixpanel": "^0.18.0",
|
|
39
|
+
"shortid": "^2.2.17",
|
|
40
|
+
"tz-lookup": "^6.1.25",
|
|
41
|
+
"ua-parser-js": "^1.0.38"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "jest",
|
|
45
|
+
"test:watch": "jest --watch",
|
|
46
|
+
"test:coverage": "jest --coverage",
|
|
47
|
+
"test:ci": "jest --ci --coverage --watchAll=false"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/js": "^9.22.0",
|
|
51
|
+
"@octokit/rest": "^19.0.5",
|
|
52
|
+
"axios": "^1.12.2",
|
|
53
|
+
"eslint": "^9.22.0",
|
|
54
|
+
"express": "^4.22.1",
|
|
55
|
+
"globals": "^16.0.0",
|
|
56
|
+
"jest": "^29.3.1",
|
|
57
|
+
"moment": "^2.29.4",
|
|
58
|
+
"moment-timezone": "^0.5.39",
|
|
59
|
+
"nock": "^13.2.9",
|
|
60
|
+
"pg": "^8.8.0",
|
|
61
|
+
"sequelize": "^6.29.0",
|
|
62
|
+
"sqlite3": "^5.1.2",
|
|
63
|
+
"supertest": "^6.3.1"
|
|
64
|
+
},
|
|
65
|
+
"overrides": {
|
|
66
|
+
"js-object-utilities": "2.2.1"
|
|
67
|
+
},
|
|
68
|
+
"bugs": {
|
|
69
|
+
"url": "https://github.com/ringcentral/rc-unified-crm-extension/issues"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://github.com/ringcentral/rc-unified-crm-extension#readme"
|
|
72
|
+
}
|
package/releaseNotes.json
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
+
"1.7.18": {
|
|
3
|
+
"global": [
|
|
4
|
+
{
|
|
5
|
+
"type": "New",
|
|
6
|
+
"description": "Support for Group SMS logging"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"type": "Better",
|
|
10
|
+
"description": "User session will log be revoked is token refresh fails"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "Fix",
|
|
14
|
+
"description": "Contact call pop issue"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
2
18
|
"1.7.16": {
|
|
3
19
|
"global": [
|
|
4
20
|
{
|
|
@@ -29,6 +29,7 @@ const logHandler = require('../../handlers/log');
|
|
|
29
29
|
const { CallLogModel } = require('../../models/callLogModel');
|
|
30
30
|
const { MessageLogModel } = require('../../models/messageLogModel');
|
|
31
31
|
const { UserModel } = require('../../models/userModel');
|
|
32
|
+
const { AccountDataModel } = require('../../models/accountDataModel');
|
|
32
33
|
const connectorRegistry = require('../../connector/registry');
|
|
33
34
|
const oauth = require('../../lib/oauth');
|
|
34
35
|
const { composeCallLog } = require('../../lib/callLogComposer');
|
|
@@ -40,12 +41,14 @@ describe('Log Handler', () => {
|
|
|
40
41
|
await CallLogModel.sync({ force: true });
|
|
41
42
|
await MessageLogModel.sync({ force: true });
|
|
42
43
|
await UserModel.sync({ force: true });
|
|
44
|
+
await AccountDataModel.sync({ force: true });
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
afterEach(async () => {
|
|
46
48
|
await CallLogModel.destroy({ where: {} });
|
|
47
49
|
await MessageLogModel.destroy({ where: {} });
|
|
48
50
|
await UserModel.destroy({ where: {} });
|
|
51
|
+
await AccountDataModel.destroy({ where: {} });
|
|
49
52
|
jest.clearAllMocks();
|
|
50
53
|
});
|
|
51
54
|
|
|
@@ -742,6 +745,228 @@ describe('Log Handler', () => {
|
|
|
742
745
|
expect(mockConnector.createMessageLog).toHaveBeenCalledTimes(0);
|
|
743
746
|
expect(mockConnector.updateMessageLog).toHaveBeenCalledTimes(1);
|
|
744
747
|
});
|
|
748
|
+
|
|
749
|
+
test('should handle group SMS with contactId suffix for message IDs', async () => {
|
|
750
|
+
// Arrange - group SMS has multiple correspondents
|
|
751
|
+
await UserModel.create({
|
|
752
|
+
id: 'test-user-id',
|
|
753
|
+
platform: 'testCRM',
|
|
754
|
+
accessToken: 'test-token',
|
|
755
|
+
rcAccountId: 'rc-account-123',
|
|
756
|
+
platformAdditionalInfo: {}
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
const mockConnector = {
|
|
760
|
+
getAuthType: jest.fn().mockResolvedValue('apiKey'),
|
|
761
|
+
getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
|
|
762
|
+
createMessageLog: jest.fn().mockResolvedValue({
|
|
763
|
+
logId: 'msg-log-group-123',
|
|
764
|
+
returnMessage: { message: 'Message logged', messageType: 'success', ttl: 2000 }
|
|
765
|
+
}),
|
|
766
|
+
updateMessageLog: jest.fn()
|
|
767
|
+
};
|
|
768
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
769
|
+
|
|
770
|
+
const incomingData = {
|
|
771
|
+
logInfo: {
|
|
772
|
+
messages: [{ id: 'msg-group-1', subject: 'Group SMS', direction: 'Outbound', creationTime: new Date() }],
|
|
773
|
+
correspondents: [
|
|
774
|
+
{ phoneNumber: '+1234567890' },
|
|
775
|
+
{ phoneNumber: '+0987654321' }
|
|
776
|
+
],
|
|
777
|
+
conversationId: 'conv-group-123',
|
|
778
|
+
conversationLogId: 'conv-log-group-123'
|
|
779
|
+
},
|
|
780
|
+
contactId: 'contact-456',
|
|
781
|
+
contactType: 'Contact',
|
|
782
|
+
contactName: 'Primary Contact',
|
|
783
|
+
additionalSubmission: {}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
// Act
|
|
787
|
+
const result = await logHandler.createMessageLog({
|
|
788
|
+
platform: 'testCRM',
|
|
789
|
+
userId: 'test-user-id',
|
|
790
|
+
incomingData
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// Assert
|
|
794
|
+
expect(result.successful).toBe(true);
|
|
795
|
+
expect(result.logIds).toContain('msg-group-1-contact-456');
|
|
796
|
+
const savedLog = await MessageLogModel.findOne({ where: { id: 'msg-group-1-contact-456' } });
|
|
797
|
+
expect(savedLog).not.toBeNull();
|
|
798
|
+
expect(savedLog.thirdPartyLogId).toBe('msg-log-group-123');
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
test('should pass correspondents to createMessageLog when group SMS has different contact names', async () => {
|
|
802
|
+
// Arrange - correspondent in cache with different name
|
|
803
|
+
await UserModel.create({
|
|
804
|
+
id: 'test-user-id',
|
|
805
|
+
platform: 'testCRM',
|
|
806
|
+
accessToken: 'test-token',
|
|
807
|
+
rcAccountId: 'rc-account-123',
|
|
808
|
+
platformAdditionalInfo: {}
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
await AccountDataModel.create({
|
|
812
|
+
rcAccountId: 'rc-account-123',
|
|
813
|
+
platformName: 'testCRM',
|
|
814
|
+
dataKey: 'contact-+0987654321',
|
|
815
|
+
data: [{ name: 'Other Contact', id: 'contact-789' }]
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
const mockConnector = {
|
|
819
|
+
getAuthType: jest.fn().mockResolvedValue('apiKey'),
|
|
820
|
+
getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
|
|
821
|
+
createMessageLog: jest.fn().mockResolvedValue({
|
|
822
|
+
logId: 'msg-log-correspondents',
|
|
823
|
+
returnMessage: { message: 'Message logged', messageType: 'success', ttl: 2000 }
|
|
824
|
+
}),
|
|
825
|
+
updateMessageLog: jest.fn()
|
|
826
|
+
};
|
|
827
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
828
|
+
|
|
829
|
+
const incomingData = {
|
|
830
|
+
logInfo: {
|
|
831
|
+
messages: [{ id: 'msg-correspondents', subject: 'Group SMS', direction: 'Outbound', creationTime: new Date() }],
|
|
832
|
+
correspondents: [
|
|
833
|
+
{ phoneNumber: '+1234567890' },
|
|
834
|
+
{ phoneNumber: '+0987654321' }
|
|
835
|
+
],
|
|
836
|
+
conversationId: 'conv-correspondents',
|
|
837
|
+
conversationLogId: 'conv-log-correspondents'
|
|
838
|
+
},
|
|
839
|
+
contactId: 'contact-456',
|
|
840
|
+
contactType: 'Contact',
|
|
841
|
+
contactName: 'Primary Contact',
|
|
842
|
+
additionalSubmission: {}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
// Act
|
|
846
|
+
await logHandler.createMessageLog({
|
|
847
|
+
platform: 'testCRM',
|
|
848
|
+
userId: 'test-user-id',
|
|
849
|
+
incomingData
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
// Assert - createMessageLog should receive correspondents with different name
|
|
853
|
+
expect(mockConnector.createMessageLog).toHaveBeenCalledWith(
|
|
854
|
+
expect.objectContaining({
|
|
855
|
+
correspondents: [[{ name: 'Other Contact', id: 'contact-789' }]]
|
|
856
|
+
})
|
|
857
|
+
);
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
test('should not add correspondent when name matches contactName in group SMS', async () => {
|
|
861
|
+
// Arrange - correspondent in cache with same name as contactName
|
|
862
|
+
await UserModel.create({
|
|
863
|
+
id: 'test-user-id',
|
|
864
|
+
platform: 'testCRM',
|
|
865
|
+
accessToken: 'test-token',
|
|
866
|
+
rcAccountId: 'rc-account-123',
|
|
867
|
+
platformAdditionalInfo: {}
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
await AccountDataModel.create({
|
|
871
|
+
rcAccountId: 'rc-account-123',
|
|
872
|
+
platformName: 'testCRM',
|
|
873
|
+
dataKey: 'contact-+0987654321',
|
|
874
|
+
data: [{ name: 'Primary Contact', id: 'contact-789' }]
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
const mockConnector = {
|
|
878
|
+
getAuthType: jest.fn().mockResolvedValue('apiKey'),
|
|
879
|
+
getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
|
|
880
|
+
createMessageLog: jest.fn().mockResolvedValue({
|
|
881
|
+
logId: 'msg-log-same-name',
|
|
882
|
+
returnMessage: { message: 'Message logged', messageType: 'success', ttl: 2000 }
|
|
883
|
+
}),
|
|
884
|
+
updateMessageLog: jest.fn()
|
|
885
|
+
};
|
|
886
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
887
|
+
|
|
888
|
+
const incomingData = {
|
|
889
|
+
logInfo: {
|
|
890
|
+
messages: [{ id: 'msg-same-name', subject: 'Group SMS', direction: 'Outbound', creationTime: new Date() }],
|
|
891
|
+
correspondents: [
|
|
892
|
+
{ phoneNumber: '+1234567890' },
|
|
893
|
+
{ phoneNumber: '+0987654321' }
|
|
894
|
+
],
|
|
895
|
+
conversationId: 'conv-same-name',
|
|
896
|
+
conversationLogId: 'conv-log-same-name'
|
|
897
|
+
},
|
|
898
|
+
contactId: 'contact-456',
|
|
899
|
+
contactType: 'Contact',
|
|
900
|
+
contactName: 'Primary Contact',
|
|
901
|
+
additionalSubmission: {}
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// Act
|
|
905
|
+
await logHandler.createMessageLog({
|
|
906
|
+
platform: 'testCRM',
|
|
907
|
+
userId: 'test-user-id',
|
|
908
|
+
incomingData
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
// Assert - correspondents should be empty when names match
|
|
912
|
+
expect(mockConnector.createMessageLog).toHaveBeenCalledWith(
|
|
913
|
+
expect.objectContaining({
|
|
914
|
+
correspondents: []
|
|
915
|
+
})
|
|
916
|
+
);
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
test('should use suffixed conversationLogId and conversationId for group SMS', async () => {
|
|
920
|
+
// Arrange
|
|
921
|
+
await UserModel.create({
|
|
922
|
+
id: 'test-user-id',
|
|
923
|
+
platform: 'testCRM',
|
|
924
|
+
accessToken: 'test-token',
|
|
925
|
+
rcAccountId: 'rc-account-123',
|
|
926
|
+
platformAdditionalInfo: {}
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
const mockConnector = {
|
|
930
|
+
getAuthType: jest.fn().mockResolvedValue('apiKey'),
|
|
931
|
+
getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
|
|
932
|
+
createMessageLog: jest.fn().mockResolvedValue({
|
|
933
|
+
logId: 'msg-log-suffix',
|
|
934
|
+
returnMessage: { message: 'Message logged', messageType: 'success', ttl: 2000 }
|
|
935
|
+
}),
|
|
936
|
+
updateMessageLog: jest.fn()
|
|
937
|
+
};
|
|
938
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
939
|
+
|
|
940
|
+
const incomingData = {
|
|
941
|
+
logInfo: {
|
|
942
|
+
messages: [{ id: 'msg-suffix', subject: 'Group SMS', direction: 'Outbound', creationTime: new Date() }],
|
|
943
|
+
correspondents: [
|
|
944
|
+
{ phoneNumber: '+1234567890' },
|
|
945
|
+
{ phoneNumber: '+0987654321' }
|
|
946
|
+
],
|
|
947
|
+
conversationId: 'conv-original',
|
|
948
|
+
conversationLogId: 'conv-log-original'
|
|
949
|
+
},
|
|
950
|
+
contactId: 'contact-999',
|
|
951
|
+
contactType: 'Contact',
|
|
952
|
+
contactName: 'Test Contact',
|
|
953
|
+
additionalSubmission: {}
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// Act
|
|
957
|
+
const result = await logHandler.createMessageLog({
|
|
958
|
+
platform: 'testCRM',
|
|
959
|
+
userId: 'test-user-id',
|
|
960
|
+
incomingData
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
// Assert - message log saved with suffixed conversationLogId
|
|
964
|
+
expect(result.successful).toBe(true);
|
|
965
|
+
const savedLog = await MessageLogModel.findOne({ where: { id: 'msg-suffix-contact-999' } });
|
|
966
|
+
expect(savedLog).not.toBeNull();
|
|
967
|
+
expect(savedLog.conversationLogId).toBe('conv-log-original-contact-999');
|
|
968
|
+
expect(savedLog.conversationId).toBe('conv-original-contact-999');
|
|
969
|
+
});
|
|
745
970
|
});
|
|
746
971
|
|
|
747
972
|
describe('saveNoteCache', () => {
|