diff --git a/app/livechat/client/collections/LivechatVisitor.js b/app/livechat/client/collections/LivechatVisitor.js deleted file mode 100644 index 006885bacf1..00000000000 --- a/app/livechat/client/collections/LivechatVisitor.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Mongo } from 'meteor/mongo'; - -export const LivechatVisitor = new Mongo.Collection('rocketchat_livechat_visitor'); diff --git a/app/livechat/client/views/app/tabbar/visitorEdit.js b/app/livechat/client/views/app/tabbar/visitorEdit.js index 249b80febff..02c1a2a035f 100644 --- a/app/livechat/client/views/app/tabbar/visitorEdit.js +++ b/app/livechat/client/views/app/tabbar/visitorEdit.js @@ -5,7 +5,6 @@ import toastr from 'toastr'; import { t } from '../../../../../utils'; import { hasRole } from '../../../../../authorization'; -import { LivechatVisitor } from '../../../collections/LivechatVisitor'; import './visitorEdit.html'; import { APIClient } from '../../../../../utils/client'; @@ -63,8 +62,12 @@ Template.visitorEdit.onCreated(async function() { this.agentDepartments = new ReactiveVar([]); this.availableUserTags = new ReactiveVar([]); - this.autorun(() => { - this.visitor.set(LivechatVisitor.findOne({ _id: Template.currentData().visitorId })); + this.autorun(async () => { + const { visitorId } = Template.currentData(); + if (visitorId) { + const { visitor } = await APIClient.v1.get(`livechat/visitors.info?visitorId=${ visitorId }`); + this.visitor.set(visitor); + } }); const rid = Template.currentData().roomId; diff --git a/app/livechat/client/views/app/tabbar/visitorInfo.js b/app/livechat/client/views/app/tabbar/visitorInfo.js index 678b84b40cb..122c18325e8 100644 --- a/app/livechat/client/views/app/tabbar/visitorInfo.js +++ b/app/livechat/client/views/app/tabbar/visitorInfo.js @@ -14,7 +14,6 @@ import { Subscriptions } from '../../../../../models'; import { settings } from '../../../../../settings'; import { t, handleError, roomTypes } from '../../../../../utils'; import { hasRole, hasPermission, hasAtLeastOnePermission } from '../../../../../authorization'; -import { LivechatVisitor } from '../../../collections/LivechatVisitor'; import './visitorInfo.html'; import { APIClient } from '../../../../../utils/client'; @@ -309,8 +308,6 @@ Template.visitorInfo.onCreated(function() { loadRoomData(rid); } }); - - this.subscribe('livechat:visitorInfo', { rid }); } this.autorun(async () => { @@ -320,7 +317,11 @@ Template.visitorInfo.onCreated(function() { } }); - this.autorun(() => { - this.user.set(LivechatVisitor.findOne({ _id: this.visitorId.get() })); + this.autorun(async () => { + const visitorId = this.visitorId.get(); + if (visitorId) { + const { visitor } = await APIClient.v1.get(`livechat/visitors.info?visitorId=${ visitorId }`); + this.user.set(visitor); + } }); }); diff --git a/app/livechat/imports/server/rest/visitors.js b/app/livechat/imports/server/rest/visitors.js new file mode 100644 index 00000000000..6df472bb20c --- /dev/null +++ b/app/livechat/imports/server/rest/visitors.js @@ -0,0 +1,16 @@ +import { check } from 'meteor/check'; + +import { API } from '../../../../api'; +import { findVisitorInfo } from '../../../server/api/lib/visitors'; + +API.v1.addRoute('livechat/visitors.info', { authRequired: true }, { + get() { + check(this.queryParams, { + visitorId: String, + }); + + const visitor = Promise.await(findVisitorInfo({ userId: this.userId, visitorId: this.queryParams.visitorId })); + + return API.v1.success(visitor); + }, +}); diff --git a/app/livechat/server/api.js b/app/livechat/server/api.js index e0b3a9b03e9..95cd633247c 100644 --- a/app/livechat/server/api.js +++ b/app/livechat/server/api.js @@ -9,3 +9,4 @@ import '../imports/server/rest/rooms.js'; import '../imports/server/rest/appearance.js'; import '../imports/server/rest/triggers.js'; import '../imports/server/rest/integrations.js'; +import '../imports/server/rest/visitors.js'; diff --git a/app/livechat/server/api/lib/visitors.js b/app/livechat/server/api/lib/visitors.js new file mode 100644 index 00000000000..f72351f9993 --- /dev/null +++ b/app/livechat/server/api/lib/visitors.js @@ -0,0 +1,17 @@ +import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; +import { LivechatVisitors } from '../../../../models/server/raw'; + +export async function findVisitorInfo({ userId, visitorId }) { + if (!await hasPermissionAsync(userId, 'view-l-room')) { + throw new Error('error-not-authorized'); + } + + const visitor = await LivechatVisitors.findOneById(visitorId); + if (!visitor) { + throw new Error('visitor-not-found'); + } + + return { + visitor, + }; +} diff --git a/app/livechat/server/publications/visitorInfo.js b/app/livechat/server/publications/visitorInfo.js index 6cca207b996..372541a3820 100644 --- a/app/livechat/server/publications/visitorInfo.js +++ b/app/livechat/server/publications/visitorInfo.js @@ -3,6 +3,7 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; import { LivechatRooms, LivechatVisitors } from '../../../models'; +console.warn('The publication "livechat:visitorInfo" is deprecated and will be removed after version v3.0.0'); Meteor.publish('livechat:visitorInfo', function({ rid: roomId }) { if (!this.userId) { return this.error(new Meteor.Error('error-not-authorized', 'Not authorized', { publish: 'livechat:visitorInfo' })); diff --git a/app/models/server/raw/LivechatVisitors.js b/app/models/server/raw/LivechatVisitors.js new file mode 100644 index 00000000000..2ba38dbbe78 --- /dev/null +++ b/app/models/server/raw/LivechatVisitors.js @@ -0,0 +1,5 @@ +import { BaseRaw } from './BaseRaw'; + +export class LivechatVisitorsRaw extends BaseRaw { + +} diff --git a/app/models/server/raw/index.js b/app/models/server/raw/index.js index f4f95371462..d12ed55f0ad 100644 --- a/app/models/server/raw/index.js +++ b/app/models/server/raw/index.js @@ -20,6 +20,8 @@ import LivechatRoomsModel from '../models/LivechatRooms'; import { LivechatRoomsRaw } from './LivechatRooms'; import MessagesModel from '../models/Messages'; import { MessagesRaw } from './Messages'; +import LivechatVisitorsModel from '../models/LivechatVisitors'; +import { LivechatVisitorsRaw } from './LivechatVisitors'; export const Permissions = new PermissionsRaw(PermissionsModel.model.rawCollection()); export const Roles = new RolesRaw(RolesModel.model.rawCollection()); @@ -32,3 +34,4 @@ export const LivechatDepartment = new LivechatDepartmentRaw(LivechatDepartmentMo export const LivechatDepartmentAgents = new LivechatDepartmentAgentsRaw(LivechatDepartmentAgentsModel.model.rawCollection()); export const LivechatRooms = new LivechatRoomsRaw(LivechatRoomsModel.model.rawCollection()); export const Messages = new MessagesRaw(MessagesModel.model.rawCollection()); +export const LivechatVisitors = new LivechatVisitorsRaw(LivechatVisitorsModel.model.rawCollection()); diff --git a/tests/end-to-end/api/livechat/visitors.js b/tests/end-to-end/api/livechat/visitors.js new file mode 100644 index 00000000000..e0af003223d --- /dev/null +++ b/tests/end-to-end/api/livechat/visitors.js @@ -0,0 +1,59 @@ +import { getCredentials, api, request, credentials } from '../../../data/api-data.js'; +import { updatePermission, updateSetting } from '../../../data/permissions.helper'; +import { createVisitor } from '../../../data/livechat/rooms.js'; + +describe('LIVECHAT - visitors', function() { + this.retries(0); + let visitor; + + before((done) => getCredentials(done)); + + before((done) => { + updateSetting('Livechat_enabled', true) + .then(() => createVisitor()) + .then((createdVisitor) => { + visitor = createdVisitor; + done(); + }); + }); + + 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(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('error-not-authorized'); + }) + .end(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) => { + expect(res.body).to.have.property('success', false); + expect(res.body.error).to.be.equal('visitor-not-found'); + }) + .end(done); + }); + }); + it('should return the visitor info', (done) => { + request.get(api(`livechat/visitors.info?visitorId=${ visitor._id }`)) + .set(credentials) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body.visitor._id).to.be.equal(visitor._id); + }) + .end(done); + }); + }); +});