Skip to content

Commit

Permalink
[NEW][ENTERPRISE] Hide message history for new channel members (#20253)
Browse files Browse the repository at this point in the history
Co-authored-by: Gabriel Thomé <gabrielallan.thome@gmail.com>
Co-authored-by: Pierre Lehnen <pierre.lehnen@rocket.chat>
Co-authored-by: Rodrigo Nascimento <rodrigoknascimento@gmail.com>
  • Loading branch information
4 people committed Jan 23, 2021
1 parent 24a9727 commit 97311da
Show file tree
Hide file tree
Showing 51 changed files with 1,228 additions and 294 deletions.
41 changes: 20 additions & 21 deletions app/api/server/lib/messages.js
@@ -1,6 +1,7 @@
import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom';
import { Rooms, Messages, Users } from '../../../models/server/raw';
import { getValue } from '../../../settings/server/raw';
import { Message } from '../../../../server/sdk';

export async function findMentionedMessages({ uid, roomId, pagination: { offset, count, sort } }) {
const room = await Rooms.findOneById(roomId);
Expand All @@ -12,16 +13,16 @@ export async function findMentionedMessages({ uid, roomId, pagination: { offset,
throw new Error('invalid-user');
}

const cursor = await Messages.findVisibleByMentionAndRoomId(user.username, roomId, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
const { records: messages, total } = await Message.get(uid, {
rid: roomId,
mentionsUsername: user.username,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
},
});

const total = await cursor.count();

const messages = await cursor.toArray();

return {
messages,
count: messages.length,
Expand Down Expand Up @@ -98,15 +99,13 @@ export async function findSnippetedMessages({ uid, roomId, pagination: { offset,
throw new Error('error-not-allowed');
}

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

const total = await cursor.count();
};

const messages = await cursor.toArray();
const { records: messages, total } = await Message.get(uid, { snippeted: true, queryOptions });

return {
messages,
Expand All @@ -123,16 +122,16 @@ export async function findDiscussionsFromRoom({ uid, roomId, text, pagination: {
throw new Error('error-not-allowed');
}

const cursor = Messages.findDiscussionsByRoomAndText(roomId, text, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
const { records: messages, total } = await Message.getDiscussions({
rid: roomId,
text,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
},
});

const total = await cursor.count();

const messages = await cursor.toArray();

return {
messages,
count: messages.length,
Expand Down
24 changes: 13 additions & 11 deletions app/api/server/v1/channels.js
Expand Up @@ -7,6 +7,7 @@ import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/s
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { API } from '../api';
import { settings } from '../../../settings';
import { Message } from '../../../../server/sdk';


// Returns the channel IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
Expand Down Expand Up @@ -337,12 +338,12 @@ API.v1.addRoute('channels.history', { authRequired: true }, {
get() {
const findResult = findChannelByIdOrName({ params: this.requestParams(), checkedArchived: false });

let latestDate = new Date();
let latestDate;
if (this.queryParams.latest) {
latestDate = new Date(this.queryParams.latest);
}

let oldestDate = undefined;
let oldestDate;
if (this.queryParams.oldest) {
oldestDate = new Date(this.queryParams.oldest);
}
Expand Down Expand Up @@ -576,15 +577,16 @@ API.v1.addRoute('channels.messages', { authRequired: true }, {
return API.v1.unauthorized();
}

const cursor = Messages.find(ourQuery, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
});

const total = cursor.count();
const messages = cursor.fetch();
const { records: messages, total } = Promise.await(Message.customQuery({
query: ourQuery,
userId: this.userId,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
messages: normalizeMessagesForUser(messages, this.userId),
Expand Down
68 changes: 38 additions & 30 deletions app/api/server/v1/chat.js
Expand Up @@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';

import { Messages } from '../../../models';
import { Message } from '../../../../server/sdk';
import { canAccessRoom, hasPermission } from '../../../authorization';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { processWebhookMessage } from '../../../lib/server';
Expand Down Expand Up @@ -408,14 +409,14 @@ API.v1.addRoute('chat.getPinnedMessages', { authRequired: true }, {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}

const cursor = Messages.findPinnedByRoom(room._id, {
skip: offset,
limit: count,
});

const total = cursor.count();

const messages = cursor.fetch();
const { records: messages, total } = Promise.await(Message.get(this.userId, {
rid: room._id,
pinned: true,
queryOptions: {
skip: offset,
limit: count,
},
}));

return API.v1.success({
messages,
Expand Down Expand Up @@ -456,16 +457,17 @@ API.v1.addRoute('chat.getThreadsList', { authRequired: true }, {
};

const threadQuery = { ...query, ...typeThread, rid, tcount: { $exists: true } };
const cursor = Messages.find(threadQuery, {
sort: sort || { tlm: -1 },
skip: offset,
limit: count,
fields,
});

const total = cursor.count();

const threads = cursor.fetch();
const { records: threads, total } = Promise.await(Message.customQuery({
query: threadQuery,
userId: this.userId,
queryOptions: {
sort: sort || { tlm: -1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
threads,
Expand Down Expand Up @@ -501,11 +503,12 @@ API.v1.addRoute('chat.syncThreadsList', { authRequired: true }, {
if (!canAccessRoom(room, user)) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
const threadQuery = Object.assign({}, query, { rid, tcount: { $exists: true } });
const threadQuery = { ...query, rid, tcount: { $exists: true } };

return API.v1.success({
threads: {
update: Messages.find({ ...threadQuery, _updatedAt: { $gt: updatedSinceDate } }, { fields, sort }).fetch(),
remove: Messages.trashFindDeletedAfter(updatedSinceDate, threadQuery, { fields, sort }).fetch(),
update: Promise.await(Message.customQuery({ query: { ...threadQuery, _updatedAt: { $gt: updatedSinceDate } }, queryOptions: { returnTotal: false, fields, sort } })).records,
remove: Promise.await(Message.getDeleted({ rid, userId: this.userId, timestamp: updatedSinceDate, query: threadQuery, queryOptions: { returnTotal: false, fields, sort } })).records,
},
});
},
Expand Down Expand Up @@ -533,16 +536,19 @@ API.v1.addRoute('chat.getThreadMessages', { authRequired: true }, {
if (!canAccessRoom(room, user)) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
const cursor = Messages.find({ ...query, tmid }, {
sort: sort || { ts: 1 },
skip: offset,
limit: count,
fields,
});

const total = cursor.count();
const ourQuery = Object.assign({}, query, { rid: thread.rid, tmid });

const messages = cursor.fetch();
const { records: messages, total } = Promise.await(Message.customQuery({
query: ourQuery,
userId: this.userId,
queryOptions: {
sort: sort || { ts: 1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
messages,
Expand Down Expand Up @@ -573,6 +579,7 @@ API.v1.addRoute('chat.syncThreadMessages', { authRequired: true }, {
} else {
updatedSinceDate = new Date(updatedSince);
}

const thread = Messages.findOneById(tmid, { fields: { rid: 1 } });
if (!thread || !thread.rid) {
throw new Meteor.Error('error-invalid-message', 'Invalid Message');
Expand All @@ -583,10 +590,11 @@ API.v1.addRoute('chat.syncThreadMessages', { authRequired: true }, {
if (!canAccessRoom(room, user)) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}

return API.v1.success({
messages: {
update: Messages.find({ ...query, tmid, _updatedAt: { $gt: updatedSinceDate } }, { fields, sort }).fetch(),
remove: Messages.trashFindDeletedAfter(updatedSinceDate, { ...query, tmid }, { fields, sort }).fetch(),
update: Promise.await(Message.customQuery({ query: { ...query, tmid, _updatedAt: { $gt: updatedSinceDate } }, queryOptions: { returnTotal: false, fields, sort } })).records,
remove: Promise.await(Message.getDeleted({ rid: thread.rid, timestamp: updatedSinceDate, query: { ...query, tmid }, queryOptions: { returnTotal: false, fields, sort } })).records,
},
});
},
Expand Down
19 changes: 12 additions & 7 deletions app/api/server/v1/groups.js
Expand Up @@ -7,6 +7,7 @@ import { Subscriptions, Rooms, Messages, Uploads, Integrations, Users } from '..
import { hasPermission, hasAtLeastOnePermission, canAccessRoom } from '../../../authorization/server';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { API } from '../api';
import { Message } from '../../../../server/sdk';

// Returns the private group subscription IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
export function findPrivateGroupByIdOrName({ params, userId, checkedArchived = true }) {
Expand Down Expand Up @@ -525,18 +526,22 @@ API.v1.addRoute('groups.messages', { authRequired: true }, {

const ourQuery = Object.assign({}, query, { rid: findResult.rid });

const messages = Messages.find(ourQuery, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
}).fetch();
const { records: messages, total } = Promise.await(Message.customQuery({
query: ourQuery,
userId: this.userId,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
messages: normalizeMessagesForUser(messages, this.userId),
count: messages.length,
offset,
total: Messages.find(ourQuery).count(),
total,
});
},
});
Expand Down
39 changes: 24 additions & 15 deletions app/api/server/v1/im.js
@@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';

import { Subscriptions, Uploads, Users, Messages, Rooms } from '../../../models';
import { Subscriptions, Uploads, Users, Rooms } from '../../../models';
import { hasPermission } from '../../../authorization';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { settings } from '../../../settings';
import { API } from '../api';
import { getDirectMessageByNameOrIdWithOptionToJoin } from '../../../lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin';
import { Message } from '../../../../server/sdk';

function findDirectMessageRoom(params, user) {
if ((!params.roomId || !params.roomId.trim()) && (!params.username || !params.username.trim())) {
Expand Down Expand Up @@ -234,18 +235,22 @@ API.v1.addRoute(['dm.messages', 'im.messages'], { authRequired: true }, {

const ourQuery = Object.assign({}, query, { rid: findResult.room._id });

const messages = Messages.find(ourQuery, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
}).fetch();
const { records: messages, total } = Promise.await(Message.customQuery({
query: ourQuery,
userId: this.userId,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
messages: normalizeMessagesForUser(messages, this.userId),
count: messages.length,
offset,
total: Messages.find(ourQuery).count(),
total,
});
},
});
Expand Down Expand Up @@ -274,18 +279,22 @@ API.v1.addRoute(['dm.messages.others', 'im.messages.others'], { authRequired: tr
const { sort, fields, query } = this.parseJsonQuery();
const ourQuery = Object.assign({}, query, { rid: room._id });

const msgs = Messages.find(ourQuery, {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
}).fetch();
const { records: msgs, total } = Promise.await(Message.customQuery({
query: ourQuery,
userId: this.userId,
queryOptions: {
sort: sort || { ts: -1 },
skip: offset,
limit: count,
fields,
},
}));

return API.v1.success({
messages: normalizeMessagesForUser(msgs, this.userId),
offset,
count: msgs.length,
total: Messages.find(ourQuery).count(),
total,
});
},
});
Expand Down
14 changes: 13 additions & 1 deletion app/channel-settings/server/methods/saveRoomSettings.js
Expand Up @@ -18,8 +18,9 @@ import { saveRoomTokenpass } from '../functions/saveRoomTokens';
import { saveRoomEncrypted } from '../functions/saveRoomEncrypted';
import { saveStreamingOptions } from '../functions/saveStreamingOptions';
import { RoomSettingsEnum, roomTypes } from '../../../utils';
import { isEnterprise } from '../../../../ee/app/license/server/license';

const fields = ['roomAvatar', 'featured', 'roomName', 'roomTopic', 'roomAnnouncement', 'roomCustomFields', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass', 'streamingOptions', 'retentionEnabled', 'retentionMaxAge', 'retentionExcludePinned', 'retentionFilesOnly', 'retentionIgnoreThreads', 'retentionOverrideGlobal', 'encrypted', 'favorite'];
const fields = ['roomAvatar', 'featured', 'roomName', 'roomTopic', 'roomAnnouncement', 'roomCustomFields', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass', 'streamingOptions', 'retentionEnabled', 'retentionMaxAge', 'retentionExcludePinned', 'retentionFilesOnly', 'retentionIgnoreThreads', 'retentionOverrideGlobal', 'encrypted', 'favorite', 'hideHistoryForNewMembers'];

const validators = {
default({ userId }) {
Expand Down Expand Up @@ -122,6 +123,14 @@ const validators = {
});
}
},
hideHistoryForNewMembers({ value }) {
if (!isEnterprise() && value) {
throw new Meteor.Error('error-action-not-allowed', 'Hiding the history for new users is not allowed.', {
method: 'saveRoomSettings',
action: 'Editing_room',
});
}
},
};

const settingSavers = {
Expand Down Expand Up @@ -217,6 +226,9 @@ const settingSavers = {
roomAvatar({ value, rid, user }) {
setRoomAvatar(rid, value, user);
},
hideHistoryForNewMembers({ value, rid }) {
Rooms.saveHideHistoryForNewMembers(rid, value);
},
};

Meteor.methods({
Expand Down

0 comments on commit 97311da

Please sign in to comment.