Skip to content

Commit c4d69f4

Browse files
chore:
1 parent d70a7b7 commit c4d69f4

File tree

5 files changed

+213
-146
lines changed

5 files changed

+213
-146
lines changed
Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,40 @@
1+
import type { ISetting } from '@rocket.chat/core-typings';
2+
import { ajv, validateForbiddenErrorResponse, validateUnauthorizedErrorResponse } from '@rocket.chat/rest-typings';
3+
14
import { API } from '../../../../api/server';
5+
import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass';
26
import { findIntegrationSettings } from '../../../server/api/lib/integrations';
37

4-
API.v1.addRoute(
8+
const livechatIntegrationsEndpoints = API.v1.get(
59
'livechat/integrations.settings',
6-
{ authRequired: true, permissionsRequired: ['view-livechat-manager'] },
710
{
8-
async get() {
9-
return API.v1.success(await findIntegrationSettings());
11+
authRequired: true,
12+
permissionsRequired: ['view-livechat-manager'],
13+
query: undefined,
14+
response: {
15+
401: validateUnauthorizedErrorResponse,
16+
403: validateForbiddenErrorResponse,
17+
200: ajv.compile<{ settings: ISetting[]; success: boolean }>({
18+
type: 'object',
19+
properties: {
20+
settings: {
21+
type: 'array',
22+
items: { $ref: '#/components/schemas/ISetting' },
23+
},
24+
success: { type: 'boolean', enum: [true] },
25+
},
26+
required: ['settings', 'success'],
27+
}),
1028
},
1129
},
30+
async function action() {
31+
return API.v1.success(await findIntegrationSettings());
32+
},
1233
);
34+
35+
type LivechatIntegrationsEndpoints = ExtractRoutesFromAPI<typeof livechatIntegrationsEndpoints>;
36+
37+
declare module '@rocket.chat/rest-typings' {
38+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface
39+
interface Endpoints extends LivechatIntegrationsEndpoints { }
40+
}
Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,71 @@
1-
import { GETLivechatConfigRouting, isGETLivechatConfigParams } from '@rocket.chat/rest-typings';
1+
import type { ILivechatAgent, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';
2+
import { ajv, GETLivechatConfigRouting, validateUnauthorizedErrorResponse } from '@rocket.chat/rest-typings';
23
import mem from 'mem';
34

45
import { API } from '../../../../api/server';
56
import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass';
6-
import { settings as serverSettings } from '../../../../settings/server';
7+
import { settings as serverSettings } from '../../../../settings/server/index';
78
import { RoutingManager } from '../../lib/RoutingManager';
89
import { online } from '../../lib/service-status';
910
import { settings, findOpenRoom, getExtraConfigInfo, findAgent, findGuestWithoutActivity } from '../lib/livechat';
1011

12+
type GETLivechatConfigParams = {
13+
token?: string;
14+
department?: string;
15+
businessUnit?: string;
16+
};
17+
18+
const GETLivechatConfigParamsSchema = {
19+
type: 'object',
20+
properties: {
21+
token: {
22+
type: 'string',
23+
nullable: true,
24+
},
25+
department: {
26+
type: 'string',
27+
nullable: true,
28+
},
29+
businessUnit: {
30+
type: 'string',
31+
nullable: true,
32+
},
33+
},
34+
additionalProperties: false,
35+
};
36+
37+
const isGETLivechatConfigParams = ajv.compile<GETLivechatConfigParams>(GETLivechatConfigParamsSchema);
38+
1139
const cachedSettings = mem(settings, { maxAge: process.env.TEST_MODE === 'true' ? 1 : 1000, cacheKey: JSON.stringify });
1240

13-
API.v1.addRoute(
14-
'livechat/config',
15-
{ validateParams: isGETLivechatConfigParams },
16-
{
17-
async get() {
41+
const livechatConfigEndpoints = API.v1
42+
.get(
43+
'livechat/config',
44+
{
45+
query: isGETLivechatConfigParams,
46+
response: {
47+
200: ajv.compile<{
48+
config: { [k: string]: string | boolean } & { room?: IOmnichannelRoom; agent?: ILivechatAgent; guest?: ILivechatVisitor };
49+
success: boolean;
50+
}>({
51+
type: 'object',
52+
properties: {
53+
config: {
54+
type: 'object',
55+
properties: {
56+
room: { $ref: '#/components/schemas/IOmnichannelRoom' },
57+
agent: { $ref: '#/components/schemas/ILivechatAgent' },
58+
guest: { $ref: '#/components/schemas/ILivechatVisitor' },
59+
},
60+
additionalProperties: true,
61+
},
62+
success: { type: 'boolean', enum: [true] },
63+
},
64+
required: ['config', 'success'],
65+
}),
66+
},
67+
},
68+
async function action() {
1869
const enabled = serverSettings.get<boolean>('Livechat_enabled');
1970

2071
if (!enabled) {
@@ -38,27 +89,26 @@ API.v1.addRoute(
3889
config: { ...config, online: status, ...extraInfo, ...(guest && { guest }), ...(room && { room }), ...(agent && { agent }) },
3990
});
4091
},
41-
},
42-
);
43-
44-
const livechatConfigEndpoints = API.v1.get(
45-
'livechat/config/routing',
46-
{
47-
response: {
48-
200: GETLivechatConfigRouting,
92+
)
93+
.get(
94+
'livechat/config/routing',
95+
{
96+
authRequired: true,
97+
response: {
98+
200: GETLivechatConfigRouting,
99+
401: validateUnauthorizedErrorResponse,
100+
},
49101
},
50-
authRequired: true,
51-
},
52-
async function action() {
53-
const config = RoutingManager.getConfig();
102+
async function action() {
103+
const config = RoutingManager.getConfig();
54104

55-
return API.v1.success({ config });
56-
},
57-
);
105+
return API.v1.success({ config });
106+
},
107+
);
58108

59109
type LivechatConfigEndpoints = ExtractRoutesFromAPI<typeof livechatConfigEndpoints>;
60110

61111
declare module '@rocket.chat/rest-typings' {
62-
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
63-
interface Endpoints extends LivechatConfigEndpoints {}
112+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface
113+
interface Endpoints extends LivechatConfigEndpoints { }
64114
}
Lines changed: 90 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,114 @@
11
import { Logger } from '@rocket.chat/logger';
2+
import { ajv, validateUnauthorizedErrorResponse } from '@rocket.chat/rest-typings';
23
import type { ExtendedFetchOptions } from '@rocket.chat/server-fetch';
34
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
45

56
import { API } from '../../../../api/server';
7+
import type { ExtractRoutesFromAPI } from '../../../../api/server/ApiClass';
68
import { settings } from '../../../../settings/server';
79

810
const logger = new Logger('WebhookTest');
911

10-
API.v1.addRoute(
12+
const livechatWebhookEndpoints = API.v1.post(
1113
'livechat/webhook.test',
12-
{ authRequired: true, permissionsRequired: ['view-livechat-webhooks'] },
1314
{
14-
async post() {
15-
const sampleData = {
16-
type: 'LivechatSession',
17-
_id: 'fasd6f5a4sd6f8a4sdf',
18-
label: 'title',
19-
topic: 'asiodojf',
20-
createdAt: new Date(),
21-
lastMessageAt: new Date(),
22-
tags: ['tag1', 'tag2', 'tag3'],
15+
authRequired: true,
16+
permissionsRequired: ['view-livechat-webhooks'],
17+
response: {
18+
401: validateUnauthorizedErrorResponse,
19+
200: ajv.compile<void>({
20+
type: 'object',
21+
properties: {
22+
success: { type: 'boolean', enum: [true] },
23+
},
24+
required: ['success'],
25+
}),
26+
},
27+
},
28+
async function action() {
29+
const sampleData = {
30+
type: 'LivechatSession',
31+
_id: 'fasd6f5a4sd6f8a4sdf',
32+
label: 'title',
33+
topic: 'asiodojf',
34+
createdAt: new Date(),
35+
lastMessageAt: new Date(),
36+
tags: ['tag1', 'tag2', 'tag3'],
37+
customFields: {
38+
productId: '123456',
39+
},
40+
visitor: {
41+
_id: '',
42+
name: 'visitor name',
43+
username: 'visitor-username',
44+
department: 'department',
45+
46+
phone: '192873192873',
47+
ip: '123.456.7.89',
48+
browser: 'Chrome',
49+
os: 'Linux',
2350
customFields: {
24-
productId: '123456',
51+
customerId: '123456',
2552
},
26-
visitor: {
27-
_id: '',
28-
name: 'visitor name',
53+
},
54+
agent: {
55+
_id: 'asdf89as6df8',
56+
username: 'agent.username',
57+
name: 'Agent Name',
58+
59+
},
60+
messages: [
61+
{
2962
username: 'visitor-username',
30-
department: 'department',
31-
32-
phone: '192873192873',
33-
ip: '123.456.7.89',
34-
browser: 'Chrome',
35-
os: 'Linux',
36-
customFields: {
37-
customerId: '123456',
38-
},
63+
msg: 'message content',
64+
ts: new Date(),
3965
},
40-
agent: {
41-
_id: 'asdf89as6df8',
66+
{
4267
username: 'agent.username',
43-
name: 'Agent Name',
44-
68+
agentId: 'asdf89as6df8',
69+
msg: 'message content from agent',
70+
ts: new Date(),
4571
},
46-
messages: [
47-
{
48-
username: 'visitor-username',
49-
msg: 'message content',
50-
ts: new Date(),
51-
},
52-
{
53-
username: 'agent.username',
54-
agentId: 'asdf89as6df8',
55-
msg: 'message content from agent',
56-
ts: new Date(),
57-
},
58-
],
59-
};
60-
const options = {
61-
method: 'POST',
62-
headers: {
63-
'X-RocketChat-Livechat-Token': settings.get<string>('Livechat_secret_token'),
64-
'Accept': 'application/json',
65-
},
66-
body: sampleData,
67-
// SECURITY: Webhooks can only be configured by users with enough privileges. It's ok to disable this check here.
68-
ignoreSsrfValidation: true,
69-
size: 10 * 1024 * 1024,
70-
} as ExtendedFetchOptions;
71-
72-
const webhookUrl = settings.get<string>('Livechat_webhookUrl');
72+
],
73+
};
74+
const options = {
75+
method: 'POST',
76+
headers: {
77+
'X-RocketChat-Livechat-Token': settings.get<string>('Livechat_secret_token'),
78+
'Accept': 'application/json',
79+
},
80+
body: sampleData,
81+
ignoreSsrfValidation: true,
82+
size: 10 * 1024 * 1024,
83+
} as ExtendedFetchOptions;
7384

74-
if (!webhookUrl) {
75-
return API.v1.failure('Webhook_URL_not_set');
76-
}
85+
const webhookUrl = settings.get<string>('Livechat_webhookUrl');
7786

78-
try {
79-
logger.debug({ msg: 'Testing webhook', webhookUrl });
80-
const request = await fetch(webhookUrl, options);
81-
const response = await request.text();
87+
if (!webhookUrl) {
88+
return API.v1.failure('Webhook_URL_not_set');
89+
}
8290

83-
logger.debug({ msg: 'Webhook response', response });
84-
if (request.status === 200) {
85-
return API.v1.success();
86-
}
91+
try {
92+
logger.debug({ msg: 'Testing webhook', host: new URL(webhookUrl).host });
93+
const request = await fetch(webhookUrl, options);
94+
const response = await request.text();
8795

88-
throw new Error('Invalid status code');
89-
} catch (error) {
90-
logger.error({ msg: 'Error testing webhook', err: error });
91-
throw new Error('error-invalid-webhook-response');
96+
logger.debug({ msg: 'Webhook response', status: request.status });
97+
if (request.status === 200) {
98+
return API.v1.success();
9299
}
93-
},
100+
101+
throw new Error('Invalid status code');
102+
} catch (error) {
103+
logger.error({ msg: 'Error testing webhook', err: error });
104+
throw new Error('error-invalid-webhook-response');
105+
}
94106
},
95107
);
108+
109+
type LivechatWebhookEndpoints = ExtractRoutesFromAPI<typeof livechatWebhookEndpoints>;
110+
111+
declare module '@rocket.chat/rest-typings' {
112+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface
113+
interface Endpoints extends LivechatWebhookEndpoints { }
114+
}

packages/core-typings/src/Ajv.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ import type { CallHistoryItem } from './ICallHistoryItem';
44
import type { ICustomSound } from './ICustomSound';
55
import type { ICustomUserStatus } from './ICustomUserStatus';
66
import type { IInvite } from './IInvite';
7+
import type { ILivechatAgent } from './ILivechatAgent';
8+
import type { ILivechatVisitor } from './ILivechatVisitor';
79
import type { IMessage } from './IMessage';
810
import type { IOAuthApps } from './IOAuthApps';
11+
import type { IOmnichannelRoom } from './IRoom';
912
import type { IPermission } from './IPermission';
1013
import type { ISubscription } from './ISubscription';
1114
import type { SlashCommand } from './SlashCommands';
1215
import type { IMediaCall } from './mediaCalls/IMediaCall';
1316

1417
export const schemas = typia.json.schemas<
1518
[
16-
ISubscription | IInvite | ICustomSound | IMessage | IOAuthApps | IPermission | IMediaCall,
19+
ISubscription | IInvite | ICustomSound | IMessage | IOAuthApps | IPermission | IMediaCall | IOmnichannelRoom | ILivechatAgent | ILivechatVisitor,
1720
CallHistoryItem,
1821
ICustomUserStatus,
1922
SlashCommand,

0 commit comments

Comments
 (0)