diff --git a/app/livechat/imports/server/rest/visitors.js b/app/livechat/imports/server/rest/visitors.js
index c828e9552e58..cc38c3bc4008 100644
--- a/app/livechat/imports/server/rest/visitors.js
+++ b/app/livechat/imports/server/rest/visitors.js
@@ -2,7 +2,7 @@
import { check } from 'meteor/check';
import { API } from '../../../../api/server';
-import { findVisitorInfo, findVisitedPages, findChatHistory } from '../../../server/api/lib/visitors';
+import { findVisitorInfo, findVisitedPages, findChatHistory, findVisitorsToAutocomplete } from '../../../server/api/lib/visitors';
API.v1.addRoute('livechat/visitors.info', { authRequired: true }, {
get() {
@@ -62,3 +62,17 @@ API.v1.addRoute('livechat/visitors.chatHistory/room/:roomId/visitor/:visitorId',
return API.v1.success(history);
},
});
+
+API.v1.addRoute('livechat/visitors.autocomplete', { authRequired: true }, {
+ get() {
+ const { selector } = this.queryParams;
+ if (!selector) {
+ return API.v1.failure('The \'selector\' param is required');
+ }
+
+ return API.v1.success(Promise.await(findVisitorsToAutocomplete({
+ userId: this.userId,
+ selector: JSON.parse(selector),
+ })));
+ },
+});
diff --git a/app/livechat/server/api/lib/visitors.js b/app/livechat/server/api/lib/visitors.js
index ad7cb3da93e5..d1c7477fdd56 100644
--- a/app/livechat/server/api/lib/visitors.js
+++ b/app/livechat/server/api/lib/visitors.js
@@ -72,3 +72,27 @@ export async function findChatHistory({ userId, roomId, visitorId, pagination: {
total,
};
}
+
+export async function findVisitorsToAutocomplete({ userId, selector }) {
+ if (!await hasPermissionAsync(userId, 'view-l-room')) {
+ return { items: [] };
+ }
+ const { exceptions = [], conditions = {} } = selector;
+
+ const options = {
+ fields: {
+ _id: 1,
+ name: 1,
+ username: 1,
+ },
+ limit: 10,
+ sort: {
+ name: 1,
+ },
+ };
+
+ const items = await LivechatVisitors.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray();
+ return {
+ items,
+ };
+}
diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js
index 49823c11f896..6f9e1957c491 100644
--- a/app/models/server/models/LivechatRooms.js
+++ b/app/models/server/models/LivechatRooms.js
@@ -252,6 +252,16 @@ export class LivechatRooms extends Base {
return this.find(query);
}
+ findByVisitorIdAndAgentId(visitorId, agentId, options) {
+ const query = {
+ t: 'l',
+ ...visitorId && { 'v._id': visitorId },
+ ...agentId && { 'servedBy._id': agentId },
+ };
+
+ return this.find(query, options);
+ }
+
findByVisitorId(visitorId) {
const query = {
t: 'l',
diff --git a/app/models/server/raw/LivechatVisitors.js b/app/models/server/raw/LivechatVisitors.js
index 7ee3f02f2cca..8be6eccd5d49 100644
--- a/app/models/server/raw/LivechatVisitors.js
+++ b/app/models/server/raw/LivechatVisitors.js
@@ -1,3 +1,5 @@
+import s from 'underscore.string';
+
import { BaseRaw } from './BaseRaw';
export class LivechatVisitorsRaw extends BaseRaw {
@@ -12,4 +14,43 @@ export class LivechatVisitorsRaw extends BaseRaw {
return this.find(query, { fields: { _id: 1 } });
}
+
+ findByNameRegexWithExceptionsAndConditions(searchTerm, exceptions = [], conditions = {}, options = {}) {
+ if (!Array.isArray(exceptions)) {
+ exceptions = [exceptions];
+ }
+
+ const nameRegex = new RegExp(`^${ s.escapeRegExp(searchTerm).trim() }`, 'i');
+
+ const match = {
+ $match: {
+ name: nameRegex,
+ _id: {
+ $nin: exceptions,
+ },
+ ...conditions,
+ },
+ };
+
+ const { fields, sort, offset, count } = options;
+ const project = {
+ $project: {
+ custom_name: { $concat: ['$username', ' - ', '$name'] },
+ ...fields,
+ },
+ };
+
+ const order = { $sort: sort || { name: 1 } };
+ const params = [match, project, order];
+
+ if (offset) {
+ params.push({ $skip: offset });
+ }
+
+ if (count) {
+ params.push({ $limit: count });
+ }
+
+ return this.col.aggregate(params);
+ }
}
diff --git a/app/ui/client/components/popupList.html b/app/ui/client/components/popupList.html
index 49318e3aea9e..135554197510 100644
--- a/app/ui/client/components/popupList.html
+++ b/app/ui/client/components/popupList.html
@@ -43,3 +43,12 @@
+
+
+
+
diff --git a/ee/app/auditing/client/templates/audit/audit.html b/ee/app/auditing/client/templates/audit/audit.html
index 1493064c8eed..b5247322ce60 100644
--- a/ee/app/auditing/client/templates/audit/audit.html
+++ b/ee/app/auditing/client/templates/audit/audit.html
@@ -18,12 +18,15 @@
{{> icon block="rc-select__arrow" icon="arrow-down" }}
- {{> auditAutocomplete key='room' hide=typeD onChange=onChange prepare=prepareRoom field='name' term='name' icon='hashtag' label="room_name" placeholder='Channel_Name_Placeholder'}}
- {{> auditAutocompleteDirectMessage key='users' hide=nTypeD onChange=onChange collection='UserAndRoom' modifier=modifierUser endpoint='users.autocomplete' field='username' icon='at' label="From" placeholder='Username_Placeholder'}}
+ {{> auditAutocomplete key='room' hide=nTypeOthers onChange=onChange prepare=prepareRoom field='name' term='name' icon='hashtag' label="room_name" placeholder='Channel_Name_Placeholder'}}
+ {{> auditAutocompleteDirectMessage key='users' hide=nTypeDM onChange=onChange collection='UserAndRoom' modifier=modifierUser endpoint='users.autocomplete' field='username' icon='at' label="From" placeholder='Username_Placeholder'}}
+ {{> auditAutocomplete key='visitor' hide=nTypeOmni onChange=onChange collection='CachedVisitorsList' modifier=modifierUser endpoint='livechat/visitors.autocomplete' field='custom_name' term='custom_name' icon='omnichannel' label="Visitor" templateItem="popupList_item_custom" placeholder='Visitor_Name_Placeholder'}}
+ {{> auditAutocomplete key='agent' hide=nTypeOmni onChange=onChange collection='CachedAgentsList' conditions=agentConditions modifier=modifierUser endpoint='users.autocomplete' field='username' icon='omnichannel' label="Agent" placeholder='Agent_Name_Placeholder'}}