Skip to content

Commit

Permalink
fix: broken error messages on room.saveInfo & missing CF validations …
Browse files Browse the repository at this point in the history
…on omni/contact api (#28367)

Co-authored-by: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com>
Co-authored-by: Kevin Aleman <11577696+KevLehman@users.noreply.github.com>
  • Loading branch information
3 people authored May 26, 2023
1 parent eeee52f commit b03fcd9
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-cougars-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fix: broken error messages on room.saveInfo & missing CF validations on omni/contact api
8 changes: 7 additions & 1 deletion apps/meteor/app/livechat/server/api/v1/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,13 @@ API.v1.addRoute(
delete guestData.phone;
}

await Promise.allSettled([Livechat.saveGuest(guestData, this.userId), Livechat.saveRoomInfo(roomData)]);
// We want this both operations to be concurrent, so we have to go with Promise.allSettled
const result = await Promise.allSettled([Livechat.saveGuest(guestData, this.userId), Livechat.saveRoomInfo(roomData)]);

const firstError = result.find((item) => item.status === 'rejected');
if (firstError) {
throw new Error((firstError as PromiseRejectedResult).reason.error);
}

await callbacks.run('livechat.saveInfo', await LivechatRooms.findOneById(roomData._id), {
user: this.user,
Expand Down
42 changes: 33 additions & 9 deletions apps/meteor/app/livechat/server/lib/Contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import type { MatchKeysAndValues, OnlyFieldsOfType } from 'mongodb';
import { LivechatVisitors, Users, LivechatRooms, LivechatCustomField, LivechatInquiry, Rooms, Subscriptions } from '@rocket.chat/models';
import type { ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';

import { trim } from '../../../../lib/utils/stringUtils';
import { i18n } from '../../../utils/lib/i18n';

type RegisterContactProps = {
_id?: string;
token: string;
Expand Down Expand Up @@ -68,16 +71,37 @@ export const Contacts = {
}
}

const allowedCF = await LivechatCustomField.findByScope<Pick<ILivechatCustomField, '_id'>>('visitor', { projection: { _id: 1 } })
.map(({ _id }) => _id)
.toArray();
const allowedCF = LivechatCustomField.findByScope<Pick<ILivechatCustomField, '_id' | 'label' | 'regexp' | 'required'>>('visitor', {
projection: { _id: 1, label: 1, regexp: 1, required: 1 },
});

const livechatData: Record<string, string> = {};

const livechatData = Object.keys(customFields)
.filter((key) => allowedCF.includes(key) && customFields[key] !== '' && customFields[key] !== undefined)
.reduce((obj: Record<string, unknown | string>, key) => {
obj[key] = customFields[key];
return obj;
}, {});
for await (const cf of allowedCF) {
if (!customFields.hasOwnProperty(cf._id)) {
if (cf.required) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
continue;
}
const cfValue: string = trim(customFields[cf._id]);

if (!cfValue || typeof cfValue !== 'string') {
if (cf.required) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
continue;
}

if (cf.regexp) {
const regex = new RegExp(cf.regexp);
if (!regex.test(cfValue)) {
throw new Error(i18n.t('error-invalid-custom-field-value', { field: cf.label }));
}
}

livechatData[cf._id] = cfValue;
}

const updateUser: { $set: MatchKeysAndValues<ILivechatVisitor>; $unset?: OnlyFieldsOfType<ILivechatVisitor> } = {
$set: {
Expand Down
71 changes: 70 additions & 1 deletion apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { LivechatPriorityWeight } from '@rocket.chat/core-typings';
import type { Response } from 'supertest';
import faker from '@faker-js/faker';

import { getCredentials, api, request, credentials } from '../../../data/api-data';
import { getCredentials, api, request, credentials, methodCall } from '../../../data/api-data';
import {
createVisitor,
createLivechatRoom,
Expand Down Expand Up @@ -1600,6 +1600,75 @@ describe('LIVECHAT - rooms', function () {
.expect('Content-Type', 'application/json')
.expect(400);
});
(IS_EE ? it : it.skip)('should throw an error if a valid custom field fails the check', async () => {
await request
.post(methodCall('livechat:saveCustomField'))
.set(credentials)
.send({
message: JSON.stringify({
method: 'livechat:saveCustomField',
params: [
null,
{
field: 'intfield',
label: 'intfield',
scope: 'room',
visibility: 'visible',
regexp: '\\d+',
searchable: true,
type: 'input',
required: false,
defaultValue: '0',
options: '',
public: false,
},
],
id: 'id',
msg: 'method',
}),
})
.expect(200);
const newVisitor = await createVisitor();
const newRoom = await createLivechatRoom(newVisitor.token);

const response = await request
.post(api('livechat/room.saveInfo'))
.set(credentials)
.send({
roomData: {
_id: newRoom._id,
livechatData: { intfield: 'asdasd' },
},
guestData: {
_id: newVisitor._id,
},
})
.expect('Content-Type', 'application/json')
.expect(400);
expect(response.body).to.have.property('success', false);
expect(response.body).to.have.property('error', 'Invalid value for intfield field');
});
(IS_EE ? it : it.skip)('should not throw an error if a valid custom field passes the check', async () => {
const newVisitor = await createVisitor();
const newRoom = await createLivechatRoom(newVisitor.token);

const response2 = await request
.post(api('livechat/room.saveInfo'))
.set(credentials)
.send({
roomData: {
_id: newRoom._id,
livechatData: { intfield: '1' },
},
guestData: {
_id: newVisitor._id,
},
})
.expect('Content-Type', 'application/json')
.expect(200);
expect(response2.body).to.have.property('success', true);
});

(IS_EE ? it : it.skip)('should update room priority', async () => {
await addPermissions({
'save-others-livechat-room-info': ['admin', 'livechat-manager'],
Expand Down

0 comments on commit b03fcd9

Please sign in to comment.