>;
- find(query: Filter, options: FindOptions): FindCursor
;
+ find
(query: Filter, options?: FindOptions): FindCursor
;
find
(query: Filter | undefined = {}, options?: FindOptions): FindCursor> | FindCursor> {
const optionsDef = this.doNotMixInclusionAndExclusionFields(options);
diff --git a/apps/meteor/server/models/raw/LivechatCustomField.ts b/apps/meteor/server/models/raw/LivechatCustomField.ts
index a0402efca92f..be37341a8464 100644
--- a/apps/meteor/server/models/raw/LivechatCustomField.ts
+++ b/apps/meteor/server/models/raw/LivechatCustomField.ts
@@ -17,6 +17,34 @@ export class LivechatCustomFieldRaw extends BaseRaw implem
return this.find({ scope }, options || {});
}
+ findMatchingCustomFields(
+ scope: ILivechatCustomField['scope'],
+ searchable = true,
+ options?: FindOptions,
+ ): FindCursor {
+ const query = {
+ scope,
+ searchable,
+ };
+
+ return this.find(query, options);
+ }
+
+ findMatchingCustomFieldsByIds(
+ ids: ILivechatCustomField['_id'][],
+ scope: ILivechatCustomField['scope'],
+ searchable = true,
+ options?: FindOptions,
+ ): FindCursor {
+ const query = {
+ _id: { $in: ids },
+ scope,
+ searchable,
+ };
+
+ return this.find(query, options);
+ }
+
async createOrUpdateCustomField(
_id: string,
field: string,
diff --git a/apps/meteor/server/models/raw/LivechatVisitors.ts b/apps/meteor/server/models/raw/LivechatVisitors.ts
index 601f344b5f6e..8a1fc40eec72 100644
--- a/apps/meteor/server/models/raw/LivechatVisitors.ts
+++ b/apps/meteor/server/models/raw/LivechatVisitors.ts
@@ -31,6 +31,7 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
{ key: { name: 1 }, sparse: true },
{ key: { username: 1 } },
{ key: { 'contactMananger.username': 1 }, sparse: true },
+ { key: { 'livechatData.$**': 1 } },
];
}
@@ -158,11 +159,12 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
/**
* Find visitors by their email or phone or username or name
*/
- findPaginatedVisitorsByEmailOrPhoneOrNameOrUsername(
+ async findPaginatedVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField(
emailOrPhone: string,
nameOrUsername: RegExp,
- options: FindOptions,
- ): FindPaginated> {
+ allowedCustomFields: string[] = [],
+ options?: FindOptions,
+ ): Promise>> {
const query = {
$or: [
{
@@ -177,12 +179,35 @@ export class LivechatVisitorsRaw extends BaseRaw implements IL
{
username: nameOrUsername,
},
+ // nameorusername is a clean regex, so we should be good
+ ...allowedCustomFields.map((c: string) => ({ [`livechatData.${c}`]: nameOrUsername })),
],
};
return this.findPaginated(query, options);
}
+ async findOneByEmailAndPhoneAndCustomField(
+ email: string | null | undefined,
+ phone: string | null | undefined,
+ customFields?: { [key: string]: RegExp },
+ ): Promise {
+ const query = Object.assign(
+ {},
+ {
+ ...(email && { visitorEmails: { address: email } }),
+ ...(phone && { phone: { phoneNumber: phone } }),
+ ...customFields,
+ },
+ );
+
+ if (Object.keys(query).length === 0) {
+ return null;
+ }
+
+ return this.findOne(query);
+ }
+
async updateLivechatDataByToken(
token: string,
key: string,
diff --git a/apps/meteor/tests/data/livechat/custom-fields.ts b/apps/meteor/tests/data/livechat/custom-fields.ts
new file mode 100644
index 000000000000..ddae4d2b888f
--- /dev/null
+++ b/apps/meteor/tests/data/livechat/custom-fields.ts
@@ -0,0 +1,52 @@
+import type { Response } from 'supertest';
+import { ILivechatCustomField } from '@rocket.chat/core-typings';
+import { credentials, request, methodCall, api } from './../api-data';
+
+export const createCustomField = (customField: ILivechatCustomField) => new Promise((resolve, reject) => {
+ request
+ .get(api('livechat/custom-fields/'+customField.label))
+ .set(credentials)
+ .send()
+ .end((err: Error, res:Response) => {
+ if (err) {
+ reject(err);
+ } else {
+ if (res.body.customField != null && res.body.customField != undefined) {
+ resolve(res.body.customField);
+ }else{
+ request
+ .post(methodCall('livechat:saveCustomField'))
+ .send({
+ message: JSON.stringify({
+ method: 'livechat:saveCustomField',
+ params: [null,customField],
+ id: 'id',
+ msg: 'method',
+ }),
+ })
+ .set(credentials)
+ .end((err: Error, res: Response): void => {
+ if (err) {
+ return reject(err);
+ }
+ resolve(res.body);
+ });
+ }
+ }
+ });
+
+});
+
+export const deleteCustomField = (customFieldID: string) => new Promise((resolve, reject) => {
+ request
+ .post(methodCall('livechat:saveCustomField'))
+ .send(customFieldID)
+ .set(credentials)
+ .end((err: Error, res: Response): void => {
+ if (err) {
+ return reject(err);
+ }
+ resolve(res.body);
+ });
+});
+
diff --git a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
index 8f4ff9df4fdc..1041ef45e35e 100644
--- a/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
+++ b/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts
@@ -1,12 +1,13 @@
/* eslint-env mocha */
import { expect } from 'chai';
-import type { ILivechatAgent, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';
+import type { ILivechatAgent, ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings';
import type { Response } from 'supertest';
import { getCredentials, api, request, credentials } from '../../../data/api-data';
import { updatePermission, updateSetting } from '../../../data/permissions.helper';
import { makeAgentAvailable, createAgent, createLivechatRoom, createVisitor, takeInquiry } from '../../../data/livechat/rooms';
+import { createCustomField, deleteCustomField } from '../../../data/livechat/custom-fields';
describe('LIVECHAT - visitors', function () {
this.retries(0);
@@ -31,28 +32,34 @@ describe('LIVECHAT - visitors', function () {
describe('livechat/visitors.info', () => {
it('should return an "unauthorized error" when the user does not have the necessary permission', (done) => {
- updatePermission('view-l-room', []).then(() => {
- request
- .get(api('livechat/visitors.info?visitorId=invalid'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(403)
- .end(done);
- });
+ updatePermission('view-l-room', [])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.info?visitorId=invalid'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(403)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ expect(res.body.error).to.be.equal('error-not-authorized');
+ });
+ })
+ .then(() => done());
});
it('should return an "visitor not found error" when the visitor doe snot exists', (done) => {
- updatePermission('view-l-room', ['admin']).then(() => {
- request
- .get(api('livechat/visitors.info?visitorId=invalid'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(400)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', false);
- expect(res.body.error).to.be.equal('visitor-not-found');
- })
- .end(done);
- });
+ updatePermission('view-l-room', ['admin'])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.info?visitorId=invalid'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ expect(res.body.error).to.be.equal('visitor-not-found');
+ });
+ })
+ .then(() => done());
});
it('should return the visitor info', (done) => {
request
@@ -70,46 +77,53 @@ describe('LIVECHAT - visitors', function () {
describe('livechat/visitors.pagesVisited', () => {
it('should return an "unauthorized error" when the user does not have the necessary permission', (done) => {
- updatePermission('view-l-room', []).then(() => {
- request
- .get(api('livechat/visitors.pagesVisited/room-id'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(403)
- .end(done);
- });
+ updatePermission('view-l-room', [])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.pagesVisited/room-id'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(403)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ expect(res.body.error).to.be.equal('error-not-authorized');
+ });
+ })
+ .then(() => done());
});
it('should return an "error" when the roomId param is not provided', (done) => {
- updatePermission('view-l-room', ['admin']).then(() => {
- request
- .get(api('livechat/visitors.pagesVisited/room-id'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(400)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', false);
- })
- .end(done);
- });
+ updatePermission('view-l-room', ['admin'])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.pagesVisited/room-id'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ });
+ })
+ .then(() => done());
});
it('should return an array of pages', (done) => {
updatePermission('view-l-room', ['admin']).then(() => {
createVisitor().then((createdVisitor: ILivechatVisitor) => {
- createLivechatRoom(createdVisitor.token).then((createdRoom: IOmnichannelRoom) => {
- request
- .get(api(`livechat/visitors.pagesVisited/${createdRoom._id}`))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(200)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', true);
- expect(res.body.pages).to.be.an('array');
- expect(res.body).to.have.property('offset');
- expect(res.body).to.have.property('total');
- expect(res.body).to.have.property('count');
- })
- .end(done);
- });
+ createLivechatRoom(createdVisitor.token)
+ .then((createdRoom: IOmnichannelRoom) => {
+ request
+ .get(api(`livechat/visitors.pagesVisited/${createdRoom._id}`))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.pages).to.be.an('array');
+ expect(res.body).to.have.property('offset');
+ expect(res.body).to.have.property('total');
+ expect(res.body).to.have.property('count');
+ });
+ })
+ .then(() => done());
});
});
});
@@ -117,47 +131,54 @@ describe('LIVECHAT - visitors', function () {
describe('livechat/visitors.chatHistory/room/room-id/visitor/visitor-id', () => {
it('should return an "unauthorized error" when the user does not have the necessary permission', (done) => {
- updatePermission('view-l-room', []).then(() => {
- request
- .get(api('livechat/visitors.chatHistory/room/room-id/visitor/visitor-id'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(403)
- .end(done);
- });
+ updatePermission('view-l-room', [])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.chatHistory/room/room-id/visitor/visitor-id'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(403)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ expect(res.body.error).to.be.equal('error-not-authorized');
+ });
+ })
+ .then(() => done());
});
it('should return an "error" when the roomId param is invalid', (done) => {
- updatePermission('view-l-room', ['admin']).then(() => {
- request
- .get(api('livechat/visitors.chatHistory/room/room-id/visitor/visitor-id'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(400)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', false);
- })
- .end(done);
- });
+ updatePermission('view-l-room', ['admin'])
+ .then(() => {
+ request
+ .get(api('livechat/visitors.chatHistory/room/room-id/visitor/visitor-id'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ });
+ })
+ .then(() => done());
});
it('should return an array of chat history', (done) => {
updatePermission('view-l-room', ['admin']).then(() => {
- createVisitor().then((createdVisitor: ILivechatVisitor) => {
- createLivechatRoom(createdVisitor.token).then((createdRoom: IOmnichannelRoom) => {
- request
- .get(api(`livechat/visitors.chatHistory/room/${createdRoom._id}/visitor/${createdVisitor._id}`))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(200)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', true);
- expect(res.body.history).to.be.an('array');
- expect(res.body).to.have.property('offset');
- expect(res.body).to.have.property('total');
- expect(res.body).to.have.property('count');
- })
- .end(done);
- });
- });
+ createVisitor()
+ .then((createdVisitor: ILivechatVisitor) => {
+ createLivechatRoom(createdVisitor.token).then((createdRoom: IOmnichannelRoom) => {
+ request
+ .get(api(`livechat/visitors.chatHistory/room/${createdRoom._id}/visitor/${createdVisitor._id}`))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.history).to.be.an('array');
+ expect(res.body).to.have.property('offset');
+ expect(res.body).to.have.property('total');
+ expect(res.body).to.have.property('count');
+ });
+ });
+ })
+ .then(() => done());
});
});
});
@@ -230,37 +251,39 @@ describe('LIVECHAT - visitors', function () {
it("should return a 'visitor-has-open-rooms' error when there are open rooms", (done) => {
createVisitor().then((createdVisitor: ILivechatVisitor) => {
- createLivechatRoom(createdVisitor.token).then(() => {
+ createLivechatRoom(createdVisitor.token)
+ .then(() => {
+ request
+ .delete(api(`livechat/visitor/${createdVisitor.token}`))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', false);
+ expect(res.body.error).to.be.equal('Cannot remove visitors with opened rooms [visitor-has-open-rooms]');
+ });
+ })
+ .then(() => done());
+ });
+ });
+
+ it('should return a visitor when the query params is all valid', (done) => {
+ createVisitor()
+ .then((createdVisitor: ILivechatVisitor) => {
request
.delete(api(`livechat/visitor/${createdVisitor.token}`))
.set(credentials)
.expect('Content-Type', 'application/json')
- .expect(400)
+ .expect(200)
.expect((res: Response) => {
- expect(res.body).to.have.property('success', false);
- expect(res.body.error).to.be.equal('Cannot remove visitors with opened rooms [visitor-has-open-rooms]');
- })
- .end(done);
- });
- });
- });
-
- it('should return a visitor when the query params is all valid', (done) => {
- createVisitor().then((createdVisitor: ILivechatVisitor) => {
- request
- .delete(api(`livechat/visitor/${createdVisitor.token}`))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(200)
- .expect((res: Response) => {
- expect(res.body).to.have.property('success', true);
- expect(res.body).to.have.property('visitor');
- expect(res.body.visitor).to.have.property('_id');
- expect(res.body.visitor).to.have.property('ts');
- expect(res.body.visitor._id).to.be.equal(createdVisitor._id);
- })
- .end(done);
- });
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('visitor');
+ expect(res.body.visitor).to.have.property('_id');
+ expect(res.body.visitor).to.have.property('ts');
+ expect(res.body.visitor._id).to.be.equal(createdVisitor._id);
+ });
+ })
+ .then(() => done());
});
it("should return a 'error-removing-visitor' error when removeGuest's result is false", (done) => {
@@ -278,14 +301,11 @@ describe('LIVECHAT - visitors', function () {
describe('livechat/visitors.autocomplete', () => {
it('should return an error when the user doesnt have the right permissions', (done) => {
- updatePermission('view-l-room', []).then(() =>
- request
- .get(api('livechat/visitors.autocomplete'))
- .set(credentials)
- .expect('Content-Type', 'application/json')
- .expect(403)
- .end(done),
- );
+ updatePermission('view-l-room', [])
+ .then(() =>
+ request.get(api('livechat/visitors.autocomplete')).set(credentials).expect('Content-Type', 'application/json').expect(403),
+ )
+ .then(() => done());
});
it('should return an error when the "selector" query parameter is not valid', (done) => {
@@ -340,9 +360,9 @@ describe('LIVECHAT - visitors', function () {
expect(visitor).to.have.property('_id');
expect(visitor).to.have.property('name');
expect(visitor._id).to.be.equal(createdVisitor._id);
- })
- .end(done);
- });
+ });
+ })
+ .then(() => done());
});
});
@@ -452,6 +472,160 @@ describe('LIVECHAT - visitors', function () {
.catch(done);
});
});
+
+ describe('GET [omnichannel/contact.search]', () => {
+ it('should fail if no email|phone|custom params are passed as query', async () => {
+ await request.get(api('omnichannel/contact.search')).set(credentials).expect('Content-Type', 'application/json').expect(400);
+ });
+ it('should fail if its trying to find by an empty string', async () => {
+ await request.get(api('omnichannel/contact.search?email=')).set(credentials).expect('Content-Type', 'application/json').expect(400);
+ });
+ it('should fail if custom is passed but is not JSON serializable', async () => {
+ await request
+ .get(api('omnichannel/contact.search?custom={a":1}'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400);
+ });
+ it('should fail if custom is an empty object and no email|phone are provided', async () => {
+ await request
+ .get(api('omnichannel/contact.search?custom={}'))
+ .set(credentials)
+ .expect('Content-Type', 'application/json')
+ .expect(400);
+ });
+ it('should find a contact by email', (done) => {
+ createVisitor()
+ .then((visitor: ILivechatVisitor) => {
+ request
+ .get(api(`omnichannel/contact.search?email=${visitor.visitorEmails?.[0].address}`))
+ .set(credentials)
+ .send()
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('contact');
+ expect(res.body.contact).to.have.property('_id');
+ expect(res.body.contact).to.have.property('name');
+ expect(res.body.contact).to.have.property('username');
+ expect(res.body.contact).to.have.property('phone');
+ expect(res.body.contact).to.have.property('visitorEmails');
+ expect(res.body.contact._id).to.be.equal(visitor._id);
+ expect(res.body.contact.phone[0].phoneNumber).to.be.equal(visitor.phone?.[0].phoneNumber);
+ // done();
+ });
+ })
+ .then(() => done())
+ .catch(done);
+ });
+ it('should find a contact by phone', (done) => {
+ createVisitor()
+ .then((visitor: ILivechatVisitor) => {
+ request
+ .get(api(`omnichannel/contact.search?phone=${visitor.phone?.[0].phoneNumber}`))
+ .set(credentials)
+ .send()
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body).to.have.property('contact');
+ expect(res.body.contact).to.have.property('_id');
+ expect(res.body.contact).to.have.property('name');
+ expect(res.body.contact).to.have.property('username');
+ expect(res.body.contact).to.have.property('phone');
+ expect(res.body.contact).to.have.property('visitorEmails');
+ expect(res.body.contact._id).to.be.equal(visitor._id);
+ expect(res.body.contact.phone[0].phoneNumber).to.be.equal(visitor.phone?.[0].phoneNumber);
+ });
+ })
+ .then(() => done())
+ .catch(done);
+ });
+ it('should find a contact by custom field', (done) => {
+ const cfID = 'address';
+ createCustomField({
+ searchable: true,
+ field: 'address',
+ label: 'address',
+ defaultValue: 'test_default_address',
+ scope: 'visitor',
+ visibility: 'public',
+ regexp: '',
+ } as unknown as ILivechatCustomField & { field: string })
+ .then((cf) => {
+ if (!cf) {
+ throw new Error('Custom field not created');
+ }
+ })
+ .then(() => createVisitor())
+ .then(() => {
+ request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ address: 'Rocket.Chat' })}`))
+ .set(credentials)
+ .send()
+ .expect('Content-Type', 'application/json')
+ .expect(200)
+ .expect((res: Response) => {
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.have.property('name');
+ expect(res.body.contact).to.have.property('username');
+ expect(res.body.contact).to.have.property('phone');
+ expect(res.body.contact).to.have.property('visitorEmails');
+ expect(res.body.contact.livechatData).to.have.property('address', 'Rocket.Chat street');
+ deleteCustomField(cfID);
+ });
+ })
+ .then(() => done())
+ .catch(done);
+ });
+
+ it('should return null if an invalid set of custom fields is passed and no other params are sent', async () => {
+ const res = await request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ nope: 'nel' })}`))
+ .set(credentials)
+ .send();
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.be.null;
+ });
+
+ it('should not break if more than 1 custom field are passed', async () => {
+ const res = await request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ nope: 'nel', another: 'field' })}`))
+ .set(credentials)
+ .send();
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.be.null;
+ });
+
+ it('should not break if bad things are passed as custom field keys', async () => {
+ const res = await request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ $regex: 'nel' })}`))
+ .set(credentials)
+ .send();
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.be.null;
+ });
+
+ it('should not break if bad things are passed as custom field keys 2', async () => {
+ const res = await request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ '$regex: { very-bad }': 'nel' })}`))
+ .set(credentials)
+ .send();
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.be.null;
+ });
+
+ it('should not break if bad things are passed as custom field values', async () => {
+ const res = await request
+ .get(api(`omnichannel/contact.search?custom=${JSON.stringify({ nope: '^((ab)*)+$' })}`))
+ .set(credentials)
+ .send();
+ expect(res.body).to.have.property('success', true);
+ expect(res.body.contact).to.be.null;
+ });
+ });
});
// TODO: Missing tests for the following endpoints:
diff --git a/packages/core-typings/src/ILivechatCustomField.ts b/packages/core-typings/src/ILivechatCustomField.ts
index 9f1ce0ffad5f..e4e66d545da6 100644
--- a/packages/core-typings/src/ILivechatCustomField.ts
+++ b/packages/core-typings/src/ILivechatCustomField.ts
@@ -10,4 +10,5 @@ export interface ILivechatCustomField extends IRocketChatRecord {
defaultValue?: string;
options?: string;
public?: boolean;
+ searchable?: boolean;
}
diff --git a/packages/model-typings/src/models/ILivechatCustomFieldModel.ts b/packages/model-typings/src/models/ILivechatCustomFieldModel.ts
index 68ead81af0bf..ebe7f420868a 100644
--- a/packages/model-typings/src/models/ILivechatCustomFieldModel.ts
+++ b/packages/model-typings/src/models/ILivechatCustomFieldModel.ts
@@ -7,4 +7,15 @@ import type { IBaseModel } from './IBaseModel';
export interface ILivechatCustomFieldModel extends IBaseModel {
findByScope(scope: ILivechatCustomField['scope'], options?: FindOptions): FindCursor;
findByScope(scope: ILivechatCustomField['scope'], options?: FindOptions): FindCursor;
+ findMatchingCustomFields(
+ scope: ILivechatCustomField['scope'],
+ searchable: boolean,
+ options?: FindOptions,
+ ): FindCursor;
+ findMatchingCustomFieldsByIds(
+ ids: ILivechatCustomField['_id'][],
+ scope: ILivechatCustomField['scope'],
+ searchable: boolean,
+ options?: FindOptions,
+ ): FindCursor;
}
diff --git a/packages/model-typings/src/models/ILivechatVisitorsModel.ts b/packages/model-typings/src/models/ILivechatVisitorsModel.ts
index e50432c76879..4e381ce55664 100644
--- a/packages/model-typings/src/models/ILivechatVisitorsModel.ts
+++ b/packages/model-typings/src/models/ILivechatVisitorsModel.ts
@@ -17,11 +17,18 @@ export interface ILivechatVisitorsModel extends IBaseModel {
custom_name: string;
}
>;
- findPaginatedVisitorsByEmailOrPhoneOrNameOrUsername(
+ findPaginatedVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField(
emailOrPhone: string,
nameOrUsername: RegExp,
- options: FindOptions,
- ): FindPaginated>;
+ allowedCustomFields: string[],
+ options?: FindOptions,
+ ): Promise>>;
+
+ findOneByEmailAndPhoneAndCustomField(
+ email: string | null | undefined,
+ phone: string | null | undefined,
+ customFields?: { [key: string]: RegExp },
+ ): Promise;
removeContactManagerByUsername(manager: string): Promise;