Skip to content

Commit

Permalink
[IMPROVE] Replace mentionedMessages publication to REST (#15540)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcosSpessatto authored and ggazzo committed Oct 9, 2019
1 parent e37ea63 commit 6eeb30d
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 38 deletions.
30 changes: 30 additions & 0 deletions app/api/server/lib/messages.js
@@ -0,0 +1,30 @@
import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom';
import { Rooms, Messages, Users } from '../../../models/server/raw';

export async function findMentionedMessages({ uid, roomId, pagination: { offset, count, sort } }) {
const room = await Rooms.findOneById(roomId);
if (!await canAccessRoomAsync(room, { _id: uid })) {
throw new Error('error-not-allowed');
}
const user = await Users.findOneById(uid, { fields: { username: 1 } });
if (!user) {
throw new Error('invalid-user');
}

const cursor = await Messages.findVisibleByMentionAndRoomId(user.username, roomId, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
});

const total = await cursor.count();

const messages = await cursor.toArray();

return {
messages,
count: messages.length,
offset,
total,
};
}
22 changes: 22 additions & 0 deletions app/api/server/v1/chat.js
Expand Up @@ -9,6 +9,7 @@ import { API } from '../api';
import Rooms from '../../../models/server/models/Rooms';
import Users from '../../../models/server/models/Users';
import { settings } from '../../../settings';
import { findMentionedMessages } from '../lib/messages';

API.v1.addRoute('chat.delete', { authRequired: true }, {
post() {
Expand Down Expand Up @@ -599,3 +600,24 @@ API.v1.addRoute('chat.unfollowMessage', { authRequired: true }, {
return API.v1.success();
},
});

API.v1.addRoute('chat.getMentionedMessages', { authRequired: true }, {
get() {
const { roomId } = this.queryParams;
const { sort } = this.parseJsonQuery();
const { offset, count } = this.getPaginationItems();
if (!roomId) {
throw new Meteor.Error('error-invalid-params', 'The required "roomId" query param is missing.');
}
const messages = Promise.await(findMentionedMessages({
uid: this.userId,
roomId,
pagination: {
offset,
count,
sort,
},
}));
return API.v1.success(messages);
},
});
14 changes: 14 additions & 0 deletions app/file-upload/server/lib/FileUpload.js
Expand Up @@ -24,6 +24,7 @@ import { hasPermission } from '../../../authorization/server/functions/hasPermis
import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom';
import { fileUploadIsValidContentType } from '../../../utils/lib/fileUploadRestrictions';
import { isValidJWT, generateJWT } from '../../../utils/server/lib/JWTHelper';
import { Messages } from '../../../models/server';

const cookie = new Cookies();
let maxFileSize = 0;
Expand Down Expand Up @@ -403,6 +404,19 @@ export const FileUpload = {
fileId,
}, settings.get('FileUpload_json_web_token_secret_for_files'));
},

removeFilesByRoomId(rid) {
Messages.find({
rid,
'file._id': {
$exists: true,
},
}, {
fields: {
'file._id': 1,
},
}).fetch().forEach((document) => FileUpload.getStore('Uploads').deleteById(document.file._id));
},
};

export class FileUploadClass {
Expand Down
3 changes: 2 additions & 1 deletion app/lib/server/functions/deleteRoom.js
@@ -1,8 +1,9 @@
import { Messages, Subscriptions, Rooms } from '../../../models';
import { callbacks } from '../../../callbacks';
import { FileUpload } from '../../../file-upload/server';

export const deleteRoom = function(rid) {
Messages.removeFilesByRoomId(rid);
FileUpload.removeFilesByRoomId(rid);
Messages.removeByRoomId(rid);
callbacks.run('beforeDeleteRoom', rid);
Subscriptions.removeByRoomId(rid);
Expand Down
2 changes: 1 addition & 1 deletion app/lib/server/functions/deleteUser.js
Expand Up @@ -86,7 +86,7 @@ export const deleteUser = function(userId) {
// Remove DMs and non-channel rooms with only 1 user (the one being deleted)
if (roomData.t === 'd' || (roomData.t !== 'c' && roomData.subscribers === 1)) {
Subscriptions.removeByRoomId(roomData.rid);
Messages.removeFilesByRoomId(roomData.rid);
FileUpload.removeFilesByRoomId(roomData.rid);
Messages.removeByRoomId(roomData.rid);
Rooms.removeById(roomData.rid);
}
Expand Down
3 changes: 2 additions & 1 deletion app/livechat/server/lib/Livechat.js
Expand Up @@ -35,6 +35,7 @@ import { LivechatInquiry } from '../../lib/LivechatInquiry';
import { sendMessage } from '../../../lib/server/functions/sendMessage';
import { updateMessage } from '../../../lib/server/functions/updateMessage';
import { deleteMessage } from '../../../lib/server/functions/deleteMessage';
import { FileUpload } from '../../../file-upload/server';

export const Livechat = {
Analytics,
Expand Down Expand Up @@ -635,7 +636,7 @@ export const Livechat = {
check(token, String);

LivechatRooms.findByVisitorToken(token).forEach((room) => {
Messages.removeFilesByRoomId(room._id);
FileUpload.removeFilesByRoomId(room._id);
Messages.removeByRoomId(room._id);
});

Expand Down
3 changes: 0 additions & 3 deletions app/mentions-flextab/client/lib/MentionedMessage.js

This file was deleted.

68 changes: 51 additions & 17 deletions app/mentions-flextab/client/views/mentionsFlexTab.js
@@ -1,16 +1,23 @@
import _ from 'underscore';
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';

import { MentionedMessage } from '../lib/MentionedMessage';
import { messageContext } from '../../../ui-utils/client/lib/messageContext';
import { upsertMessageBulk } from '../../../ui-utils/client/lib/RoomHistoryManager';
import { APIClient } from '../../../utils/client';
import { Messages, Users } from '../../../models/client';

const LIMIT_DEFAULT = 50;

Template.mentionsFlexTab.helpers({
hasMessages() {
return Template.instance().cursor.count() > 0;
return Template.instance().messages.find().count();
},
messages() {
return Template.instance().cursor;
const instance = Template.instance();
return instance.messages.find({}, { limit: instance.limit.get(), sort: { ts: -1 } });
},
hasMore() {
return Template.instance().hasMore.get();
Expand All @@ -19,23 +26,50 @@ Template.mentionsFlexTab.helpers({
});

Template.mentionsFlexTab.onCreated(function() {
this.cursor = MentionedMessage.find({
rid: this.data.rid,
}, {
sort: {
ts: -1,
},
});
this.messages = new Mongo.Collection(null);

this.hasMore = new ReactiveVar(true);
this.limit = new ReactiveVar(50);
return this.autorun(() => {
const mentionedMessageFind = MentionedMessage.find({ rid: this.data.rid });
return this.subscribe('mentionedMessages', this.data.rid, this.limit.get(), () => {
if (mentionedMessageFind.count() < this.limit.get()) {
return this.hasMore.set(false);
}
this.limit = new ReactiveVar(LIMIT_DEFAULT);

this.autorun(() => {
const query = {
_hidden: { $ne: true },
'mentions.username': Users.findOne(Meteor.userId(), { fields: { username: 1 } }).username,
rid: this.data.rid,
_updatedAt: {
$gt: new Date(),
},
};

this.cursor && this.cursor.stop();

this.limit.set(LIMIT_DEFAULT);

this.cursor = Messages.find(query).observe({
added: ({ _id, ...message }) => {
this.messages.upsert({ _id }, message);
},
changed: ({ _id, ...message }) => {
this.messages.upsert({ _id }, message);
},
removed: ({ _id }) => {
this.messages.remove({ _id });
},
});
});

this.autorun(async () => {
const limit = this.limit.get();
const { messages, total } = await APIClient.v1.get(`chat.getMentionedMessages?roomId=${ this.data.rid }&count=${ limit }`);

upsertMessageBulk({ msgs: messages }, this.messages);

this.hasMore.set(total > limit);
});
});

Template.mentionsFlexTab.onDestroyed(function() {
this.cursor.stop();
});

Template.mentionsFlexTab.events({
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { Meteor } from 'meteor/meteor';
import { Users, Messages } from '../../../models';

Meteor.publish('mentionedMessages', function(rid, limit = 50) {
console.warn('The publication "mentionedMessages" is deprecated and will be removed after version v3.0.0');
if (!this.userId) {
return this.ready();
}
Expand Down
14 changes: 0 additions & 14 deletions app/models/server/models/Messages.js
Expand Up @@ -4,7 +4,6 @@ import _ from 'underscore';
import { Base } from './_Base';
import Rooms from './Rooms';
import { settings } from '../../../settings/server/functions/settings';
import { FileUpload } from '../../../file-upload/server/lib/FileUpload';

export class Messages extends Base {
constructor() {
Expand Down Expand Up @@ -905,19 +904,6 @@ export class Messages extends Base {
return this.remove(query);
}

async removeFilesByRoomId(roomId) {
this.find({
rid: roomId,
'file._id': {
$exists: true,
},
}, {
fields: {
'file._id': 1,
},
}).fetch().forEach((document) => FileUpload.getStore('Uploads').deleteById(document.file._id));
}

getMessageByFileId(fileID) {
return this.findOne({ 'file._id': fileID });
}
Expand Down
13 changes: 13 additions & 0 deletions app/models/server/raw/Messages.js
@@ -0,0 +1,13 @@
import { BaseRaw } from './BaseRaw';

export class MessagesRaw extends BaseRaw {
findVisibleByMentionAndRoomId(username, rid, options) {
const query = {
_hidden: { $ne: true },
'mentions.username': username,
rid,
};

return this.find(query, options);
}
}
3 changes: 3 additions & 0 deletions app/models/server/raw/index.js
Expand Up @@ -14,6 +14,8 @@ import LivechatDepartmentModel from '../models/LivechatDepartment';
import { LivechatDepartmentRaw } from './LivechatDepartment';
import LivechatDepartmentAgentsModel from '../models/LivechatDepartmentAgents';
import { LivechatDepartmentAgentsRaw } from './LivechatDepartmentAgents';
import MessagesModel from '../models/Messages';
import { MessagesRaw } from './Messages';

export const Permissions = new PermissionsRaw(PermissionsModel.model.rawCollection());
export const Roles = new RolesRaw(RolesModel.model.rawCollection());
Expand All @@ -23,3 +25,4 @@ export const Users = new UsersRaw(UsersModel.model.rawCollection());
export const Rooms = new RoomsRaw(RoomsModel.model.rawCollection());
export const LivechatDepartment = new LivechatDepartmentRaw(LivechatDepartmentModel.model.rawCollection());
export const LivechatDepartmentAgents = new LivechatDepartmentAgentsRaw(LivechatDepartmentAgentsModel.model.rawCollection());
export const Messages = new MessagesRaw(MessagesModel.model.rawCollection());
3 changes: 2 additions & 1 deletion server/startup/migrations/v131.js
@@ -1,5 +1,6 @@
import { Migrations } from '../../../app/migrations';
import { Users, Subscriptions, Rooms, Messages } from '../../../app/models';
import { FileUpload } from '../../../app/file-upload/server';

Migrations.add({
version: 131,
Expand Down Expand Up @@ -35,7 +36,7 @@ Migrations.add({
// Remove direct messages and also non-channel rooms with only 1 user (the one being deleted)
if (room.t === 'd' || (room.t !== 'c' && Subscriptions.findByRoomId(room._id).count() === 1)) {
Subscriptions.removeByRoomId(subscription.rid);
Messages.removeFilesByRoomId(subscription.rid);
FileUpload.removeFilesByRoomId(subscription.rid);
Messages.removeByRoomId(subscription.rid);
Rooms.removeById(subscription.rid);
}
Expand Down
41 changes: 41 additions & 0 deletions tests/end-to-end/api/05-chat.js
Expand Up @@ -2076,4 +2076,45 @@ describe('Threads', () => {
});
});
});

describe('[/chat.getMentionedMessages]', () => {
it('should return an error when the required "roomId" parameter is not sent', (done) => {
request.get(api('chat.getMentionedMessages'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-invalid-params');
})
.end(done);
});

it('should return an error when the roomId is invalid', (done) => {
request.get(api('chat.getMentionedMessages?roomId=invalid-room'))
.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-allowed');
})
.end(done);
});

it('should return the mentioned messages', (done) => {
request.get(api('chat.getMentionedMessages?roomId=GENERAL'))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.messages).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);
});
});
});

0 comments on commit 6eeb30d

Please sign in to comment.