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 @@ {{{modifier item.name}}} + + 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'}}