mirror of
https://github.com/RocketChat/Rocket.Chat.git
synced 2025-12-28 14:58:55 +00:00
fix: livechat/visitor not updating custom fields some times (#31890)
This commit is contained in:
parent
469afbd4d5
commit
0570f6740a
6
.changeset/happy-pillows-call.md
Normal file
6
.changeset/happy-pillows-call.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@rocket.chat/meteor": patch
|
||||
"@rocket.chat/model-typings": patch
|
||||
---
|
||||
|
||||
Changed logic that process custom fields from visitors when updating its data, making the process more reliable and faster.
|
||||
@ -1,4 +1,4 @@
|
||||
import type { ILivechatVisitor, IRoom } from '@rocket.chat/core-typings';
|
||||
import type { ILivechatCustomField, ILivechatVisitor, IRoom } from '@rocket.chat/core-typings';
|
||||
import { LivechatVisitors as VisitorsRaw, LivechatCustomField, LivechatRooms } from '@rocket.chat/models';
|
||||
import { Match, check } from 'meteor/check';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
@ -68,16 +68,46 @@ API.v1.addRoute('livechat/visitor', {
|
||||
);
|
||||
}
|
||||
|
||||
if (customFields && Array.isArray(customFields)) {
|
||||
for await (const field of customFields) {
|
||||
const customField = await LivechatCustomField.findOneById(field.key);
|
||||
if (!customField) {
|
||||
continue;
|
||||
}
|
||||
const { key, value, overwrite } = field;
|
||||
if (customField.scope === 'visitor' && !(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) {
|
||||
return API.v1.failure();
|
||||
}
|
||||
if (customFields && Array.isArray(customFields) && customFields.length > 0) {
|
||||
const keys = customFields.map((field) => field.key);
|
||||
const errors: string[] = [];
|
||||
|
||||
const processedKeys = await Promise.all(
|
||||
await LivechatCustomField.findByIdsAndScope<Pick<ILivechatCustomField, '_id'>>(keys, 'visitor', {
|
||||
projection: { _id: 1 },
|
||||
})
|
||||
.map(async (field) => {
|
||||
const customField = customFields.find((f) => f.key === field._id);
|
||||
if (!customField) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { key, value, overwrite } = customField;
|
||||
// TODO: Change this to Bulk update
|
||||
if (!(await VisitorsRaw.updateLivechatDataByToken(token, key, value, overwrite))) {
|
||||
errors.push(key);
|
||||
}
|
||||
|
||||
return key;
|
||||
})
|
||||
.toArray(),
|
||||
);
|
||||
|
||||
if (processedKeys.length !== keys.length) {
|
||||
LivechatTyped.logger.warn({
|
||||
msg: 'Some custom fields were not processed',
|
||||
visitorId,
|
||||
missingKeys: keys.filter((key) => !processedKeys.includes(key)),
|
||||
});
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
LivechatTyped.logger.error({
|
||||
msg: 'Error updating custom fields',
|
||||
visitorId,
|
||||
errors,
|
||||
});
|
||||
throw new Error('error-updating-custom-fields');
|
||||
}
|
||||
|
||||
visitor = await VisitorsRaw.findOneEnabledById(visitorId, {});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { ILivechatCustomField, RocketChatRecordDeleted } from '@rocket.chat/core-typings';
|
||||
import type { ILivechatCustomFieldModel } from '@rocket.chat/model-typings';
|
||||
import type { Db, Collection, IndexDescription, FindOptions, FindCursor } from 'mongodb';
|
||||
import type { Db, Collection, IndexDescription, FindOptions, FindCursor, Document } from 'mongodb';
|
||||
|
||||
import { BaseRaw } from './BaseRaw';
|
||||
|
||||
@ -73,4 +73,12 @@ export class LivechatCustomFieldRaw extends BaseRaw<ILivechatCustomField> implem
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
findByIdsAndScope<T extends Document = ILivechatCustomField>(
|
||||
ids: ILivechatCustomField['_id'][],
|
||||
scope: ILivechatCustomField['scope'],
|
||||
options?: FindOptions<ILivechatCustomField>,
|
||||
): FindCursor<T> {
|
||||
return this.find<T>({ _id: { $in: ids }, scope }, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,6 +115,105 @@ describe('LIVECHAT - visitors', function () {
|
||||
expect(body2.visitor).to.have.property('phone');
|
||||
expect(body2.visitor.phone[0].phoneNumber).to.equal(phone);
|
||||
});
|
||||
it('should update a visitor custom fields when customFields key is provided', async () => {
|
||||
const token = `${new Date().getTime()}-test`;
|
||||
const customFieldName = `new_custom_field_${Date.now()}`;
|
||||
await createCustomField({
|
||||
searchable: true,
|
||||
field: customFieldName,
|
||||
label: customFieldName,
|
||||
defaultValue: 'test_default_address',
|
||||
scope: 'visitor',
|
||||
visibility: 'public',
|
||||
regexp: '',
|
||||
});
|
||||
const { body } = await request.post(api('livechat/visitor')).send({
|
||||
visitor: {
|
||||
token,
|
||||
customFields: [{ key: customFieldName, value: 'Not a real address :)', overwrite: true }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(body).to.have.property('success', true);
|
||||
expect(body).to.have.property('visitor');
|
||||
expect(body.visitor).to.have.property('token', token);
|
||||
expect(body.visitor).to.have.property('livechatData');
|
||||
expect(body.visitor.livechatData).to.have.property(customFieldName, 'Not a real address :)');
|
||||
});
|
||||
|
||||
it('should not update a custom field when it does not exists', async () => {
|
||||
const token = `${new Date().getTime()}-test`;
|
||||
const customFieldName = `new_custom_field_${Date.now()}`;
|
||||
const { body } = await request.post(api('livechat/visitor')).send({
|
||||
visitor: {
|
||||
token,
|
||||
customFields: [{ key: customFieldName, value: 'Not a real address :)', overwrite: true }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(body).to.have.property('success', true);
|
||||
expect(body).to.have.property('visitor');
|
||||
expect(body.visitor).to.have.property('token', token);
|
||||
expect(body.visitor).to.not.have.property('livechatData');
|
||||
});
|
||||
|
||||
it('should not update a custom field when the scope of it is not visitor', async () => {
|
||||
const token = `${new Date().getTime()}-test`;
|
||||
const customFieldName = `new_custom_field_${Date.now()}`;
|
||||
await createCustomField({
|
||||
searchable: true,
|
||||
field: customFieldName,
|
||||
label: customFieldName,
|
||||
defaultValue: 'test_default_address',
|
||||
scope: 'room',
|
||||
visibility: 'public',
|
||||
regexp: '',
|
||||
});
|
||||
const { body } = await request.post(api('livechat/visitor')).send({
|
||||
visitor: {
|
||||
token,
|
||||
customFields: [{ key: customFieldName, value: 'Not a real address :)', overwrite: true }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(body).to.have.property('success', true);
|
||||
expect(body).to.have.property('visitor');
|
||||
expect(body.visitor).to.have.property('token', token);
|
||||
expect(body.visitor).to.not.have.property('livechatData');
|
||||
});
|
||||
|
||||
it('should not update a custom field whe the overwrite flag is false', async () => {
|
||||
const token = `${new Date().getTime()}-test`;
|
||||
const customFieldName = `new_custom_field_${Date.now()}`;
|
||||
await createCustomField({
|
||||
searchable: true,
|
||||
field: customFieldName,
|
||||
label: customFieldName,
|
||||
defaultValue: 'test_default_address',
|
||||
scope: 'visitor',
|
||||
visibility: 'public',
|
||||
regexp: '',
|
||||
});
|
||||
await request.post(api('livechat/visitor')).send({
|
||||
visitor: {
|
||||
token,
|
||||
customFields: [{ key: customFieldName, value: 'Not a real address :)', overwrite: true }],
|
||||
},
|
||||
});
|
||||
|
||||
const { body } = await request.post(api('livechat/visitor')).send({
|
||||
visitor: {
|
||||
token,
|
||||
customFields: [{ key: customFieldName, value: 'This should not change!', overwrite: false }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(body).to.have.property('success', true);
|
||||
expect(body).to.have.property('visitor');
|
||||
expect(body.visitor).to.have.property('token', token);
|
||||
expect(body.visitor).to.have.property('livechatData');
|
||||
expect(body.visitor.livechatData).to.have.property(customFieldName, 'Not a real address :)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('livechat/visitors.info', () => {
|
||||
|
||||
@ -34,4 +34,9 @@ export interface ILivechatCustomFieldModel extends IBaseModel<ILivechatCustomFie
|
||||
visibility: ILivechatCustomField['visibility'],
|
||||
extraData: any,
|
||||
): Promise<ILivechatCustomField>;
|
||||
findByIdsAndScope<T extends Document = ILivechatCustomField>(
|
||||
ids: ILivechatCustomField['_id'][],
|
||||
scope: ILivechatCustomField['scope'],
|
||||
options?: FindOptions<ILivechatCustomField>,
|
||||
): FindCursor<T>;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user