From 101f77dd7933e31e562b8cb9098fcf73c4672b9b Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 28 Feb 2020 14:29:51 -0300 Subject: [PATCH 01/64] improve room types usage --- app/api/server/v1/im.js | 7 ++-- .../client/views/channelSettings.js | 24 +++++++------- .../server/functions/saveRoomName.js | 2 +- app/lib/lib/roomTypes/direct.js | 10 +++++- app/lib/lib/roomTypes/private.js | 4 +++ app/lib/lib/roomTypes/public.js | 10 +++++- ...DirectMessageByNameOrIdWithOptionToJoin.js | 7 ++++ .../server/functions/processWebhookMessage.js | 5 +-- app/lib/server/methods/addUsersToRoom.js | 2 +- app/lib/server/methods/archiveRoom.js | 9 +++--- app/lib/server/methods/joinRoom.js | 5 +++ app/lib/server/methods/leaveRoom.js | 7 +++- app/ui-admin/client/rooms/adminRooms.js | 2 +- app/ui-flextab/client/tabs/membersList.js | 16 +++++----- app/ui-flextab/client/tabs/userActions.js | 32 ++++++++++++++++--- app/ui-sidenav/client/roomList.js | 2 +- app/ui-utils/client/lib/ChannelActions.js | 4 +-- app/ui/client/views/app/createChannel.js | 4 +-- app/ui/client/views/app/room.js | 4 +-- app/utils/client/index.js | 2 +- app/utils/lib/RoomTypeConfig.js | 18 +++++++++++ app/utils/server/index.js | 2 +- server/methods/eraseRoom.js | 2 +- server/methods/muteUserInRoom.js | 7 ++-- server/methods/unmuteUserInRoom.js | 3 +- 25 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js diff --git a/app/api/server/v1/im.js b/app/api/server/v1/im.js index 5afd41d05cb1..68bcc4db3ec3 100644 --- a/app/api/server/v1/im.js +++ b/app/api/server/v1/im.js @@ -1,26 +1,25 @@ import { Meteor } from 'meteor/meteor'; -import { getRoomByNameOrIdWithOptionToJoin } from '../../../lib'; import { Subscriptions, Uploads, Users, Messages, 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'; function findDirectMessageRoom(params, user) { if ((!params.roomId || !params.roomId.trim()) && (!params.username || !params.username.trim())) { throw new Meteor.Error('error-room-param-not-provided', 'Body param "roomId" or "username" is required'); } - const room = getRoomByNameOrIdWithOptionToJoin({ + const room = getDirectMessageByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: params.username || params.roomId, - type: 'd', }); const canAccess = Meteor.call('canAccessRoom', room._id, user._id); if (!canAccess || !room || room.t !== 'd') { - throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "username" param provided does not match any dirct message'); + throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "username" param provided does not match any direct message'); } const subscription = Subscriptions.findOneByRoomIdAndUserId(room._id, user._id); diff --git a/app/channel-settings/client/views/channelSettings.js b/app/channel-settings/client/views/channelSettings.js index 5b1a31bfcd56..0075d457a1be 100644 --- a/app/channel-settings/client/views/channelSettings.js +++ b/app/channel-settings/client/views/channelSettings.js @@ -29,7 +29,7 @@ const common = { }); const roomType = room && room.t; - return roomType && roomTypes.roomTypes[roomType].canBeDeleted(hasPermission, room); + return roomType && roomTypes.getConfig(roomType).canBeDeleted(hasPermission, room); }, canEditRoom() { const { _id } = Template.instance().room; @@ -223,7 +223,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'text', label: 'Name', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.NAME); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.NAME); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -270,7 +270,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'markdown', label: 'Topic', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.TOPIC); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.TOPIC); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -289,7 +289,7 @@ Template.channelSettingsEditing.onCreated(function() { return Template.instance().room.announcement; }, canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.ANNOUNCEMENT); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.ANNOUNCEMENT); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -305,7 +305,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'text', label: 'Description', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.DESCRIPTION); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.DESCRIPTION); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -386,7 +386,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.READ_ONLY); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.READ_ONLY); }, canEdit() { return !room.broadcast && hasAllPermission('set-readonly', room._id); @@ -401,7 +401,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.REACT_WHEN_READ_ONLY); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.REACT_WHEN_READ_ONLY); }, canEdit() { return !room.broadcast && hasAllPermission('set-react-when-readonly', room._id); @@ -418,7 +418,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange( + return roomTypes.getConfig(room.t).allowRoomSettingChange( room, RoomSettingsEnum.SYSTEM_MESSAGES, ); @@ -460,7 +460,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.ARCHIVE_OR_UNARCHIVE); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.ARCHIVE_OR_UNARCHIVE); }, canEdit() { return hasAtLeastOnePermission(['archive-room', 'unarchive-room'], room._id); @@ -501,7 +501,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.BROADCAST); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.BROADCAST); }, canEdit() { return false; @@ -516,7 +516,7 @@ Template.channelSettingsEditing.onCreated(function() { showingValue: new ReactiveVar(false), realValue: null, canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.JOIN_CODE) && hasAllPermission('edit-room', room._id); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.JOIN_CODE) && hasAllPermission('edit-room', room._id); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -679,7 +679,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.E2E); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.E2E); }, canEdit() { return hasAllPermission('edit-room', room._id); diff --git a/app/channel-settings/server/functions/saveRoomName.js b/app/channel-settings/server/functions/saveRoomName.js index be509b42e74e..5ce24f9c7829 100644 --- a/app/channel-settings/server/functions/saveRoomName.js +++ b/app/channel-settings/server/functions/saveRoomName.js @@ -14,7 +14,7 @@ const updateRoomName = (rid, displayName, isDiscussion) => { export const saveRoomName = function(rid, displayName, user, sendMessage = true) { const room = Rooms.findOneById(rid); - if (roomTypes.roomTypes[room.t].preventRenaming()) { + if (roomTypes.getConfig(room.t).preventRenaming()) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { function: 'RocketChat.saveRoomdisplayName', }); diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index dc6a35a79275..63709aa76c19 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -3,7 +3,7 @@ import { Session } from 'meteor/session'; import { ChatRoom, Subscriptions } from '../../../models'; import { openRoom } from '../../../ui-utils'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; import { hasPermission, hasAtLeastOnePermission } from '../../../authorization'; import { settings } from '../../../settings'; import { getUserAvatarURL } from '../../../utils/lib/getUserAvatarURL'; @@ -118,6 +118,14 @@ export class DirectMessageRoomType extends RoomTypeConfig { } } + allowMemberAction(room, action) { + switch (action) { + case RoomMemberActions.MUTE: + default: + return false; + } + } + enableMembersListProfile() { return true; } diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index 9de5cf1fac9a..219ebbc8e9dd 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -98,6 +98,10 @@ export class PrivateRoomType extends RoomTypeConfig { } } + allowMemberAction(/* room, action */) { + return true; + } + enableMembersListProfile() { return true; } diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 4cef013026a6..b4a4bfc42a42 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -4,7 +4,7 @@ import { openRoom } from '../../../ui-utils'; import { ChatRoom, ChatSubscription } from '../../../models'; import { settings } from '../../../settings'; import { hasAtLeastOnePermission } from '../../../authorization'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; import { getAvatarURL } from '../../../utils/lib/getAvatarURL'; export class PublicRoomRoute extends RoomTypeRouteConfig { @@ -113,6 +113,14 @@ export class PublicRoomType extends RoomTypeConfig { } } + allowMemberAction(room, action) { + switch (action) { + case RoomMemberActions.MUTE: + default: + return true; + } + } + getUiText(context) { switch (context) { case UiTextContext.HIDE_WARNING: diff --git a/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js b/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js new file mode 100644 index 000000000000..f21980cba5ad --- /dev/null +++ b/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js @@ -0,0 +1,7 @@ +import { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; + +export const getDirectMessageByNameOrIdWithOptionToJoin = (args) => + getRoomByNameOrIdWithOptionToJoin({ ...args, type: 'd' }); + +export const getDirectMessageByIdWithOptionToJoin = (args) => + getDirectMessageByNameOrIdWithOptionToJoin({ ...args, tryDirectByUserIdOnly: true }); diff --git a/app/lib/server/functions/processWebhookMessage.js b/app/lib/server/functions/processWebhookMessage.js index c51f4fb85b96..a667203b47a5 100644 --- a/app/lib/server/functions/processWebhookMessage.js +++ b/app/lib/server/functions/processWebhookMessage.js @@ -5,6 +5,7 @@ import s from 'underscore.string'; import { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; import { sendMessage } from './sendMessage'; import { Subscriptions } from '../../../models'; +import { getDirectMessageByIdWithOptionToJoin, getDirectMessageByNameOrIdWithOptionToJoin } from './getDirectMessageByNameOrIdWithOptionToJoin'; export const processWebhookMessage = function(messageObj, user, defaultValues = { channel: '', alias: '', avatar: '', emoji: '' }, mustBeJoined = false) { const sentData = []; @@ -21,7 +22,7 @@ export const processWebhookMessage = function(messageObj, user, defaultValues = room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, joinChannel: true }); break; case '@': - room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, type: 'd' }); + room = getDirectMessageByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue }); break; default: channelValue = channelType + channelValue; @@ -33,7 +34,7 @@ export const processWebhookMessage = function(messageObj, user, defaultValues = } // We didn't get a room, let's try finding direct messages - room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, type: 'd', tryDirectByUserIdOnly: true }); + room = getDirectMessageByIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue }); if (room) { break; } diff --git a/app/lib/server/methods/addUsersToRoom.js b/app/lib/server/methods/addUsersToRoom.js index 63eaa7594a83..9070fa080d5e 100644 --- a/app/lib/server/methods/addUsersToRoom.js +++ b/app/lib/server/methods/addUsersToRoom.js @@ -30,7 +30,7 @@ Meteor.methods({ const userInRoom = subscription != null; // Can't add to direct room ever - if (room.t === 'd') { + if (room.t === 'd') { // TODO CHANGE throw new Meteor.Error('error-cant-invite-for-direct-room', 'Can\'t invite user to direct rooms', { method: 'addUsersToRoom', }); diff --git a/app/lib/server/methods/archiveRoom.js b/app/lib/server/methods/archiveRoom.js index 3bc7ee6634b1..ced684c6b12c 100644 --- a/app/lib/server/methods/archiveRoom.js +++ b/app/lib/server/methods/archiveRoom.js @@ -4,6 +4,7 @@ import { check } from 'meteor/check'; import { Rooms } from '../../../models'; import { hasPermission } from '../../../authorization'; import { archiveRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ archiveRoom(rid) { @@ -19,12 +20,12 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'archiveRoom' }); } - if (!hasPermission(Meteor.userId(), 'archive-room', room._id)) { - throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'archiveRoom' }); + if (roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.ARCHIVE)) { + throw new Meteor.Error('error-direct-message-room', `rooms type: ${ room.r } can not be archived`, { method: 'archiveRoom' }); } - if (room.t === 'd') { - throw new Meteor.Error('error-direct-message-room', 'Direct Messages can not be archived', { method: 'archiveRoom' }); + if (!hasPermission(Meteor.userId(), 'archive-room', room._id)) { + throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'archiveRoom' }); } return archiveRoom(rid); diff --git a/app/lib/server/methods/joinRoom.js b/app/lib/server/methods/joinRoom.js index a82773b6dfee..76a4a99ce91c 100644 --- a/app/lib/server/methods/joinRoom.js +++ b/app/lib/server/methods/joinRoom.js @@ -5,6 +5,7 @@ import { hasPermission, canAccessRoom } from '../../../authorization'; import { Rooms } from '../../../models'; import { Tokenpass, updateUserTokenpassBalances } from '../../../tokenpass/server'; import { addUserToRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ joinRoom(rid, code) { @@ -20,6 +21,10 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); } + if (roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.JOIN)) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); + } + // TODO we should have a 'beforeJoinRoom' call back so external services can do their own validations const user = Meteor.user(); if (room.tokenpass && user && user.services && user.services.tokenpass) { diff --git a/app/lib/server/methods/leaveRoom.js b/app/lib/server/methods/leaveRoom.js index 7cde6187ba2a..8ad49033e9f6 100644 --- a/app/lib/server/methods/leaveRoom.js +++ b/app/lib/server/methods/leaveRoom.js @@ -4,6 +4,7 @@ import { check } from 'meteor/check'; import { hasPermission, hasRole, getUsersInRole } from '../../../authorization'; import { Subscriptions, Rooms } from '../../../models'; import { removeUserFromRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ leaveRoom(rid) { @@ -16,7 +17,11 @@ Meteor.methods({ const room = Rooms.findOneById(rid); const user = Meteor.user(); - if (room.t === 'd' || (room.t === 'c' && !hasPermission(user._id, 'leave-c')) || (room.t === 'p' && !hasPermission(user._id, 'leave-p'))) { + if (roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.LEAVE)) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' }); + } + + if ((room.t === 'c' && !hasPermission(user._id, 'leave-c')) || (room.t === 'p' && !hasPermission(user._id, 'leave-p'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' }); } diff --git a/app/ui-admin/client/rooms/adminRooms.js b/app/ui-admin/client/rooms/adminRooms.js index dc103caf69cb..4a7133850330 100644 --- a/app/ui-admin/client/rooms/adminRooms.js +++ b/app/ui-admin/client/rooms/adminRooms.js @@ -40,7 +40,7 @@ Template.adminRooms.helpers({ return Template.instance().rooms.get().length; }, type() { - return TAPi18n.__(roomTypes.roomTypes[this.t].label); + return TAPi18n.__(roomTypes.getConfig(this.t).label); }, 'default'() { if (this.default) { diff --git a/app/ui-flextab/client/tabs/membersList.js b/app/ui-flextab/client/tabs/membersList.js index c7a6a3ec86bc..811d171d2554 100644 --- a/app/ui-flextab/client/tabs/membersList.js +++ b/app/ui-flextab/client/tabs/membersList.js @@ -23,7 +23,7 @@ Template.membersList.helpers({ isGroupChat() { const room = ChatRoom.findOne(this.rid, { reactive: false }); - return roomTypes.roomTypes[room.t].isGroupChat(); + return roomTypes.getConfig(room.t).isGroupChat(); }, isDirectChat() { @@ -98,7 +98,7 @@ Template.membersList.helpers({ canAddUser() { const roomData = Session.get(`roomData${ this._id }`); if (!roomData) { return ''; } - return (() => roomTypes.roomTypes[roomData.t].canAddUser(roomData))(); + return (() => roomTypes.getConfig(roomData.t).canAddUser(roomData))(); }, canInviteUser() { @@ -123,10 +123,10 @@ Template.membersList.helpers({ tabBar: Template.currentData().tabBar, username: Template.instance().userDetail.get(), clear: Template.instance().clearUserDetail, - showAll: roomTypes.roomTypes[room.t].userDetailShowAll(room) || false, - hideAdminControls: roomTypes.roomTypes[room.t].userDetailShowAdmin(room) || false, + showAll: roomTypes.getConfig(room.t).userDetailShowAll(room) || false, + hideAdminControls: roomTypes.getConfig(room.t).userDetailShowAdmin(room) || false, video: ['d'].includes(room && room.t), - showBackButton: roomTypes.roomTypes[room.t].isGroupChat(), + showBackButton: roomTypes.getConfig(room.t).isGroupChat(), }; }, displayName() { @@ -183,8 +183,8 @@ Template.membersList.events({ const room = Session.get(`roomData${ instance.data.rid }`); const _actions = getActions({ user: this.user.user, - hideAdminControls: roomTypes.roomTypes[room.t].userDetailShowAdmin(room) || false, - directActions: roomTypes.roomTypes[room.t].userDetailShowAll(room) || false, + hideAdminControls: roomTypes.getConfig(room.t).userDetailShowAdmin(room) || false, + directActions: roomTypes.getConfig(room.t).userDetailShowAll(room) || false, }) .map((action) => (typeof action === 'function' ? action.call(this) : action)) .filter((action) => action && (!action.condition || action.condition.call(this))); @@ -235,7 +235,7 @@ Template.membersList.events({ 'autocompleteselect #user-add-search'(event, template, doc) { const roomData = Session.get(`roomData${ template.data.rid }`); - if (roomTypes.roomTypes[roomData.t].canAddUser(roomData)) { + if (roomTypes.getConfig(roomData.t).canAddUser(roomData)) { return Meteor.call('addUserToRoom', { rid: roomData._id, username: doc.username }, function(error) { if (error) { return handleError(error); diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index d1947e1e8661..41df3fb08384 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -11,6 +11,7 @@ import { modal } from '../../../ui-utils'; import { t, handleError, roomTypes } from '../../../utils'; import { settings } from '../../../settings'; import { hasPermission, hasAllPermission, userHasAllPermission } from '../../../authorization'; +import { RoomMemberActions } from '../../../utils/client'; const canSetLeader = () => hasAllPermission('set-leader', Session.get('openedRoom')); @@ -49,12 +50,12 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { user && user._id && !!RoomRoles.findOne({ rid: Session.get('openedRoom'), 'u._id': user._id, roles: 'moderator' }); const isInDirectMessageRoom = () => { const room = ChatRoom.findOne(Session.get('openedRoom')); - return (room && room.t) === 'd'; + return roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK); }; - const isMuted = () => { - const room = ChatRoom.findOne(Session.get('openedRoom')); + const room = ChatRoom.findOne(Session.get('openedRoom')); + const isMuted = () => { if (room && room.ro) { if (_.isArray(room.unmuted) && room.unmuted.indexOf(user && user.username) !== -1) { return false; @@ -191,6 +192,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !isInDirectMessageRoom() || isSelf(this.username)) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK)) { + return; + } if (canBlockUser()) { return { icon: 'ban', @@ -208,6 +212,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetOwner()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_OWNER)) { + return; + } if (isOwner()) { return { group: 'channel', @@ -243,6 +250,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetLeader()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_LEADER)) { + return; + } if (isLeader()) { return { group: 'channel', @@ -279,6 +289,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetModerator()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_MODERATOR)) { + return; + } if (isModerator()) { return { group: 'channel', @@ -315,6 +328,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || user._id === Meteor.userId()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.IGNORE)) { + return; + } if (isIgnored()) { return { group: 'channel', @@ -333,6 +349,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canMuteUser()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { + return; + } if (isMuted()) { return { group: 'channel', @@ -412,7 +431,12 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { return this.instance.clear(); }))); }), - condition: () => directActions && canRemoveUser(), + condition: () => { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.KICK)) { + return; + } + return directActions && canRemoveUser(); + }, }, { icon: 'edit', name: 'Edit', diff --git a/app/ui-sidenav/client/roomList.js b/app/ui-sidenav/client/roomList.js index 8648099a7b05..23c0661a30a0 100644 --- a/app/ui-sidenav/client/roomList.js +++ b/app/ui-sidenav/client/roomList.js @@ -128,7 +128,7 @@ Template.roomList.helpers({ if (instance.data.anonymous) { return 'No_channels_yet'; } - return roomTypes.roomTypes[instance.data.identifier].getUiText(UiTextContext.NO_ROOMS_SUBSCRIBED) || 'No_channels_yet'; + return roomTypes.getConfig(instance.data.identifier).getUiText(UiTextContext.NO_ROOMS_SUBSCRIBED) || 'No_channels_yet'; }, }); diff --git a/app/ui-utils/client/lib/ChannelActions.js b/app/ui-utils/client/lib/ChannelActions.js index 1fb6493a6fc5..fe5c1fddd45e 100644 --- a/app/ui-utils/client/lib/ChannelActions.js +++ b/app/ui-utils/client/lib/ChannelActions.js @@ -7,7 +7,7 @@ import { RoomManager } from './RoomManager'; import { t, UiTextContext, roomTypes, handleError } from '../../../utils'; export function hide(type, rid, name) { - const warnText = roomTypes.roomTypes[type].getUiText(UiTextContext.HIDE_WARNING); + const warnText = roomTypes.getConfig(type).getUiText(UiTextContext.HIDE_WARNING); modal.open({ title: t('Are_you_sure'), @@ -37,7 +37,7 @@ export function hide(type, rid, name) { } export async function leave(type, rid, name) { - const warnText = roomTypes.roomTypes[type].getUiText(UiTextContext.LEAVE_WARNING); + const warnText = roomTypes.getConfig(type).getUiText(UiTextContext.LEAVE_WARNING); modal.open({ title: t('Are_you_sure'), diff --git a/app/ui/client/views/app/createChannel.js b/app/ui/client/views/app/createChannel.js index 44b929cb3176..3d1b56de00f7 100644 --- a/app/ui/client/views/app/createChannel.js +++ b/app/ui/client/views/app/createChannel.js @@ -157,7 +157,7 @@ Template.createChannel.helpers({ return roomTypes.roomTypesOrder.filter( (roomTypeOrder) => roomTypeOrder.order < orderLow, ).map( - (roomTypeOrder) => roomTypes.roomTypes[roomTypeOrder.identifier], + (roomTypeOrder) => roomTypes.getConfig(roomTypeOrder.identifier), ).filter((roomType) => roomType.creationTemplate); }, roomTypesAfterStandard() { @@ -165,7 +165,7 @@ Template.createChannel.helpers({ return roomTypes.roomTypesOrder.filter( (roomTypeOrder) => roomTypeOrder.order > orderHigh, ).map( - (roomTypeOrder) => roomTypes.roomTypes[roomTypeOrder.identifier], + (roomTypeOrder) => roomTypes.getConfig(roomTypeOrder.identifier), ).filter((roomType) => roomType.creationTemplate); }, }); diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 312209a977b6..24817753d495 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -59,7 +59,7 @@ const openProfileTab = (e, instance, username) => { } const roomData = Session.get(`roomData${ RoomManager.openedRoom }`); - if (roomTypes.roomTypes[roomData.t].enableMembersListProfile()) { + if (roomTypes.getConfig(roomData.t).enableMembersListProfile()) { instance.userDetail.set(username); } @@ -1287,7 +1287,7 @@ Template.room.onRendered(function() { this.autorun(() => { const subscription = Subscriptions.findOne({ rid }, { fields: { alert: 1, unread: 1 } }); read(); - return subscription && (subscription.alert || subscription.unread) && readMessage.refreshUnreadMark(rid); + return subscription && (subscription.alert || subscription.unread);// && readMessage.refreshUnreadMark(rid); }); this.autorun(() => { diff --git a/app/utils/client/index.js b/app/utils/client/index.js index 129c1acf9a7f..6b2060f5d0e2 100644 --- a/app/utils/client/index.js +++ b/app/utils/client/index.js @@ -6,7 +6,7 @@ export { handleError } from './lib/handleError'; export { getUserPreference } from '../lib/getUserPreference'; export { fileUploadMediaWhiteList, fileUploadIsValidContentType } from '../lib/fileUploadRestrictions'; export { roomTypes } from './lib/roomTypes'; -export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, UiTextContext } from '../lib/RoomTypeConfig'; +export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../lib/RoomTypeConfig'; export { RoomTypesCommon } from '../lib/RoomTypesCommon'; export { getUserAvatarURL } from '../lib/getUserAvatarURL'; export { slashCommands } from '../lib/slashCommand'; diff --git a/app/utils/lib/RoomTypeConfig.js b/app/utils/lib/RoomTypeConfig.js index ac0aa49d3519..fbb205b49109 100644 --- a/app/utils/lib/RoomTypeConfig.js +++ b/app/utils/lib/RoomTypeConfig.js @@ -24,6 +24,20 @@ export const RoomSettingsEnum = { E2E: 'encrypted', }; +export const RoomMemberActions = { + ARCHIVE: 'archive', + IGNORE: 'ignore', + BLOCK: 'block', + MUTE: 'mute', + SET_AS_OWNER: 'setAsOwner', + SET_AS_LEADER: 'setAsLeader', + SET_AS_MODERATOR: 'setAsModerator', + LEAVE: 'leave', + KICK: 'kick', + JOIN: 'join', + INVITE: 'invite', +}; + export const UiTextContext = { CLOSE_WARNING: 'closeWarning', HIDE_WARNING: 'hideWarning', @@ -154,6 +168,10 @@ export class RoomTypeConfig { return true; } + allowMemberAction(/* room, action */) { + return false; + } + /** * Return a room's name * diff --git a/app/utils/server/index.js b/app/utils/server/index.js index 07d2f50c4970..e8d909ef79c4 100644 --- a/app/utils/server/index.js +++ b/app/utils/server/index.js @@ -4,7 +4,7 @@ export { Info } from '../rocketchat.info'; export { getUserPreference } from '../lib/getUserPreference'; export { fileUploadMediaWhiteList, fileUploadIsValidContentType } from '../lib/fileUploadRestrictions'; export { roomTypes } from './lib/roomTypes'; -export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, UiTextContext } from '../lib/RoomTypeConfig'; +export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../lib/RoomTypeConfig'; export { RoomTypesCommon } from '../lib/RoomTypesCommon'; export { isDocker } from './functions/isDocker'; export { getMongoInfo } from './functions/getMongoInfo'; diff --git a/server/methods/eraseRoom.js b/server/methods/eraseRoom.js index 5be022bc14b5..f5d8d2261d84 100644 --- a/server/methods/eraseRoom.js +++ b/server/methods/eraseRoom.js @@ -25,7 +25,7 @@ Meteor.methods({ }); } - if (!roomTypes.roomTypes[room.t].canBeDeleted(hasPermission, room)) { + if (!roomTypes.getConfig(room.t).canBeDeleted(hasPermission, room)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'eraseRoom', }); diff --git a/server/methods/muteUserInRoom.js b/server/methods/muteUserInRoom.js index 9f39ce95543b..6589f7632deb 100644 --- a/server/methods/muteUserInRoom.js +++ b/server/methods/muteUserInRoom.js @@ -4,6 +4,7 @@ import { Match, check } from 'meteor/check'; import { Rooms, Subscriptions, Users, Messages } from '../../app/models'; import { hasPermission } from '../../app/authorization'; import { callbacks } from '../../app/callbacks'; +import { roomTypes, RoomMemberActions } from '../../app/utils/server'; Meteor.methods({ muteUserInRoom(data) { @@ -34,7 +35,7 @@ Meteor.methods({ }); } - if (['c', 'p'].includes(room.t) === false) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { throw new Meteor.Error('error-invalid-room-type', `${ room.t } is not a valid room type`, { method: 'muteUserInRoom', type: room.t, @@ -63,9 +64,7 @@ Meteor.methods({ }, }); - Meteor.defer(function() { - callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); - }); + callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); return true; }, diff --git a/server/methods/unmuteUserInRoom.js b/server/methods/unmuteUserInRoom.js index 4c4e8db537a9..705affbf5cf6 100644 --- a/server/methods/unmuteUserInRoom.js +++ b/server/methods/unmuteUserInRoom.js @@ -4,6 +4,7 @@ import { Match, check } from 'meteor/check'; import { hasPermission } from '../../app/authorization'; import { callbacks } from '../../app/callbacks'; import { Rooms, Subscriptions, Users, Messages } from '../../app/models'; +import { RoomMemberActions, roomTypes } from '../../app/utils/server'; Meteor.methods({ unmuteUserInRoom(data) { @@ -28,7 +29,7 @@ Meteor.methods({ }); } - if (['c', 'p'].includes(room.t) === false) { + if (roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { throw new Meteor.Error('error-invalid-room-type', `${ room.t } is not a valid room type`, { method: 'unmuteUserInRoom', type: room.t, From 4fb654c2eb9f377a0f538198df655c74a703ab89 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 28 Feb 2020 14:29:51 -0300 Subject: [PATCH 02/64] improve room types usage --- app/api/server/v1/im.js | 7 ++-- .../client/views/channelSettings.js | 24 +++++++------- .../server/functions/saveRoomName.js | 2 +- app/lib/lib/roomTypes/direct.js | 10 +++++- app/lib/lib/roomTypes/private.js | 4 +++ app/lib/lib/roomTypes/public.js | 10 +++++- ...DirectMessageByNameOrIdWithOptionToJoin.js | 7 ++++ .../server/functions/processWebhookMessage.js | 5 +-- app/lib/server/methods/addUsersToRoom.js | 2 +- app/lib/server/methods/archiveRoom.js | 9 +++--- app/lib/server/methods/joinRoom.js | 5 +++ app/lib/server/methods/leaveRoom.js | 7 +++- app/ui-admin/client/rooms/adminRooms.js | 2 +- app/ui-flextab/client/tabs/membersList.js | 16 +++++----- app/ui-flextab/client/tabs/userActions.js | 32 ++++++++++++++++--- app/ui-sidenav/client/roomList.js | 2 +- app/ui-utils/client/lib/ChannelActions.js | 4 +-- app/ui/client/views/app/createChannel.js | 4 +-- app/ui/client/views/app/room.js | 4 +-- app/utils/client/index.js | 2 +- app/utils/lib/RoomTypeConfig.js | 18 +++++++++++ app/utils/server/index.js | 2 +- server/methods/eraseRoom.js | 2 +- server/methods/muteUserInRoom.js | 7 ++-- server/methods/unmuteUserInRoom.js | 3 +- 25 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js diff --git a/app/api/server/v1/im.js b/app/api/server/v1/im.js index 5afd41d05cb1..68bcc4db3ec3 100644 --- a/app/api/server/v1/im.js +++ b/app/api/server/v1/im.js @@ -1,26 +1,25 @@ import { Meteor } from 'meteor/meteor'; -import { getRoomByNameOrIdWithOptionToJoin } from '../../../lib'; import { Subscriptions, Uploads, Users, Messages, 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'; function findDirectMessageRoom(params, user) { if ((!params.roomId || !params.roomId.trim()) && (!params.username || !params.username.trim())) { throw new Meteor.Error('error-room-param-not-provided', 'Body param "roomId" or "username" is required'); } - const room = getRoomByNameOrIdWithOptionToJoin({ + const room = getDirectMessageByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: params.username || params.roomId, - type: 'd', }); const canAccess = Meteor.call('canAccessRoom', room._id, user._id); if (!canAccess || !room || room.t !== 'd') { - throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "username" param provided does not match any dirct message'); + throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "username" param provided does not match any direct message'); } const subscription = Subscriptions.findOneByRoomIdAndUserId(room._id, user._id); diff --git a/app/channel-settings/client/views/channelSettings.js b/app/channel-settings/client/views/channelSettings.js index 5b1a31bfcd56..0075d457a1be 100644 --- a/app/channel-settings/client/views/channelSettings.js +++ b/app/channel-settings/client/views/channelSettings.js @@ -29,7 +29,7 @@ const common = { }); const roomType = room && room.t; - return roomType && roomTypes.roomTypes[roomType].canBeDeleted(hasPermission, room); + return roomType && roomTypes.getConfig(roomType).canBeDeleted(hasPermission, room); }, canEditRoom() { const { _id } = Template.instance().room; @@ -223,7 +223,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'text', label: 'Name', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.NAME); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.NAME); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -270,7 +270,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'markdown', label: 'Topic', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.TOPIC); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.TOPIC); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -289,7 +289,7 @@ Template.channelSettingsEditing.onCreated(function() { return Template.instance().room.announcement; }, canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.ANNOUNCEMENT); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.ANNOUNCEMENT); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -305,7 +305,7 @@ Template.channelSettingsEditing.onCreated(function() { type: 'text', label: 'Description', canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.DESCRIPTION); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.DESCRIPTION); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -386,7 +386,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.READ_ONLY); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.READ_ONLY); }, canEdit() { return !room.broadcast && hasAllPermission('set-readonly', room._id); @@ -401,7 +401,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.REACT_WHEN_READ_ONLY); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.REACT_WHEN_READ_ONLY); }, canEdit() { return !room.broadcast && hasAllPermission('set-react-when-readonly', room._id); @@ -418,7 +418,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange( + return roomTypes.getConfig(room.t).allowRoomSettingChange( room, RoomSettingsEnum.SYSTEM_MESSAGES, ); @@ -460,7 +460,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.ARCHIVE_OR_UNARCHIVE); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.ARCHIVE_OR_UNARCHIVE); }, canEdit() { return hasAtLeastOnePermission(['archive-room', 'unarchive-room'], room._id); @@ -501,7 +501,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.BROADCAST); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.BROADCAST); }, canEdit() { return false; @@ -516,7 +516,7 @@ Template.channelSettingsEditing.onCreated(function() { showingValue: new ReactiveVar(false), realValue: null, canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.JOIN_CODE) && hasAllPermission('edit-room', room._id); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.JOIN_CODE) && hasAllPermission('edit-room', room._id); }, canEdit() { return hasAllPermission('edit-room', room._id); @@ -679,7 +679,7 @@ Template.channelSettingsEditing.onCreated(function() { isToggle: true, processing: new ReactiveVar(false), canView() { - return roomTypes.roomTypes[room.t].allowRoomSettingChange(room, RoomSettingsEnum.E2E); + return roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.E2E); }, canEdit() { return hasAllPermission('edit-room', room._id); diff --git a/app/channel-settings/server/functions/saveRoomName.js b/app/channel-settings/server/functions/saveRoomName.js index be509b42e74e..5ce24f9c7829 100644 --- a/app/channel-settings/server/functions/saveRoomName.js +++ b/app/channel-settings/server/functions/saveRoomName.js @@ -14,7 +14,7 @@ const updateRoomName = (rid, displayName, isDiscussion) => { export const saveRoomName = function(rid, displayName, user, sendMessage = true) { const room = Rooms.findOneById(rid); - if (roomTypes.roomTypes[room.t].preventRenaming()) { + if (roomTypes.getConfig(room.t).preventRenaming()) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { function: 'RocketChat.saveRoomdisplayName', }); diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index dc6a35a79275..63709aa76c19 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -3,7 +3,7 @@ import { Session } from 'meteor/session'; import { ChatRoom, Subscriptions } from '../../../models'; import { openRoom } from '../../../ui-utils'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; import { hasPermission, hasAtLeastOnePermission } from '../../../authorization'; import { settings } from '../../../settings'; import { getUserAvatarURL } from '../../../utils/lib/getUserAvatarURL'; @@ -118,6 +118,14 @@ export class DirectMessageRoomType extends RoomTypeConfig { } } + allowMemberAction(room, action) { + switch (action) { + case RoomMemberActions.MUTE: + default: + return false; + } + } + enableMembersListProfile() { return true; } diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index 9de5cf1fac9a..219ebbc8e9dd 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -98,6 +98,10 @@ export class PrivateRoomType extends RoomTypeConfig { } } + allowMemberAction(/* room, action */) { + return true; + } + enableMembersListProfile() { return true; } diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 4cef013026a6..b4a4bfc42a42 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -4,7 +4,7 @@ import { openRoom } from '../../../ui-utils'; import { ChatRoom, ChatSubscription } from '../../../models'; import { settings } from '../../../settings'; import { hasAtLeastOnePermission } from '../../../authorization'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; import { getAvatarURL } from '../../../utils/lib/getAvatarURL'; export class PublicRoomRoute extends RoomTypeRouteConfig { @@ -113,6 +113,14 @@ export class PublicRoomType extends RoomTypeConfig { } } + allowMemberAction(room, action) { + switch (action) { + case RoomMemberActions.MUTE: + default: + return true; + } + } + getUiText(context) { switch (context) { case UiTextContext.HIDE_WARNING: diff --git a/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js b/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js new file mode 100644 index 000000000000..f21980cba5ad --- /dev/null +++ b/app/lib/server/functions/getDirectMessageByNameOrIdWithOptionToJoin.js @@ -0,0 +1,7 @@ +import { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; + +export const getDirectMessageByNameOrIdWithOptionToJoin = (args) => + getRoomByNameOrIdWithOptionToJoin({ ...args, type: 'd' }); + +export const getDirectMessageByIdWithOptionToJoin = (args) => + getDirectMessageByNameOrIdWithOptionToJoin({ ...args, tryDirectByUserIdOnly: true }); diff --git a/app/lib/server/functions/processWebhookMessage.js b/app/lib/server/functions/processWebhookMessage.js index c51f4fb85b96..a667203b47a5 100644 --- a/app/lib/server/functions/processWebhookMessage.js +++ b/app/lib/server/functions/processWebhookMessage.js @@ -5,6 +5,7 @@ import s from 'underscore.string'; import { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; import { sendMessage } from './sendMessage'; import { Subscriptions } from '../../../models'; +import { getDirectMessageByIdWithOptionToJoin, getDirectMessageByNameOrIdWithOptionToJoin } from './getDirectMessageByNameOrIdWithOptionToJoin'; export const processWebhookMessage = function(messageObj, user, defaultValues = { channel: '', alias: '', avatar: '', emoji: '' }, mustBeJoined = false) { const sentData = []; @@ -21,7 +22,7 @@ export const processWebhookMessage = function(messageObj, user, defaultValues = room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, joinChannel: true }); break; case '@': - room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, type: 'd' }); + room = getDirectMessageByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue }); break; default: channelValue = channelType + channelValue; @@ -33,7 +34,7 @@ export const processWebhookMessage = function(messageObj, user, defaultValues = } // We didn't get a room, let's try finding direct messages - room = getRoomByNameOrIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue, type: 'd', tryDirectByUserIdOnly: true }); + room = getDirectMessageByIdWithOptionToJoin({ currentUserId: user._id, nameOrId: channelValue }); if (room) { break; } diff --git a/app/lib/server/methods/addUsersToRoom.js b/app/lib/server/methods/addUsersToRoom.js index 63eaa7594a83..9070fa080d5e 100644 --- a/app/lib/server/methods/addUsersToRoom.js +++ b/app/lib/server/methods/addUsersToRoom.js @@ -30,7 +30,7 @@ Meteor.methods({ const userInRoom = subscription != null; // Can't add to direct room ever - if (room.t === 'd') { + if (room.t === 'd') { // TODO CHANGE throw new Meteor.Error('error-cant-invite-for-direct-room', 'Can\'t invite user to direct rooms', { method: 'addUsersToRoom', }); diff --git a/app/lib/server/methods/archiveRoom.js b/app/lib/server/methods/archiveRoom.js index 3bc7ee6634b1..46a87435fcc9 100644 --- a/app/lib/server/methods/archiveRoom.js +++ b/app/lib/server/methods/archiveRoom.js @@ -4,6 +4,7 @@ import { check } from 'meteor/check'; import { Rooms } from '../../../models'; import { hasPermission } from '../../../authorization'; import { archiveRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ archiveRoom(rid) { @@ -19,12 +20,12 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'archiveRoom' }); } - if (!hasPermission(Meteor.userId(), 'archive-room', room._id)) { - throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'archiveRoom' }); + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.ARCHIVE)) { + throw new Meteor.Error('error-direct-message-room', `rooms type: ${ room.t } can not be archived`, { method: 'archiveRoom' }); } - if (room.t === 'd') { - throw new Meteor.Error('error-direct-message-room', 'Direct Messages can not be archived', { method: 'archiveRoom' }); + if (!hasPermission(Meteor.userId(), 'archive-room', room._id)) { + throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'archiveRoom' }); } return archiveRoom(rid); diff --git a/app/lib/server/methods/joinRoom.js b/app/lib/server/methods/joinRoom.js index a82773b6dfee..c92f729dd4ec 100644 --- a/app/lib/server/methods/joinRoom.js +++ b/app/lib/server/methods/joinRoom.js @@ -5,6 +5,7 @@ import { hasPermission, canAccessRoom } from '../../../authorization'; import { Rooms } from '../../../models'; import { Tokenpass, updateUserTokenpassBalances } from '../../../tokenpass/server'; import { addUserToRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ joinRoom(rid, code) { @@ -20,6 +21,10 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.JOIN)) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); + } + // TODO we should have a 'beforeJoinRoom' call back so external services can do their own validations const user = Meteor.user(); if (room.tokenpass && user && user.services && user.services.tokenpass) { diff --git a/app/lib/server/methods/leaveRoom.js b/app/lib/server/methods/leaveRoom.js index 7cde6187ba2a..561d7bdb548a 100644 --- a/app/lib/server/methods/leaveRoom.js +++ b/app/lib/server/methods/leaveRoom.js @@ -4,6 +4,7 @@ import { check } from 'meteor/check'; import { hasPermission, hasRole, getUsersInRole } from '../../../authorization'; import { Subscriptions, Rooms } from '../../../models'; import { removeUserFromRoom } from '../functions'; +import { roomTypes, RoomMemberActions } from '../../../utils/server'; Meteor.methods({ leaveRoom(rid) { @@ -16,7 +17,11 @@ Meteor.methods({ const room = Rooms.findOneById(rid); const user = Meteor.user(); - if (room.t === 'd' || (room.t === 'c' && !hasPermission(user._id, 'leave-c')) || (room.t === 'p' && !hasPermission(user._id, 'leave-p'))) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.LEAVE)) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' }); + } + + if ((room.t === 'c' && !hasPermission(user._id, 'leave-c')) || (room.t === 'p' && !hasPermission(user._id, 'leave-p'))) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' }); } diff --git a/app/ui-admin/client/rooms/adminRooms.js b/app/ui-admin/client/rooms/adminRooms.js index dc103caf69cb..4a7133850330 100644 --- a/app/ui-admin/client/rooms/adminRooms.js +++ b/app/ui-admin/client/rooms/adminRooms.js @@ -40,7 +40,7 @@ Template.adminRooms.helpers({ return Template.instance().rooms.get().length; }, type() { - return TAPi18n.__(roomTypes.roomTypes[this.t].label); + return TAPi18n.__(roomTypes.getConfig(this.t).label); }, 'default'() { if (this.default) { diff --git a/app/ui-flextab/client/tabs/membersList.js b/app/ui-flextab/client/tabs/membersList.js index c7a6a3ec86bc..811d171d2554 100644 --- a/app/ui-flextab/client/tabs/membersList.js +++ b/app/ui-flextab/client/tabs/membersList.js @@ -23,7 +23,7 @@ Template.membersList.helpers({ isGroupChat() { const room = ChatRoom.findOne(this.rid, { reactive: false }); - return roomTypes.roomTypes[room.t].isGroupChat(); + return roomTypes.getConfig(room.t).isGroupChat(); }, isDirectChat() { @@ -98,7 +98,7 @@ Template.membersList.helpers({ canAddUser() { const roomData = Session.get(`roomData${ this._id }`); if (!roomData) { return ''; } - return (() => roomTypes.roomTypes[roomData.t].canAddUser(roomData))(); + return (() => roomTypes.getConfig(roomData.t).canAddUser(roomData))(); }, canInviteUser() { @@ -123,10 +123,10 @@ Template.membersList.helpers({ tabBar: Template.currentData().tabBar, username: Template.instance().userDetail.get(), clear: Template.instance().clearUserDetail, - showAll: roomTypes.roomTypes[room.t].userDetailShowAll(room) || false, - hideAdminControls: roomTypes.roomTypes[room.t].userDetailShowAdmin(room) || false, + showAll: roomTypes.getConfig(room.t).userDetailShowAll(room) || false, + hideAdminControls: roomTypes.getConfig(room.t).userDetailShowAdmin(room) || false, video: ['d'].includes(room && room.t), - showBackButton: roomTypes.roomTypes[room.t].isGroupChat(), + showBackButton: roomTypes.getConfig(room.t).isGroupChat(), }; }, displayName() { @@ -183,8 +183,8 @@ Template.membersList.events({ const room = Session.get(`roomData${ instance.data.rid }`); const _actions = getActions({ user: this.user.user, - hideAdminControls: roomTypes.roomTypes[room.t].userDetailShowAdmin(room) || false, - directActions: roomTypes.roomTypes[room.t].userDetailShowAll(room) || false, + hideAdminControls: roomTypes.getConfig(room.t).userDetailShowAdmin(room) || false, + directActions: roomTypes.getConfig(room.t).userDetailShowAll(room) || false, }) .map((action) => (typeof action === 'function' ? action.call(this) : action)) .filter((action) => action && (!action.condition || action.condition.call(this))); @@ -235,7 +235,7 @@ Template.membersList.events({ 'autocompleteselect #user-add-search'(event, template, doc) { const roomData = Session.get(`roomData${ template.data.rid }`); - if (roomTypes.roomTypes[roomData.t].canAddUser(roomData)) { + if (roomTypes.getConfig(roomData.t).canAddUser(roomData)) { return Meteor.call('addUserToRoom', { rid: roomData._id, username: doc.username }, function(error) { if (error) { return handleError(error); diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index d1947e1e8661..41df3fb08384 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -11,6 +11,7 @@ import { modal } from '../../../ui-utils'; import { t, handleError, roomTypes } from '../../../utils'; import { settings } from '../../../settings'; import { hasPermission, hasAllPermission, userHasAllPermission } from '../../../authorization'; +import { RoomMemberActions } from '../../../utils/client'; const canSetLeader = () => hasAllPermission('set-leader', Session.get('openedRoom')); @@ -49,12 +50,12 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { user && user._id && !!RoomRoles.findOne({ rid: Session.get('openedRoom'), 'u._id': user._id, roles: 'moderator' }); const isInDirectMessageRoom = () => { const room = ChatRoom.findOne(Session.get('openedRoom')); - return (room && room.t) === 'd'; + return roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK); }; - const isMuted = () => { - const room = ChatRoom.findOne(Session.get('openedRoom')); + const room = ChatRoom.findOne(Session.get('openedRoom')); + const isMuted = () => { if (room && room.ro) { if (_.isArray(room.unmuted) && room.unmuted.indexOf(user && user.username) !== -1) { return false; @@ -191,6 +192,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !isInDirectMessageRoom() || isSelf(this.username)) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK)) { + return; + } if (canBlockUser()) { return { icon: 'ban', @@ -208,6 +212,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetOwner()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_OWNER)) { + return; + } if (isOwner()) { return { group: 'channel', @@ -243,6 +250,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetLeader()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_LEADER)) { + return; + } if (isLeader()) { return { group: 'channel', @@ -279,6 +289,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetModerator()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_MODERATOR)) { + return; + } if (isModerator()) { return { group: 'channel', @@ -315,6 +328,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || user._id === Meteor.userId()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.IGNORE)) { + return; + } if (isIgnored()) { return { group: 'channel', @@ -333,6 +349,9 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canMuteUser()) { return; } + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { + return; + } if (isMuted()) { return { group: 'channel', @@ -412,7 +431,12 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { return this.instance.clear(); }))); }), - condition: () => directActions && canRemoveUser(), + condition: () => { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.KICK)) { + return; + } + return directActions && canRemoveUser(); + }, }, { icon: 'edit', name: 'Edit', diff --git a/app/ui-sidenav/client/roomList.js b/app/ui-sidenav/client/roomList.js index 8648099a7b05..23c0661a30a0 100644 --- a/app/ui-sidenav/client/roomList.js +++ b/app/ui-sidenav/client/roomList.js @@ -128,7 +128,7 @@ Template.roomList.helpers({ if (instance.data.anonymous) { return 'No_channels_yet'; } - return roomTypes.roomTypes[instance.data.identifier].getUiText(UiTextContext.NO_ROOMS_SUBSCRIBED) || 'No_channels_yet'; + return roomTypes.getConfig(instance.data.identifier).getUiText(UiTextContext.NO_ROOMS_SUBSCRIBED) || 'No_channels_yet'; }, }); diff --git a/app/ui-utils/client/lib/ChannelActions.js b/app/ui-utils/client/lib/ChannelActions.js index 1fb6493a6fc5..fe5c1fddd45e 100644 --- a/app/ui-utils/client/lib/ChannelActions.js +++ b/app/ui-utils/client/lib/ChannelActions.js @@ -7,7 +7,7 @@ import { RoomManager } from './RoomManager'; import { t, UiTextContext, roomTypes, handleError } from '../../../utils'; export function hide(type, rid, name) { - const warnText = roomTypes.roomTypes[type].getUiText(UiTextContext.HIDE_WARNING); + const warnText = roomTypes.getConfig(type).getUiText(UiTextContext.HIDE_WARNING); modal.open({ title: t('Are_you_sure'), @@ -37,7 +37,7 @@ export function hide(type, rid, name) { } export async function leave(type, rid, name) { - const warnText = roomTypes.roomTypes[type].getUiText(UiTextContext.LEAVE_WARNING); + const warnText = roomTypes.getConfig(type).getUiText(UiTextContext.LEAVE_WARNING); modal.open({ title: t('Are_you_sure'), diff --git a/app/ui/client/views/app/createChannel.js b/app/ui/client/views/app/createChannel.js index 44b929cb3176..3d1b56de00f7 100644 --- a/app/ui/client/views/app/createChannel.js +++ b/app/ui/client/views/app/createChannel.js @@ -157,7 +157,7 @@ Template.createChannel.helpers({ return roomTypes.roomTypesOrder.filter( (roomTypeOrder) => roomTypeOrder.order < orderLow, ).map( - (roomTypeOrder) => roomTypes.roomTypes[roomTypeOrder.identifier], + (roomTypeOrder) => roomTypes.getConfig(roomTypeOrder.identifier), ).filter((roomType) => roomType.creationTemplate); }, roomTypesAfterStandard() { @@ -165,7 +165,7 @@ Template.createChannel.helpers({ return roomTypes.roomTypesOrder.filter( (roomTypeOrder) => roomTypeOrder.order > orderHigh, ).map( - (roomTypeOrder) => roomTypes.roomTypes[roomTypeOrder.identifier], + (roomTypeOrder) => roomTypes.getConfig(roomTypeOrder.identifier), ).filter((roomType) => roomType.creationTemplate); }, }); diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 312209a977b6..24817753d495 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -59,7 +59,7 @@ const openProfileTab = (e, instance, username) => { } const roomData = Session.get(`roomData${ RoomManager.openedRoom }`); - if (roomTypes.roomTypes[roomData.t].enableMembersListProfile()) { + if (roomTypes.getConfig(roomData.t).enableMembersListProfile()) { instance.userDetail.set(username); } @@ -1287,7 +1287,7 @@ Template.room.onRendered(function() { this.autorun(() => { const subscription = Subscriptions.findOne({ rid }, { fields: { alert: 1, unread: 1 } }); read(); - return subscription && (subscription.alert || subscription.unread) && readMessage.refreshUnreadMark(rid); + return subscription && (subscription.alert || subscription.unread);// && readMessage.refreshUnreadMark(rid); }); this.autorun(() => { diff --git a/app/utils/client/index.js b/app/utils/client/index.js index 129c1acf9a7f..6b2060f5d0e2 100644 --- a/app/utils/client/index.js +++ b/app/utils/client/index.js @@ -6,7 +6,7 @@ export { handleError } from './lib/handleError'; export { getUserPreference } from '../lib/getUserPreference'; export { fileUploadMediaWhiteList, fileUploadIsValidContentType } from '../lib/fileUploadRestrictions'; export { roomTypes } from './lib/roomTypes'; -export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, UiTextContext } from '../lib/RoomTypeConfig'; +export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../lib/RoomTypeConfig'; export { RoomTypesCommon } from '../lib/RoomTypesCommon'; export { getUserAvatarURL } from '../lib/getUserAvatarURL'; export { slashCommands } from '../lib/slashCommand'; diff --git a/app/utils/lib/RoomTypeConfig.js b/app/utils/lib/RoomTypeConfig.js index ac0aa49d3519..fbb205b49109 100644 --- a/app/utils/lib/RoomTypeConfig.js +++ b/app/utils/lib/RoomTypeConfig.js @@ -24,6 +24,20 @@ export const RoomSettingsEnum = { E2E: 'encrypted', }; +export const RoomMemberActions = { + ARCHIVE: 'archive', + IGNORE: 'ignore', + BLOCK: 'block', + MUTE: 'mute', + SET_AS_OWNER: 'setAsOwner', + SET_AS_LEADER: 'setAsLeader', + SET_AS_MODERATOR: 'setAsModerator', + LEAVE: 'leave', + KICK: 'kick', + JOIN: 'join', + INVITE: 'invite', +}; + export const UiTextContext = { CLOSE_WARNING: 'closeWarning', HIDE_WARNING: 'hideWarning', @@ -154,6 +168,10 @@ export class RoomTypeConfig { return true; } + allowMemberAction(/* room, action */) { + return false; + } + /** * Return a room's name * diff --git a/app/utils/server/index.js b/app/utils/server/index.js index 07d2f50c4970..e8d909ef79c4 100644 --- a/app/utils/server/index.js +++ b/app/utils/server/index.js @@ -4,7 +4,7 @@ export { Info } from '../rocketchat.info'; export { getUserPreference } from '../lib/getUserPreference'; export { fileUploadMediaWhiteList, fileUploadIsValidContentType } from '../lib/fileUploadRestrictions'; export { roomTypes } from './lib/roomTypes'; -export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, UiTextContext } from '../lib/RoomTypeConfig'; +export { RoomTypeRouteConfig, RoomTypeConfig, RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../lib/RoomTypeConfig'; export { RoomTypesCommon } from '../lib/RoomTypesCommon'; export { isDocker } from './functions/isDocker'; export { getMongoInfo } from './functions/getMongoInfo'; diff --git a/server/methods/eraseRoom.js b/server/methods/eraseRoom.js index 5be022bc14b5..f5d8d2261d84 100644 --- a/server/methods/eraseRoom.js +++ b/server/methods/eraseRoom.js @@ -25,7 +25,7 @@ Meteor.methods({ }); } - if (!roomTypes.roomTypes[room.t].canBeDeleted(hasPermission, room)) { + if (!roomTypes.getConfig(room.t).canBeDeleted(hasPermission, room)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'eraseRoom', }); diff --git a/server/methods/muteUserInRoom.js b/server/methods/muteUserInRoom.js index 9f39ce95543b..6589f7632deb 100644 --- a/server/methods/muteUserInRoom.js +++ b/server/methods/muteUserInRoom.js @@ -4,6 +4,7 @@ import { Match, check } from 'meteor/check'; import { Rooms, Subscriptions, Users, Messages } from '../../app/models'; import { hasPermission } from '../../app/authorization'; import { callbacks } from '../../app/callbacks'; +import { roomTypes, RoomMemberActions } from '../../app/utils/server'; Meteor.methods({ muteUserInRoom(data) { @@ -34,7 +35,7 @@ Meteor.methods({ }); } - if (['c', 'p'].includes(room.t) === false) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { throw new Meteor.Error('error-invalid-room-type', `${ room.t } is not a valid room type`, { method: 'muteUserInRoom', type: room.t, @@ -63,9 +64,7 @@ Meteor.methods({ }, }); - Meteor.defer(function() { - callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); - }); + callbacks.run('afterMuteUser', { mutedUser, fromUser }, room); return true; }, diff --git a/server/methods/unmuteUserInRoom.js b/server/methods/unmuteUserInRoom.js index 4c4e8db537a9..4ee4eb768c03 100644 --- a/server/methods/unmuteUserInRoom.js +++ b/server/methods/unmuteUserInRoom.js @@ -4,6 +4,7 @@ import { Match, check } from 'meteor/check'; import { hasPermission } from '../../app/authorization'; import { callbacks } from '../../app/callbacks'; import { Rooms, Subscriptions, Users, Messages } from '../../app/models'; +import { RoomMemberActions, roomTypes } from '../../app/utils/server'; Meteor.methods({ unmuteUserInRoom(data) { @@ -28,7 +29,7 @@ Meteor.methods({ }); } - if (['c', 'p'].includes(room.t) === false) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { throw new Meteor.Error('error-invalid-room-type', `${ room.t } is not a valid room type`, { method: 'unmuteUserInRoom', type: room.t, From 69da2cf5fe2e179087bfc5325c6d4be7e477f5de Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sat, 29 Feb 2020 20:39:29 -0300 Subject: [PATCH 03/64] fix admin actions --- app/ui-flextab/client/tabs/userActions.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index 41df3fb08384..b2dba4774afd 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -192,7 +192,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !isInDirectMessageRoom() || isSelf(this.username)) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK)) { return; } if (canBlockUser()) { @@ -212,7 +212,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetOwner()) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_OWNER)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_OWNER)) { return; } if (isOwner()) { @@ -250,7 +250,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetLeader()) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_LEADER)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_LEADER)) { return; } if (isLeader()) { @@ -289,7 +289,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canSetModerator()) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_MODERATOR)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.SET_AS_MODERATOR)) { return; } if (isModerator()) { @@ -328,7 +328,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || user._id === Meteor.userId()) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.IGNORE)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.IGNORE)) { return; } if (isIgnored()) { @@ -349,7 +349,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { if (!directActions || !canMuteUser()) { return; } - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.MUTE)) { return; } if (isMuted()) { @@ -432,7 +432,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { }))); }), condition: () => { - if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.KICK)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.KICK)) { return; } return directActions && canRemoveUser(); From 2af1f32e419c321051f0b11baa2da33b6765a19f Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sat, 29 Feb 2020 21:55:17 -0300 Subject: [PATCH 04/64] allow create dm between multiple users --- app/lib/server/functions/createDirectRoom.js | 79 +++++++----- app/lib/server/functions/createRoom.js | 13 +- app/lib/server/startup/settings.js | 4 + app/ui-utils/client/lib/openRoom.js | 2 +- server/methods/createDirectMessage.js | 124 ++++--------------- 5 files changed, 80 insertions(+), 142 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 67d516adff7d..a2ec3b8736f1 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -1,47 +1,58 @@ import { Rooms, Subscriptions } from '../../../models/server'; +import { settings } from '../../../settings/lib/settings'; +import { getDefaultSubscriptionPref } from '../../../utils'; -export const createDirectRoom = function(source, target, extraData, options) { - const rid = [source._id, target._id].sort().join(''); +const generate = (fname, name, user, extra) => ({ + open: false, + alert: false, + unread: 0, + userMentions: 0, + groupMentions: 0, + ...user.customFields && { customFields: user.customFields }, + ...getDefaultSubscriptionPref(user), + ...extra, + t: 'd', + fname, + name, + u: { + _id: user._id, + username: user.username, + }, +}); - Rooms.upsert({ _id: rid }, { - $setOnInsert: Object.assign({ - t: 'd', - usernames: [source.username, target.username], - msgs: 0, - ts: new Date(), - }, extraData), - }); +const getFname = (uid, members) => members.filter(({ _id }) => _id !== uid).map(({ name, username }) => name || username).join(', '); +const getName = (uid, members) => members.filter(({ _id }) => _id !== uid).map(({ username }) => username).join(', '); - Subscriptions.upsert({ rid, 'u._id': target._id }, { - $setOnInsert: Object.assign({ - name: source.username, - t: 'd', - open: true, - alert: true, - unread: 0, - u: { - _id: target._id, - username: target.username, - }, - }, options.subscriptionExtra), - }); +export const createDirectRoom = function(members, roomExtraData = {}, options = {}) { + if (members.length > settings.get('DirectMesssage_maxUsers')) { + return; + } + + const rid = members.map(({ _id }) => _id).sort().join(''); // TODO provide a better rid heuristic - Subscriptions.upsert({ rid, 'u._id': source._id }, { - $setOnInsert: Object.assign({ - name: target.username, + const { insertedId } = Rooms.upsert({ _id: rid }, { + $setOnInsert: { t: 'd', - open: true, - alert: true, - unread: 0, - u: { - _id: source._id, - username: source.username, - }, - }, options.subscriptionExtra), + usernames: members.map(({ username }) => username), + usersCount: members.length, + msgs: 0, + ts: new Date(), + ...roomExtraData, + }, }); + if (members.length === 1) { // dm to yourself + Subscriptions.upsert({ rid, 'u._id': members[0]._id }, { + $setOnInsert: generate(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra, open: true }), + }); + } else { + members.forEach((member) => Subscriptions.upsert({ rid, 'u._id': member._id }, { + $setOnInsert: generate(getFname(member._id, members), getName(member._id, members), member, { ...options.subscriptionExtra, ...options.creator === member._id && { open: true } }), + })); + } return { _id: rid, t: 'd', + inserted: !!insertedId, }; }; diff --git a/app/lib/server/functions/createRoom.js b/app/lib/server/functions/createRoom.js index 434ecc8ac086..7403f607eee3 100644 --- a/app/lib/server/functions/createRoom.js +++ b/app/lib/server/functions/createRoom.js @@ -11,7 +11,7 @@ import { createDirectRoom } from './createDirectRoom'; export const createRoom = function(type, name, owner, members, readOnly, extraData = {}, options = {}) { if (type === 'd') { - return createDirectRoom(members[0], members[1], extraData, options); + return createDirectRoom(members, extraData, options); } name = s.trim(name); @@ -23,6 +23,7 @@ export const createRoom = function(type, name, owner, members, readOnly, extraDa } owner = Users.findOneByUsernameIgnoringCase(owner, { fields: { username: 1 } }); + if (!owner) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: 'RocketChat.createRoom' }); } @@ -44,7 +45,7 @@ export const createRoom = function(type, name, owner, members, readOnly, extraDa validRoomNameOptions.nameValidationRegex = options.nameValidationRegex; } - let room = Object.assign({ + let room = { name: getValidRoomName(name, null, validRoomNameOptions), fname: name, t: type, @@ -54,14 +55,10 @@ export const createRoom = function(type, name, owner, members, readOnly, extraDa _id: owner._id, username: owner.username, }, - }, extraData, { + ...extraData, ts: now, ro: readOnly === true, - }); - - if (type === 'd') { - room.usernames = members; - } + }; if (Apps && Apps.isLoaded()) { const prevent = Promise.await(Apps.getBridges().getListenerBridge().roomEvent('IPreRoomCreatePrevent', room)); diff --git a/app/lib/server/startup/settings.js b/app/lib/server/startup/settings.js index 8bd5252c2978..e91f8d171b7c 100644 --- a/app/lib/server/startup/settings.js +++ b/app/lib/server/startup/settings.js @@ -1102,6 +1102,10 @@ settings.addGroup('Message', function() { values: MessageTypesValues, }); + this.add('DirectMesssage_maxUsers', 8, { + type: 'int', + public: true, + }); this.add('Message_ErasureType', 'Delete', { type: 'select', diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index 10116d1d1e92..2a4248954b9c 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -59,7 +59,7 @@ export const openRoom = function(type, name) { const room = roomTypes.findRoom(type, name, user); if (room == null) { if (type === 'd') { - Meteor.call('createDirectMessage', name, function(error) { + Meteor.call('createDirectMessage', ...name.split(', '), function(error) { // TODO provide an function to handle if (!error) { RoomManager.close(type + name); return openRoom('d', name); diff --git a/server/methods/createDirectMessage.js b/server/methods/createDirectMessage.js index c2d2dcc9d17f..fee760db8e34 100644 --- a/server/methods/createDirectMessage.js +++ b/server/methods/createDirectMessage.js @@ -3,15 +3,15 @@ import { check } from 'meteor/check'; import { settings } from '../../app/settings'; import { hasPermission } from '../../app/authorization'; -import { Users, Rooms, Subscriptions } from '../../app/models'; -import { getDefaultSubscriptionPref } from '../../app/utils'; +import { Users, Rooms } from '../../app/models'; import { RateLimiter } from '../../app/lib'; import { callbacks } from '../../app/callbacks'; import { addUser } from '../../app/federation/server/functions/addUser'; +import { createDirectRoom } from '../../app/lib/server'; Meteor.methods({ - createDirectMessage(username) { - check(username, String); + createDirectMessage(...usernames) { + check(usernames, [String]); if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { @@ -27,7 +27,7 @@ Meteor.methods({ }); } - if (settings.get('Message_AllowDirectMessagesToYourself') === false && me.username === username) { + if (settings.get('Message_AllowDirectMessagesToYourself') === false && usernames.length === 1 && me.username === usernames[0]) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'createDirectMessage', }); @@ -39,109 +39,35 @@ Meteor.methods({ }); } - let to = Users.findOneByUsernameIgnoringCase(username); - // If the username does have an `@`, but does not exist locally, we create it first - if (!to && username.indexOf('@') !== -1) { - to = addUser(username); - } + const users = usernames.filter((username) => username !== me.username).map((username) => { + let to = Users.findOneByUsernameIgnoringCase(username); - if (!to) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'createDirectMessage', - }); - } + // If the username does have an `@`, but does not exist locally, we create it first + if (!to && username.indexOf('@') !== -1) { + to = addUser(username); + } - if (!hasPermission(to._id, 'view-d-room')) { - throw new Meteor.Error('error-not-allowed', 'Target user not allowed to receive messages', { - method: 'createDirectMessage', - }); - } + if (!to) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'createDirectMessage', + }); + } - const rid = [me._id, to._id].sort().join(''); - - const now = new Date(); - - // Make sure we have a room - const roomUpsertResult = Rooms.upsert({ - _id: rid, - }, { - $set: { - usernames: [me.username, to.username], - }, - $setOnInsert: { - t: 'd', - msgs: 0, - ts: now, - usersCount: 2, - }, + if (!hasPermission(to._id, 'view-d-room')) { + throw new Meteor.Error('error-not-allowed', `Target user ${ username } not allowed to receive messages`, { + method: 'createDirectMessage', + }); + } + return to; }); - const myNotificationPref = getDefaultSubscriptionPref(me); - - // Make user I have a subcription to this room - const upsertSubscription = { - $set: { - ls: now, - open: true, - }, - $setOnInsert: { - fname: to.name, - name: to.username, - t: 'd', - alert: false, - unread: 0, - userMentions: 0, - groupMentions: 0, - customFields: me.customFields, - u: { - _id: me._id, - username: me.username, - }, - ts: now, - ...myNotificationPref, - }, - }; - - if (to.active === false) { - upsertSubscription.$set.archived = true; - } - - Subscriptions.upsert({ - rid, - $and: [{ 'u._id': me._id }], // work around to solve problems with upsert and dot - }, upsertSubscription); - - const toNotificationPref = getDefaultSubscriptionPref(to); - - Subscriptions.upsert({ - rid, - $and: [{ 'u._id': to._id }], // work around to solve problems with upsert and dot - }, { - $setOnInsert: { - fname: me.name, - name: me.username, - t: 'd', - open: false, - alert: false, - unread: 0, - userMentions: 0, - groupMentions: 0, - customFields: to.customFields, - u: { - _id: to._id, - username: to.username, - }, - ts: now, - ...toNotificationPref, - }, - }); + const { _id: rid, inserted } = createDirectRoom([me, ...users], { }, users === 0 || users.length > 1 ? { subscriptionExtra: { open: true } } : { creator: me._id }); // If the room is new, run a callback - if (roomUpsertResult.insertedId) { + if (inserted) { const insertedRoom = Rooms.findOneById(rid); - - callbacks.run('afterCreateDirectRoom', insertedRoom, { from: me, to }); + callbacks.run('afterCreateDirectRoom', insertedRoom, { from: me, to: users[0] }); // TODO CHECK FEDERATION } return { From b82cfb78310edd2428a2008bd41217c3737814ad Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sat, 29 Feb 2020 22:23:28 -0300 Subject: [PATCH 05/64] Update openRoom.js --- app/ui-utils/client/lib/openRoom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index 2a4248954b9c..fc8ba7c295fe 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -59,7 +59,7 @@ export const openRoom = function(type, name) { const room = roomTypes.findRoom(type, name, user); if (room == null) { if (type === 'd') { - Meteor.call('createDirectMessage', ...name.split(', '), function(error) { // TODO provide an function to handle + Meteor.call('createDirectMessage', ...name.split(', '), function(error) { // TODO provide a function to handle if (!error) { RoomManager.close(type + name); return openRoom('d', name); From c5336ffae77c907b76891cc4df905c39f630e355 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 2 Mar 2020 10:06:58 -0300 Subject: [PATCH 06/64] fix open --- app/lib/server/functions/createDirectRoom.js | 7 ++++--- server/methods/createDirectMessage.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index a2ec3b8736f1..2ceecc5c7a7c 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -3,7 +3,6 @@ import { settings } from '../../../settings/lib/settings'; import { getDefaultSubscriptionPref } from '../../../utils'; const generate = (fname, name, user, extra) => ({ - open: false, alert: false, unread: 0, userMentions: 0, @@ -42,11 +41,13 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = }); if (members.length === 1) { // dm to yourself Subscriptions.upsert({ rid, 'u._id': members[0]._id }, { - $setOnInsert: generate(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra, open: true }), + $set: { open: true }, + $setOnInsert: generate(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra }), }); } else { members.forEach((member) => Subscriptions.upsert({ rid, 'u._id': member._id }, { - $setOnInsert: generate(getFname(member._id, members), getName(member._id, members), member, { ...options.subscriptionExtra, ...options.creator === member._id && { open: true } }), + ...options.creator === member._id && { $set: { open: true } }, + $setOnInsert: generate(getFname(member._id, members), getName(member._id, members), member, { ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 } }), })); } diff --git a/server/methods/createDirectMessage.js b/server/methods/createDirectMessage.js index fee760db8e34..f0b51b426094 100644 --- a/server/methods/createDirectMessage.js +++ b/server/methods/createDirectMessage.js @@ -62,7 +62,7 @@ Meteor.methods({ return to; }); - const { _id: rid, inserted } = createDirectRoom([me, ...users], { }, users === 0 || users.length > 1 ? { subscriptionExtra: { open: true } } : { creator: me._id }); + const { _id: rid, inserted } = createDirectRoom([me, ...users], { }, { creator: me._id }); // If the room is new, run a callback if (inserted) { From b845c7c39f7508273161cc6c9a055b8779531fef Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 2 Mar 2020 10:22:07 -0300 Subject: [PATCH 07/64] improve name generation --- app/lib/server/functions/createDirectRoom.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 2ceecc5c7a7c..125f15e2f488 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -2,7 +2,7 @@ import { Rooms, Subscriptions } from '../../../models/server'; import { settings } from '../../../settings/lib/settings'; import { getDefaultSubscriptionPref } from '../../../utils'; -const generate = (fname, name, user, extra) => ({ +const generateSubscription = (fname, name, user, extra) => ({ alert: false, unread: 0, userMentions: 0, @@ -27,12 +27,14 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = return; } + const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); + const rid = members.map(({ _id }) => _id).sort().join(''); // TODO provide a better rid heuristic const { insertedId } = Rooms.upsert({ _id: rid }, { $setOnInsert: { t: 'd', - usernames: members.map(({ username }) => username), + usernames: sortedMembers.map(({ username }) => username), usersCount: members.length, msgs: 0, ts: new Date(), @@ -42,12 +44,12 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = if (members.length === 1) { // dm to yourself Subscriptions.upsert({ rid, 'u._id': members[0]._id }, { $set: { open: true }, - $setOnInsert: generate(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra }), + $setOnInsert: generateSubscription(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra }), }); } else { members.forEach((member) => Subscriptions.upsert({ rid, 'u._id': member._id }, { ...options.creator === member._id && { $set: { open: true } }, - $setOnInsert: generate(getFname(member._id, members), getName(member._id, members), member, { ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 } }), + $setOnInsert: generateSubscription(getFname(member._id, sortedMembers), getName(member._id, sortedMembers), member, { ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 } }), })); } From 678f832d1592c53662049752af45711b4f254b5e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 2 Mar 2020 17:38:18 -0300 Subject: [PATCH 08/64] throw error on creating a dm with more users --- app/lib/server/functions/createDirectRoom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 125f15e2f488..4fced890f6ab 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -24,7 +24,7 @@ const getName = (uid, members) => members.filter(({ _id }) => _id !== uid).map(( export const createDirectRoom = function(members, roomExtraData = {}, options = {}) { if (members.length > settings.get('DirectMesssage_maxUsers')) { - return; + throw new Error('error-direct-message-max-user-exceeded'); } const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); From 44d5c50bfe246c3a6d1c7b0d5496984a0c581274 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 2 Mar 2020 19:29:19 -0300 Subject: [PATCH 09/64] more harcoded settings --- app/channel-settings/server/functions/saveRoomType.js | 5 ++++- app/channel-settings/server/methods/saveRoomSettings.js | 3 ++- app/e2e/client/rocketchat.e2e.room.js | 3 ++- app/file-upload/server/lib/FileUpload.js | 4 ++-- app/lib/lib/roomTypes/direct.js | 1 + app/slashcommands-unarchiveroom/server/server.js | 3 ++- app/ui-flextab/client/tabs/userActions.js | 2 +- app/utils/lib/RoomTypeConfig.js | 3 ++- server/methods/removeUserFromRoom.js | 3 ++- 9 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/channel-settings/server/functions/saveRoomType.js b/app/channel-settings/server/functions/saveRoomType.js index 00b181d72812..58d94aa4682a 100644 --- a/app/channel-settings/server/functions/saveRoomType.js +++ b/app/channel-settings/server/functions/saveRoomType.js @@ -4,6 +4,7 @@ import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { Rooms, Subscriptions, Messages } from '../../../models'; import { settings } from '../../../settings'; +import { roomTypes, RoomSettingsEnum } from '../../../utils'; export const saveRoomType = function(rid, roomType, user, sendMessage = true) { if (!Match.test(rid, String)) { @@ -24,11 +25,13 @@ export const saveRoomType = function(rid, roomType, user, sendMessage = true) { _id: rid, }); } - if (room.t === 'd') { + + if (!roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.TYPE)) { throw new Meteor.Error('error-direct-room', 'Can\'t change type of direct rooms', { function: 'RocketChat.saveRoomType', }); } + const result = Rooms.setTypeById(rid, roomType) && Subscriptions.updateTypeByRoomId(rid, roomType); if (result && sendMessage) { let message; diff --git a/app/channel-settings/server/methods/saveRoomSettings.js b/app/channel-settings/server/methods/saveRoomSettings.js index 9883340a5451..91d7fbcecf41 100644 --- a/app/channel-settings/server/methods/saveRoomSettings.js +++ b/app/channel-settings/server/methods/saveRoomSettings.js @@ -15,6 +15,7 @@ import { saveReactWhenReadOnly } from '../functions/saveReactWhenReadOnly'; import { saveRoomSystemMessages } from '../functions/saveRoomSystemMessages'; import { saveRoomTokenpass } from '../functions/saveRoomTokens'; import { saveStreamingOptions } from '../functions/saveStreamingOptions'; +import { RoomSettingsEnum, roomTypes } from '../../../utils'; const fields = ['roomName', 'roomTopic', 'roomAnnouncement', 'roomCustomFields', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode', 'tokenpass', 'streamingOptions', 'retentionEnabled', 'retentionMaxAge', 'retentionExcludePinned', 'retentionFilesOnly', 'retentionOverrideGlobal', 'encrypted']; Meteor.methods({ @@ -90,7 +91,7 @@ Meteor.methods({ action: 'Change_Room_Type', }); } - if (setting === 'encrypted' && value !== room.encrypted && (room.t !== 'd' && room.t !== 'p')) { + if (setting === 'encrypted' && value !== room.encrypted && !roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomSettingsEnum.E2E)) { throw new Meteor.Error('error-action-not-allowed', 'Only groups or direct channels can enable encryption', { method: 'saveRoomSettings', action: 'Change_Room_Encrypted', diff --git a/app/e2e/client/rocketchat.e2e.room.js b/app/e2e/client/rocketchat.e2e.room.js index d4f59fdcbc28..c9776f49fb2d 100644 --- a/app/e2e/client/rocketchat.e2e.room.js +++ b/app/e2e/client/rocketchat.e2e.room.js @@ -25,6 +25,7 @@ import { import { Notifications } from '../../notifications'; import { Rooms, Subscriptions } from '../../models'; import { call } from '../../ui-utils'; +import { roomTypes, RoomSettingsEnum } from '../../utils'; export class E2ERoom { constructor(userId, roomId, t) { @@ -97,7 +98,7 @@ export class E2ERoom { } isSupportedRoomType(type) { - return ['d', 'p'].includes(type); + return roomTypes.getConfig(type).allowRoomSettingChange({}, RoomSettingsEnum.E2E); } async importGroupKey(groupKey) { diff --git a/app/file-upload/server/lib/FileUpload.js b/app/file-upload/server/lib/FileUpload.js index c66fe0276c73..fafd92f034b1 100644 --- a/app/file-upload/server/lib/FileUpload.js +++ b/app/file-upload/server/lib/FileUpload.js @@ -64,7 +64,7 @@ export const FileUpload = { const user = file.userId ? Meteor.users.findOne(file.userId) : null; const room = Rooms.findOneById(file.rid); - const directMessageAllow = settings.get('FileUpload_Enabled_Direct'); + const directMessageAllowed = settings.get('FileUpload_Enabled_Direct'); const fileUploadAllowed = settings.get('FileUpload_Enabled'); if (canAccessRoom(room, user, file) !== true) { return false; @@ -75,7 +75,7 @@ export const FileUpload = { throw new Meteor.Error('error-file-upload-disabled', reason); } - if (!directMessageAllow && room.t === 'd') { + if (!directMessageAllowed && room.t === 'd') { const reason = TAPi18n.__('File_not_allowed_direct_messages', language); throw new Meteor.Error('error-direct-message-file-upload-not-allowed', reason); } diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 63709aa76c19..aeb2e35e7abb 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -103,6 +103,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { allowRoomSettingChange(room, setting) { switch (setting) { + case RoomSettingsEnum.TYPE: case RoomSettingsEnum.NAME: case RoomSettingsEnum.SYSTEM_MESSAGES: case RoomSettingsEnum.DESCRIPTION: diff --git a/app/slashcommands-unarchiveroom/server/server.js b/app/slashcommands-unarchiveroom/server/server.js index 48ddc822911d..8db88950cf51 100644 --- a/app/slashcommands-unarchiveroom/server/server.js +++ b/app/slashcommands-unarchiveroom/server/server.js @@ -6,6 +6,7 @@ import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { Rooms, Messages } from '../../models'; import { slashCommands } from '../../utils'; import { Notifications } from '../../notifications'; +import { roomTypes, RoomMemberActions } from '../../utils/server'; function Unarchive(command, params, item) { if (command !== 'unarchive' || !Match.test(params, String)) { @@ -38,7 +39,7 @@ function Unarchive(command, params, item) { } // You can not archive direct messages. - if (room.t === 'd') { + if (!roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.ARCHIVE)) { return; } diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index b2dba4774afd..3810405133c2 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -432,7 +432,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { }))); }), condition: () => { - if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.KICK)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.REMOVE_USER)) { return; } return directActions && canRemoveUser(); diff --git a/app/utils/lib/RoomTypeConfig.js b/app/utils/lib/RoomTypeConfig.js index fbb205b49109..e8b1af163e17 100644 --- a/app/utils/lib/RoomTypeConfig.js +++ b/app/utils/lib/RoomTypeConfig.js @@ -11,6 +11,7 @@ if (Meteor.isServer) { } export const RoomSettingsEnum = { + TYPE: 'type', NAME: 'roomName', TOPIC: 'roomTopic', ANNOUNCEMENT: 'roomAnnouncement', @@ -33,7 +34,7 @@ export const RoomMemberActions = { SET_AS_LEADER: 'setAsLeader', SET_AS_MODERATOR: 'setAsModerator', LEAVE: 'leave', - KICK: 'kick', + REMOVE_USER: 'removeUser', JOIN: 'join', INVITE: 'invite', }; diff --git a/server/methods/removeUserFromRoom.js b/server/methods/removeUserFromRoom.js index 45839078e7a6..e9a1d3f2c3d5 100644 --- a/server/methods/removeUserFromRoom.js +++ b/server/methods/removeUserFromRoom.js @@ -4,6 +4,7 @@ import { Match, check } from 'meteor/check'; import { hasPermission, hasRole, getUsersInRole, removeUserFromRoles } from '../../app/authorization'; import { Users, Subscriptions, Rooms, Messages } from '../../app/models'; import { callbacks } from '../../app/callbacks'; +import { roomTypes, RoomMemberActions } from '../../app/utils/server'; Meteor.methods({ removeUserFromRoom(data) { @@ -28,7 +29,7 @@ Meteor.methods({ const room = Rooms.findOneById(data.rid); - if (!room || room.t === 'd') { + if (!room || !roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.REMOVE_USER)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'removeUserFromRoom', }); From ec134543e38d73d9ffb3b4fee2ef144c7877735a Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 2 Mar 2020 20:07:46 -0300 Subject: [PATCH 10/64] fix review --- app/ui/client/views/app/room.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 24817753d495..c88ad16ecf63 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -1287,7 +1287,7 @@ Template.room.onRendered(function() { this.autorun(() => { const subscription = Subscriptions.findOne({ rid }, { fields: { alert: 1, unread: 1 } }); read(); - return subscription && (subscription.alert || subscription.unread);// && readMessage.refreshUnreadMark(rid); + return subscription && (subscription.alert || subscription.unread) && readMessage.refreshUnreadMark(rid); }); this.autorun(() => { From f6627837644f389d65dc19dd5a1468a253d4525e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 13 Mar 2020 18:01:10 -0300 Subject: [PATCH 11/64] create foreword component --- app/ui/client/index.js | 1 + app/ui/client/views/app/RoomForeword.html | 3 + app/ui/client/views/app/RoomForeword.js | 73 +++++++++++++++++++++++ app/ui/client/views/app/room.html | 3 +- app/ui/client/views/app/room.js | 5 +- server/publications/room/index.js | 1 + 6 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 app/ui/client/views/app/RoomForeword.html create mode 100644 app/ui/client/views/app/RoomForeword.js diff --git a/app/ui/client/index.js b/app/ui/client/index.js index 786881dac290..4814ef166220 100644 --- a/app/ui/client/index.js +++ b/app/ui/client/index.js @@ -43,6 +43,7 @@ import './views/app/invite'; import './views/app/videoCall/videoButtons'; import './views/app/videoCall/videoCall'; import './views/app/photoswipe'; +import './views/app/RoomForeword'; import './components/icon'; import './components/status'; import './components/table.html'; diff --git a/app/ui/client/views/app/RoomForeword.html b/app/ui/client/views/app/RoomForeword.html new file mode 100644 index 000000000000..72b2b7734c0e --- /dev/null +++ b/app/ui/client/views/app/RoomForeword.html @@ -0,0 +1,3 @@ + diff --git a/app/ui/client/views/app/RoomForeword.js b/app/ui/client/views/app/RoomForeword.js new file mode 100644 index 000000000000..fde4d1a22bff --- /dev/null +++ b/app/ui/client/views/app/RoomForeword.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { Meteor } from 'meteor/meteor'; +import { Avatar, Margins, Flex, Box } from '@rocket.chat/fuselage'; +import { Template } from 'meteor/templating'; + +import './RoomForeword.html'; +import { Rooms, Users } from '../../../../models'; +import { useTranslation } from '../../../../../client/contexts/TranslationContext'; + + +const RoomForeword = ({ room, user }) => { + const t = useTranslation(); + + if (room.t !== 'd') { + return t('Start_of_conversation'); + } + + const users = room.usernames.filter((username) => username !== user.username); + if (users.length < 1) { + return null; + } + + return + + + + + + + {users.map((username, index) => )} + + + + + + { t('You have joined a new direct message with') } + + + + + + {users.map((username, index) => {username})} + + + + + + + ; +}; + +Template.RoomForeword.onRendered(async function() { + const { MeteorProvider } = await import('../../../../../client/providers/MeteorProvider'); + const ReactDOM = await import('react-dom'); + this.container = this.firstNode; + this.autorun(() => { + const data = Template.currentData(); + const { _id: rid } = data; + + const user = Users.findOne(Meteor.userId(), { username: 1 }); + + const room = Rooms.findOne({ _id: rid }); + ReactDOM.render(React.createElement(MeteorProvider, { + children: React.createElement(RoomForeword, { ...data, room, user }), + }), this.container); + }); +}); + + +Template.RoomForeword.onDestroyed(async function() { + const ReactDOM = await import('react-dom'); + this.container && ReactDOM.unmountComponentAtNode(this.container); +}); diff --git a/app/ui/client/views/app/room.html b/app/ui/client/views/app/room.html index 09ee9c49e4c5..2ec39c4854ea 100644 --- a/app/ui/client/views/app/room.html +++ b/app/ui/client/views/app/room.html @@ -121,7 +121,8 @@ {{/unless}} {{/if}} - {{_ "Start_of_conversation"}} + + {{> RoomForeword }} {{/if}} {{/if}} diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index c88ad16ecf63..99f9b4be2181 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -876,6 +876,9 @@ Template.room.events({ FlowRouter.go(FlowRouter.current().context.pathname, null, { msg: repliedMessageId, hash: Random.id() }); }, 'click .mention-link'(e, instance) { + e.stopPropagation(); + e.preventDefault(); + if (!Meteor.userId()) { return; } @@ -891,8 +894,6 @@ Template.room.events({ } if (group) { - e.stopPropagation(); - e.preventDefault(); openMembersListTab(instance, group); return; } diff --git a/server/publications/room/index.js b/server/publications/room/index.js index 8b4f3794beac..8763aac418bb 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -30,6 +30,7 @@ export const fields = { retention: 1, prid: 1, usersCount: 1, + usernames: 1, // @TODO create an API to register this fields based on room type livechatData: 1, From 9afea45b5bee69ace7a647ed06682ef48a415376 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 16 Mar 2020 09:44:55 -0300 Subject: [PATCH 12/64] fix review --- app/lib/lib/roomTypes/direct.js | 8 ++------ app/lib/lib/roomTypes/public.js | 8 ++------ app/lib/server/methods/addUsersToRoom.js | 2 +- app/slashcommands-unarchiveroom/server/server.js | 2 +- server/methods/removeUserFromRoom.js | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index aeb2e35e7abb..fd3aa2347d27 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -119,12 +119,8 @@ export class DirectMessageRoomType extends RoomTypeConfig { } } - allowMemberAction(room, action) { - switch (action) { - case RoomMemberActions.MUTE: - default: - return false; - } + allowMemberAction(/* room, action */) { + return false; } enableMembersListProfile() { diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index b4a4bfc42a42..7f94ca58f024 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -113,12 +113,8 @@ export class PublicRoomType extends RoomTypeConfig { } } - allowMemberAction(room, action) { - switch (action) { - case RoomMemberActions.MUTE: - default: - return true; - } + allowMemberAction(/* room, action */) { + return true; } getUiText(context) { diff --git a/app/lib/server/methods/addUsersToRoom.js b/app/lib/server/methods/addUsersToRoom.js index 9070fa080d5e..63eaa7594a83 100644 --- a/app/lib/server/methods/addUsersToRoom.js +++ b/app/lib/server/methods/addUsersToRoom.js @@ -30,7 +30,7 @@ Meteor.methods({ const userInRoom = subscription != null; // Can't add to direct room ever - if (room.t === 'd') { // TODO CHANGE + if (room.t === 'd') { throw new Meteor.Error('error-cant-invite-for-direct-room', 'Can\'t invite user to direct rooms', { method: 'addUsersToRoom', }); diff --git a/app/slashcommands-unarchiveroom/server/server.js b/app/slashcommands-unarchiveroom/server/server.js index 8db88950cf51..be2c56e47cb0 100644 --- a/app/slashcommands-unarchiveroom/server/server.js +++ b/app/slashcommands-unarchiveroom/server/server.js @@ -39,7 +39,7 @@ function Unarchive(command, params, item) { } // You can not archive direct messages. - if (!roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.ARCHIVE)) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.ARCHIVE)) { return; } diff --git a/server/methods/removeUserFromRoom.js b/server/methods/removeUserFromRoom.js index e9a1d3f2c3d5..d97a30ee9ca7 100644 --- a/server/methods/removeUserFromRoom.js +++ b/server/methods/removeUserFromRoom.js @@ -29,7 +29,7 @@ Meteor.methods({ const room = Rooms.findOneById(data.rid); - if (!room || !roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.REMOVE_USER)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.REMOVE_USER)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'removeUserFromRoom', }); From aacb65b92942aa60d466e318a49eb90a5f8e8dc5 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 16 Mar 2020 09:44:55 -0300 Subject: [PATCH 13/64] fix review --- app/lib/lib/roomTypes/direct.js | 10 +++------- app/lib/lib/roomTypes/public.js | 10 +++------- app/lib/server/methods/addUsersToRoom.js | 2 +- app/slashcommands-unarchiveroom/server/server.js | 2 +- server/methods/removeUserFromRoom.js | 2 +- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index aeb2e35e7abb..42dd405c6fcf 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -3,7 +3,7 @@ import { Session } from 'meteor/session'; import { ChatRoom, Subscriptions } from '../../../models'; import { openRoom } from '../../../ui-utils'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; import { hasPermission, hasAtLeastOnePermission } from '../../../authorization'; import { settings } from '../../../settings'; import { getUserAvatarURL } from '../../../utils/lib/getUserAvatarURL'; @@ -119,12 +119,8 @@ export class DirectMessageRoomType extends RoomTypeConfig { } } - allowMemberAction(room, action) { - switch (action) { - case RoomMemberActions.MUTE: - default: - return false; - } + allowMemberAction(/* room, action */) { + return false; } enableMembersListProfile() { diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index b4a4bfc42a42..11d688731eff 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -4,7 +4,7 @@ import { openRoom } from '../../../ui-utils'; import { ChatRoom, ChatSubscription } from '../../../models'; import { settings } from '../../../settings'; import { hasAtLeastOnePermission } from '../../../authorization'; -import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; +import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils'; import { getAvatarURL } from '../../../utils/lib/getAvatarURL'; export class PublicRoomRoute extends RoomTypeRouteConfig { @@ -113,12 +113,8 @@ export class PublicRoomType extends RoomTypeConfig { } } - allowMemberAction(room, action) { - switch (action) { - case RoomMemberActions.MUTE: - default: - return true; - } + allowMemberAction(/* room, action */) { + return true; } getUiText(context) { diff --git a/app/lib/server/methods/addUsersToRoom.js b/app/lib/server/methods/addUsersToRoom.js index 9070fa080d5e..63eaa7594a83 100644 --- a/app/lib/server/methods/addUsersToRoom.js +++ b/app/lib/server/methods/addUsersToRoom.js @@ -30,7 +30,7 @@ Meteor.methods({ const userInRoom = subscription != null; // Can't add to direct room ever - if (room.t === 'd') { // TODO CHANGE + if (room.t === 'd') { throw new Meteor.Error('error-cant-invite-for-direct-room', 'Can\'t invite user to direct rooms', { method: 'addUsersToRoom', }); diff --git a/app/slashcommands-unarchiveroom/server/server.js b/app/slashcommands-unarchiveroom/server/server.js index 8db88950cf51..be2c56e47cb0 100644 --- a/app/slashcommands-unarchiveroom/server/server.js +++ b/app/slashcommands-unarchiveroom/server/server.js @@ -39,7 +39,7 @@ function Unarchive(command, params, item) { } // You can not archive direct messages. - if (!roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.ARCHIVE)) { + if (!roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.ARCHIVE)) { return; } diff --git a/server/methods/removeUserFromRoom.js b/server/methods/removeUserFromRoom.js index e9a1d3f2c3d5..d97a30ee9ca7 100644 --- a/server/methods/removeUserFromRoom.js +++ b/server/methods/removeUserFromRoom.js @@ -29,7 +29,7 @@ Meteor.methods({ const room = Rooms.findOneById(data.rid); - if (!room || !roomTypes.getConfig(room.t).allowRoomSettingChange(room, RoomMemberActions.REMOVE_USER)) { + if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.REMOVE_USER)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'removeUserFromRoom', }); From 31fbfdca341dab71ac317165eb5bb9cfaaf22221 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 16 Mar 2020 15:39:08 -0300 Subject: [PATCH 14/64] avatars and user info --- app/lib/client/defaultTabBars.js | 26 +++++++++++++++++++ app/lib/lib/roomTypes/direct.js | 16 ++++++++++++ app/ui-flextab/client/tabs/membersList.js | 6 ++--- app/ui-master/public/icons/Group.svg | 6 +++++ app/ui-sidenav/client/chatRoomItem.js | 8 +++--- .../client/components/header/headerRoom.html | 4 +-- app/ui/client/components/header/headerRoom.js | 12 ++++----- app/ui/client/views/app/room.js | 9 +++++-- private/public/icons.svg | 8 +++++- public/public/icons.html | 8 +++++- 10 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 app/ui-master/public/icons/Group.svg diff --git a/app/lib/client/defaultTabBars.js b/app/lib/client/defaultTabBars.js index 4ce7441e4c58..11cb8a1fb09c 100644 --- a/app/lib/client/defaultTabBars.js +++ b/app/lib/client/defaultTabBars.js @@ -3,6 +3,7 @@ import { Session } from 'meteor/session'; import { TabBar } from '../../ui-utils'; import { Rooms } from '../../models'; import { hasAllPermission } from '../../authorization'; +import { roomTypes } from '../../utils/client'; TabBar.addButton({ groups: ['channel', 'group', 'direct'], @@ -20,6 +21,31 @@ TabBar.addButton({ icon: 'user', template: 'membersList', order: 2, + condition() { + const rid = Session.get('openedRoom'); + const room = Rooms.findOne({ + _id: rid, + }); + + return !roomTypes.getConfig(room.t).isGroupChat(room); + }, +}); + +TabBar.addButton({ + groups: ['direct'], + id: 'user-info', + i18nTitle: 'Members_List', + icon: 'group', + template: 'membersList', + order: 2, + condition() { + const rid = Session.get('openedRoom'); + const room = Rooms.findOne({ + _id: rid, + }); + + return roomTypes.getConfig(room.t).isGroupChat(room); + }, }); TabBar.addButton({ diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 42dd405c6fcf..2eb3e43a506b 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -7,6 +7,7 @@ import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnu import { hasPermission, hasAtLeastOnePermission } from '../../../authorization'; import { settings } from '../../../settings'; import { getUserAvatarURL } from '../../../utils/lib/getUserAvatarURL'; +import { getAvatarURL } from '../../../utils/lib/getAvatarURL'; export class DirectMessageRoomRoute extends RoomTypeRouteConfig { constructor() { @@ -36,6 +37,14 @@ export class DirectMessageRoomType extends RoomTypeConfig { }); } + + getIcon(roomData) { + if (roomData.usernames && roomData.usernames.length > 2) { + return 'group'; + } + return this.icon; + } + findRoom(identifier) { if (!hasPermission('view-d-room')) { return null; @@ -162,10 +171,17 @@ export class DirectMessageRoomType extends RoomTypeConfig { } getAvatarPath(roomData) { + if (roomData.usernames.length > 2) { + return getAvatarURL({ username: roomData.usernames.length + roomData.usernames.join() }); + } return getUserAvatarURL(roomData.name || this.roomName(roomData)); } includeInDashboard() { return true; } + + isGroupChat(room) { + return room.usernames && room.usernames.length > 2; + } } diff --git a/app/ui-flextab/client/tabs/membersList.js b/app/ui-flextab/client/tabs/membersList.js index 811d171d2554..1e732a910e38 100644 --- a/app/ui-flextab/client/tabs/membersList.js +++ b/app/ui-flextab/client/tabs/membersList.js @@ -23,7 +23,7 @@ Template.membersList.helpers({ isGroupChat() { const room = ChatRoom.findOne(this.rid, { reactive: false }); - return roomTypes.getConfig(room.t).isGroupChat(); + return roomTypes.getConfig(room.t).isGroupChat(room); }, isDirectChat() { @@ -117,7 +117,7 @@ Template.membersList.helpers({ }, userInfoDetail() { - const room = ChatRoom.findOne(this.rid, { fields: { t: 1 } }); + const room = ChatRoom.findOne(this.rid, { fields: { t: 1, usernames: 1 } }); return { tabBar: Template.currentData().tabBar, @@ -126,7 +126,7 @@ Template.membersList.helpers({ showAll: roomTypes.getConfig(room.t).userDetailShowAll(room) || false, hideAdminControls: roomTypes.getConfig(room.t).userDetailShowAdmin(room) || false, video: ['d'].includes(room && room.t), - showBackButton: roomTypes.getConfig(room.t).isGroupChat(), + showBackButton: roomTypes.getConfig(room.t).isGroupChat(room), }; }, displayName() { diff --git a/app/ui-master/public/icons/Group.svg b/app/ui-master/public/icons/Group.svg new file mode 100644 index 000000000000..d5c0f584de1a --- /dev/null +++ b/app/ui-master/public/icons/Group.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/ui-sidenav/client/chatRoomItem.js b/app/ui-sidenav/client/chatRoomItem.js index 801c415babe9..60b33657e9c8 100644 --- a/app/ui-sidenav/client/chatRoomItem.js +++ b/app/ui-sidenav/client/chatRoomItem.js @@ -16,12 +16,14 @@ Template.chatRoomItem.helpers({ const archivedClass = this.archived ? 'archived' : false; - const icon = this.t !== 'd' && roomTypes.getIcon(this); + const room = Rooms.findOne(this.rid); + + const icon = this.t === 'd' ? roomTypes.getIcon(room) : roomTypes.getIcon(this); const roomData = { ...this, - icon, - avatar: roomType.getAvatarPath(this), + icon: icon !== 'at' && icon, + avatar: roomTypes.getConfig(this.t).getAvatarPath(room), username: this.name, route: roomTypes.getRouteLink(this.t, this), name: roomType.roomName(this), diff --git a/app/ui/client/components/header/headerRoom.html b/app/ui/client/components/header/headerRoom.html index 456547049fed..9b849f09cb2b 100644 --- a/app/ui/client/components/header/headerRoom.html +++ b/app/ui/client/components/header/headerRoom.html @@ -29,7 +29,7 @@ {{#if isDirect}}
- {{> avatar username=avatarBackground}} + {{> avatar url=avatarBackground}}
{{/if}} @@ -41,7 +41,7 @@
{{roomName}}
@{{secondaryName}}
{{/unless}} - {{#if isDirect}} + {{#if hasPresence}} {{# userPresence uid=uid}}
{{userStatusText}}
diff --git a/app/ui/client/components/header/headerRoom.js b/app/ui/client/components/header/headerRoom.js index 52f5360d7f5c..e75a7d7dd461 100644 --- a/app/ui/client/components/header/headerRoom.js +++ b/app/ui/client/components/header/headerRoom.js @@ -28,6 +28,11 @@ const getUserStatusText = (id) => { Template.headerRoom.helpers({ isDiscussion: () => Template.instance().state.get('discussion'), + hasPresence() { + const room = Rooms.findOne(this._id); + return !roomTypes.getConfig(room.t).isGroupChat(room); + }, + isDirect() { return Rooms.findOne(this._id).t === 'd'; }, isToggleFavoriteButtonVisible: () => Template.instance().state.get('favorite') !== null, isToggleFavoriteButtonChecked: () => Template.instance().state.get('favorite'), toggleFavoriteButtonIconLabel: () => (Template.instance().state.get('favorite') ? t('Unfavorite') : t('Favorite')), @@ -41,7 +46,7 @@ Template.headerRoom.helpers({ avatarBackground() { const roomData = Session.get(`roomData${ this._id }`); if (!roomData) { return ''; } - return roomTypes.getSecondaryRoomName(roomData.t, roomData) || roomTypes.getRoomName(roomData.t, roomData); + return roomTypes.getConfig(roomData.t).getAvatarPath(roomData); }, buttons() { return TabBar.getButtons(); @@ -51,11 +56,6 @@ Template.headerRoom.helpers({ const sub = ChatSubscription.findOne({ rid: this._id }, { fields: { autoTranslate: 1, autoTranslateLanguage: 1 } }); return settings.get('AutoTranslate_Enabled') && ((sub != null ? sub.autoTranslate : undefined) === true) && (sub.autoTranslateLanguage != null); }, - - isDirect() { - return Rooms.findOne(this._id).t === 'd'; - }, - roomName() { const roomData = Session.get(`roomData${ this._id }`); if (!roomData) { return ''; } diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 99f9b4be2181..adac00557799 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -1035,10 +1035,16 @@ Template.room.onCreated(function() { this.subscription = new ReactiveVar(); this.state = new ReactiveDict(); + this.userDetail = new ReactiveVar(FlowRouter.getParam('username')); this.autorun(() => { const rid = Template.currentData()._id; - this.state.set('announcement', Rooms.findOne({ _id: rid }, { fields: { announcement: 1 } }).announcement); + const room = Rooms.findOne({ _id: rid }, { fields: { announcement: 1, usernames: 1, t: 1 } }); + this.state.set('announcement', room.announcement); + + if (roomTypes.getConfig(room.t).isGroupChat(room)) { + this.userDetail.set(undefined); + } }); this.autorun(() => { @@ -1062,7 +1068,6 @@ Template.room.onCreated(function() { this.flexTemplate = new ReactiveVar(); - this.userDetail = new ReactiveVar(FlowRouter.getParam('username')); this.groupDetail = new ReactiveVar(); this.tabBar = new RocketChatTabBar(); diff --git a/private/public/icons.svg b/private/public/icons.svg index 4edb27e8e126..6f56e679f24e 100644 --- a/private/public/icons.svg +++ b/private/public/icons.svg @@ -155,6 +155,12 @@ + + + + + + @@ -371,4 +377,4 @@ - \ No newline at end of file + diff --git a/public/public/icons.html b/public/public/icons.html index 597ab48c8d05..67fd1497f83f 100644 --- a/public/public/icons.html +++ b/public/public/icons.html @@ -22,7 +22,7 @@ height: 20px; color: blue; } -
+
@@ -179,6 +179,12 @@ + + + + + + From db7584dab563c0f029c75864f352ab13c1a1405c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 16 Mar 2020 19:42:54 -0300 Subject: [PATCH 15/64] create direct message modal --- app/lib/server/functions/createDirectRoom.js | 5 +- app/ui-master/public/icons/Group.svg | 6 - app/ui-master/public/icons/group.svg | 6 + app/ui-sidenav/client/sidebarHeader.js | 69 +++++------ app/ui/client/index.js | 1 + .../client/views/app/CreateDirectMessage.html | 32 +++++ .../client/views/app/CreateDirectMessage.js | 112 ++++++++++++++++++ private/public/icons.svg | 12 +- public/public/icons.html | 10 +- server/methods/createDirectMessage.js | 4 +- 10 files changed, 204 insertions(+), 53 deletions(-) delete mode 100644 app/ui-master/public/icons/Group.svg create mode 100644 app/ui-master/public/icons/group.svg create mode 100644 app/ui/client/views/app/CreateDirectMessage.html create mode 100755 app/ui/client/views/app/CreateDirectMessage.js diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 4fced890f6ab..658b9fbc8df0 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -31,10 +31,12 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = const rid = members.map(({ _id }) => _id).sort().join(''); // TODO provide a better rid heuristic + const usernames = sortedMembers.map(({ username }) => username); + const { insertedId } = Rooms.upsert({ _id: rid }, { $setOnInsert: { t: 'd', - usernames: sortedMembers.map(({ username }) => username), + usernames, usersCount: members.length, msgs: 0, ts: new Date(), @@ -55,6 +57,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = return { _id: rid, + usernames, t: 'd', inserted: !!insertedId, }; diff --git a/app/ui-master/public/icons/Group.svg b/app/ui-master/public/icons/Group.svg deleted file mode 100644 index d5c0f584de1a..000000000000 --- a/app/ui-master/public/icons/Group.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/app/ui-master/public/icons/group.svg b/app/ui-master/public/icons/group.svg new file mode 100644 index 000000000000..987955ea978b --- /dev/null +++ b/app/ui-master/public/icons/group.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/ui-sidenav/client/sidebarHeader.js b/app/ui-sidenav/client/sidebarHeader.js index 90562d7f83d3..7384482f5019 100644 --- a/app/ui-sidenav/client/sidebarHeader.js +++ b/app/ui-sidenav/client/sidebarHeader.js @@ -9,6 +9,7 @@ import { callbacks } from '../../callbacks'; import { settings } from '../../settings'; import { hasAtLeastOnePermission } from '../../authorization'; import { userStatus } from '../../user-status'; +import { hasPermission } from '../../authorization/client'; const setStatus = (status, statusText) => { AccountBox.setStatus(status, statusText); @@ -155,14 +156,14 @@ const toolbarButtons = (user) => [{ { name: t('Create_new'), icon: 'edit-rounded', - condition: () => hasAtLeastOnePermission(['create-c', 'create-p']), + condition: () => hasAtLeastOnePermission(['create-c', 'create-p', 'create-d', 'start-discussion', 'start-discussion-other-user']), hasPopup: true, action: (e) => { - const createChannel = (e) => { + const action = (title, content) => (e) => { e.preventDefault(); modal.open({ - title: t('Create_A_New_Channel'), - content: 'createChannel', + title: t(title), + content, data: { onCreate() { modal.close(); @@ -175,42 +176,42 @@ const toolbarButtons = (user) => [{ }); }; - const discussionEnabled = settings.get('Discussion_enabled'); - if (!discussionEnabled) { - return createChannel(e); + const createChannel = action('Create_A_New_Channel', 'createChannel'); + const createDirectMessage = action('Direct Message', 'CreateDirectMessage'); + const createDiscussion = action('Discussion_title', 'CreateDiscussion'); + + + const items = [ + hasAtLeastOnePermission(['create-c', 'create-p']) + && { + icon: 'hashtag', + name: t('Channel'), + action: createChannel, + }, + hasPermission('create-d') + && { + icon: 'group', + name: t('Direct_Messages'), + action: createDirectMessage, + }, + settings.get('Discussion_enabled') && hasAtLeastOnePermission(['start-discussion', 'start-discussion-other-user']) + && { + icon: 'discussion', + name: t('Discussion'), + action: createDiscussion, + }, + ].filter(Boolean); + + if (items.length === 1) { + return items[0].action(e); } + const config = { columns: [ { groups: [ { - items: [ - { - icon: 'hashtag', - name: t('Channel'), - action: createChannel, - }, - { - icon: 'discussion', - name: t('Discussion'), - action: (e) => { - e.preventDefault(); - modal.open({ - title: t('Discussion_title'), - content: 'CreateDiscussion', - data: { - onCreate() { - modal.close(); - }, - }, - modifier: 'modal', - showConfirmButton: false, - showCancelButton: false, - confirmOnEnter: false, - }); - }, - }, - ], + items, }, ], }, diff --git a/app/ui/client/index.js b/app/ui/client/index.js index 4814ef166220..f44ba3083e41 100644 --- a/app/ui/client/index.js +++ b/app/ui/client/index.js @@ -33,6 +33,7 @@ import './views/cmsPage'; import './views/404/roomNotFound'; import './views/app/burger'; import './views/app/createChannel'; +import './views/app/CreateDirectMessage'; import './views/app/editStatus'; import './views/app/fullModal'; import './views/app/home'; diff --git a/app/ui/client/views/app/CreateDirectMessage.html b/app/ui/client/views/app/CreateDirectMessage.html new file mode 100644 index 000000000000..e2824f6ec155 --- /dev/null +++ b/app/ui/client/views/app/CreateDirectMessage.html @@ -0,0 +1,32 @@ +
+
+
+ {{> SearchCreateDiscussion + onClickTag=onClickTagUser + deleteLastItem=deleteLastItemUser + list=selectedUsers + onSelect=onSelectUser + collection='UserAndRoom' + endpoint='users.autocomplete' + field='username' + sort='username' + label="Invite_Users" + placeholder="Username_Placeholder" + name="directMessageUsers" + icon="at" + noMatchTemplate="userSearchEmpty" + templateItem="popupList_item_default" + modifier=userModifier + }} +
+

{{_ "Discussion_description"}}

+
+
+ +
+
+ + diff --git a/app/ui/client/views/app/CreateDirectMessage.js b/app/ui/client/views/app/CreateDirectMessage.js new file mode 100755 index 000000000000..b0cbcc392f65 --- /dev/null +++ b/app/ui/client/views/app/CreateDirectMessage.js @@ -0,0 +1,112 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { ReactiveVar } from 'meteor/reactive-var'; + + +import { roomTypes } from '../../../../utils/client'; +import { ChatSubscription } from '../../../../models/client'; +import { call } from '../../../../ui-utils/client'; + +import './CreateDirectMessage.html'; + +Template.CreateDirectMessage.helpers({ + onSelectUser() { + return Template.instance().onSelectUser; + }, + createIsDisabled() { + return Template.instance().selectedUsers.get().length === 0 ? 'disabled' : ''; + }, + parentChannel() { + const instance = Template.instance(); + return instance.parentChannel.get(); + }, + selectedUsers() { + const myUsername = Meteor.user().username; + const { message } = this; + const users = Template.instance().selectedUsers.get().map((e) => e); + if (message) { + users.unshift(message.u); + } + return users.filter(({ username }) => myUsername !== username); + }, + + onClickTagUser() { + return Template.instance().onClickTagUser; + }, + deleteLastItemUser() { + return Template.instance().deleteLastItemUser; + }, + onClickTagRoom() { + return Template.instance().onClickTagRoom; + }, + selectedRoom() { + return Template.instance().selectedRoom.get(); + }, + userModifier() { + return (filter, text = '') => { + const f = filter.get(); + return `@${ f.length === 0 ? text : text.replace(new RegExp(filter.get()), (part) => `${ part }`) }`; + }; + }, + nameSuggestion() { + return Template.instance().discussionName.get(); + }, +}); + +Template.CreateDirectMessage.events({ + async 'submit #create-dm, click .js-save-dm'(event, instance) { + event.preventDefault(); + const users = instance.selectedUsers.get().map(({ username }) => username).filter((value, index, self) => self.indexOf(value) === index); + + const result = await call('createDirectMessage', ...users); + + if (instance.data.onCreate) { + instance.data.onCreate(result); + } + const user = Meteor.user(); + roomTypes.openRouteLink(result.t, { ...result, name: result.usernames.filter((username) => username !== user.username).join(', ') }); + }, +}); + +Template.CreateDirectMessage.onRendered(function() { + this.find('#directMessageUsers').focus(); +}); + +Template.CreateDirectMessage.onCreated(function() { + const { rid, message: msg } = this.data; + + const parentRoom = rid && ChatSubscription.findOne({ rid }); + + // if creating a discussion from inside a discussion, uses the same channel as parent channel + const room = parentRoom && parentRoom.prid ? ChatSubscription.findOne({ rid: parentRoom.prid }) : parentRoom; + + if (room) { + room.text = room.name; + } + + this.selectedUsers = new ReactiveVar([]); + + this.onSelectUser = ({ item: user }) => { + if (user.username === (msg && msg.u.username)) { + return; + } + + if (user.username === Meteor.user().username) { + return; + } + const users = this.selectedUsers.get(); + if (!users.find((u) => user.username === u.username)) { + this.selectedUsers.set([...users, user]); + } + }; + + this.onClickTagUser = ({ username }) => { + this.selectedUsers.set(this.selectedUsers.get().filter((user) => user.username !== username)); + }; + + this.deleteLastItemUser = () => { + const arr = this.selectedUsers.get(); + arr.pop(); + this.selectedUsers.set(arr); + }; +}); diff --git a/private/public/icons.svg b/private/public/icons.svg index 6f56e679f24e..deb8ff2d9df8 100644 --- a/private/public/icons.svg +++ b/private/public/icons.svg @@ -155,11 +155,11 @@ - - - - - + + + + + @@ -377,4 +377,4 @@ - + \ No newline at end of file diff --git a/public/public/icons.html b/public/public/icons.html index 67fd1497f83f..5bbce9b034ed 100644 --- a/public/public/icons.html +++ b/public/public/icons.html @@ -179,11 +179,11 @@ - - - - - + + + + + diff --git a/server/methods/createDirectMessage.js b/server/methods/createDirectMessage.js index f0b51b426094..73add7027e46 100644 --- a/server/methods/createDirectMessage.js +++ b/server/methods/createDirectMessage.js @@ -62,7 +62,7 @@ Meteor.methods({ return to; }); - const { _id: rid, inserted } = createDirectRoom([me, ...users], { }, { creator: me._id }); + const { _id: rid, inserted, ...room } = createDirectRoom([me, ...users], { }, { creator: me._id }); // If the room is new, run a callback if (inserted) { @@ -71,7 +71,9 @@ Meteor.methods({ } return { + t: 'd', rid, + ...room, }; }, }); From 8fdfbee49f620d398cd6bdb3d640076dee660a61 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Mon, 16 Mar 2020 20:04:28 -0300 Subject: [PATCH 16/64] removed duplicated code --- app/ui-flextab/client/tabs/userActions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index 3810405133c2..070d7ff6ea9f 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -48,10 +48,6 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { user && user._id && !!RoomRoles.findOne({ rid: Session.get('openedRoom'), 'u._id': user._id, roles: 'owner' }); const isModerator = () => user && user._id && !!RoomRoles.findOne({ rid: Session.get('openedRoom'), 'u._id': user._id, roles: 'moderator' }); - const isInDirectMessageRoom = () => { - const room = ChatRoom.findOne(Session.get('openedRoom')); - return roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK); - }; const room = ChatRoom.findOne(Session.get('openedRoom')); @@ -189,7 +185,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { }, }; }, function() { - if (!directActions || !isInDirectMessageRoom() || isSelf(this.username)) { + if (!directActions || isSelf(this.username)) { return; } if (!room || !roomTypes.getConfig(room.t).allowMemberAction(room, RoomMemberActions.BLOCK)) { From 4ab0e571f0091cf8fceb7ec1d5f6794a4c8efc03 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 17 Mar 2020 11:31:02 -0300 Subject: [PATCH 17/64] fix undefined room --- app/lib/client/defaultTabBars.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/client/defaultTabBars.js b/app/lib/client/defaultTabBars.js index 11cb8a1fb09c..12d0c02579d5 100644 --- a/app/lib/client/defaultTabBars.js +++ b/app/lib/client/defaultTabBars.js @@ -27,7 +27,7 @@ TabBar.addButton({ _id: rid, }); - return !roomTypes.getConfig(room.t).isGroupChat(room); + return room && !roomTypes.getConfig(room.t).isGroupChat(room); }, }); @@ -44,7 +44,7 @@ TabBar.addButton({ _id: rid, }); - return roomTypes.getConfig(room.t).isGroupChat(room); + return room && roomTypes.getConfig(room.t).isGroupChat(room); }, }); From 16f782d35eaac28391b373053b656ce9f872f56a Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 19 Mar 2020 11:26:47 -0300 Subject: [PATCH 18/64] prevent errors --- app/lib/lib/roomTypes/direct.js | 2 +- app/ui-sidenav/client/chatRoomItem.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 2eb3e43a506b..f14ca51d2cdf 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -171,7 +171,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { } getAvatarPath(roomData) { - if (roomData.usernames.length > 2) { + if (roomData.usernames && roomData.usernames.length > 2) { return getAvatarURL({ username: roomData.usernames.length + roomData.usernames.join() }); } return getUserAvatarURL(roomData.name || this.roomName(roomData)); diff --git a/app/ui-sidenav/client/chatRoomItem.js b/app/ui-sidenav/client/chatRoomItem.js index 60b33657e9c8..7107aa5473ee 100644 --- a/app/ui-sidenav/client/chatRoomItem.js +++ b/app/ui-sidenav/client/chatRoomItem.js @@ -23,7 +23,7 @@ Template.chatRoomItem.helpers({ const roomData = { ...this, icon: icon !== 'at' && icon, - avatar: roomTypes.getConfig(this.t).getAvatarPath(room), + avatar: roomTypes.getConfig(this.t).getAvatarPath(room || this), username: this.name, route: roomTypes.getRouteLink(this.t, this), name: roomType.roomName(this), From 69e2840dc1bd05a2adc36711d2b4c7f659bbf577 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 01:29:11 -0300 Subject: [PATCH 19/64] update mention component --- app/ui/client/views/app/RoomForeword.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ui/client/views/app/RoomForeword.js b/app/ui/client/views/app/RoomForeword.js index fde4d1a22bff..88afefde4699 100644 --- a/app/ui/client/views/app/RoomForeword.js +++ b/app/ui/client/views/app/RoomForeword.js @@ -1,6 +1,6 @@ import React from 'react'; import { Meteor } from 'meteor/meteor'; -import { Avatar, Margins, Flex, Box } from '@rocket.chat/fuselage'; +import { Avatar, Margins, Flex, Box, Tag } from '@rocket.chat/fuselage'; import { Template } from 'meteor/templating'; import './RoomForeword.html'; @@ -39,7 +39,7 @@ const RoomForeword = ({ room, user }) => { - {users.map((username, index) => {username})} + {users.map((username, index) => {username})} From 20fb2b7cdf9f08586042f48f8e9b19cd3a4c6d94 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 01:42:25 -0300 Subject: [PATCH 20/64] i18n --- app/ui/client/views/app/CreateDirectMessage.html | 3 +-- app/ui/client/views/app/RoomForeword.js | 2 +- packages/rocketchat-i18n/i18n/en.i18n.json | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/ui/client/views/app/CreateDirectMessage.html b/app/ui/client/views/app/CreateDirectMessage.html index e2824f6ec155..5472f585849f 100644 --- a/app/ui/client/views/app/CreateDirectMessage.html +++ b/app/ui/client/views/app/CreateDirectMessage.html @@ -13,7 +13,7 @@ endpoint='users.autocomplete' field='username' sort='username' - label="Invite_Users" + label="Direct_message_creation_description" placeholder="Username_Placeholder" name="directMessageUsers" icon="at" @@ -22,7 +22,6 @@ modifier=userModifier }}
-

{{_ "Discussion_description"}}

diff --git a/app/ui/client/views/app/RoomForeword.js b/app/ui/client/views/app/RoomForeword.js index 88afefde4699..09f4d2419846 100644 --- a/app/ui/client/views/app/RoomForeword.js +++ b/app/ui/client/views/app/RoomForeword.js @@ -33,7 +33,7 @@ const RoomForeword = ({ room, user }) => { - { t('You have joined a new direct message with') } + { t('Direct_message_you_have_joined') } diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index aa7a476aed71..16d67e11cf6e 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1117,6 +1117,8 @@ "Desktop_Notifications_Not_Enabled": "Desktop Notifications are Not Enabled", "Details": "Details", "Different_Style_For_User_Mentions": "Different style for user mentions", + "Direct_message_creation_description" : "You are about to create a chat with multiple users. Add the ones you would like to talk, everyone in te same place, using direct messages.", + "Direct_message_you_have_joined": "You have joined a new direct message with", "Direct_message_someone": "Direct message someone", "Direct_Messages": "Direct Messages", "Direct_Reply": "Direct Reply", From 738368352ffce8ce12f5e5c462dd979e3174cf6d Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 12:35:13 -0300 Subject: [PATCH 21/64] Add avatar stack --- app/ui/client/views/app/RoomForeword.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/ui/client/views/app/RoomForeword.js b/app/ui/client/views/app/RoomForeword.js index 09f4d2419846..ef068e3b3219 100644 --- a/app/ui/client/views/app/RoomForeword.js +++ b/app/ui/client/views/app/RoomForeword.js @@ -26,9 +26,9 @@ const RoomForeword = ({ room, user }) => { - - {users.map((username, index) => )} - + + {users.map((username, index) => )} + From ff2c1dfbfdd4d1fd34ebba750d4b3da8f6a78f0c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 17:16:49 -0300 Subject: [PATCH 22/64] private and public url by id --- app/lib/lib/roomTypes/direct.js | 11 +++--- app/lib/lib/roomTypes/private.js | 9 +++-- app/lib/lib/roomTypes/public.js | 9 +++-- app/ui-utils/client/lib/openRoom.js | 44 +++++++++++------------- app/ui/client/lib/notification.js | 6 ++-- app/ui/client/views/app/createChannel.js | 3 +- app/utils/lib/RoomTypesCommon.js | 1 + 7 files changed, 45 insertions(+), 38 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index f14ca51d2cdf..8caade773583 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -13,16 +13,16 @@ export class DirectMessageRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'direct', - path: '/direct/:username', + path: '/direct/:rid', }); } action(params) { - return openRoom('d', params.username); + return openRoom('d', params.rid); } link(sub) { - return { username: sub.name }; + return { rid: sub.rid }; } } @@ -52,7 +52,10 @@ export class DirectMessageRoomType extends RoomTypeConfig { const query = { t: 'd', - name: identifier, + $or: [ + { name: identifier }, + { rid: identifier }, + ], }; const subscription = Subscriptions.findOne(query); diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index 219ebbc8e9dd..11c960ea694b 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -13,12 +13,12 @@ export class PrivateRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'group', - path: '/group/:name', + path: '/group/:rid', }); } action(params) { - return openRoom('p', params.name); + return openRoom('p', params.rid); } } @@ -43,7 +43,10 @@ export class PrivateRoomType extends RoomTypeConfig { findRoom(identifier) { const query = { t: 'p', - name: identifier, + $or: [ + { name: identifier }, + { _id: identifier }, + ], }; return ChatRoom.findOne(query); diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 11d688731eff..5f46a1575f9a 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -11,12 +11,12 @@ export class PublicRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'channel', - path: '/channel/:name', + path: '/channel/:rid', }); } action(params) { - return openRoom('c', params.name); + return openRoom('c', params.rid); } } @@ -41,7 +41,10 @@ export class PublicRoomType extends RoomTypeConfig { findRoom(identifier) { const query = { t: 'c', - name: identifier, + $or: [ + { name: identifier }, + { _id: identifier }, + ], }; return ChatRoom.findOne(query); } diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index 40f92a2019c9..f704d2bb2eb5 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -47,43 +47,39 @@ export const openRoom = function(type, name) { return; } - if (RoomManager.open(type + name).ready() !== true) { - if (settings.get('Accounts_AllowAnonymousRead')) { - BlazeLayout.render('main'); - } - replaceCenterDomBy(getDomOfLoading()); - return; - } - if (window.currentTracker) { - window.currentTracker = undefined; - } - c.stop(); - const room = roomTypes.findRoom(type, name, user); if (room == null) { if (type === 'd') { Meteor.call('createDirectMessage', ...name.split(', '), function(error) { // TODO provide a function to handle if (!error) { - RoomManager.close(type + name); - return openRoom('d', name); + return; + // RoomManager.close(type + name); + // return openRoom('d', name); } Session.set('roomNotFound', { type, name, error }); BlazeLayout.render('main', { center: 'roomNotFound' }); }); - } else { - Meteor.call('getRoomByTypeAndName', type, name, function(error, record) { - if (error) { - Session.set('roomNotFound', { type, name, error }); - return BlazeLayout.render('main', { center: 'roomNotFound' }); - } - Rooms.upsert({ _id: record._id }, _.omit(record, '_id')); - RoomManager.close(type + name); - return openRoom(type, name); - }); } return; } + if (RoomManager.open(type + name).ready() !== true) { + if (settings.get('Accounts_AllowAnonymousRead')) { + BlazeLayout.render('main'); + } + replaceCenterDomBy(getDomOfLoading()); + return; + } + if (window.currentTracker) { + window.currentTracker = undefined; + } + + c.stop(); + if (room._id !== name && type === 'd') { + RoomManager.close(type + name); + return FlowRouter.go('direct', { username: room._id }, FlowRouter.current().queryParams); + } + const roomDom = RoomManager.getDomOfRoom(type + name, room._id); const mainNode = replaceCenterDomBy(roomDom); diff --git a/app/ui/client/lib/notification.js b/app/ui/client/lib/notification.js index 27ff9d7e903a..f04028cffc06 100644 --- a/app/ui/client/lib/notification.js +++ b/app/ui/client/lib/notification.js @@ -65,11 +65,11 @@ export const KonchatNotification = { window.focus(); switch (notification.payload.type) { case 'd': - return FlowRouter.go('direct', { username: notification.payload.sender.username }, FlowRouter.current().queryParams); + return FlowRouter.go('direct', { rid: notification.payload.sender.username }, FlowRouter.current().queryParams); // TODO CHANGE case 'c': - return FlowRouter.go('channel', { name: notification.payload.name }, FlowRouter.current().queryParams); + return FlowRouter.go('channel', { rid: notification.payload.name }, FlowRouter.current().queryParams); case 'p': - return FlowRouter.go('group', { name: notification.payload.name }, FlowRouter.current().queryParams); + return FlowRouter.go('group', { rid: notification.payload.name }, FlowRouter.current().queryParams); } }; } diff --git a/app/ui/client/views/app/createChannel.js b/app/ui/client/views/app/createChannel.js index 3d1b56de00f7..778f2a708d40 100644 --- a/app/ui/client/views/app/createChannel.js +++ b/app/ui/client/views/app/createChannel.js @@ -264,7 +264,8 @@ Template.createChannel.events({ if (instance.data.onCreate) { instance.data.onCreate(result); } - return FlowRouter.go(isPrivate ? 'group' : 'channel', { name: result.name }, FlowRouter.current().queryParams); + + return FlowRouter.go(isPrivate ? 'group' : 'channel', { ...result }, FlowRouter.current().queryParams); }); return false; }, diff --git a/app/utils/lib/RoomTypesCommon.js b/app/utils/lib/RoomTypesCommon.js index abe097dbf8c9..5b6bdc0cd2b4 100644 --- a/app/utils/lib/RoomTypesCommon.js +++ b/app/utils/lib/RoomTypesCommon.js @@ -104,6 +104,7 @@ export class RoomTypesCommon { routeData = this.roomTypes[roomType].route.link(subData); } else if (subData && subData.name) { routeData = { + rid: subData.rid || subData._id, name: subData.name, }; } From 8f3bbab6d288456448a119d466c5d47af8777ce4 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 17:36:25 -0300 Subject: [PATCH 23/64] new old icon --- app/lib/client/defaultTabBars.js | 2 +- app/ui-sidenav/client/sidebarHeader.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/lib/client/defaultTabBars.js b/app/lib/client/defaultTabBars.js index 12d0c02579d5..e506e18efc72 100644 --- a/app/lib/client/defaultTabBars.js +++ b/app/lib/client/defaultTabBars.js @@ -35,7 +35,7 @@ TabBar.addButton({ groups: ['direct'], id: 'user-info', i18nTitle: 'Members_List', - icon: 'group', + icon: 'team', template: 'membersList', order: 2, condition() { diff --git a/app/ui-sidenav/client/sidebarHeader.js b/app/ui-sidenav/client/sidebarHeader.js index 7384482f5019..c290db9ace53 100644 --- a/app/ui-sidenav/client/sidebarHeader.js +++ b/app/ui-sidenav/client/sidebarHeader.js @@ -177,7 +177,7 @@ const toolbarButtons = (user) => [{ }; const createChannel = action('Create_A_New_Channel', 'createChannel'); - const createDirectMessage = action('Direct Message', 'CreateDirectMessage'); + const createDirectMessage = action('Direct_Message', 'CreateDirectMessage'); const createDiscussion = action('Discussion_title', 'CreateDiscussion'); @@ -190,7 +190,7 @@ const toolbarButtons = (user) => [{ }, hasPermission('create-d') && { - icon: 'group', + icon: 'team', name: t('Direct_Messages'), action: createDirectMessage, }, From 9363b26a73b546bb0acdd3c36d9599cb654cb52c Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 20:15:44 -0300 Subject: [PATCH 24/64] old icon --- app/lib/lib/roomTypes/direct.js | 2 +- app/ui-sidenav/client/sidebarHeader.js | 2 +- app/ui-utils/client/lib/openRoom.js | 2 +- private/public/icons.svg | 8 +------- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 8caade773583..2d14824f2ac7 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -40,7 +40,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { getIcon(roomData) { if (roomData.usernames && roomData.usernames.length > 2) { - return 'group'; + return 'team'; } return this.icon; } diff --git a/app/ui-sidenav/client/sidebarHeader.js b/app/ui-sidenav/client/sidebarHeader.js index c290db9ace53..1117e6460b5b 100644 --- a/app/ui-sidenav/client/sidebarHeader.js +++ b/app/ui-sidenav/client/sidebarHeader.js @@ -177,7 +177,7 @@ const toolbarButtons = (user) => [{ }; const createChannel = action('Create_A_New_Channel', 'createChannel'); - const createDirectMessage = action('Direct_Message', 'CreateDirectMessage'); + const createDirectMessage = action('Direct_Messages', 'CreateDirectMessage'); const createDiscussion = action('Discussion_title', 'CreateDiscussion'); diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index f704d2bb2eb5..dbc0c802bca1 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -8,7 +8,7 @@ import { Session } from 'meteor/session'; import mem from 'mem'; import _ from 'underscore'; -import { ChatSubscription, Rooms } from '../../../models'; +import { ChatSubscription } from '../../../models'; import { settings } from '../../../settings'; import { callbacks } from '../../../callbacks'; import { roomTypes, handleError } from '../../../utils'; diff --git a/private/public/icons.svg b/private/public/icons.svg index 97dc95e70f3e..8025023cec7a 100644 --- a/private/public/icons.svg +++ b/private/public/icons.svg @@ -155,12 +155,6 @@ - - - - - - @@ -377,4 +371,4 @@ - \ No newline at end of file + From d9f0a1e6ae17a86d6e11deabad617da7b749cf27 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Fri, 20 Mar 2020 20:32:24 -0300 Subject: [PATCH 25/64] updage fuselage --- package-lock.json | 916 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 10 +- 2 files changed, 891 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31bc73de2f2f..813ff0ca9e4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2716,43 +2716,899 @@ } }, "@rocket.chat/fuselage": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.3.0.tgz", - "integrity": "sha512-nZdtJtEjZO2ZKQafo0ijANRAlr+wSQ9PzsjpRcan4XVaOdnS7Yri7ZlqtA2jdmHyr5/bbQzReM0WudujS5JMyg==", + "version": "0.6.0", "requires": { - "@rocket.chat/fuselage-tokens": "^0.3.0", - "@rocket.chat/icons": "^0.3.0" + "@rocket.chat/css-in-js": "^0.6.0", + "@rocket.chat/fuselage-tokens": "^0.6.0", + "@rocket.chat/icons": "^0.6.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.4", + "requires": { + "source-map": "^0.5.0" + } + }, + "@babel/parser": { + "version": "7.7.5" + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.7.4" + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@rocket.chat/css-in-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.5.0.tgz", + "integrity": "sha512-+D+CIqU+8nMgwU0rFlDjkdhlAHlfeOA4XRvu2RD1pb+p1J2TBnPv0ITQtI3qoVnXuVB6ld27oANXD1u3DWfQuQ==", + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/stylis": "^0.8.5" + } + }, + "@rocket.chat/fuselage-tokens": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.5.0.tgz", + "integrity": "sha512-OmklqorygKsBzPfeFOt8lTmsSH7t+10sIB8qIzyaEvl4ieohzqCAk4mg0NIZ1857fP4bjxW16txjSYZNn4DYKQ==" + }, + "@rocket.chat/icons": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.5.0.tgz", + "integrity": "sha512-OW6+8L3ZeeCuX8pNm4FER5DCTVhGKggFZzldWeUEqxXQH6xCdZfOAmCPijwqg5YO1aJTvlSn9bqp1gMwz8hc6w==" + }, + "@storybook/addon-actions": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/client-api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/theming": "5.2.8", + "react": "^16.8.3", + "react-inspector": "^3.0.2" + }, + "dependencies": { + "@storybook/components": { + "version": "5.2.8", + "requires": { + "@storybook/theming": "5.2.8", + "markdown-to-jsx": "^6.9.1", + "react": "^16.8.3", + "react-dom": "^16.8.3", + "react-focus-lock": "^1.18.3", + "react-helmet-async": "^1.0.2", + "react-popper-tooltip": "^2.8.3", + "react-syntax-highlighter": "^8.0.1", + "react-textarea-autosize": "^7.1.0", + "simplebar-react": "^1.0.0-alpha.6" + }, + "dependencies": { + "react-dom": { + "version": "16.11.0", + "dependencies": { + "scheduler": { + "version": "0.18.0" + } + } + }, + "react-helmet-async": { + "version": "1.0.4" + }, + "react-popper-tooltip": { + "version": "2.10.0", + "requires": { + "react-popper": "^1.3.4" + } + }, + "simplebar-react": { + "version": "1.2.3" + } + } + }, + "create-react-context": { + "version": "0.3.0" + }, + "markdown-to-jsx": { + "version": "6.10.3" + }, + "react": { + "version": "16.11.0" + }, + "react-clientside-effect": { + "version": "1.2.2" + }, + "react-focus-lock": { + "version": "1.19.1", + "requires": { + "react-clientside-effect": "^1.2.0" + } + }, + "react-inspector": { + "version": "3.0.2" + }, + "react-popper": { + "version": "1.3.6", + "requires": { + "create-react-context": "^0.3.0" + } + }, + "react-syntax-highlighter": { + "version": "8.1.0" + }, + "react-textarea-autosize": { + "version": "7.1.2" + }, + "scheduler": { + "version": "0.17.0" + } + } + }, + "@storybook/addon-backgrounds": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/theming": "5.2.8", + "react": "^16.8.3" + }, + "dependencies": { + "@storybook/components": { + "version": "5.2.8", + "requires": { + "@storybook/theming": "5.2.8", + "markdown-to-jsx": "^6.9.1", + "react": "^16.8.3", + "react-dom": "^16.8.3", + "react-focus-lock": "^1.18.3", + "react-helmet-async": "^1.0.2", + "react-popper-tooltip": "^2.8.3", + "react-syntax-highlighter": "^8.0.1", + "react-textarea-autosize": "^7.1.0", + "simplebar-react": "^1.0.0-alpha.6" + }, + "dependencies": { + "react-dom": { + "version": "16.11.0", + "dependencies": { + "scheduler": { + "version": "0.18.0" + } + } + }, + "react-helmet-async": { + "version": "1.0.4" + }, + "react-popper-tooltip": { + "version": "2.10.0", + "requires": { + "react-popper": "^1.3.4" + } + }, + "simplebar-react": { + "version": "1.2.3" + } + } + }, + "create-react-context": { + "version": "0.3.0" + }, + "markdown-to-jsx": { + "version": "6.10.3" + }, + "react": { + "version": "16.11.0" + }, + "react-clientside-effect": { + "version": "1.2.2" + }, + "react-focus-lock": { + "version": "1.19.1", + "requires": { + "react-clientside-effect": "^1.2.0" + } + }, + "react-popper": { + "version": "1.3.6", + "requires": { + "create-react-context": "^0.3.0" + } + }, + "react-syntax-highlighter": { + "version": "8.1.0" + }, + "react-textarea-autosize": { + "version": "7.1.2" + }, + "scheduler": { + "version": "0.17.0" + } + } + }, + "@storybook/addon-centered": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8" + } + }, + "@storybook/addon-docs": { + "version": "5.2.8", + "requires": { + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.3", + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/router": "5.2.8", + "@storybook/source-loader": "5.2.8", + "@storybook/theming": "5.2.8" + } + }, + "@storybook/addon-jest": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/theming": "5.2.8", + "react": "^16.8.3", + "react-sizeme": "^2.5.2" + }, + "dependencies": { + "react": { + "version": "16.11.0" + }, + "react-sizeme": { + "version": "2.6.10" + } + } + }, + "@storybook/addon-knobs": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/client-api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/theming": "5.2.8" + } + }, + "@storybook/addon-links": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/router": "5.2.8" + } + }, + "@storybook/addon-options": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8" + } + }, + "@storybook/addon-viewport": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/theming": "5.2.8" + } + }, + "@storybook/addons": { + "version": "5.2.8", + "requires": { + "@storybook/api": "5.2.8", + "@storybook/channels": "5.2.8", + "@storybook/core-events": "5.2.8" + } + }, + "@storybook/api": { + "version": "5.2.8", + "requires": { + "@storybook/channels": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/router": "5.2.8", + "@storybook/theming": "5.2.8", + "react": "^16.8.3" + }, + "dependencies": { + "react": { + "version": "16.11.0" + } + } + }, + "@storybook/channel-postmessage": { + "version": "5.2.8", + "requires": { + "@storybook/channels": "5.2.8" + } + }, + "@storybook/channels": { + "version": "5.2.8" + }, + "@storybook/client-api": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/channel-postmessage": "5.2.8", + "@storybook/channels": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/router": "5.2.8", + "is-plain-object": "^3.0.0" + } + }, + "@storybook/components": { + "version": "5.2.8", + "requires": { + "@storybook/theming": "5.2.8", + "markdown-to-jsx": "^6.9.1", + "react": "^16.8.3", + "react-dom": "^16.8.3", + "react-focus-lock": "^1.18.3", + "react-helmet-async": "^1.0.2", + "react-popper-tooltip": "^2.8.3", + "react-syntax-highlighter": "^8.0.1", + "react-textarea-autosize": "^7.1.0", + "simplebar-react": "^1.0.0-alpha.6" + }, + "dependencies": { + "create-react-context": { + "version": "0.3.0" + }, + "markdown-to-jsx": { + "version": "6.10.3" + }, + "react": { + "version": "16.11.0" + }, + "react-clientside-effect": { + "version": "1.2.2" + }, + "react-dom": { + "version": "16.11.0", + "dependencies": { + "scheduler": { + "version": "0.18.0" + } + } + }, + "react-focus-lock": { + "version": "1.19.1", + "requires": { + "react-clientside-effect": "^1.2.0" + } + }, + "react-helmet-async": { + "version": "1.0.4" + }, + "react-popper": { + "version": "1.3.6", + "requires": { + "create-react-context": "^0.3.0" + } + }, + "react-popper-tooltip": { + "version": "2.10.0", + "requires": { + "react-popper": "^1.3.4" + } + }, + "react-syntax-highlighter": { + "version": "8.1.0" + }, + "react-textarea-autosize": { + "version": "7.1.2" + }, + "scheduler": { + "version": "0.17.0" + }, + "simplebar-react": { + "version": "1.2.3" + } + } + }, + "@storybook/core": { + "version": "5.2.8", + "requires": { + "@babel/plugin-proposal-object-rest-spread": "^7.6.2", + "@babel/preset-env": "^7.7.1", + "@storybook/addons": "5.2.8", + "@storybook/channel-postmessage": "5.2.8", + "@storybook/client-api": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/node-logger": "5.2.8", + "@storybook/router": "5.2.8", + "@storybook/theming": "5.2.8", + "@storybook/ui": "5.2.8", + "autoprefixer": "^9.4.9", + "find-cache-dir": "^3.0.0", + "resolve": "^1.11.0", + "terser-webpack-plugin": "^1.2.4", + "webpack": "^4.33.0" + }, + "dependencies": { + "@babel/preset-env": { + "version": "7.7.6", + "requires": { + "@babel/plugin-proposal-object-rest-spread": "^7.7.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.4.7", + "semver": "^5.5.0" + }, + "dependencies": { + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.7.7" + }, + "semver": { + "version": "5.7.1" + } + } + }, + "autoprefixer": { + "version": "9.7.1", + "requires": { + "browserslist": "^4.7.2", + "caniuse-lite": "^1.0.30001006", + "postcss": "^7.0.21", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "browserslist": { + "version": "4.7.3", + "requires": { + "caniuse-lite": "^1.0.30001010", + "node-releases": "^1.1.40" + }, + "dependencies": { + "caniuse-lite": { + "version": "1.0.30001015" + } + } + } + } + }, + "caniuse-lite": { + "version": "1.0.30001012" + }, + "enhanced-resolve": { + "version": "4.1.1", + "requires": { + "memory-fs": "^0.5.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0" + } + } + }, + "find-cache-dir": { + "version": "3.2.0", + "requires": { + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + } + }, + "node-releases": { + "version": "1.1.42" + }, + "postcss": { + "version": "7.0.23", + "requires": { + "source-map": "^0.6.1" + } + }, + "serialize-javascript": { + "version": "1.9.1" + }, + "source-map": { + "version": "0.6.1" + }, + "terser-webpack-plugin": { + "version": "1.4.1", + "requires": { + "find-cache-dir": "^2.1.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "requires": { + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "requires": { + "semver": "^5.6.0" + } + }, + "pkg-dir": { + "version": "3.0.0" + }, + "semver": { + "version": "5.7.1" + } + } + }, + "webpack": { + "version": "4.41.2", + "requires": { + "acorn": "^6.2.1", + "enhanced-resolve": "^4.1.0", + "terser-webpack-plugin": "^1.4.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "requires": { + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "requires": { + "semver": "^5.6.0" + } + }, + "pkg-dir": { + "version": "3.0.0" + }, + "semver": { + "version": "5.7.1" + }, + "serialize-javascript": { + "version": "2.1.2" + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "requires": { + "find-cache-dir": "^2.1.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1" + } + }, + "webpack": { + "version": "4.41.4", + "requires": { + "acorn": "^6.2.1", + "enhanced-resolve": "^4.1.0", + "terser-webpack-plugin": "^1.4.3" + } + } + } + } + } + }, + "@storybook/core-events": { + "version": "5.2.8" + }, + "@storybook/node-logger": { + "version": "5.2.8" + }, + "@storybook/react": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/core": "5.2.8", + "@storybook/node-logger": "5.2.8", + "mini-css-extract-plugin": "^0.7.0", + "webpack": "^4.33.0" + }, + "dependencies": { + "enhanced-resolve": { + "version": "4.1.1", + "requires": { + "memory-fs": "^0.5.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0" + } + } + }, + "mini-css-extract-plugin": { + "version": "0.7.0" + }, + "webpack": { + "version": "4.41.2", + "requires": { + "acorn": "^6.2.1", + "enhanced-resolve": "^4.1.0", + "terser-webpack-plugin": "^1.4.1" + } + } + } + }, + "@storybook/router": { + "version": "5.2.8" + }, + "@storybook/source-loader": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/router": "5.2.8" + } + }, + "@storybook/theming": { + "version": "5.2.8" + }, + "@storybook/ui": { + "version": "5.2.8", + "requires": { + "@storybook/addons": "5.2.8", + "@storybook/api": "5.2.8", + "@storybook/channels": "5.2.8", + "@storybook/components": "5.2.8", + "@storybook/core-events": "5.2.8", + "@storybook/router": "5.2.8", + "@storybook/theming": "5.2.8", + "markdown-to-jsx": "^6.9.3", + "react": "^16.8.3", + "react-dom": "^16.8.3", + "react-helmet-async": "^1.0.2", + "react-hotkeys": "2.0.0-pre4", + "react-sizeme": "^2.6.7", + "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "markdown-to-jsx": { + "version": "6.10.3" + }, + "react": { + "version": "16.11.0" + }, + "react-dom": { + "version": "16.11.0", + "requires": { + "scheduler": "^0.17.0" + } + }, + "react-helmet-async": { + "version": "1.0.4" + }, + "react-hotkeys": { + "version": "2.0.0-pre4" + }, + "react-sizeme": { + "version": "2.6.10" + }, + "regenerator-runtime": { + "version": "0.13.3" + }, + "scheduler": { + "version": "0.17.0" + } + } + }, + "acorn": { + "version": "6.4.0" + }, + "autoprefixer": { + "version": "9.7.3", + "requires": { + "browserslist": "^4.8.0", + "caniuse-lite": "^1.0.30001012", + "postcss": "^7.0.23", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "caniuse-lite": { + "version": "1.0.30001015" + } + } + }, + "browserslist": { + "version": "4.8.2", + "requires": { + "caniuse-lite": "^1.0.30001015", + "node-releases": "^1.1.42" + } + }, + "caniuse-lite": { + "version": "1.0.30001016" + }, + "core-js-compat": { + "version": "3.6.0", + "requires": { + "browserslist": "^4.8.2", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0" + } + } + }, + "emoji-regex": { + "version": "7.0.3" + }, + "enhanced-resolve": { + "version": "4.1.0" + }, + "is-plain-object": { + "version": "3.0.0", + "requires": { + "isobject": "^4.0.0" + } + }, + "isobject": { + "version": "4.0.0" + }, + "locate-path": { + "version": "5.0.0", + "requires": { + "p-locate": "^4.1.0" + } + }, + "loki": { + "version": "0.16.0", + "requires": { + "fs-extra": "^7.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1" + } + } + }, + "make-dir": { + "version": "3.0.0" + }, + "mini-css-extract-plugin": { + "version": "0.8.2" + }, + "node-releases": { + "version": "1.1.43" + }, + "p-locate": { + "version": "4.1.0" + }, + "path-exists": { + "version": "4.0.0" + }, + "pkg-dir": { + "version": "4.2.0", + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + } + } + }, + "postcss": { + "version": "7.0.24", + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1" + } + } + }, + "postcss-value-parser": { + "version": "4.0.2" + }, + "react-dom": { + "version": "16.12.0", + "requires": { + "scheduler": "^0.18.0" + } + }, + "resolve": { + "version": "1.12.0" + }, + "sass-loader": { + "version": "8.0.0", + "requires": { + "schema-utils": "^2.1.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.6.1" + } + } + }, + "scheduler": { + "version": "0.18.0" + }, + "source-map": { + "version": "0.5.7" + }, + "string-width": { + "version": "3.1.0", + "requires": { + "emoji-regex": "^7.0.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1" + } + } + }, + "webpack": { + "version": "4.41.4", + "requires": { + "acorn": "^6.2.1", + "enhanced-resolve": "^4.1.0", + "terser-webpack-plugin": "^1.4.3" + }, + "dependencies": { + "enhanced-resolve": { + "version": "4.1.1", + "requires": { + "memory-fs": "^0.5.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0" + } + } + } + } + }, + "webpack-cli": { + "version": "3.3.10", + "requires": { + "enhanced-resolve": "4.1.0", + "yargs": "13.2.4" + } + }, + "yargs": { + "version": "13.2.4", + "requires": { + "string-width": "^3.0.0" + } + } } }, "@rocket.chat/fuselage-hooks": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.3.0.tgz", - "integrity": "sha512-VpRyEhntgJ1HLYtaRmOzdHTpfGxkyyD9ElxBwEENMcu4/Ke6brIttznevndjaZWznfF/VV+15vcFovimRt/giQ==" - }, - "@rocket.chat/fuselage-tokens": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.3.0.tgz", - "integrity": "sha512-PEFww6Q4gRmBo97nA6JHICSYHqQuCDHS4KFS070ofdaRParEaBhrQ8CBF21RpIXZpofk9d4nR96JdI0uf6rWOw==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.6.0.tgz", + "integrity": "sha512-RacebD01VEL1UWa+0qt0X5KwyAzx9bgfk0RC2T9WfwcYWntI0MX3RlMnM6Ld8KwTqOpWs5iIpOasQYCCKM7Ljw==" }, "@rocket.chat/fuselage-ui-kit": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.3.0.tgz", - "integrity": "sha512-V5HhWREpiTCkZ8ww5ow2Iafa9sB/uWGXEa5s0sOJEpGmgXZIRsUQlgcbD87Dm2fx57AXJR19Os4HxVNodF55Ow==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.0.tgz", + "integrity": "sha512-PGCw+IvNsW4A/msAahUXpkv6A6PDcxTGhMEGmA/DiOc7Y72u+7giQl43vLTuW/u5pafJ0gG83TKNxwCBcHPw8g==", "requires": { - "@rocket.chat/ui-kit": "^0.3.0" - }, - "dependencies": { - "@rocket.chat/ui-kit": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.3.0.tgz", - "integrity": "sha512-YAV5l6iVIWuileg5DOU/0NQ/23/AULEr8UblIUSF3OShPN8nWanGMdG0E6xFLyXT+KHvmvzhiQe0/ju3Tk7x8A==" - } + "@rocket.chat/ui-kit": "^0.6.0" } }, "@rocket.chat/icons": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.3.0.tgz", - "integrity": "sha512-cE8tq4MzfqJq3AiSKMQS6RWj5gYKDhnQZNP63q0ljtvcZDzGX/LL3zmACmrCwwjT4Y0XNp2CpPW9mNFtG20iNQ==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.6.0.tgz", + "integrity": "sha512-Kl2C5m9glngFq6J2JxvijMMmrq6f+TAcxPUUEYeglHiORvIJtfYgHT7dwzLhlUiAwMUJSBVsYUzvsAvgiOxdbQ==" }, "@rocket.chat/livechat": { "version": "1.3.1", @@ -2842,9 +3698,9 @@ } }, "@rocket.chat/ui-kit": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.3.0.tgz", - "integrity": "sha512-YAV5l6iVIWuileg5DOU/0NQ/23/AULEr8UblIUSF3OShPN8nWanGMdG0E6xFLyXT+KHvmvzhiQe0/ju3Tk7x8A==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.6.0.tgz", + "integrity": "sha512-Mh82FDw2AOp88LI0IqqT20N6g+cNHfmnXsUU5BZUFh9rI5dMZDrOiYEOZpiWyC5idnWjlmPnxiANemyb8e3Gow==" }, "@settlin/spacebars-loader": { "version": "1.0.7", diff --git a/package.json b/package.json index cb3ff0f6100a..5d5998c80943 100644 --- a/package.json +++ b/package.json @@ -124,11 +124,11 @@ "@google-cloud/storage": "^2.3.1", "@google-cloud/vision": "^1.8.0", "@rocket.chat/apps-engine": "^1.12.0", - "@rocket.chat/fuselage": "^0.3.0", - "@rocket.chat/fuselage-hooks": "^0.3.0", - "@rocket.chat/fuselage-ui-kit": "^0.3.0", - "@rocket.chat/icons": "^0.3.0", - "@rocket.chat/ui-kit": "^0.3.0", + "@rocket.chat/fuselage": "^0.6.0", + "@rocket.chat/fuselage-hooks": "^0.6.0", + "@rocket.chat/fuselage-ui-kit": "^0.6.0", + "@rocket.chat/icons": "^0.6.0", + "@rocket.chat/ui-kit": "^0.6.0", "@slack/client": "^4.8.0", "adm-zip": "RocketChat/adm-zip", "archiver": "^3.0.0", From af3fac7a04f4e3db3957ca3357e6eb02a7f26128 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Fri, 20 Mar 2020 23:55:23 -0300 Subject: [PATCH 26/64] Change DM room _id --- app/lib/server/functions/createDirectRoom.js | 44 ++++++++++++-------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index a2162407bd6d..423eb1908149 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -30,35 +30,45 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); - const rid = members.map(({ _id }) => _id).sort().join(''); // TODO provide a better rid heuristic + const usernames = members.map(({ username }) => username); - const usernames = sortedMembers.map(({ username }) => username); + const room = Rooms.findOne({ t: 'd', usernames: { $all: usernames } }, { fields: { _id: 1 } }); - const { insertedId } = Rooms.upsert({ _id: rid }, { - $setOnInsert: { - t: 'd', - usernames, - usersCount: members.length, - msgs: 0, - ts: new Date(), - ...roomExtraData, - }, + const rid = room?._id || Rooms.insert({ + t: 'd', + usernames, + usersCount: members.length, + msgs: 0, + ts: new Date(), + ...roomExtraData, }); + const newRoom = !room; + if (members.length === 1) { // dm to yourself Subscriptions.upsert({ rid, 'u._id': members[0]._id }, { $set: { open: true }, $setOnInsert: generateSubscription(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra }), }); } else { - members.forEach((member) => Subscriptions.upsert({ rid, 'u._id': member._id }, { - ...options.creator === member._id && { $set: { open: true } }, - $setOnInsert: generateSubscription(getFname(member._id, sortedMembers), getName(member._id, sortedMembers), member, { ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 } }), - })); + members.forEach((member) => + Subscriptions.upsert({ rid, 'u._id': member._id }, { + ...options.creator === member._id && { $set: { open: true } }, + $setOnInsert: generateSubscription( + getFname(member._id, sortedMembers), + getName(member._id, sortedMembers), + member, + { + ...options.subscriptionExtra, + ...options.creator !== member._id && { open: members.length > 2 } + }, + ), + }) + ); } // If the room is new, run a callback - if (insertedId) { + if (newRoom) { const insertedRoom = Rooms.findOneById(rid); callbacks.run('afterCreateDirectRoom', insertedRoom, { from: members[0], to: members[1] }); // TODO PLEASE CHECK FEDERATION!!! @@ -68,6 +78,6 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = _id: rid, usernames, t: 'd', - inserted: !!insertedId, + inserted: newRoom, }; }; From a9dcb6007c8c2cd3f695c4e3373b856bc48147b7 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 00:01:03 -0300 Subject: [PATCH 27/64] Use model --- app/lib/server/functions/createDirectRoom.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 423eb1908149..45a10b60d59f 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -32,7 +32,9 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = const usernames = members.map(({ username }) => username); - const room = Rooms.findOne({ t: 'd', usernames: { $all: usernames } }, { fields: { _id: 1 } }); + const room = Rooms.findDirectRoomContainingAllUsernames(usernames, { fields: { _id: 1 } }); + + const isNewRoom = !room; const rid = room?._id || Rooms.insert({ t: 'd', @@ -43,8 +45,6 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = ...roomExtraData, }); - const newRoom = !room; - if (members.length === 1) { // dm to yourself Subscriptions.upsert({ rid, 'u._id': members[0]._id }, { $set: { open: true }, @@ -68,7 +68,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = } // If the room is new, run a callback - if (newRoom) { + if (isNewRoom) { const insertedRoom = Rooms.findOneById(rid); callbacks.run('afterCreateDirectRoom', insertedRoom, { from: members[0], to: members[1] }); // TODO PLEASE CHECK FEDERATION!!! @@ -78,6 +78,6 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = _id: rid, usernames, t: 'd', - inserted: newRoom, + inserted: isNewRoom, }; }; From 41fb60e671ee9d21171ad5e81217b457faf13606 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 00:02:38 -0300 Subject: [PATCH 28/64] Fix lint --- app/lib/server/functions/createDirectRoom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 45a10b60d59f..c61f4c8ceae2 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -63,7 +63,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = ...options.creator !== member._id && { open: members.length > 2 } }, ), - }) + }), ); } From af95eaa15f334db813a8add34335d8eb4e94f1fe Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sat, 21 Mar 2020 00:44:54 -0300 Subject: [PATCH 29/64] WIP --- app/ui-utils/client/lib/openRoom.js | 7 +++---- app/ui/client/views/app/CreateDirectMessage.js | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index e1c429fc58cd..aafa66ed81f3 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -50,16 +50,15 @@ export const openRoom = function(type, name) { const room = roomTypes.findRoom(type, name, user); if (room == null) { if (type === 'd') { - Meteor.call('createDirectMessage', ...name.split(', '), function(error) { // TODO provide a function to handle + Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle if (!error) { - return; - // RoomManager.close(type + name); - // return openRoom('d', name); + return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); } Session.set('roomNotFound', { type, name, error }); BlazeLayout.render('main', { center: 'roomNotFound' }); }); } + c.stop(); return; } diff --git a/app/ui/client/views/app/CreateDirectMessage.js b/app/ui/client/views/app/CreateDirectMessage.js index b0cbcc392f65..d267758ba803 100755 --- a/app/ui/client/views/app/CreateDirectMessage.js +++ b/app/ui/client/views/app/CreateDirectMessage.js @@ -1,3 +1,4 @@ +import { Tracker } from 'meteor/tracker'; import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; import { ReactiveVar } from 'meteor/reactive-var'; @@ -6,8 +7,8 @@ import { ReactiveVar } from 'meteor/reactive-var'; import { roomTypes } from '../../../../utils/client'; import { ChatSubscription } from '../../../../models/client'; import { call } from '../../../../ui-utils/client'; - import './CreateDirectMessage.html'; +import { Subscriptions } from '../../../../models/client/models/Subscriptions'; Template.CreateDirectMessage.helpers({ onSelectUser() { @@ -53,6 +54,18 @@ Template.CreateDirectMessage.helpers({ }, }); +const waitUntilRoomBeInserted = async (rid) => { + return new Promise((resolve) => { + Tracker.autorun((c) => { + const room = Subscriptions.findOne({ rid }); + if (room) { + c.stop(); + return resolve(room); + } + }); + }); +}; + Template.CreateDirectMessage.events({ async 'submit #create-dm, click .js-save-dm'(event, instance) { event.preventDefault(); @@ -63,6 +76,9 @@ Template.CreateDirectMessage.events({ if (instance.data.onCreate) { instance.data.onCreate(result); } + + await waitUntilRoomBeInserted(result.rid); + const user = Meteor.user(); roomTypes.openRouteLink(result.t, { ...result, name: result.usernames.filter((username) => username !== user.username).join(', ') }); }, From e64ef38383976819d87b8420be667ab592cfba4d Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 00:57:14 -0300 Subject: [PATCH 30/64] Fix lint --- app/lib/server/functions/createDirectRoom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index c61f4c8ceae2..62d99f64f76c 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -60,7 +60,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = member, { ...options.subscriptionExtra, - ...options.creator !== member._id && { open: members.length > 2 } + ...options.creator !== member._id && { open: members.length > 2 }, }, ), }), From f113b177a1c4feaf467441f6a9fc22f3bb3ded68 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 02:31:37 -0300 Subject: [PATCH 31/64] Fix direct message creation --- app/notifications/server/lib/Notifications.js | 3 +++ .../client/views/app/CreateDirectMessage.js | 19 ++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/notifications/server/lib/Notifications.js b/app/notifications/server/lib/Notifications.js index 7881aa650d40..003db8f22f14 100644 --- a/app/notifications/server/lib/Notifications.js +++ b/app/notifications/server/lib/Notifications.js @@ -38,6 +38,9 @@ class RoomStreamer extends Meteor.Streamer { case 'inserted': rooms.push({ rid }); this.on(rid, roomEvent); + + // after a subscription is added need to emit the room again + roomEvent('inserted', Rooms.findOneById(rid)); break; case 'removed': diff --git a/app/ui/client/views/app/CreateDirectMessage.js b/app/ui/client/views/app/CreateDirectMessage.js index d267758ba803..df5bec5f78aa 100755 --- a/app/ui/client/views/app/CreateDirectMessage.js +++ b/app/ui/client/views/app/CreateDirectMessage.js @@ -8,7 +8,6 @@ import { roomTypes } from '../../../../utils/client'; import { ChatSubscription } from '../../../../models/client'; import { call } from '../../../../ui-utils/client'; import './CreateDirectMessage.html'; -import { Subscriptions } from '../../../../models/client/models/Subscriptions'; Template.CreateDirectMessage.helpers({ onSelectUser() { @@ -54,17 +53,15 @@ Template.CreateDirectMessage.helpers({ }, }); -const waitUntilRoomBeInserted = async (rid) => { - return new Promise((resolve) => { - Tracker.autorun((c) => { - const room = Subscriptions.findOne({ rid }); - if (room) { - c.stop(); - return resolve(room); - } - }); +const waitUntilRoomBeInserted = async (rid) => new Promise((resolve) => { + Tracker.autorun((c) => { + const room = roomTypes.findRoom('d', rid, Meteor.user()); + if (room) { + c.stop(); + return resolve(room); + } }); -}; +}); Template.CreateDirectMessage.events({ async 'submit #create-dm, click .js-save-dm'(event, instance) { From e27655bc0aa8ac48dd1e2c74098cd741ebb852d0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 03:09:26 -0300 Subject: [PATCH 32/64] Fix loading from URL --- app/lib/lib/roomTypes/direct.js | 2 +- app/lib/lib/roomTypes/private.js | 4 ++-- app/lib/lib/roomTypes/public.js | 4 ++-- app/models/server/models/Rooms.js | 12 ++++++++++++ app/ui-utils/client/lib/openRoom.js | 27 +++++++++++++++++++-------- server/publications/room/index.js | 2 +- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 2d14824f2ac7..d04060e36385 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -22,7 +22,7 @@ export class DirectMessageRoomRoute extends RoomTypeRouteConfig { } link(sub) { - return { rid: sub.rid }; + return { rid: sub.rid || sub.name }; } } diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index 11c960ea694b..df0c5fc7f7a0 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -13,12 +13,12 @@ export class PrivateRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'group', - path: '/group/:rid', + path: '/group/:name', }); } action(params) { - return openRoom('p', params.rid); + return openRoom('p', params.name); } } diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 5f46a1575f9a..4675cfc8dc66 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -11,12 +11,12 @@ export class PublicRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'channel', - path: '/channel/:rid', + path: '/channel/:name', }); } action(params) { - return openRoom('c', params.rid); + return openRoom('c', params.name); } } diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index 633a4055df91..af12f4739753 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -490,6 +490,18 @@ export class Rooms extends Base { return this.findOne(query, options); } + findByTypeAndNameOrId(type, identifier, options) { + const query = { + t: type, + $or: [ + { name: identifier }, + { _id: identifier }, + ], + }; + + return this.findOne(query, options); + } + findByTypeAndNameContaining(type, name, options) { const nameRegex = new RegExp(s.trim(s.escapeRegExp(name)), 'i'); diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index aafa66ed81f3..b7bd43a9cf62 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -8,7 +8,7 @@ import { Session } from 'meteor/session'; import mem from 'mem'; import _ from 'underscore'; -import { ChatSubscription } from '../../../models'; +import { ChatSubscription, Rooms } from '../../../models'; import { settings } from '../../../settings'; import { callbacks } from '../../../callbacks'; import { roomTypes, handleError } from '../../../utils'; @@ -49,15 +49,26 @@ export const openRoom = function(type, name) { const room = roomTypes.findRoom(type, name, user); if (room == null) { - if (type === 'd') { - Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle - if (!error) { - return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + Meteor.call('getRoomByTypeAndName', type, name, function(error, record) { + if (error) { + if (type === 'd') { + return Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle + if (!error) { + return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + } + Session.set('roomNotFound', { type, name, error }); + BlazeLayout.render('main', { center: 'roomNotFound' }); + }); } + Session.set('roomNotFound', { type, name, error }); - BlazeLayout.render('main', { center: 'roomNotFound' }); - }); - } + return BlazeLayout.render('main', { center: 'roomNotFound' }); + } + Rooms.upsert({ _id: record._id }, _.omit(record, '_id')); + RoomManager.close(type + name); + return openRoom(type, name); + }); + c.stop(); return; } diff --git a/server/publications/room/index.js b/server/publications/room/index.js index 8763aac418bb..e4def8f1868d 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -92,7 +92,7 @@ Meteor.methods({ const roomFind = roomTypes.getRoomFind(type); - const room = roomFind ? roomFind.call(this, name) : Rooms.findByTypeAndName(type, name); + const room = roomFind ? roomFind.call(this, name) : Rooms.findByTypeAndNameOrId(type, name); if (!room) { throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getRoomByTypeAndName' }); From e82ef9aa8837981ad78193eaf498a156d29ccb6a Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 03:09:26 -0300 Subject: [PATCH 33/64] Fix loading from URL --- app/lib/lib/roomTypes/direct.js | 2 +- app/lib/lib/roomTypes/private.js | 4 ++-- app/lib/lib/roomTypes/public.js | 4 ++-- app/models/server/models/Rooms.js | 12 ++++++++++++ app/ui-utils/client/lib/openRoom.js | 27 +++++++++++++++++++-------- app/ui/client/lib/notification.js | 4 ++-- server/publications/room/index.js | 2 +- 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 2d14824f2ac7..d04060e36385 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -22,7 +22,7 @@ export class DirectMessageRoomRoute extends RoomTypeRouteConfig { } link(sub) { - return { rid: sub.rid }; + return { rid: sub.rid || sub.name }; } } diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index 11c960ea694b..df0c5fc7f7a0 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -13,12 +13,12 @@ export class PrivateRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'group', - path: '/group/:rid', + path: '/group/:name', }); } action(params) { - return openRoom('p', params.rid); + return openRoom('p', params.name); } } diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 5f46a1575f9a..4675cfc8dc66 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -11,12 +11,12 @@ export class PublicRoomRoute extends RoomTypeRouteConfig { constructor() { super({ name: 'channel', - path: '/channel/:rid', + path: '/channel/:name', }); } action(params) { - return openRoom('c', params.rid); + return openRoom('c', params.name); } } diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index 633a4055df91..af12f4739753 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -490,6 +490,18 @@ export class Rooms extends Base { return this.findOne(query, options); } + findByTypeAndNameOrId(type, identifier, options) { + const query = { + t: type, + $or: [ + { name: identifier }, + { _id: identifier }, + ], + }; + + return this.findOne(query, options); + } + findByTypeAndNameContaining(type, name, options) { const nameRegex = new RegExp(s.trim(s.escapeRegExp(name)), 'i'); diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index aafa66ed81f3..b7bd43a9cf62 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -8,7 +8,7 @@ import { Session } from 'meteor/session'; import mem from 'mem'; import _ from 'underscore'; -import { ChatSubscription } from '../../../models'; +import { ChatSubscription, Rooms } from '../../../models'; import { settings } from '../../../settings'; import { callbacks } from '../../../callbacks'; import { roomTypes, handleError } from '../../../utils'; @@ -49,15 +49,26 @@ export const openRoom = function(type, name) { const room = roomTypes.findRoom(type, name, user); if (room == null) { - if (type === 'd') { - Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle - if (!error) { - return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + Meteor.call('getRoomByTypeAndName', type, name, function(error, record) { + if (error) { + if (type === 'd') { + return Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle + if (!error) { + return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + } + Session.set('roomNotFound', { type, name, error }); + BlazeLayout.render('main', { center: 'roomNotFound' }); + }); } + Session.set('roomNotFound', { type, name, error }); - BlazeLayout.render('main', { center: 'roomNotFound' }); - }); - } + return BlazeLayout.render('main', { center: 'roomNotFound' }); + } + Rooms.upsert({ _id: record._id }, _.omit(record, '_id')); + RoomManager.close(type + name); + return openRoom(type, name); + }); + c.stop(); return; } diff --git a/app/ui/client/lib/notification.js b/app/ui/client/lib/notification.js index f04028cffc06..2d78a4bde333 100644 --- a/app/ui/client/lib/notification.js +++ b/app/ui/client/lib/notification.js @@ -67,9 +67,9 @@ export const KonchatNotification = { case 'd': return FlowRouter.go('direct', { rid: notification.payload.sender.username }, FlowRouter.current().queryParams); // TODO CHANGE case 'c': - return FlowRouter.go('channel', { rid: notification.payload.name }, FlowRouter.current().queryParams); + return FlowRouter.go('channel', { name: notification.payload.name }, FlowRouter.current().queryParams); case 'p': - return FlowRouter.go('group', { rid: notification.payload.name }, FlowRouter.current().queryParams); + return FlowRouter.go('group', { name: notification.payload.name }, FlowRouter.current().queryParams); } }; } diff --git a/server/publications/room/index.js b/server/publications/room/index.js index 8763aac418bb..e4def8f1868d 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -92,7 +92,7 @@ Meteor.methods({ const roomFind = roomTypes.getRoomFind(type); - const room = roomFind ? roomFind.call(this, name) : Rooms.findByTypeAndName(type, name); + const room = roomFind ? roomFind.call(this, name) : Rooms.findByTypeAndNameOrId(type, name); if (!room) { throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'getRoomByTypeAndName' }); From 11ac5cc9cf8fa14bb41f4a4193965aea7e84ed6d Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 04:21:33 -0300 Subject: [PATCH 34/64] Undo public private room type find --- app/lib/lib/roomTypes/private.js | 5 +---- app/lib/lib/roomTypes/public.js | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index df0c5fc7f7a0..219ebbc8e9dd 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -43,10 +43,7 @@ export class PrivateRoomType extends RoomTypeConfig { findRoom(identifier) { const query = { t: 'p', - $or: [ - { name: identifier }, - { _id: identifier }, - ], + name: identifier, }; return ChatRoom.findOne(query); diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 4675cfc8dc66..11d688731eff 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -41,10 +41,7 @@ export class PublicRoomType extends RoomTypeConfig { findRoom(identifier) { const query = { t: 'c', - $or: [ - { name: identifier }, - { _id: identifier }, - ], + name: identifier, }; return ChatRoom.findOne(query); } From d153e9f4d097c7b4cc9144e6a42a6feaa8eefda1 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Sat, 21 Mar 2020 19:26:02 -0300 Subject: [PATCH 35/64] Use single function to update name and username --- app/lib/server/functions/createDirectRoom.js | 18 ++-- app/lib/server/functions/saveUser.js | 15 ++-- app/lib/server/functions/saveUserIdentity.js | 93 ++++++++++++++++++++ app/lib/server/functions/setRealName.js | 11 +-- app/lib/server/functions/setUsername.js | 28 +----- app/lib/server/methods/setUsername.js | 5 +- app/models/server/models/Rooms.js | 10 +++ app/models/server/models/Subscriptions.js | 29 ++++++ server/methods/saveUserProfile.js | 13 +-- 9 files changed, 167 insertions(+), 55 deletions(-) create mode 100644 app/lib/server/functions/saveUserIdentity.js diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 62d99f64f76c..f2254d40ca0f 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -20,8 +20,8 @@ const generateSubscription = (fname, name, user, extra) => ({ }, }); -const getFname = (uid, members) => members.filter(({ _id }) => _id !== uid).map(({ name, username }) => name || username).join(', '); -const getName = (uid, members) => members.filter(({ _id }) => _id !== uid).map(({ username }) => username).join(', '); +const getFname = (members) => members.map(({ name, username }) => name || username).join(', '); +const getName = (members) => members.map(({ username }) => username).join(','); export const createDirectRoom = function(members, roomExtraData = {}, options = {}) { if (members.length > (settings.get('DirectMesssage_maxUsers') || 1)) { @@ -42,6 +42,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = usersCount: members.length, msgs: 0, ts: new Date(), + uids: sortedMembers.map(({ _id }) => _id), ...roomExtraData, }); @@ -51,20 +52,23 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = $setOnInsert: generateSubscription(members[0].name || members[0].username, members[0].username, members[0], { ...options.subscriptionExtra }), }); } else { - members.forEach((member) => + members.forEach((member) => { + const otherMembers = sortedMembers.filter(({ _id }) => _id !== member._id); + Subscriptions.upsert({ rid, 'u._id': member._id }, { ...options.creator === member._id && { $set: { open: true } }, $setOnInsert: generateSubscription( - getFname(member._id, sortedMembers), - getName(member._id, sortedMembers), + getFname(otherMembers), + getName(otherMembers), member, { + uids: otherMembers.map(({ _id }) => _id), ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 }, }, ), - }), - ); + }); + }); } // If the room is new, run a callback diff --git a/app/lib/server/functions/saveUser.js b/app/lib/server/functions/saveUser.js index b52edb7d1097..65b6eccd1a31 100644 --- a/app/lib/server/functions/saveUser.js +++ b/app/lib/server/functions/saveUser.js @@ -10,8 +10,9 @@ import { getRoles, hasPermission } from '../../../authorization'; import { settings } from '../../../settings'; import { passwordPolicy } from '../lib/passwordPolicy'; import { validateEmailDomain } from '../lib'; +import { saveUserIdentity } from './saveUserIdentity'; -import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setRealName, setUsername, setStatusText } from '.'; +import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setStatusText } from '.'; let html = ''; let passwordChangedHtml = ''; @@ -264,12 +265,12 @@ export const saveUser = function(userId, userData) { validateUserEditing(userId, userData); // update user - if (userData.username) { - setUsername(userData._id, userData.username); - } - - if (userData.hasOwnProperty('name')) { - setRealName(userData._id, userData.name); + if (userData.username || userData.hasOwnProperty('name')) { + saveUserIdentity(userId, { + _id: userData._id, + username: userData.username, + name: userData.name, + }); } if (typeof userData.statusText === 'string') { diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js new file mode 100644 index 000000000000..722528cfb09a --- /dev/null +++ b/app/lib/server/functions/saveUserIdentity.js @@ -0,0 +1,93 @@ +import { setUsername } from './setUsername'; +import { setRealName } from './setRealName'; +import { Messages, Rooms, Subscriptions, LivechatDepartmentAgents, Users } from '../../../models/server'; +import { FileUpload } from '../../../file-upload/server'; + +const getFname = (members) => members.map(({ name, username }) => name || username).join(', '); +const getName = (members) => members.map(({ username }) => username).join(','); + +const updateGroupDMsName = (user) => { + const userIds = new Set(); + const users = new Map([[user._id, user]]); + + const rooms = Rooms.findGroupDMsByUids(user._id, { fields: { uids: 1 } }); + + if (rooms.count() === 0) { + return; + } + + // add all users to single array so we can fetch details from them all at once + rooms.forEach((room) => room.uids.forEach((uid) => uid !== user._id && userIds.add(uid))); + + Users.findByIds([...userIds], { fields: { username: 1, name: 1 } }) + .forEach((user) => users.set(user._id, user)); + + const getMembers = (uids) => uids.map((uid) => users.get(uid)); + + // loop rooms to update the subcriptions from them all + rooms.forEach((room) => { + const members = getMembers(room.uids); + const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); + + const subs = Subscriptions.findByRoomId(room._id, { fields: { _id: 1, 'u._id': 1 } }); + subs.forEach((sub) => { + const otherMembers = sortedMembers.filter(({ _id }) => _id !== sub.u._id); + + Subscriptions.updateNameAndFnameById(sub._id, getName(otherMembers), getFname(otherMembers)); + }); + }); +}; + +/** + * + * @param {string} userId user performing the action + * @param {object} changes changes to the user + */ +export function saveUserIdentity(userId, { _id, name, username }) { + if (!_id) { + return false; + } + + const user = Users.findOneById(_id); + + const previousUsername = user.username; + + if (username) { + user.username = username; + setUsername(_id, username, user); + } + + if (name) { + setRealName(_id, name, user); + } + + // Username is available; if coming from old username, update all references + if (previousUsername && username) { + Messages.updateAllUsernamesByUserId(user._id, username); + Messages.updateUsernameOfEditByUserId(user._id, username); + Messages.findByMention(previousUsername).forEach(function(msg) { + const updatedMsg = msg.msg.replace(new RegExp(`@${ previousUsername }`, 'ig'), `@${ username }`); + return Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg); + }); + Rooms.replaceUsername(previousUsername, username); + Rooms.replaceMutedUsername(previousUsername, username); + Rooms.replaceUsernameOfUserByUserId(user._id, username); + Subscriptions.setUserUsernameByUserId(user._id, username); + + LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username); + + const fileStore = FileUpload.getStore('Avatars'); + const file = fileStore.model.findOneByName(previousUsername); + if (file) { + fileStore.model.updateFileNameById(file._id, username); + } + } + + // update name and fname of 1-on-1 direct messages + Subscriptions.updateDirectNameAndFnameByName(previousUsername, username, name); + + // update name and fname of group direct messages + updateGroupDMsName(user); + + return true; +} diff --git a/app/lib/server/functions/setRealName.js b/app/lib/server/functions/setRealName.js index 40262fd612bf..190fc1b739bc 100644 --- a/app/lib/server/functions/setRealName.js +++ b/app/lib/server/functions/setRealName.js @@ -1,20 +1,20 @@ import { Meteor } from 'meteor/meteor'; import s from 'underscore.string'; -import { Users, Subscriptions } from '../../../models'; +import { Users } from '../../../models/server'; import { settings } from '../../../settings'; import { Notifications } from '../../../notifications'; import { hasPermission } from '../../../authorization'; import { RateLimiter } from '../lib'; -export const _setRealName = function(userId, name) { +export const _setRealName = function(userId, name, fullUser) { name = s.trim(name); if (!userId || (settings.get('Accounts_RequireNameForSignUp') && !name)) { return false; } - const user = Users.findOneById(userId); + const user = fullUser || Users.findOneById(userId); // User already has desired name, return if (s.trim(user.name) === name) { @@ -29,11 +29,6 @@ export const _setRealName = function(userId, name) { } user.name = name; - // if user has no username, there is no need to updated any direct messages (there is none) - if (user.username && user.username !== '') { - Subscriptions.updateDirectFNameByName(user.username, name); - } - if (settings.get('UI_Use_Real_Name') === true) { Notifications.notifyLogged('Users:NameChanged', { _id: user._id, diff --git a/app/lib/server/functions/setUsername.js b/app/lib/server/functions/setUsername.js index 7656e7dbe4af..6e5f08cf3990 100644 --- a/app/lib/server/functions/setUsername.js +++ b/app/lib/server/functions/setUsername.js @@ -2,9 +2,8 @@ import { Meteor } from 'meteor/meteor'; import s from 'underscore.string'; import { Accounts } from 'meteor/accounts-base'; -import { FileUpload } from '../../../file-upload'; import { settings } from '../../../settings'; -import { Users, Messages, Subscriptions, Rooms, LivechatDepartmentAgents, Invites } from '../../../models'; +import { Users, Invites } from '../../../models/server'; import { hasPermission } from '../../../authorization'; import { RateLimiter } from '../lib'; import { Notifications } from '../../../notifications/server'; @@ -12,7 +11,7 @@ import { addUserToRoom } from './addUserToRoom'; import { checkUsernameAvailability, setUserAvatar, getAvatarSuggestionForUser } from '.'; -export const _setUsername = function(userId, u) { +export const _setUsername = function(userId, u, fullUser) { const username = s.trim(u); if (!userId || !username) { return false; @@ -26,7 +25,7 @@ export const _setUsername = function(userId, u) { if (!nameValidation.test(username)) { return false; } - const user = Users.findOneById(userId); + const user = fullUser || Users.findOneById(userId); // User already has desired username, return if (user.username === username) { return user; @@ -68,27 +67,6 @@ export const _setUsername = function(userId, u) { setUserAvatar(user, gravatar.blob, gravatar.contentType, 'gravatar'); } } - // Username is available; if coming from old username, update all references - if (previousUsername) { - Messages.updateAllUsernamesByUserId(user._id, username); - Messages.updateUsernameOfEditByUserId(user._id, username); - Messages.findByMention(previousUsername).forEach(function(msg) { - const updatedMsg = msg.msg.replace(new RegExp(`@${ previousUsername }`, 'ig'), `@${ username }`); - return Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg); - }); - Rooms.replaceUsername(previousUsername, username); - Rooms.replaceMutedUsername(previousUsername, username); - Rooms.replaceUsernameOfUserByUserId(user._id, username); - Subscriptions.setUserUsernameByUserId(user._id, username); - Subscriptions.setNameForDirectRoomsWithOldName(previousUsername, username); - LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username); - - const fileStore = FileUpload.getStore('Avatars'); - const file = fileStore.model.findOneByName(previousUsername); - if (file) { - fileStore.model.updateFileNameById(file._id, username); - } - } // If it's the first username and the user has an invite Token, then join the invite room if (!previousUsername && user.inviteToken) { diff --git a/app/lib/server/methods/setUsername.js b/app/lib/server/methods/setUsername.js index 5a8ed788d8fa..10a604038857 100644 --- a/app/lib/server/methods/setUsername.js +++ b/app/lib/server/methods/setUsername.js @@ -5,8 +5,9 @@ import _ from 'underscore'; import { settings } from '../../../settings'; import { Users } from '../../../models'; import { callbacks } from '../../../callbacks'; -import { setUsername, checkUsernameAvailability } from '../functions'; +import { checkUsernameAvailability } from '../functions'; import { RateLimiter } from '../lib'; +import { saveUserIdentity } from '../functions/saveUserIdentity'; Meteor.methods({ setUsername(username, param = {}) { @@ -42,7 +43,7 @@ Meteor.methods({ throw new Meteor.Error('error-field-unavailable', `${ _.escape(username) } is already in use :(`, { method: 'setUsername', field: username }); } - if (!setUsername(user._id, username)) { + if (!saveUserIdentity(user._id, { _id: user._id, username })) { throw new Meteor.Error('error-could-not-change-username', 'Could not change username', { method: 'setUsername' }); } diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index af12f4739753..879d6207a370 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -19,6 +19,9 @@ export class Rooms extends Base { this.tryEnsureIndex({ prid: 1 }, { sparse: true }); // Livechat - statistics this.tryEnsureIndex({ closedAt: 1 }, { sparse: true }); + + // field used for DMs only + this.tryEnsureIndex({ uids: 1 }, { sparse: true }); } findOneByIdOrName(_idOrName, options) { @@ -539,6 +542,13 @@ export class Rooms extends Base { return this.find(query, options); } + findGroupDMsByUids(uids, options) { + return this.find({ + usersCount: { $gt: 2 }, + uids, + }, options); + } + // UPDATE addImportIds(_id, importIds) { importIds = [].concat(importIds); diff --git a/app/models/server/models/Subscriptions.js b/app/models/server/models/Subscriptions.js index 86a00565d4c2..ff93bf8ed0c9 100644 --- a/app/models/server/models/Subscriptions.js +++ b/app/models/server/models/Subscriptions.js @@ -822,6 +822,19 @@ export class Subscriptions extends Base { return this.update(query, update, { multi: true }); } + updateNameAndFnameById(_id, name, fname) { + const query = { _id }; + + const update = { + $set: { + name, + fname, + }, + }; + + return this.update(query, update, { multi: true }); + } + setUserUsernameByUserId(userId, username) { const query = { 'u._id': userId }; @@ -849,6 +862,22 @@ export class Subscriptions extends Base { return this.update(query, update, { multi: true }); } + updateDirectNameAndFnameByName(name, newName, newFname) { + const query = { + name, + t: 'd', + }; + + const update = { + $set: { + ...newName && { name: newName }, + ...newFname && { fname: newFname }, + }, + }; + + return this.update(query, update, { multi: true }); + } + incUnreadForRoomIdExcludingUserId(roomId, userId, inc) { if (inc == null) { inc = 1; diff --git a/server/methods/saveUserProfile.js b/server/methods/saveUserProfile.js index 9a1487a40a4b..250f465c734f 100644 --- a/server/methods/saveUserProfile.js +++ b/server/methods/saveUserProfile.js @@ -6,6 +6,7 @@ import { saveCustomFields, passwordPolicy } from '../../app/lib'; import { Users } from '../../app/models'; import { settings as rcSettings } from '../../app/settings'; import { twoFactorRequired } from '../../app/2fa/server/twoFactorRequired'; +import { saveUserIdentity } from '../../app/lib/server/functions/saveUserIdentity'; Meteor.methods({ saveUserProfile: twoFactorRequired(function(settings, customFields) { @@ -42,12 +43,12 @@ Meteor.methods({ return true; } - if (settings.realname || (!settings.realname && !rcSettings.get('Accounts_RequireNameForSignUp'))) { - Meteor.call('setRealName', settings.realname); - } - - if (settings.username) { - Meteor.call('setUsername', settings.username); + if (settings.realname || (!settings.realname && !rcSettings.get('Accounts_RequireNameForSignUp')) || settings.username) { + saveUserIdentity(this.userId, { + _id: this.userId, + name: settings.realname, + username: settings.username, + }); } if (settings.statusText || settings.statusText === '') { From 59f8466f5f449908ef45256519e92b6acd94662f Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sun, 22 Mar 2020 00:41:21 -0300 Subject: [PATCH 36/64] improve openRoom --- app/ui-utils/client/lib/openRoom.js | 128 ++++++++++++++-------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index b7bd43a9cf62..60582d856107 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -11,7 +11,8 @@ import _ from 'underscore'; import { ChatSubscription, Rooms } from '../../../models'; import { settings } from '../../../settings'; import { callbacks } from '../../../callbacks'; -import { roomTypes, handleError } from '../../../utils'; +import { roomTypes } from '../../../utils'; +import { call } from './callMethod'; import { RoomManager, fireGlobalEvent, RoomHistoryManager } from '..'; @@ -39,88 +40,87 @@ function replaceCenterDomBy(dom) { return mainNode; } -export const openRoom = function(type, name) { - window.currentTracker = Tracker.autorun(function(c) { +const waitUntilRoomBeInserted = async (type, rid) => new Promise((resolve) => { + Tracker.autorun((c) => { + const room = roomTypes.findRoom(type, rid, Meteor.user()); + if (room) { + c.stop(); + return resolve(room); + } + }); +}); + +export const openRoom = async function(type, name) { + window.currentTracker && window.currentTracker.stop(); + window.currentTracker = Tracker.autorun(async function(c) { const user = Meteor.user(); if ((user && user.username == null) || (user == null && settings.get('Accounts_AllowAnonymousRead') === false)) { BlazeLayout.render('main'); return; } - const room = roomTypes.findRoom(type, name, user); - if (room == null) { - Meteor.call('getRoomByTypeAndName', type, name, function(error, record) { - if (error) { - if (type === 'd') { - return Meteor.call('createDirectMessage', ...name.split(', '), function(error, result) { // TODO provide a function to handle - if (!error) { - return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); - } - Session.set('roomNotFound', { type, name, error }); - BlazeLayout.render('main', { center: 'roomNotFound' }); - }); - } - - Session.set('roomNotFound', { type, name, error }); - return BlazeLayout.render('main', { center: 'roomNotFound' }); + try { + const room = roomTypes.findRoom(type, name, user) || await call('getRoomByTypeAndName', type, name); + + if (RoomManager.open(type + name).ready() !== true) { + if (settings.get('Accounts_AllowAnonymousRead')) { + BlazeLayout.render('main'); } - Rooms.upsert({ _id: record._id }, _.omit(record, '_id')); - RoomManager.close(type + name); - return openRoom(type, name); - }); + replaceCenterDomBy(getDomOfLoading()); + return; + } c.stop(); - return; - } - if (RoomManager.open(type + name).ready() !== true) { - if (settings.get('Accounts_AllowAnonymousRead')) { - BlazeLayout.render('main'); + Rooms.upsert({ _id: room._id }, _.omit(room, '_id')); + + if (window.currentTracker) { + window.currentTracker = undefined; } - replaceCenterDomBy(getDomOfLoading()); - return; - } - if (window.currentTracker) { - window.currentTracker = undefined; - } - c.stop(); - if (room._id !== name && type === 'd') { - RoomManager.close(type + name); - return FlowRouter.go('direct', { rid: room._id }, FlowRouter.current().queryParams); - } + if (room._id !== name && type === 'd') { // Redirect old url using username to rid + RoomManager.close(type + name); + return FlowRouter.go('direct', { rid: room._id }, FlowRouter.current().queryParams); + } - const roomDom = RoomManager.getDomOfRoom(type + name, room._id); - const mainNode = replaceCenterDomBy(roomDom); + const roomDom = RoomManager.getDomOfRoom(type + name, room._id); + const mainNode = replaceCenterDomBy(roomDom); - if (mainNode) { - if (roomDom.classList.contains('room-container')) { - roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop; + if (mainNode) { + if (roomDom.classList.contains('room-container')) { + roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop; + } } - } - Session.set('openedRoom', room._id); - RoomManager.openedRoom = room._id; + Session.set('openedRoom', room._id); + RoomManager.openedRoom = room._id; - fireGlobalEvent('room-opened', _.omit(room, 'usernames')); + fireGlobalEvent('room-opened', _.omit(room, 'usernames')); - Session.set('editRoomTitle', false); - // KonchatNotification.removeRoomNotification(params._id) - // update user's room subscription - const sub = ChatSubscription.findOne({ rid: room._id }); - if (sub && sub.open === false) { - Meteor.call('openRoom', room._id, function(err) { - if (err) { - return handleError(err); - } - }); - } + Session.set('editRoomTitle', false); + // KonchatNotification.removeRoomNotification(params._id) + // update user's room subscription + const sub = ChatSubscription.findOne({ rid: room._id }); + if (sub && sub.open === false) { + call('openRoom', room._id); + } - if (FlowRouter.getQueryParam('msg')) { - const msg = { _id: FlowRouter.getQueryParam('msg'), rid: room._id }; - RoomHistoryManager.getSurroundingMessages(msg); - } + if (FlowRouter.getQueryParam('msg')) { + const msg = { _id: FlowRouter.getQueryParam('msg'), rid: room._id }; + RoomHistoryManager.getSurroundingMessages(msg); + } - return callbacks.run('enter-room', sub); + return callbacks.run('enter-room', sub); + } catch (error) { + c.stop(); + if (type !== 'd') { + const result = await call('createDirectMessage', ...name.split(', ')).then((result) => waitUntilRoomBeInserted(type, result.rid)).catch(() => {}); + if (result) { + return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + } + } + Session.set('roomNotFound', { type, name, error }); + return BlazeLayout.render('main', { center: 'roomNotFound' }); + } }); }; From a3702ee422e395f16961383826ead90b4ca51c92 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sun, 22 Mar 2020 01:30:15 -0300 Subject: [PATCH 37/64] Federation support --- .../server/hooks/afterCreateDirectRoom.js | 33 +++++-------------- app/lib/server/functions/createDirectRoom.js | 2 +- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/app/federation/server/hooks/afterCreateDirectRoom.js b/app/federation/server/hooks/afterCreateDirectRoom.js index 1c792b280f7d..a0048fcb24a6 100644 --- a/app/federation/server/hooks/afterCreateDirectRoom.js +++ b/app/federation/server/hooks/afterCreateDirectRoom.js @@ -29,36 +29,19 @@ async function afterCreateDirectRoom(room, extras) { // Ensure a genesis event for this room const genesisEvent = await FederationRoomEvents.createGenesisEvent(getFederationDomain(), normalizedRoom); - // - // Source User - // - - // Add the source user to the room - const sourceUser = extras.from; - const normalizedSourceUser = normalizers.normalizeUser(sourceUser); - - const sourceSubscription = Subscriptions.findOne({ rid: normalizedRoom._id, 'u._id': normalizedSourceUser._id }); - const normalizedSourceSubscription = normalizers.normalizeSubscription(sourceSubscription); - - // Build the source user event - const sourceUserEvent = await FederationRoomEvents.createAddUserEvent(getFederationDomain(), normalizedRoom._id, normalizedSourceUser, normalizedSourceSubscription); - - // - // Target User - // - // Add the target user to the room - const targetUser = extras.to; - const normalizedTargetUser = normalizers.normalizeUser(targetUser); + const events = await Promise.all(extras.members.map((member) => { + const normalizedMember = normalizers.normalizeUser(member); - const targetSubscription = Subscriptions.findOne({ rid: normalizedRoom._id, 'u._id': normalizedTargetUser._id }); - const normalizedTargetSubscription = normalizers.normalizeSubscription(targetSubscription); + const sourceSubscription = Subscriptions.findOne({ rid: normalizedRoom._id, 'u._id': normalizedMember._id }); + const normalizedSourceSubscription = normalizers.normalizeSubscription(sourceSubscription); - // Dispatch the target user event - const targetUserEvent = await FederationRoomEvents.createAddUserEvent(getFederationDomain(), normalizedRoom._id, normalizedTargetUser, normalizedTargetSubscription); + // Build the user event + return FederationRoomEvents.createAddUserEvent(getFederationDomain(), normalizedRoom._id, normalizedMember, normalizedSourceSubscription); + })); // Dispatch the events - dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, sourceUserEvent, targetUserEvent]); + dispatchEvents(normalizedRoom.federation.domains, [genesisEvent, ...events]); } catch (err) { await deleteRoom(room._id); diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index f2254d40ca0f..8ff2f1f0e39f 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -75,7 +75,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = if (isNewRoom) { const insertedRoom = Rooms.findOneById(rid); - callbacks.run('afterCreateDirectRoom', insertedRoom, { from: members[0], to: members[1] }); // TODO PLEASE CHECK FEDERATION!!! + callbacks.run('afterCreateDirectRoom', insertedRoom, { members }); } return { From b5d820b205229978e3ef224c4905f1515a6a1cf8 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Sun, 22 Mar 2020 02:41:09 -0300 Subject: [PATCH 38/64] fix usser set username --- app/lib/server/functions/saveUserIdentity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js index 722528cfb09a..ee5ca6e83827 100644 --- a/app/lib/server/functions/saveUserIdentity.js +++ b/app/lib/server/functions/saveUserIdentity.js @@ -53,8 +53,8 @@ export function saveUserIdentity(userId, { _id, name, username }) { const previousUsername = user.username; if (username) { - user.username = username; setUsername(_id, username, user); + user.username = username; } if (name) { From 4fd5c039aac071da63d905db857fd7386a68edd4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 10:45:37 -0300 Subject: [PATCH 39/64] Better error handling --- app/lib/server/functions/saveUserIdentity.js | 17 ++++++--- server/methods/saveUserProfile.js | 40 ++++++++++---------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js index ee5ca6e83827..9cf9df5e1e3a 100644 --- a/app/lib/server/functions/saveUserIdentity.js +++ b/app/lib/server/functions/saveUserIdentity.js @@ -43,22 +43,29 @@ const updateGroupDMsName = (user) => { * @param {string} userId user performing the action * @param {object} changes changes to the user */ -export function saveUserIdentity(userId, { _id, name, username }) { +export function saveUserIdentity(userId, { _id, name: rawName, username: rawUsername }) { if (!_id) { return false; } + const name = String(rawName).trim(); + const username = String(rawUsername).trim(); + const user = Users.findOneById(_id); const previousUsername = user.username; - if (username) { - setUsername(_id, username, user); + if (typeof rawUsername !== 'undefined') { + if (!setUsername(_id, username, user)) { + return false; + } user.username = username; } - if (name) { - setRealName(_id, name, user); + if (typeof rawName !== 'undefined') { + if (!setRealName(_id, name, user)) { + return false; + } } // Username is available; if coming from old username, update all references diff --git a/server/methods/saveUserProfile.js b/server/methods/saveUserProfile.js index 250f465c734f..b197a3a038f4 100644 --- a/server/methods/saveUserProfile.js +++ b/server/methods/saveUserProfile.js @@ -8,6 +8,22 @@ import { settings as rcSettings } from '../../app/settings'; import { twoFactorRequired } from '../../app/2fa/server/twoFactorRequired'; import { saveUserIdentity } from '../../app/lib/server/functions/saveUserIdentity'; +function checkPassword(user = {}, typedPassword) { + if (!(user.services && user.services.password && user.services.password.bcrypt && user.services.password.bcrypt.trim())) { + return true; + } + + const passCheck = Accounts._checkPassword(user, { + digest: typedPassword.toLowerCase(), + algorithm: 'sha-256', + }); + + if (passCheck.error) { + return false; + } + return true; +} + Meteor.methods({ saveUserProfile: twoFactorRequired(function(settings, customFields) { check(settings, Object); @@ -27,28 +43,14 @@ Meteor.methods({ const user = Users.findOneById(this.userId); - function checkPassword(user = {}, typedPassword) { - if (!(user.services && user.services.password && user.services.password.bcrypt && user.services.password.bcrypt.trim())) { - return true; - } - - const passCheck = Accounts._checkPassword(user, { - digest: typedPassword.toLowerCase(), - algorithm: 'sha-256', - }); - - if (passCheck.error) { - return false; - } - return true; - } - - if (settings.realname || (!settings.realname && !rcSettings.get('Accounts_RequireNameForSignUp')) || settings.username) { - saveUserIdentity(this.userId, { + if (settings.realname || settings.username) { + if (!saveUserIdentity(this.userId, { _id: this.userId, name: settings.realname, username: settings.username, - }); + })) { + throw new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', { method: 'saveUserProfile' }); + } } if (settings.statusText || settings.statusText === '') { From d56c917a9b27afc03007f69f09acac8d2a58453d Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 15:49:49 -0300 Subject: [PATCH 40/64] Show error --- app/lib/server/functions/createDirectRoom.js | 1 - app/lib/server/functions/saveUser.js | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 8ff2f1f0e39f..413a6c8a50dc 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -62,7 +62,6 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = getName(otherMembers), member, { - uids: otherMembers.map(({ _id }) => _id), ...options.subscriptionExtra, ...options.creator !== member._id && { open: members.length > 2 }, }, diff --git a/app/lib/server/functions/saveUser.js b/app/lib/server/functions/saveUser.js index 65b6eccd1a31..953a14e2b5c7 100644 --- a/app/lib/server/functions/saveUser.js +++ b/app/lib/server/functions/saveUser.js @@ -265,12 +265,14 @@ export const saveUser = function(userId, userData) { validateUserEditing(userId, userData); // update user - if (userData.username || userData.hasOwnProperty('name')) { - saveUserIdentity(userId, { + if (userData.hasOwnProperty('username') || userData.hasOwnProperty('name')) { + if (!saveUserIdentity(userId, { _id: userData._id, username: userData.username, name: userData.name, - }); + })) { + throw new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', { method: 'saveUser' }); + } } if (typeof userData.statusText === 'string') { From 116559961250ef1bf441eee44bae9e9475613e42 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 16:43:46 -0300 Subject: [PATCH 41/64] Update group DMs when removing an user --- app/lib/server/functions/createDirectRoom.js | 7 ++-- app/lib/server/functions/deleteUser.js | 24 +++++++---- app/lib/server/functions/saveUserIdentity.js | 36 +---------------- .../server/functions/updateGroupDMsName.js | 40 +++++++++++++++++++ app/models/server/models/Rooms.js | 38 +++++++++++++++++- app/models/server/models/Subscriptions.js | 2 +- 6 files changed, 99 insertions(+), 48 deletions(-) create mode 100644 app/lib/server/functions/updateGroupDMsName.js diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 413a6c8a50dc..68942b1a4da8 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -30,9 +30,10 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); - const usernames = members.map(({ username }) => username); + const usernames = sortedMembers.map(({ username }) => username); + const uids = sortedMembers.map(({ _id }) => _id); - const room = Rooms.findDirectRoomContainingAllUsernames(usernames, { fields: { _id: 1 } }); + const room = Rooms.findDirectRoomContainingAllUserIDs(uids, { fields: { _id: 1 } }); const isNewRoom = !room; @@ -42,7 +43,7 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = usersCount: members.length, msgs: 0, ts: new Date(), - uids: sortedMembers.map(({ _id }) => _id), + uids, ...roomExtraData, }); diff --git a/app/lib/server/functions/deleteUser.js b/app/lib/server/functions/deleteUser.js index 4962c5522f06..f5b59b8c7e24 100644 --- a/app/lib/server/functions/deleteUser.js +++ b/app/lib/server/functions/deleteUser.js @@ -2,10 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { FileUpload } from '../../../file-upload'; -import { Users, Subscriptions, Messages, Rooms, Integrations, FederationServers } from '../../../models'; -import { hasRole, getUsersInRole } from '../../../authorization'; -import { settings } from '../../../settings'; -import { Notifications } from '../../../notifications'; +import { Users, Subscriptions, Messages, Rooms, Integrations, FederationServers } from '../../../models/server'; +import { hasRole, getUsersInRole } from '../../../authorization/server'; +import { settings } from '../../../settings/server'; +import { Notifications } from '../../../notifications/server'; +import { updateGroupDMsName } from './updateGroupDMsName'; export const deleteUser = function(userId) { const user = Users.findOneById(userId, { @@ -87,8 +88,8 @@ export const deleteUser = function(userId) { roomData.subscribers = Subscriptions.findByRoomId(roomData.rid).count(); } - // Remove DMs and non-channel rooms with only 1 user (the one being deleted) - if (roomData.t === 'd' || (roomData.t !== 'c' && roomData.subscribers === 1)) { + // Remove non-channel rooms with only 1 user (the one being deleted) + if (roomData.t !== 'c' && roomData.subscribers === 1) { Subscriptions.removeByRoomId(roomData.rid); FileUpload.removeFilesByRoomId(roomData.rid); Messages.removeByRoomId(roomData.rid); @@ -96,9 +97,12 @@ export const deleteUser = function(userId) { } }); - Subscriptions.removeByUserId(userId); // Remove user subscriptions + // TODO: do not remove group DMs + Rooms.updateGroupDMsRemovingUsernamesByUsername(user.username); // Remove direct rooms with the user Rooms.removeDirectRoomContainingUsername(user.username); // Remove direct rooms with the user + Subscriptions.removeByUserId(userId); // Remove user subscriptions + // removes user's avatar if (user.avatarOrigin === 'upload' || user.avatarOrigin === 'url') { FileUpload.getStore('Avatars').deleteByName(user.username); @@ -108,7 +112,11 @@ export const deleteUser = function(userId) { Notifications.notifyLogged('Users:Deleted', { userId }); } - Users.removeById(userId); // Remove user from users database + // Remove user from users database + Users.removeById(userId); + + // update name and fname of group direct messages + updateGroupDMsName(user); // Refresh the servers list FederationServers.refreshServers(); diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js index 9cf9df5e1e3a..e0e519d070a9 100644 --- a/app/lib/server/functions/saveUserIdentity.js +++ b/app/lib/server/functions/saveUserIdentity.js @@ -2,41 +2,7 @@ import { setUsername } from './setUsername'; import { setRealName } from './setRealName'; import { Messages, Rooms, Subscriptions, LivechatDepartmentAgents, Users } from '../../../models/server'; import { FileUpload } from '../../../file-upload/server'; - -const getFname = (members) => members.map(({ name, username }) => name || username).join(', '); -const getName = (members) => members.map(({ username }) => username).join(','); - -const updateGroupDMsName = (user) => { - const userIds = new Set(); - const users = new Map([[user._id, user]]); - - const rooms = Rooms.findGroupDMsByUids(user._id, { fields: { uids: 1 } }); - - if (rooms.count() === 0) { - return; - } - - // add all users to single array so we can fetch details from them all at once - rooms.forEach((room) => room.uids.forEach((uid) => uid !== user._id && userIds.add(uid))); - - Users.findByIds([...userIds], { fields: { username: 1, name: 1 } }) - .forEach((user) => users.set(user._id, user)); - - const getMembers = (uids) => uids.map((uid) => users.get(uid)); - - // loop rooms to update the subcriptions from them all - rooms.forEach((room) => { - const members = getMembers(room.uids); - const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); - - const subs = Subscriptions.findByRoomId(room._id, { fields: { _id: 1, 'u._id': 1 } }); - subs.forEach((sub) => { - const otherMembers = sortedMembers.filter(({ _id }) => _id !== sub.u._id); - - Subscriptions.updateNameAndFnameById(sub._id, getName(otherMembers), getFname(otherMembers)); - }); - }); -}; +import { updateGroupDMsName } from './updateGroupDMsName'; /** * diff --git a/app/lib/server/functions/updateGroupDMsName.js b/app/lib/server/functions/updateGroupDMsName.js new file mode 100644 index 000000000000..7fb3b08a7195 --- /dev/null +++ b/app/lib/server/functions/updateGroupDMsName.js @@ -0,0 +1,40 @@ +import { Rooms, Subscriptions, Users } from '../../../models/server'; + +const getFname = (members) => members.map(({ name, username }) => name || username).join(', '); +const getName = (members) => members.map(({ username }) => username).join(','); + +export const updateGroupDMsName = (user) => { + if (!user.username) { + return; + } + + const userIds = new Set(); + const users = new Map(); + + const rooms = Rooms.findGroupDMsByUids(user._id, { fields: { uids: 1 } }); + + if (rooms.count() === 0) { + return; + } + + // add all users to single array so we can fetch details from them all at once + rooms.forEach((room) => room.uids.forEach((uid) => uid !== user._id && userIds.add(uid))); + + Users.findByIds([...userIds], { fields: { username: 1, name: 1 } }) + .forEach((user) => users.set(user._id, user)); + + const getMembers = (uids) => uids.map((uid) => users.get(uid)).filter(Boolean); + + // loop rooms to update the subcriptions from them all + rooms.forEach((room) => { + const members = getMembers(room.uids); + const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); + + const subs = Subscriptions.findByRoomId(room._id, { fields: { _id: 1, 'u._id': 1 } }); + subs.forEach((sub) => { + const otherMembers = sortedMembers.filter(({ _id }) => _id !== sub.u._id); + + Subscriptions.updateNameAndFnameById(sub._id, getName(otherMembers), getFname(otherMembers)); + }); + }); +}; diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index 879d6207a370..9580e63ab6c9 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -484,6 +484,15 @@ export class Rooms extends Base { return this.findOne(query, options); } + findDirectRoomContainingAllUserIDs(uid, options) { + const query = { + t: 'd', + uids: { $size: uid.length, $all: uid }, + }; + + return this.findOne(query, options); + } + findByTypeAndName(type, name, options) { const query = { name, @@ -659,11 +668,12 @@ export class Rooms extends Base { return this.update(query, update); } - incUsersCountByIds(ids, inc = 1) { + incUsersCountNotDMsByIds(ids, inc = 1) { const query = { _id: { $in: ids, }, + t: { $ne: 'd' }, }; const update = { @@ -952,6 +962,22 @@ export class Rooms extends Base { return this.update(query, update); } + updateGroupDMsRemovingUsernamesByUsername(username) { + const query = { + t: 'd', + usernames: username, + usersCount: { $gt: 2 }, + }; + + const update = { + $pull: { + usernames: username, + }, + }; + + return this.update(query, update, { multi: true }); + } + // INSERT createWithTypeNameUserAndUsernames(type, name, fname, user, usernames, extraData) { const room = { @@ -1004,10 +1030,20 @@ export class Rooms extends Base { return this.remove(query); } + remove1on1ById(_id) { + const query = { + _id, + usersCount: { $lte: 2 }, + }; + + return this.remove(query); + } + removeDirectRoomContainingUsername(username) { const query = { t: 'd', usernames: username, + usersCount: { $lte: 2 }, }; return this.remove(query); diff --git a/app/models/server/models/Subscriptions.js b/app/models/server/models/Subscriptions.js index ff93bf8ed0c9..50396a886367 100644 --- a/app/models/server/models/Subscriptions.js +++ b/app/models/server/models/Subscriptions.js @@ -1296,7 +1296,7 @@ export class Subscriptions extends Base { const result = this.remove(query); if (Match.test(result, Number) && result > 0) { - Rooms.incUsersCountByIds(roomIds, -1); + Rooms.incUsersCountNotDMsByIds(roomIds, -1); } return result; From 9023e7f56ea6a760c8ebca986e614098168f40b9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 17:22:55 -0300 Subject: [PATCH 42/64] Do not update undefined values --- app/lib/server/functions/saveUserIdentity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js index e0e519d070a9..ad3ea575ad63 100644 --- a/app/lib/server/functions/saveUserIdentity.js +++ b/app/lib/server/functions/saveUserIdentity.js @@ -57,7 +57,7 @@ export function saveUserIdentity(userId, { _id, name: rawName, username: rawUser } // update name and fname of 1-on-1 direct messages - Subscriptions.updateDirectNameAndFnameByName(previousUsername, username, name); + Subscriptions.updateDirectNameAndFnameByName(previousUsername, rawUsername && username, rawName && name); // update name and fname of group direct messages updateGroupDMsName(user); From 4d55cfde74bf5e8d6da5d7f3ac8b936dfdb6c407 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 20:05:27 -0300 Subject: [PATCH 43/64] Add migration to set uids field for existent DMs --- server/publications/room/index.js | 1 + server/startup/migrations/index.js | 1 + server/startup/migrations/v178.js | 78 ++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 server/startup/migrations/v178.js diff --git a/server/publications/room/index.js b/server/publications/room/index.js index e4def8f1868d..c6393f94045a 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -53,6 +53,7 @@ export const fields = { e2eKeyId: 1, departmentId: 1, servedBy: 1, + uids: 1, }; const roomMap = (record) => { diff --git a/server/startup/migrations/index.js b/server/startup/migrations/index.js index 1dd59ebbd7cc..ecc2aa96f5ee 100644 --- a/server/startup/migrations/index.js +++ b/server/startup/migrations/index.js @@ -175,4 +175,5 @@ import './v174'; import './v175'; import './v176'; import './v177'; +import './v178'; import './xrun'; diff --git a/server/startup/migrations/v178.js b/server/startup/migrations/v178.js new file mode 100644 index 000000000000..77846789f289 --- /dev/null +++ b/server/startup/migrations/v178.js @@ -0,0 +1,78 @@ +import { Meteor } from 'meteor/meteor'; + +import { Migrations } from '../../../app/migrations/server'; +import { Rooms } from '../../../app/models/server'; + +const batchSize = 5000; + +const getIds = (_id) => { + if (_id.length === 17) { + return [_id]; + } + + if (_id.match(/rocket\.cat/)) { + return [ + 'rocket.cat', + _id.replace('rocket.cat', ''), + ]; + } + + const total = _id.length; + + const id1 = _id.substr(0, Math.ceil(total / 2)); + const id2 = _id.substr(Math.ceil(total / 2)); + + // if (id1 === id2) { + // return id1; + // } + + return [id1, id2]; +}; + +async function migrateDMs(models, total, current) { + const { roomCollection } = models; + + console.log(`DM rooms schema migration ${ current }/${ total }`); + + const items = await roomCollection.find({ t: 'd', uids: { $exists: false } }, { fields: { _id: 1 } }).limit(batchSize).toArray(); + + const actions = items.map((room) => roomCollection.updateOne({ _id: room._id }, { + $set: { + uids: getIds(room._id), + }, + })); + + const batch = Promise.all(actions); + if (actions.length === batchSize) { + await batch; + return migrateDMs(models, total, current + batchSize); + } + + return batch; +} + +Migrations.add({ + version: 178, + up() { + const roomCollection = Rooms.model.rawCollection(); + + /* + * Move visitor navigation history to messages + */ + Meteor.setTimeout(async () => { + const rooms = roomCollection.find({ t: 'd' }); + const total = await rooms.count(); + await rooms.close(); + + if (total < batchSize) { + return migrateDMs({ roomCollection }, total, 0); + } + + console.log('Changing schema of Direct Message rooms, this may take a long time ...'); + + await migrateDMs({ roomCollection }, total, 0); + + console.log('Changing schema of Direct Message rooms finished.'); + }, 1000); + }, +}); From 0d929862d0158403d494993781aa0b242a77e9e2 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 23 Mar 2020 23:44:27 -0300 Subject: [PATCH 44/64] Use Future to lock up the migration until it finishes --- server/startup/migrations/v178.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/server/startup/migrations/v178.js b/server/startup/migrations/v178.js index 77846789f289..90e918e76595 100644 --- a/server/startup/migrations/v178.js +++ b/server/startup/migrations/v178.js @@ -1,4 +1,5 @@ import { Meteor } from 'meteor/meteor'; +import Future from 'fibers/future'; import { Migrations } from '../../../app/migrations/server'; import { Rooms } from '../../../app/models/server'; @@ -6,10 +7,12 @@ import { Rooms } from '../../../app/models/server'; const batchSize = 5000; const getIds = (_id) => { + // DM alone if (_id.length === 17) { return [_id]; } + // DM with rocket.cat if (_id.match(/rocket\.cat/)) { return [ 'rocket.cat', @@ -19,11 +22,13 @@ const getIds = (_id) => { const total = _id.length; + // regular DMs const id1 = _id.substr(0, Math.ceil(total / 2)); const id2 = _id.substr(Math.ceil(total / 2)); + // buggy (?) DM alone but with duplicated _id // if (id1 === id2) { - // return id1; + // return [id1]; // } return [id1, id2]; @@ -54,17 +59,16 @@ async function migrateDMs(models, total, current) { Migrations.add({ version: 178, up() { + const fut = new Future(); + const roomCollection = Rooms.model.rawCollection(); - /* - * Move visitor navigation history to messages - */ Meteor.setTimeout(async () => { const rooms = roomCollection.find({ t: 'd' }); const total = await rooms.count(); await rooms.close(); - if (total < batchSize) { + if (total < batchSize * 2) { return migrateDMs({ roomCollection }, total, 0); } @@ -73,6 +77,10 @@ Migrations.add({ await migrateDMs({ roomCollection }, total, 0); console.log('Changing schema of Direct Message rooms finished.'); - }, 1000); + + fut.return(); + }, 200); + + fut.wait(); }, }); From 501fea288e6fb43cd1ee952b97382548970322b3 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Mar 2020 00:46:12 -0300 Subject: [PATCH 45/64] Fix user creation --- app/lib/server/functions/saveUserIdentity.js | 46 ++++++++++---------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/app/lib/server/functions/saveUserIdentity.js b/app/lib/server/functions/saveUserIdentity.js index ad3ea575ad63..62e0a123a7f6 100644 --- a/app/lib/server/functions/saveUserIdentity.js +++ b/app/lib/server/functions/saveUserIdentity.js @@ -34,33 +34,35 @@ export function saveUserIdentity(userId, { _id, name: rawName, username: rawUser } } - // Username is available; if coming from old username, update all references - if (previousUsername && username) { - Messages.updateAllUsernamesByUserId(user._id, username); - Messages.updateUsernameOfEditByUserId(user._id, username); - Messages.findByMention(previousUsername).forEach(function(msg) { - const updatedMsg = msg.msg.replace(new RegExp(`@${ previousUsername }`, 'ig'), `@${ username }`); - return Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg); - }); - Rooms.replaceUsername(previousUsername, username); - Rooms.replaceMutedUsername(previousUsername, username); - Rooms.replaceUsernameOfUserByUserId(user._id, username); - Subscriptions.setUserUsernameByUserId(user._id, username); + // if coming from old username, update all references + if (previousUsername) { + if (typeof rawUsername !== 'undefined') { + Messages.updateAllUsernamesByUserId(user._id, username); + Messages.updateUsernameOfEditByUserId(user._id, username); + Messages.findByMention(previousUsername).forEach(function(msg) { + const updatedMsg = msg.msg.replace(new RegExp(`@${ previousUsername }`, 'ig'), `@${ username }`); + return Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg); + }); + Rooms.replaceUsername(previousUsername, username); + Rooms.replaceMutedUsername(previousUsername, username); + Rooms.replaceUsernameOfUserByUserId(user._id, username); + Subscriptions.setUserUsernameByUserId(user._id, username); - LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username); + LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username); - const fileStore = FileUpload.getStore('Avatars'); - const file = fileStore.model.findOneByName(previousUsername); - if (file) { - fileStore.model.updateFileNameById(file._id, username); + const fileStore = FileUpload.getStore('Avatars'); + const file = fileStore.model.findOneByName(previousUsername); + if (file) { + fileStore.model.updateFileNameById(file._id, username); + } } - } - // update name and fname of 1-on-1 direct messages - Subscriptions.updateDirectNameAndFnameByName(previousUsername, rawUsername && username, rawName && name); + // update name and fname of 1-on-1 direct messages + Subscriptions.updateDirectNameAndFnameByName(previousUsername, rawUsername && username, rawName && name); - // update name and fname of group direct messages - updateGroupDMsName(user); + // update name and fname of group direct messages + updateGroupDMsName(user); + } return true; } From 318e43aee9c010106e53bf14f9b5ff88aa069f52 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Mar 2020 00:50:43 -0300 Subject: [PATCH 46/64] Get other uid from room object --- app/ui-sidenav/client/sidebarItem.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/ui-sidenav/client/sidebarItem.js b/app/ui-sidenav/client/sidebarItem.js index d1eb0292ba6e..16516a5c9bdd 100644 --- a/app/ui-sidenav/client/sidebarItem.js +++ b/app/ui-sidenav/client/sidebarItem.js @@ -5,7 +5,7 @@ import { Template } from 'meteor/templating'; import { t, getUserPreference, roomTypes } from '../../utils'; import { popover, renderMessageBody, menu } from '../../ui-utils'; -import { Users, ChatSubscription } from '../../models'; +import { Users, ChatSubscription, Rooms } from '../../models/client'; import { settings } from '../../settings'; import { hasAtLeastOnePermission } from '../../authorization'; import { timeAgo } from '../../lib/client/lib/formatDate'; @@ -200,12 +200,25 @@ Template.sidebarItem.events({ }, }); +const getOtherUserId = (rid, userId) => { + const room = Rooms.findOne({ _id: rid }, { fields: { uids: 1 } }); + + if (!room || !room.uids || room.uids.length > 2) { + return false; + } + + const other = room && room.uids.filter((uid) => uid !== userId); + + return other && other[0]; +}; + Template.sidebarItemIcon.helpers({ uid() { if (!this.rid) { return this._id; } - return this.rid.replace(this.u._id, ''); + + return getOtherUserId(this.rid, Meteor.userId()); }, isRoom() { return this.rid || this._id; From 18e4bf4ca41d44cc25dbe345f18c879e04a6bc8d Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Mar 2020 01:06:37 -0300 Subject: [PATCH 47/64] Fix avatar when using Real Names --- app/lib/lib/roomTypes/direct.js | 11 ++++++----- app/ui-sidenav/client/chatRoomItem.js | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index d04060e36385..7190136375e8 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -39,7 +39,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { getIcon(roomData) { - if (roomData.usernames && roomData.usernames.length > 2) { + if (roomData.uids && roomData.uids.length > 2) { return 'team'; } return this.icon; @@ -173,11 +173,12 @@ export class DirectMessageRoomType extends RoomTypeConfig { return { title, text }; } - getAvatarPath(roomData) { - if (roomData.usernames && roomData.usernames.length > 2) { - return getAvatarURL({ username: roomData.usernames.length + roomData.usernames.join() }); + getAvatarPath(roomData, subData) { + if (roomData.uids && roomData.uids.length > 2) { + return getAvatarURL({ username: roomData.uids.length + roomData.usernames.join() }); } - return getUserAvatarURL(roomData.name || this.roomName(roomData)); + const sub = subData || Subscriptions.findOne({ rid: roomData._id }, { fields: { name: 1 } }); + return getUserAvatarURL(sub.name || this.roomName(roomData)); } includeInDashboard() { diff --git a/app/ui-sidenav/client/chatRoomItem.js b/app/ui-sidenav/client/chatRoomItem.js index 7107aa5473ee..dbb7d0c0e37a 100644 --- a/app/ui-sidenav/client/chatRoomItem.js +++ b/app/ui-sidenav/client/chatRoomItem.js @@ -23,7 +23,7 @@ Template.chatRoomItem.helpers({ const roomData = { ...this, icon: icon !== 'at' && icon, - avatar: roomTypes.getConfig(this.t).getAvatarPath(room || this), + avatar: roomTypes.getConfig(this.t).getAvatarPath(room, this), username: this.name, route: roomTypes.getRouteLink(this.t, this), name: roomType.roomName(this), From ae50b48dd6191abdf0d6a1d9c45068d619fbd390 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Mar 2020 01:07:19 -0300 Subject: [PATCH 48/64] Add space to room name --- app/lib/server/functions/createDirectRoom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 68942b1a4da8..22ab4282b607 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -21,7 +21,7 @@ const generateSubscription = (fname, name, user, extra) => ({ }); const getFname = (members) => members.map(({ name, username }) => name || username).join(', '); -const getName = (members) => members.map(({ username }) => username).join(','); +const getName = (members) => members.map(({ username }) => username).join(', '); export const createDirectRoom = function(members, roomExtraData = {}, options = {}) { if (members.length > (settings.get('DirectMesssage_maxUsers') || 1)) { From 18d5d504fc24612e93dd6ec2e9a3a31dbef5b005 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 24 Mar 2020 02:11:25 -0300 Subject: [PATCH 49/64] Fix migration for small datasets --- server/startup/migrations/v178.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/startup/migrations/v178.js b/server/startup/migrations/v178.js index 90e918e76595..b2fef7806cc9 100644 --- a/server/startup/migrations/v178.js +++ b/server/startup/migrations/v178.js @@ -69,7 +69,8 @@ Migrations.add({ await rooms.close(); if (total < batchSize * 2) { - return migrateDMs({ roomCollection }, total, 0); + await migrateDMs({ roomCollection }, total, 0); + return fut.return(); } console.log('Changing schema of Direct Message rooms, this may take a long time ...'); From 16f519022d9786f6a8c554b24ce9d508d445a8f2 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 24 Mar 2020 02:02:53 -0300 Subject: [PATCH 50/64] Fix: StreamCast was not working correctly (#16983) --- server/stream/streamBroadcast.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/stream/streamBroadcast.js b/server/stream/streamBroadcast.js index 983b351f1874..9d2d5c714885 100644 --- a/server/stream/streamBroadcast.js +++ b/server/stream/streamBroadcast.js @@ -10,7 +10,7 @@ import { Logger, LoggerManager } from '../../app/logger'; import { hasPermission } from '../../app/authorization'; import { settings } from '../../app/settings'; import { isDocker, getURL } from '../../app/utils'; -import { Users } from '../../app/models/server/models/Users'; +import { Users } from '../../app/models/server'; process.env.PORT = String(process.env.PORT).trim(); process.env.INSTANCE_IP = String(process.env.INSTANCE_IP).trim(); @@ -218,7 +218,7 @@ function startStreamCastBroadcast(value) { const scope = {}; return instance.emitWithScope(eventName, scope, args); } - return instance.emitWithoutBroadcast(eventName, args); + return instance._emit(eventName, args); }); return connection.subscribe('stream'); From 1bf9f2b8bb3770e8028fc8c93b3b7a80518979cf Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Mar 2020 12:46:22 -0300 Subject: [PATCH 51/64] direct message rid --- app/integrations/server/lib/triggerHandler.js | 35 +++++++++++-------- app/otr/client/rocketchat.otr.room.js | 3 +- app/otr/client/views/otrFlexTab.js | 3 +- app/ui-sidenav/client/sidebarItem.js | 18 ++-------- .../client/lib/getUidDirectMessage.js | 15 ++++++++ app/ui/client/components/header/headerRoom.js | 5 +-- .../server/cronProcessDownloads.js | 2 +- 7 files changed, 47 insertions(+), 34 deletions(-) create mode 100644 app/ui-utils/client/lib/getUidDirectMessage.js diff --git a/app/integrations/server/lib/triggerHandler.js b/app/integrations/server/lib/triggerHandler.js index 04c4227fa023..56665db0c757 100644 --- a/app/integrations/server/lib/triggerHandler.js +++ b/app/integrations/server/lib/triggerHandler.js @@ -496,28 +496,35 @@ integrations.triggerHandler = new class RocketChatIntegrationHandler { if (room) { switch (room.t) { case 'd': - const id = room._id.replace(message.u._id, ''); - const username = _.without(room.usernames, message.u.username)[0]; - - if (this.triggers[`@${ id }`]) { - for (const trigger of Object.values(this.triggers[`@${ id }`])) { - triggersToExecute.push(trigger); - } - } - if (this.triggers.all_direct_messages) { for (const trigger of Object.values(this.triggers.all_direct_messages)) { triggersToExecute.push(trigger); } } - if (id !== username && this.triggers[`@${ username }`]) { - for (const trigger of Object.values(this.triggers[`@${ username }`])) { - triggersToExecute.push(trigger); - } + if (!room.uids) { + return; } - break; + room.uids.forEach((uid) => { + if (this.triggers[`@${ uid }`]) { + for (const trigger of Object.values(this.triggers[`@${ uid }`])) { + triggersToExecute.push(trigger); + } + } + }); + + room.usernames.forEach((username) => { + if (room.uids.includes(username) || username === message.u.username) { + return; + } + if (this.triggers[`@${ username }`]) { + for (const trigger of Object.values(this.triggers[`@${ username }`])) { + triggersToExecute.push(trigger); + } + } + }); + break; case 'c': if (this.triggers.all_public_channels) { for (const trigger of Object.values(this.triggers.all_public_channels)) { diff --git a/app/otr/client/rocketchat.otr.room.js b/app/otr/client/rocketchat.otr.room.js index 2747f625d180..fcb34184e376 100644 --- a/app/otr/client/rocketchat.otr.room.js +++ b/app/otr/client/rocketchat.otr.room.js @@ -12,12 +12,13 @@ import toastr from 'toastr'; import { OTR } from './rocketchat.otr'; import { Notifications } from '../../notifications'; import { modal } from '../../ui-utils'; +import { getUidDirectMessage } from '../../ui-utils/client/lib/getUidDirectMessage'; OTR.Room = class { constructor(userId, roomId) { this.userId = userId; this.roomId = roomId; - this.peerId = roomId.replace(userId, ''); + this.peerId = getUidDirectMessage(roomId); this.established = new ReactiveVar(false); this.establishing = new ReactiveVar(false); diff --git a/app/otr/client/views/otrFlexTab.js b/app/otr/client/views/otrFlexTab.js index f15f69e4b204..12c01d98d8c3 100644 --- a/app/otr/client/views/otrFlexTab.js +++ b/app/otr/client/views/otrFlexTab.js @@ -4,6 +4,7 @@ import { Template } from 'meteor/templating'; import { OTR } from '../rocketchat.otr'; import { modal } from '../../../ui-utils'; import { t } from '../../../utils'; +import { getUidDirectMessage } from '../../../ui-utils/client/lib/getUidDirectMessage'; Template.otrFlexTab.helpers({ otrAvailable() { @@ -16,7 +17,7 @@ Template.otrFlexTab.helpers({ } if (this.rid) { - const peerId = this.rid.replace(Meteor.userId(), ''); + const peerId = getUidDirectMessage(this.rid); if (peerId) { const user = Meteor.users.findOne(peerId); const online = user && user.status !== 'offline'; diff --git a/app/ui-sidenav/client/sidebarItem.js b/app/ui-sidenav/client/sidebarItem.js index 16516a5c9bdd..1021b70a8674 100644 --- a/app/ui-sidenav/client/sidebarItem.js +++ b/app/ui-sidenav/client/sidebarItem.js @@ -5,10 +5,11 @@ import { Template } from 'meteor/templating'; import { t, getUserPreference, roomTypes } from '../../utils'; import { popover, renderMessageBody, menu } from '../../ui-utils'; -import { Users, ChatSubscription, Rooms } from '../../models/client'; +import { Users, ChatSubscription } from '../../models/client'; import { settings } from '../../settings'; import { hasAtLeastOnePermission } from '../../authorization'; import { timeAgo } from '../../lib/client/lib/formatDate'; +import { getUidDirectMessage } from '../../ui-utils/client/lib/getUidDirectMessage'; Template.sidebarItem.helpers({ streaming() { @@ -200,25 +201,12 @@ Template.sidebarItem.events({ }, }); -const getOtherUserId = (rid, userId) => { - const room = Rooms.findOne({ _id: rid }, { fields: { uids: 1 } }); - - if (!room || !room.uids || room.uids.length > 2) { - return false; - } - - const other = room && room.uids.filter((uid) => uid !== userId); - - return other && other[0]; -}; - Template.sidebarItemIcon.helpers({ uid() { if (!this.rid) { return this._id; } - - return getOtherUserId(this.rid, Meteor.userId()); + return getUidDirectMessage(this.rid); }, isRoom() { return this.rid || this._id; diff --git a/app/ui-utils/client/lib/getUidDirectMessage.js b/app/ui-utils/client/lib/getUidDirectMessage.js new file mode 100644 index 000000000000..ecfe3b48fc99 --- /dev/null +++ b/app/ui-utils/client/lib/getUidDirectMessage.js @@ -0,0 +1,15 @@ +import { Meteor } from 'meteor/meteor'; + +import { Rooms } from '../../../models/client'; + +export const getUidDirectMessage = (rid, userId = Meteor.userId()) => { + const room = Rooms.findOne({ _id: rid }, { fields: { uids: 1 } }); + + if (!room || !room.uids || room.uids.length > 2) { + return false; + } + + const other = room && room.uids.filter((uid) => uid !== userId); + + return other && other[0]; +}; diff --git a/app/ui/client/components/header/headerRoom.js b/app/ui/client/components/header/headerRoom.js index e75a7d7dd461..ec921d7e1901 100644 --- a/app/ui/client/components/header/headerRoom.js +++ b/app/ui/client/components/header/headerRoom.js @@ -13,6 +13,7 @@ import { settings } from '../../../../settings'; import { emoji } from '../../../../emoji'; import { Markdown } from '../../../../markdown/client'; import { hasAllPermission } from '../../../../authorization'; +import { getUidDirectMessage } from '../../../../ui-utils/client/lib/getUidDirectMessage'; import './headerRoom.html'; @@ -38,7 +39,7 @@ Template.headerRoom.helpers({ toggleFavoriteButtonIconLabel: () => (Template.instance().state.get('favorite') ? t('Unfavorite') : t('Favorite')), toggleFavoriteButtonIcon: () => (Template.instance().state.get('favorite') ? 'star-filled' : 'star'), uid() { - return this._id.replace(Meteor.userId(), ''); + return getUidDirectMessage(this._id); }, back() { return Template.instance().data.back; @@ -192,7 +193,7 @@ const loadUserStatusText = () => { return; } - const userId = id.replace(Meteor.userId(), ''); + const userId = getUidDirectMessage(id); // If the user is already on the local collection, the method call is not necessary const found = Meteor.users.findOne(userId, { fields: { _id: 1 } }); diff --git a/app/user-data-download/server/cronProcessDownloads.js b/app/user-data-download/server/cronProcessDownloads.js index 552c420dd230..e8388c7a17c0 100644 --- a/app/user-data-download/server/cronProcessDownloads.js +++ b/app/user-data-download/server/cronProcessDownloads.js @@ -47,7 +47,7 @@ const loadUserSubscriptions = function(exportOperation) { const roomId = subscription.rid; const roomData = Rooms.findOneById(roomId); const roomName = roomData && roomData.name && subscription.t !== 'd' ? roomData.name : roomId; - const userId = subscription.t === 'd' ? roomId.replace(exportUserId, '') : null; + const [userId] = subscription.t === 'd' ? roomId.uids.filter((uid) => uid !== exportUserId) : [null]; const fileName = exportOperation.fullExport ? roomId : roomName; const fileType = exportOperation.fullExport ? 'json' : 'html'; const targetFile = `${ fileName }.${ fileType }`; From 772def5dac41f0d85761b92f30df40dabdb6f816 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Mar 2020 12:47:06 -0300 Subject: [PATCH 52/64] room info --- app/lib/client/defaultTabBars.js | 2 +- app/ui/client/views/app/room.js | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/lib/client/defaultTabBars.js b/app/lib/client/defaultTabBars.js index e506e18efc72..25938ee9db4c 100644 --- a/app/lib/client/defaultTabBars.js +++ b/app/lib/client/defaultTabBars.js @@ -33,7 +33,7 @@ TabBar.addButton({ TabBar.addButton({ groups: ['direct'], - id: 'user-info', + id: 'user-info-group', i18nTitle: 'Members_List', icon: 'team', template: 'membersList', diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 1015a10977d6..10e86a148aa6 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -1019,7 +1019,22 @@ Template.room.onCreated(function() { this.subscription = new ReactiveVar(); this.state = new ReactiveDict(); - this.userDetail = new ReactiveVar(FlowRouter.getParam('username')); + this.userDetail = new ReactiveVar(''); + const user = Meteor.user(); + this.autorun((c) => { + const room = Rooms.findOne({ _id: rid }, { + fields: { + t: 1, + usernames: 1, + }, + }); + + if (room.t !== 'd') { + return c.stop(); + } + + this.userDetail.set(room.usernames.filter((username) => username !== user.username)[0]); + }); this.autorun(() => { const rid = Template.currentData()._id; @@ -1352,7 +1367,7 @@ Template.room.onRendered(function() { const room = Rooms.findOne({ _id: template.data._id }); if (!room) { - FlowRouter.go('home'); + return FlowRouter.go('home'); } callbacks.run('onRenderRoom', template, room); From ab7a0041717c1870dfa91b0306ef69aac7536bb9 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Mar 2020 12:47:53 -0300 Subject: [PATCH 53/64] open room --- app/ui-flextab/client/tabs/userActions.js | 2 +- app/ui-utils/client/lib/callMethod.js | 9 +++++++++ app/ui-utils/client/lib/openRoom.js | 8 ++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/ui-flextab/client/tabs/userActions.js b/app/ui-flextab/client/tabs/userActions.js index 070d7ff6ea9f..cc0bd80ecc3b 100644 --- a/app/ui-flextab/client/tabs/userActions.js +++ b/app/ui-flextab/client/tabs/userActions.js @@ -101,7 +101,7 @@ export const getActions = ({ user, directActions, hideAdminControls }) => { icon: 'message', name: t('Conversation'), action: prevent(getUser, ({ username }) => - Meteor.call('createDirectMessage', username, success((result) => result.rid && FlowRouter.go('direct', { username }, FlowRouter.current().queryParams))), + Meteor.call('createDirectMessage', username, success((result) => result.rid && FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams))), ), condition() { return canDirectMessageTo(this.username, directActions); diff --git a/app/ui-utils/client/lib/callMethod.js b/app/ui-utils/client/lib/callMethod.js index 9b5f3e9d5afe..390c1ea21bc8 100644 --- a/app/ui-utils/client/lib/callMethod.js +++ b/app/ui-utils/client/lib/callMethod.js @@ -17,3 +17,12 @@ export const call = (method, ...params) => new Promise((resolve, reject) => { return resolve(result); }); }); + +export const callMethod = (method, ...params) => new Promise((resolve, reject) => { + Meteor.call(method, ...params, (err, result) => { + if (err) { + return reject(err); + } + return resolve(result); + }); +}); diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index 60582d856107..18d644323c83 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -12,7 +12,7 @@ import { ChatSubscription, Rooms } from '../../../models'; import { settings } from '../../../settings'; import { callbacks } from '../../../callbacks'; import { roomTypes } from '../../../utils'; -import { call } from './callMethod'; +import { call, callMethod } from './callMethod'; import { RoomManager, fireGlobalEvent, RoomHistoryManager } from '..'; @@ -60,7 +60,7 @@ export const openRoom = async function(type, name) { } try { - const room = roomTypes.findRoom(type, name, user) || await call('getRoomByTypeAndName', type, name); + const room = roomTypes.findRoom(type, name, user) || await callMethod('getRoomByTypeAndName', type, name); if (RoomManager.open(type + name).ready() !== true) { if (settings.get('Accounts_AllowAnonymousRead')) { @@ -113,10 +113,10 @@ export const openRoom = async function(type, name) { return callbacks.run('enter-room', sub); } catch (error) { c.stop(); - if (type !== 'd') { + if (type === 'd') { const result = await call('createDirectMessage', ...name.split(', ')).then((result) => waitUntilRoomBeInserted(type, result.rid)).catch(() => {}); if (result) { - return FlowRouter.go('direct', { rid: result.rid }, FlowRouter.current().queryParams); + return FlowRouter.go('direct', { rid: result._id }, FlowRouter.current().queryParams); } } Session.set('roomNotFound', { type, name, error }); From a0bae6a3e721ba640701ce3c7cb4469baeab5ed2 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Mar 2020 12:48:02 -0300 Subject: [PATCH 54/64] ? --- app/lib/lib/roomTypes/direct.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 7190136375e8..3eb05ff5b702 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -174,7 +174,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { } getAvatarPath(roomData, subData) { - if (roomData.uids && roomData.uids.length > 2) { + if (roomData && roomData.uids && roomData.uids.length > 2) { return getAvatarURL({ username: roomData.uids.length + roomData.usernames.join() }); } const sub = subData || Subscriptions.findOne({ rid: roomData._id }, { fields: { name: 1 } }); From 22e2ab8002b3c0655288cf319fb846ca3625c7a9 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 24 Mar 2020 17:58:58 -0300 Subject: [PATCH 55/64] update fuselage --- package-lock.json | 1385 +++++++++------------------------------------ package.json | 10 +- 2 files changed, 274 insertions(+), 1121 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2ead87b9eda..229c05548a64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2372,8 +2372,7 @@ "@emotion/stylis": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", - "dev": true + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" }, "@emotion/unitless": { "version": "0.7.4", @@ -2611,1004 +2610,158 @@ "lodash.uniq": "^4.5.0", "octokit-pagination-methods": "^1.1.0", "universal-user-agent": "^2.0.0", - "url-template": "^2.0.8" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@reach/router": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.0.tgz", - "integrity": "sha512-LLuwmgR1vW+nHdvZfJjp/3Dk3xP0H+GkH6XQWWpYrYwLDnEArZ9TR9YTkWPTLN8Ua5ZAkaTSRqACvRqplMNA8w==", - "dev": true, - "requires": { - "create-react-context": "0.3.0", - "invariant": "^2.2.3", - "prop-types": "^15.6.1", - "react-lifecycles-compat": "^3.0.4" - } - }, - "@rocket.chat/apps-engine": { - "version": "1.13.0-beta.2857", - "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.13.0-beta.2857.tgz", - "integrity": "sha512-zWOmvGv1p1sj7s4aJAoPWIJ9Mmuz7Hlq3BKQYNh8ELjM1IiRXd1dwuyl+5q1hBuru+QZ7T7QZ+qCOa2OcM8tfQ==", - "requires": { - "adm-zip": "^0.4.9", - "cryptiles": "^4.1.3", - "lodash.clonedeep": "^4.5.0", - "semver": "^5.5.0", - "stack-trace": "0.0.10", - "typescript": "^2.9.2", - "uuid": "^3.2.1" - }, - "dependencies": { - "adm-zip": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", - "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" - }, - "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" - } - } - }, - "@rocket.chat/eslint-config": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/eslint-config/-/eslint-config-0.3.0.tgz", - "integrity": "sha512-3AlJvlohi7uwYRbKJP/v3uFCAI69J/2bU/rDAfF0GDifGDPsHAfhLIzSOshtjjIiQHtHeJ/Hg9yz/5U6E9pCrg==", - "dev": true, - "requires": { - "eslint-plugin-import": "^2.17.2" - } - }, - "@rocket.chat/fuselage": { - "version": "0.6.0", - "requires": { - "@rocket.chat/css-in-js": "^0.6.0", - "@rocket.chat/fuselage-tokens": "^0.6.0", - "@rocket.chat/icons": "^0.6.0" - }, - "dependencies": { - "@babel/generator": { - "version": "7.7.4", - "requires": { - "source-map": "^0.5.0" - } - }, - "@babel/parser": { - "version": "7.7.5" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.7.4" - }, - "@emotion/hash": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", - "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" - }, - "@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" - }, - "@rocket.chat/css-in-js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.5.0.tgz", - "integrity": "sha512-+D+CIqU+8nMgwU0rFlDjkdhlAHlfeOA4XRvu2RD1pb+p1J2TBnPv0ITQtI3qoVnXuVB6ld27oANXD1u3DWfQuQ==", - "requires": { - "@emotion/hash": "^0.8.0", - "@emotion/stylis": "^0.8.5" - } - }, - "@rocket.chat/fuselage-tokens": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.5.0.tgz", - "integrity": "sha512-OmklqorygKsBzPfeFOt8lTmsSH7t+10sIB8qIzyaEvl4ieohzqCAk4mg0NIZ1857fP4bjxW16txjSYZNn4DYKQ==" - }, - "@rocket.chat/icons": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.5.0.tgz", - "integrity": "sha512-OW6+8L3ZeeCuX8pNm4FER5DCTVhGKggFZzldWeUEqxXQH6xCdZfOAmCPijwqg5YO1aJTvlSn9bqp1gMwz8hc6w==" - }, - "@storybook/addon-actions": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/client-api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/theming": "5.2.8", - "react": "^16.8.3", - "react-inspector": "^3.0.2" - }, - "dependencies": { - "@storybook/components": { - "version": "5.2.8", - "requires": { - "@storybook/theming": "5.2.8", - "markdown-to-jsx": "^6.9.1", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-focus-lock": "^1.18.3", - "react-helmet-async": "^1.0.2", - "react-popper-tooltip": "^2.8.3", - "react-syntax-highlighter": "^8.0.1", - "react-textarea-autosize": "^7.1.0", - "simplebar-react": "^1.0.0-alpha.6" - }, - "dependencies": { - "react-dom": { - "version": "16.11.0", - "dependencies": { - "scheduler": { - "version": "0.18.0" - } - } - }, - "react-helmet-async": { - "version": "1.0.4" - }, - "react-popper-tooltip": { - "version": "2.10.0", - "requires": { - "react-popper": "^1.3.4" - } - }, - "simplebar-react": { - "version": "1.2.3" - } - } - }, - "create-react-context": { - "version": "0.3.0" - }, - "markdown-to-jsx": { - "version": "6.10.3" - }, - "react": { - "version": "16.11.0" - }, - "react-clientside-effect": { - "version": "1.2.2" - }, - "react-focus-lock": { - "version": "1.19.1", - "requires": { - "react-clientside-effect": "^1.2.0" - } - }, - "react-inspector": { - "version": "3.0.2" - }, - "react-popper": { - "version": "1.3.6", - "requires": { - "create-react-context": "^0.3.0" - } - }, - "react-syntax-highlighter": { - "version": "8.1.0" - }, - "react-textarea-autosize": { - "version": "7.1.2" - }, - "scheduler": { - "version": "0.17.0" - } - } - }, - "@storybook/addon-backgrounds": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/theming": "5.2.8", - "react": "^16.8.3" - }, - "dependencies": { - "@storybook/components": { - "version": "5.2.8", - "requires": { - "@storybook/theming": "5.2.8", - "markdown-to-jsx": "^6.9.1", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-focus-lock": "^1.18.3", - "react-helmet-async": "^1.0.2", - "react-popper-tooltip": "^2.8.3", - "react-syntax-highlighter": "^8.0.1", - "react-textarea-autosize": "^7.1.0", - "simplebar-react": "^1.0.0-alpha.6" - }, - "dependencies": { - "react-dom": { - "version": "16.11.0", - "dependencies": { - "scheduler": { - "version": "0.18.0" - } - } - }, - "react-helmet-async": { - "version": "1.0.4" - }, - "react-popper-tooltip": { - "version": "2.10.0", - "requires": { - "react-popper": "^1.3.4" - } - }, - "simplebar-react": { - "version": "1.2.3" - } - } - }, - "create-react-context": { - "version": "0.3.0" - }, - "markdown-to-jsx": { - "version": "6.10.3" - }, - "react": { - "version": "16.11.0" - }, - "react-clientside-effect": { - "version": "1.2.2" - }, - "react-focus-lock": { - "version": "1.19.1", - "requires": { - "react-clientside-effect": "^1.2.0" - } - }, - "react-popper": { - "version": "1.3.6", - "requires": { - "create-react-context": "^0.3.0" - } - }, - "react-syntax-highlighter": { - "version": "8.1.0" - }, - "react-textarea-autosize": { - "version": "7.1.2" - }, - "scheduler": { - "version": "0.17.0" - } - } - }, - "@storybook/addon-centered": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8" - } - }, - "@storybook/addon-docs": { - "version": "5.2.8", - "requires": { - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.3", - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/router": "5.2.8", - "@storybook/source-loader": "5.2.8", - "@storybook/theming": "5.2.8" - } - }, - "@storybook/addon-jest": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/theming": "5.2.8", - "react": "^16.8.3", - "react-sizeme": "^2.5.2" - }, - "dependencies": { - "react": { - "version": "16.11.0" - }, - "react-sizeme": { - "version": "2.6.10" - } - } - }, - "@storybook/addon-knobs": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/client-api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/theming": "5.2.8" - } - }, - "@storybook/addon-links": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/router": "5.2.8" - } - }, - "@storybook/addon-options": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8" - } - }, - "@storybook/addon-viewport": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/theming": "5.2.8" - } - }, - "@storybook/addons": { - "version": "5.2.8", - "requires": { - "@storybook/api": "5.2.8", - "@storybook/channels": "5.2.8", - "@storybook/core-events": "5.2.8" - } - }, - "@storybook/api": { - "version": "5.2.8", - "requires": { - "@storybook/channels": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/router": "5.2.8", - "@storybook/theming": "5.2.8", - "react": "^16.8.3" - }, - "dependencies": { - "react": { - "version": "16.11.0" - } - } - }, - "@storybook/channel-postmessage": { - "version": "5.2.8", - "requires": { - "@storybook/channels": "5.2.8" - } - }, - "@storybook/channels": { - "version": "5.2.8" - }, - "@storybook/client-api": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/channel-postmessage": "5.2.8", - "@storybook/channels": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/router": "5.2.8", - "is-plain-object": "^3.0.0" - } - }, - "@storybook/components": { - "version": "5.2.8", - "requires": { - "@storybook/theming": "5.2.8", - "markdown-to-jsx": "^6.9.1", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-focus-lock": "^1.18.3", - "react-helmet-async": "^1.0.2", - "react-popper-tooltip": "^2.8.3", - "react-syntax-highlighter": "^8.0.1", - "react-textarea-autosize": "^7.1.0", - "simplebar-react": "^1.0.0-alpha.6" - }, - "dependencies": { - "create-react-context": { - "version": "0.3.0" - }, - "markdown-to-jsx": { - "version": "6.10.3" - }, - "react": { - "version": "16.11.0" - }, - "react-clientside-effect": { - "version": "1.2.2" - }, - "react-dom": { - "version": "16.11.0", - "dependencies": { - "scheduler": { - "version": "0.18.0" - } - } - }, - "react-focus-lock": { - "version": "1.19.1", - "requires": { - "react-clientside-effect": "^1.2.0" - } - }, - "react-helmet-async": { - "version": "1.0.4" - }, - "react-popper": { - "version": "1.3.6", - "requires": { - "create-react-context": "^0.3.0" - } - }, - "react-popper-tooltip": { - "version": "2.10.0", - "requires": { - "react-popper": "^1.3.4" - } - }, - "react-syntax-highlighter": { - "version": "8.1.0" - }, - "react-textarea-autosize": { - "version": "7.1.2" - }, - "scheduler": { - "version": "0.17.0" - }, - "simplebar-react": { - "version": "1.2.3" - } - } - }, - "@storybook/core": { - "version": "5.2.8", - "requires": { - "@babel/plugin-proposal-object-rest-spread": "^7.6.2", - "@babel/preset-env": "^7.7.1", - "@storybook/addons": "5.2.8", - "@storybook/channel-postmessage": "5.2.8", - "@storybook/client-api": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/node-logger": "5.2.8", - "@storybook/router": "5.2.8", - "@storybook/theming": "5.2.8", - "@storybook/ui": "5.2.8", - "autoprefixer": "^9.4.9", - "find-cache-dir": "^3.0.0", - "resolve": "^1.11.0", - "terser-webpack-plugin": "^1.2.4", - "webpack": "^4.33.0" - }, - "dependencies": { - "@babel/preset-env": { - "version": "7.7.6", - "requires": { - "@babel/plugin-proposal-object-rest-spread": "^7.7.4", - "browserslist": "^4.6.0", - "core-js-compat": "^3.4.7", - "semver": "^5.5.0" - }, - "dependencies": { - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.7.7" - }, - "semver": { - "version": "5.7.1" - } - } - }, - "autoprefixer": { - "version": "9.7.1", - "requires": { - "browserslist": "^4.7.2", - "caniuse-lite": "^1.0.30001006", - "postcss": "^7.0.21", - "postcss-value-parser": "^4.0.2" - }, - "dependencies": { - "browserslist": { - "version": "4.7.3", - "requires": { - "caniuse-lite": "^1.0.30001010", - "node-releases": "^1.1.40" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001015" - } - } - } - } - }, - "caniuse-lite": { - "version": "1.0.30001012" - }, - "enhanced-resolve": { - "version": "4.1.1", - "requires": { - "memory-fs": "^0.5.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0" - } - } - }, - "find-cache-dir": { - "version": "3.2.0", - "requires": { - "make-dir": "^3.0.0", - "pkg-dir": "^4.1.0" - } - }, - "node-releases": { - "version": "1.1.42" - }, - "postcss": { - "version": "7.0.23", - "requires": { - "source-map": "^0.6.1" - } - }, - "serialize-javascript": { - "version": "1.9.1" - }, - "source-map": { - "version": "0.6.1" - }, - "terser-webpack-plugin": { - "version": "1.4.1", - "requires": { - "find-cache-dir": "^2.1.0", - "serialize-javascript": "^1.7.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "2.1.0", - "requires": { - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "requires": { - "semver": "^5.6.0" - } - }, - "pkg-dir": { - "version": "3.0.0" - }, - "semver": { - "version": "5.7.1" - } - } - }, - "webpack": { - "version": "4.41.2", - "requires": { - "acorn": "^6.2.1", - "enhanced-resolve": "^4.1.0", - "terser-webpack-plugin": "^1.4.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "2.1.0", - "requires": { - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "requires": { - "semver": "^5.6.0" - } - }, - "pkg-dir": { - "version": "3.0.0" - }, - "semver": { - "version": "5.7.1" - }, - "serialize-javascript": { - "version": "2.1.2" - }, - "terser-webpack-plugin": { - "version": "1.4.3", - "requires": { - "find-cache-dir": "^2.1.0", - "serialize-javascript": "^2.1.2", - "source-map": "^0.6.1" - } - }, - "webpack": { - "version": "4.41.4", - "requires": { - "acorn": "^6.2.1", - "enhanced-resolve": "^4.1.0", - "terser-webpack-plugin": "^1.4.3" - } - } - } - } - } - }, - "@storybook/core-events": { - "version": "5.2.8" - }, - "@storybook/node-logger": { - "version": "5.2.8" - }, - "@storybook/react": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/core": "5.2.8", - "@storybook/node-logger": "5.2.8", - "mini-css-extract-plugin": "^0.7.0", - "webpack": "^4.33.0" - }, - "dependencies": { - "enhanced-resolve": { - "version": "4.1.1", - "requires": { - "memory-fs": "^0.5.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0" - } - } - }, - "mini-css-extract-plugin": { - "version": "0.7.0" - }, - "webpack": { - "version": "4.41.2", - "requires": { - "acorn": "^6.2.1", - "enhanced-resolve": "^4.1.0", - "terser-webpack-plugin": "^1.4.1" - } - } - } - }, - "@storybook/router": { - "version": "5.2.8" - }, - "@storybook/source-loader": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/router": "5.2.8" - } - }, - "@storybook/theming": { - "version": "5.2.8" - }, - "@storybook/ui": { - "version": "5.2.8", - "requires": { - "@storybook/addons": "5.2.8", - "@storybook/api": "5.2.8", - "@storybook/channels": "5.2.8", - "@storybook/components": "5.2.8", - "@storybook/core-events": "5.2.8", - "@storybook/router": "5.2.8", - "@storybook/theming": "5.2.8", - "markdown-to-jsx": "^6.9.3", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-helmet-async": "^1.0.2", - "react-hotkeys": "2.0.0-pre4", - "react-sizeme": "^2.6.7", - "regenerator-runtime": "^0.13.2" - }, - "dependencies": { - "markdown-to-jsx": { - "version": "6.10.3" - }, - "react": { - "version": "16.11.0" - }, - "react-dom": { - "version": "16.11.0", - "requires": { - "scheduler": "^0.17.0" - } - }, - "react-helmet-async": { - "version": "1.0.4" - }, - "react-hotkeys": { - "version": "2.0.0-pre4" - }, - "react-sizeme": { - "version": "2.6.10" - }, - "regenerator-runtime": { - "version": "0.13.3" - }, - "scheduler": { - "version": "0.17.0" - } - } - }, - "acorn": { - "version": "6.4.0" - }, - "autoprefixer": { - "version": "9.7.3", - "requires": { - "browserslist": "^4.8.0", - "caniuse-lite": "^1.0.30001012", - "postcss": "^7.0.23", - "postcss-value-parser": "^4.0.2" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001015" - } - } - }, - "browserslist": { - "version": "4.8.2", - "requires": { - "caniuse-lite": "^1.0.30001015", - "node-releases": "^1.1.42" - } - }, - "caniuse-lite": { - "version": "1.0.30001016" - }, - "core-js-compat": { - "version": "3.6.0", - "requires": { - "browserslist": "^4.8.2", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0" - } - } - }, - "emoji-regex": { - "version": "7.0.3" - }, - "enhanced-resolve": { - "version": "4.1.0" - }, - "is-plain-object": { - "version": "3.0.0", - "requires": { - "isobject": "^4.0.0" - } - }, - "isobject": { - "version": "4.0.0" - }, - "locate-path": { - "version": "5.0.0", - "requires": { - "p-locate": "^4.1.0" - } - }, - "loki": { - "version": "0.16.0", - "requires": { - "fs-extra": "^7.0.1" - }, - "dependencies": { - "fs-extra": { - "version": "7.0.1" - } - } - }, - "make-dir": { - "version": "3.0.0" - }, - "mini-css-extract-plugin": { - "version": "0.8.2" - }, - "node-releases": { - "version": "1.1.43" - }, - "p-locate": { - "version": "4.1.0" - }, - "path-exists": { - "version": "4.0.0" - }, - "pkg-dir": { - "version": "4.2.0", - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - } - } - }, - "postcss": { - "version": "7.0.24", - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1" - } - } - }, - "postcss-value-parser": { - "version": "4.0.2" - }, - "react-dom": { - "version": "16.12.0", - "requires": { - "scheduler": "^0.18.0" - } - }, - "resolve": { - "version": "1.12.0" - }, - "sass-loader": { - "version": "8.0.0", - "requires": { - "schema-utils": "^2.1.0" - }, - "dependencies": { - "schema-utils": { - "version": "2.6.1" - } - } - }, - "scheduler": { - "version": "0.18.0" - }, - "source-map": { - "version": "0.5.7" - }, - "string-width": { - "version": "3.1.0", - "requires": { - "emoji-regex": "^7.0.1" - } - }, - "terser-webpack-plugin": { - "version": "1.4.3", - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1" - } - } - }, - "webpack": { - "version": "4.41.4", - "requires": { - "acorn": "^6.2.1", - "enhanced-resolve": "^4.1.0", - "terser-webpack-plugin": "^1.4.3" - }, - "dependencies": { - "enhanced-resolve": { - "version": "4.1.1", - "requires": { - "memory-fs": "^0.5.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0" - } - } - } - } - }, - "webpack-cli": { - "version": "3.3.10", - "requires": { - "enhanced-resolve": "4.1.0", - "yargs": "13.2.4" - } + "url-template": "^2.0.8" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@reach/router": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.0.tgz", + "integrity": "sha512-LLuwmgR1vW+nHdvZfJjp/3Dk3xP0H+GkH6XQWWpYrYwLDnEArZ9TR9YTkWPTLN8Ua5ZAkaTSRqACvRqplMNA8w==", + "dev": true, + "requires": { + "create-react-context": "0.3.0", + "invariant": "^2.2.3", + "prop-types": "^15.6.1", + "react-lifecycles-compat": "^3.0.4" + } + }, + "@rocket.chat/apps-engine": { + "version": "1.13.0-beta.2857", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.13.0-beta.2857.tgz", + "integrity": "sha512-zWOmvGv1p1sj7s4aJAoPWIJ9Mmuz7Hlq3BKQYNh8ELjM1IiRXd1dwuyl+5q1hBuru+QZ7T7QZ+qCOa2OcM8tfQ==", + "requires": { + "adm-zip": "^0.4.9", + "cryptiles": "^4.1.3", + "lodash.clonedeep": "^4.5.0", + "semver": "^5.5.0", + "stack-trace": "0.0.10", + "typescript": "^2.9.2", + "uuid": "^3.2.1" + }, + "dependencies": { + "adm-zip": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", + "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" }, - "yargs": { - "version": "13.2.4", - "requires": { - "string-width": "^3.0.0" - } + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" + } + } + }, + "@rocket.chat/css-in-js": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.6.1.tgz", + "integrity": "sha512-LNvPIj06YQmEI7kl1RFHAOk6ts95lCczafl5Nqx5jXo5SY8XKCjrR0qK1awD5sTSU9mGrDv/rE3tPTKbQPIH6A==", + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/stylis": "^0.8.5" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" } } }, + "@rocket.chat/eslint-config": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/eslint-config/-/eslint-config-0.3.0.tgz", + "integrity": "sha512-3AlJvlohi7uwYRbKJP/v3uFCAI69J/2bU/rDAfF0GDifGDPsHAfhLIzSOshtjjIiQHtHeJ/Hg9yz/5U6E9pCrg==", + "dev": true, + "requires": { + "eslint-plugin-import": "^2.17.2" + } + }, + "@rocket.chat/fuselage": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.1.tgz", + "integrity": "sha512-B3Q7hoD3gw2qfbUmqwT8byOiRnJQju3ozHJcBMyJ8z9qFDdf2qBpMbU0FQ8Gq/lrIy4cSv17+kI5RtOURyfadQ==", + "requires": { + "@rocket.chat/css-in-js": "^0.6.1", + "@rocket.chat/fuselage-tokens": "^0.6.1", + "@rocket.chat/icons": "^0.6.1" + } + }, "@rocket.chat/fuselage-hooks": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.6.0.tgz", - "integrity": "sha512-RacebD01VEL1UWa+0qt0X5KwyAzx9bgfk0RC2T9WfwcYWntI0MX3RlMnM6Ld8KwTqOpWs5iIpOasQYCCKM7Ljw==" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.6.1.tgz", + "integrity": "sha512-/M4lqd3D443GgKstncUokNgJYii7BgiaDLlIgV8LhDcWeLPzc2xDlRfrSmFN7MGcazmrwECq5DUmDSnbVsoCyw==" + }, + "@rocket.chat/fuselage-tokens": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.6.1.tgz", + "integrity": "sha512-8G3h9PTT6I57wddxvJCBqLmGJwzce3v6cSTOjcvnMAQ8xYEjY+NXK2Asq/Xh4Nxwhqwl7vsQLHbBz6XBCNqWZQ==" }, "@rocket.chat/fuselage-ui-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.0.tgz", - "integrity": "sha512-PGCw+IvNsW4A/msAahUXpkv6A6PDcxTGhMEGmA/DiOc7Y72u+7giQl43vLTuW/u5pafJ0gG83TKNxwCBcHPw8g==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.1.tgz", + "integrity": "sha512-Pj2vU4NXmZl+WznJVtVWBD9fHDyL5kt1y0rGDteoOobHLrCnJVwSCTvBDcgO4rTlf5seiqV/qTE7Qdo0Fm5vdg==", "requires": { - "@rocket.chat/ui-kit": "^0.6.0" + "@rocket.chat/ui-kit": "^0.6.1" } }, "@rocket.chat/icons": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.6.0.tgz", - "integrity": "sha512-Kl2C5m9glngFq6J2JxvijMMmrq6f+TAcxPUUEYeglHiORvIJtfYgHT7dwzLhlUiAwMUJSBVsYUzvsAvgiOxdbQ==" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.6.1.tgz", + "integrity": "sha512-uXg4oXscOQKhNP5DxF/O5f9zG8rKfLVJoXzv3AhNf/YGutqwUzLUCzt3O6bO2aeL43GjdfhxD9tZnpZlviZM9Q==" }, "@rocket.chat/livechat": { "version": "1.4.0", @@ -3698,9 +2851,9 @@ } }, "@rocket.chat/ui-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.6.0.tgz", - "integrity": "sha512-Mh82FDw2AOp88LI0IqqT20N6g+cNHfmnXsUU5BZUFh9rI5dMZDrOiYEOZpiWyC5idnWjlmPnxiANemyb8e3Gow==" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.6.1.tgz", + "integrity": "sha512-YlcrDZta5CiqIF6F4w+V6zpOGlb/O9vNKctAfnM7YPBnIz2ERnjZ+jkGH5mD6yfLaQa0YMdMseJXofWlLrPayw==" }, "@samverschueren/stream-to-observable": { "version": "0.3.0", @@ -15917,28 +15070,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -15949,14 +15102,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -15974,28 +15127,28 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true @@ -16012,21 +15165,21 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true @@ -16043,14 +15196,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -16082,14 +15235,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": false, + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -16109,7 +15262,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -16127,14 +15280,14 @@ }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -16144,14 +15297,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -16161,7 +15314,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true @@ -16189,7 +15342,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -16244,7 +15397,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -16273,7 +15426,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -16286,21 +15439,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -16310,21 +15463,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -16335,7 +15488,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true @@ -16349,7 +15502,7 @@ }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -16362,7 +15515,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -16371,7 +15524,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -16397,21 +15550,21 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true @@ -16425,21 +15578,21 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -16451,7 +15604,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -16461,7 +15614,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -16471,7 +15624,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -16494,14 +15647,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -16511,7 +15664,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true @@ -20949,7 +20102,7 @@ "dependencies": { "asn1.js": { "version": "4.10.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", @@ -20959,7 +20112,7 @@ }, "assert": { "version": "1.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", "requires": { "util": "0.10.3" @@ -20967,7 +20120,7 @@ "dependencies": { "util": { "version": "0.10.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "requires": { "inherits": "2.0.1" @@ -20977,22 +20130,22 @@ }, "base64-js": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bn.js": { "version": "4.11.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "brorand": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browserify-aes": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -21005,7 +20158,7 @@ }, "browserify-cipher": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", @@ -21015,7 +20168,7 @@ }, "browserify-des": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", @@ -21026,7 +20179,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -21035,7 +20188,7 @@ }, "browserify-sign": { "version": "4.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "requires": { "bn.js": "^4.1.1", @@ -21049,7 +20202,7 @@ }, "browserify-zlib": { "version": "0.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { "pako": "~1.0.5" @@ -21057,7 +20210,7 @@ }, "buffer": { "version": "5.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { "base64-js": "^1.0.2", @@ -21066,17 +20219,17 @@ }, "buffer-xor": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-status-codes": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "cipher-base": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", @@ -21085,7 +20238,7 @@ }, "console-browserify": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "requires": { "date-now": "^0.1.4" @@ -21093,17 +20246,17 @@ }, "constants-browserify": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { "bn.js": "^4.1.0", @@ -21112,7 +20265,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -21124,7 +20277,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -21137,7 +20290,7 @@ }, "crypto-browserify": { "version": "3.12.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { "browserify-cipher": "^1.0.0", @@ -21155,12 +20308,12 @@ }, "date-now": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" }, "des.js": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "requires": { "inherits": "^2.0.1", @@ -21169,7 +20322,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -21179,12 +20332,12 @@ }, "domain-browser": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, "elliptic": { "version": "6.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { "bn.js": "^4.4.0", @@ -21198,12 +20351,12 @@ }, "events": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" }, "evp_bytestokey": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { "md5.js": "^1.3.4", @@ -21212,7 +20365,7 @@ }, "hash-base": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { "inherits": "^2.0.1", @@ -21221,7 +20374,7 @@ }, "hash.js": { "version": "1.1.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { "inherits": "^2.0.3", @@ -21230,14 +20383,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "hmac-drbg": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { "hash.js": "^1.0.3", @@ -21247,27 +20400,27 @@ }, "https-browserify": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "ieee754": { "version": "1.1.13", - "resolved": false, + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "md5.js": { "version": "1.3.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", @@ -21277,7 +20430,7 @@ }, "miller-rabin": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { "bn.js": "^4.0.0", @@ -21286,27 +20439,27 @@ }, "minimalistic-assert": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "os-browserify": { "version": "0.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, "pako": { "version": "1.0.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" }, "parse-asn1": { "version": "5.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "requires": { "asn1.js": "^4.0.0", @@ -21319,12 +20472,12 @@ }, "path-browserify": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.0.tgz", "integrity": "sha512-Hkavx/nY4/plImrZPHRk2CL9vpOymZLgEbMNX1U0bjcBL7QN9wODxyx0yaMZURSQaUtSEvDrfAvxa9oPb0at9g==" }, "pbkdf2": { "version": "3.0.17", - "resolved": false, + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { "create-hash": "^1.1.2", @@ -21336,17 +20489,17 @@ }, "process": { "version": "0.11.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "public-encrypt": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", @@ -21359,22 +20512,22 @@ }, "punycode": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "querystring": { "version": "0.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "randombytes": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" @@ -21382,7 +20535,7 @@ }, "randomfill": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { "randombytes": "^2.0.5", @@ -21391,7 +20544,7 @@ }, "readable-stream": { "version": "3.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "requires": { "inherits": "^2.0.3", @@ -21401,14 +20554,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "ripemd160": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", @@ -21417,17 +20570,17 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "setimmediate": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "sha.js": { "version": "2.4.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -21436,7 +20589,7 @@ }, "stream-browserify": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { "inherits": "~2.0.1", @@ -21445,7 +20598,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -21459,14 +20612,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -21476,7 +20629,7 @@ }, "stream-http": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.0.0.tgz", "integrity": "sha512-JELJfd+btL9GHtxU3+XXhg9NLYrKFnhybfvRuDghtyVkOFydz3PKNT1df07AMr88qW03WHF+FSV0PySpXignCA==", "requires": { "builtin-status-codes": "^3.0.0", @@ -21487,7 +20640,7 @@ }, "string_decoder": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "requires": { "safe-buffer": "~5.1.0" @@ -21495,7 +20648,7 @@ }, "timers-browserify": { "version": "2.0.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "requires": { "setimmediate": "^1.0.4" @@ -21503,12 +20656,12 @@ }, "tty-browserify": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" }, "url": { "version": "0.11.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "requires": { "punycode": "1.3.2", @@ -21517,14 +20670,14 @@ "dependencies": { "punycode": { "version": "1.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" } } }, "util": { "version": "0.11.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "requires": { "inherits": "2.0.3" @@ -21532,24 +20685,24 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "vm-browserify": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" }, "xtend": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } diff --git a/package.json b/package.json index d14163170593..171e6b8e0e8a 100644 --- a/package.json +++ b/package.json @@ -125,11 +125,11 @@ "@google-cloud/storage": "^2.3.1", "@google-cloud/vision": "^1.8.0", "@rocket.chat/apps-engine": "^1.13.0-beta.2857", - "@rocket.chat/fuselage": "^0.6.0", - "@rocket.chat/fuselage-hooks": "^0.6.0", - "@rocket.chat/fuselage-ui-kit": "^0.6.0", - "@rocket.chat/icons": "^0.6.0", - "@rocket.chat/ui-kit": "^0.6.0", + "@rocket.chat/fuselage": "^0.6.1", + "@rocket.chat/fuselage-hooks": "^0.6.1", + "@rocket.chat/fuselage-ui-kit": "^0.6.1", + "@rocket.chat/icons": "^0.6.1", + "@rocket.chat/ui-kit": "^0.6.1", "@slack/client": "^4.8.0", "adm-zip": "RocketChat/adm-zip", "archiver": "^3.0.0", From 9e53578d9aeb91f02d2b8ec9d6737dc1b37c4444 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 17:14:38 -0300 Subject: [PATCH 56/64] Add support to group DMs to Apps engine --- app/apps/server/bridges/rooms.js | 5 ++--- app/apps/server/converters/rooms.js | 2 ++ server/methods/createDirectMessage.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/apps/server/bridges/rooms.js b/app/apps/server/bridges/rooms.js index 250f25aa22c3..d8bc4e76d4ac 100644 --- a/app/apps/server/bridges/rooms.js +++ b/app/apps/server/bridges/rooms.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import { Rooms, Subscriptions, Users } from '../../../models'; +import { Rooms, Subscriptions, Users } from '../../../models/server'; import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom'; export class AppRoomBridge { @@ -38,8 +38,7 @@ export class AppRoomBridge { delete extraData.customFields; let info; if (room.type === RoomType.DIRECT_MESSAGE) { - members.splice(members.indexOf(room.creator.username), 1); - info = Meteor.call(method, members[0]); + info = Meteor.call(method, ...members); } else { info = Meteor.call(method, rcRoom.name, members, rcRoom.ro, rcRoom.customFields, extraData); } diff --git a/app/apps/server/converters/rooms.js b/app/apps/server/converters/rooms.js index d39050d7d0e3..9da3e5267e8a 100644 --- a/app/apps/server/converters/rooms.js +++ b/app/apps/server/converters/rooms.js @@ -79,6 +79,7 @@ export class AppRoomsConverter { servedBy, closedBy, members: room.members, + uids: room.uids, default: typeof room.isDefault === 'undefined' ? false : room.isDefault, ro: typeof room.isReadOnly === 'undefined' ? false : room.isReadOnly, sysMes: typeof room.displaySystemMessages === 'undefined' ? true : room.displaySystemMessages, @@ -105,6 +106,7 @@ export class AppRoomsConverter { displayName: 'fname', slugifiedName: 'name', members: 'members', + uids: 'uids', messageCount: 'msgs', createdAt: 'ts', updatedAt: '_updatedAt', diff --git a/server/methods/createDirectMessage.js b/server/methods/createDirectMessage.js index 19cf01bb5ff4..8ecf775c2722 100644 --- a/server/methods/createDirectMessage.js +++ b/server/methods/createDirectMessage.js @@ -55,7 +55,7 @@ Meteor.methods({ return to; }); - const { _id: rid, inserted, ...room } = createRoom('d', null, null, [me, ...users], { }, { creator: me._id }); + const { _id: rid, inserted, ...room } = createRoom('d', null, null, [me, ...users], null, { }, { creator: me._id }); return { t: 'd', From 4d933f840e91cbdb055c05536e47dde4b9096545 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 18:23:18 -0300 Subject: [PATCH 57/64] Code style --- app/integrations/server/lib/triggerHandler.js | 41 +++++++------------ app/lib/lib/roomTypes/direct.js | 6 +-- app/models/server/models/Rooms.js | 10 +---- 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/app/integrations/server/lib/triggerHandler.js b/app/integrations/server/lib/triggerHandler.js index 56665db0c757..eca745531fa4 100644 --- a/app/integrations/server/lib/triggerHandler.js +++ b/app/integrations/server/lib/triggerHandler.js @@ -492,55 +492,44 @@ integrations.triggerHandler = new class RocketChatIntegrationHandler { } getTriggersToExecute(room, message) { - const triggersToExecute = []; + const triggersToExecute = new Set(); if (room) { switch (room.t) { case 'd': if (this.triggers.all_direct_messages) { for (const trigger of Object.values(this.triggers.all_direct_messages)) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } - if (!room.uids) { - return; - } - - room.uids.forEach((uid) => { - if (this.triggers[`@${ uid }`]) { - for (const trigger of Object.values(this.triggers[`@${ uid }`])) { - triggersToExecute.push(trigger); - } + room.uids.filter((uid) => this.triggers[`@${ uid }`]).forEach((uid) => { + for (const trigger of Object.values(this.triggers[`@${ uid }`])) { + triggersToExecute.add(trigger); } }); - room.usernames.forEach((username) => { - if (room.uids.includes(username) || username === message.u.username) { - return; - } - if (this.triggers[`@${ username }`]) { - for (const trigger of Object.values(this.triggers[`@${ username }`])) { - triggersToExecute.push(trigger); - } + room.usernames.filter((username) => username !== message.u.username && this.triggers[`@${ username }`]).forEach((username) => { + for (const trigger of Object.values(this.triggers[`@${ username }`])) { + triggersToExecute.add(trigger); } }); break; case 'c': if (this.triggers.all_public_channels) { for (const trigger of Object.values(this.triggers.all_public_channels)) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } if (this.triggers[`#${ room._id }`]) { for (const trigger of Object.values(this.triggers[`#${ room._id }`])) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } if (room._id !== room.name && this.triggers[`#${ room.name }`]) { for (const trigger of Object.values(this.triggers[`#${ room.name }`])) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } break; @@ -548,25 +537,25 @@ integrations.triggerHandler = new class RocketChatIntegrationHandler { default: if (this.triggers.all_private_groups) { for (const trigger of Object.values(this.triggers.all_private_groups)) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } if (this.triggers[`#${ room._id }`]) { for (const trigger of Object.values(this.triggers[`#${ room._id }`])) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } if (room._id !== room.name && this.triggers[`#${ room.name }`]) { for (const trigger of Object.values(this.triggers[`#${ room.name }`])) { - triggersToExecute.push(trigger); + triggersToExecute.add(trigger); } } break; } } - return triggersToExecute; + return [...triggersToExecute]; } executeTriggers(...args) { diff --git a/app/lib/lib/roomTypes/direct.js b/app/lib/lib/roomTypes/direct.js index 3eb05ff5b702..b564d3e3e012 100644 --- a/app/lib/lib/roomTypes/direct.js +++ b/app/lib/lib/roomTypes/direct.js @@ -39,7 +39,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { getIcon(roomData) { - if (roomData.uids && roomData.uids.length > 2) { + if (this.isGroupChat(roomData)) { return 'team'; } return this.icon; @@ -174,7 +174,7 @@ export class DirectMessageRoomType extends RoomTypeConfig { } getAvatarPath(roomData, subData) { - if (roomData && roomData.uids && roomData.uids.length > 2) { + if (roomData && this.isGroupChat(roomData)) { return getAvatarURL({ username: roomData.uids.length + roomData.usernames.join() }); } const sub = subData || Subscriptions.findOne({ rid: roomData._id }, { fields: { name: 1 } }); @@ -186,6 +186,6 @@ export class DirectMessageRoomType extends RoomTypeConfig { } isGroupChat(room) { - return room.usernames && room.usernames.length > 2; + return room.uids && room.uids.length > 2; } } diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index 9580e63ab6c9..a9034630737f 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -466,19 +466,11 @@ export class Rooms extends Base { return this.find(query, options); } - findDirectRoomContainingUsername(username, options) { - const query = { - t: 'd', - usernames: username, - }; - - return this.find(query, options); - } - findDirectRoomContainingAllUsernames(usernames, options) { const query = { t: 'd', usernames: { $size: usernames.length, $all: usernames }, + usersCount: usernames.length, }; return this.findOne(query, options); From f587f0d1de4a3383e945664a927aad0cb90c4a30 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 18:28:57 -0300 Subject: [PATCH 58/64] Rename field on Apps Engine uids -> userIds --- app/apps/server/converters/rooms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/apps/server/converters/rooms.js b/app/apps/server/converters/rooms.js index 9da3e5267e8a..a511f471d256 100644 --- a/app/apps/server/converters/rooms.js +++ b/app/apps/server/converters/rooms.js @@ -79,7 +79,7 @@ export class AppRoomsConverter { servedBy, closedBy, members: room.members, - uids: room.uids, + uids: room.userIds, default: typeof room.isDefault === 'undefined' ? false : room.isDefault, ro: typeof room.isReadOnly === 'undefined' ? false : room.isReadOnly, sysMes: typeof room.displaySystemMessages === 'undefined' ? true : room.displaySystemMessages, @@ -106,7 +106,7 @@ export class AppRoomsConverter { displayName: 'fname', slugifiedName: 'name', members: 'members', - uids: 'uids', + userIds: 'uids', messageCount: 'msgs', createdAt: 'ts', updatedAt: '_updatedAt', From 9d64a4e85a8e696b2b7e001b96fd36ad18815be8 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 25 Mar 2020 18:34:29 -0300 Subject: [PATCH 59/64] fix review --- .../client/views/app/CreateDirectMessage.js | 20 ------------------- server/publications/room/index.js | 1 - 2 files changed, 21 deletions(-) diff --git a/app/ui/client/views/app/CreateDirectMessage.js b/app/ui/client/views/app/CreateDirectMessage.js index df5bec5f78aa..667a4e63d49a 100755 --- a/app/ui/client/views/app/CreateDirectMessage.js +++ b/app/ui/client/views/app/CreateDirectMessage.js @@ -1,11 +1,8 @@ import { Tracker } from 'meteor/tracker'; import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; - import { roomTypes } from '../../../../utils/client'; -import { ChatSubscription } from '../../../../models/client'; import { call } from '../../../../ui-utils/client'; import './CreateDirectMessage.html'; @@ -86,24 +83,7 @@ Template.CreateDirectMessage.onRendered(function() { }); Template.CreateDirectMessage.onCreated(function() { - const { rid, message: msg } = this.data; - - const parentRoom = rid && ChatSubscription.findOne({ rid }); - - // if creating a discussion from inside a discussion, uses the same channel as parent channel - const room = parentRoom && parentRoom.prid ? ChatSubscription.findOne({ rid: parentRoom.prid }) : parentRoom; - - if (room) { - room.text = room.name; - } - - this.selectedUsers = new ReactiveVar([]); - this.onSelectUser = ({ item: user }) => { - if (user.username === (msg && msg.u.username)) { - return; - } - if (user.username === Meteor.user().username) { return; } diff --git a/server/publications/room/index.js b/server/publications/room/index.js index c6393f94045a..3f6baf33fa5c 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -30,7 +30,6 @@ export const fields = { retention: 1, prid: 1, usersCount: 1, - usernames: 1, // @TODO create an API to register this fields based on room type livechatData: 1, From 0973778a14d8b65926099d71710150d1e3834b1d Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 19:54:50 -0300 Subject: [PATCH 60/64] Move migration to 179 --- server/startup/migrations/index.js | 1 + server/startup/migrations/v179.js | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 server/startup/migrations/v179.js diff --git a/server/startup/migrations/index.js b/server/startup/migrations/index.js index ecc2aa96f5ee..6ad1177c8965 100644 --- a/server/startup/migrations/index.js +++ b/server/startup/migrations/index.js @@ -176,4 +176,5 @@ import './v175'; import './v176'; import './v177'; import './v178'; +import './v179'; import './xrun'; diff --git a/server/startup/migrations/v179.js b/server/startup/migrations/v179.js new file mode 100644 index 000000000000..b2fef7806cc9 --- /dev/null +++ b/server/startup/migrations/v179.js @@ -0,0 +1,87 @@ +import { Meteor } from 'meteor/meteor'; +import Future from 'fibers/future'; + +import { Migrations } from '../../../app/migrations/server'; +import { Rooms } from '../../../app/models/server'; + +const batchSize = 5000; + +const getIds = (_id) => { + // DM alone + if (_id.length === 17) { + return [_id]; + } + + // DM with rocket.cat + if (_id.match(/rocket\.cat/)) { + return [ + 'rocket.cat', + _id.replace('rocket.cat', ''), + ]; + } + + const total = _id.length; + + // regular DMs + const id1 = _id.substr(0, Math.ceil(total / 2)); + const id2 = _id.substr(Math.ceil(total / 2)); + + // buggy (?) DM alone but with duplicated _id + // if (id1 === id2) { + // return [id1]; + // } + + return [id1, id2]; +}; + +async function migrateDMs(models, total, current) { + const { roomCollection } = models; + + console.log(`DM rooms schema migration ${ current }/${ total }`); + + const items = await roomCollection.find({ t: 'd', uids: { $exists: false } }, { fields: { _id: 1 } }).limit(batchSize).toArray(); + + const actions = items.map((room) => roomCollection.updateOne({ _id: room._id }, { + $set: { + uids: getIds(room._id), + }, + })); + + const batch = Promise.all(actions); + if (actions.length === batchSize) { + await batch; + return migrateDMs(models, total, current + batchSize); + } + + return batch; +} + +Migrations.add({ + version: 178, + up() { + const fut = new Future(); + + const roomCollection = Rooms.model.rawCollection(); + + Meteor.setTimeout(async () => { + const rooms = roomCollection.find({ t: 'd' }); + const total = await rooms.count(); + await rooms.close(); + + if (total < batchSize * 2) { + await migrateDMs({ roomCollection }, total, 0); + return fut.return(); + } + + console.log('Changing schema of Direct Message rooms, this may take a long time ...'); + + await migrateDMs({ roomCollection }, total, 0); + + console.log('Changing schema of Direct Message rooms finished.'); + + fut.return(); + }, 200); + + fut.wait(); + }, +}); From 8c3aeb9922c91ff5522b349da5eca36da0faf575 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 19:56:38 -0300 Subject: [PATCH 61/64] Update Apps Engine beta version --- package-lock.json | 259 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 128 insertions(+), 133 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84fc1463d727..f9284e1d890b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2844,9 +2844,9 @@ } }, "@rocket.chat/apps-engine": { - "version": "1.13.0-beta.2857", - "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.13.0-beta.2857.tgz", - "integrity": "sha512-zWOmvGv1p1sj7s4aJAoPWIJ9Mmuz7Hlq3BKQYNh8ELjM1IiRXd1dwuyl+5q1hBuru+QZ7T7QZ+qCOa2OcM8tfQ==", + "version": "1.13.0-beta.2931", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.13.0-beta.2931.tgz", + "integrity": "sha512-+0imJAd/vb0Yfqg+FUTCZ9e0+wZyh9ZCwtCakOmuJN5hp40NtouiVnTqwzHwUHwfHd8NYmxQ8Vb35zLsvUiYbg==", "requires": { "adm-zip": "^0.4.9", "cryptiles": "^4.1.3", @@ -2857,11 +2857,6 @@ "uuid": "^3.2.1" }, "dependencies": { - "adm-zip": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", - "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" - }, "typescript": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", @@ -15348,28 +15343,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -15380,14 +15375,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -15405,28 +15400,28 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true @@ -15443,21 +15438,21 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true @@ -15474,14 +15469,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -15513,14 +15508,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -15540,7 +15535,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -15558,14 +15553,14 @@ }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -15575,14 +15570,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -15592,7 +15587,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true @@ -15620,7 +15615,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -15675,7 +15670,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -15704,7 +15699,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -15717,21 +15712,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -15741,21 +15736,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -15766,7 +15761,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true @@ -15780,7 +15775,7 @@ }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -15793,7 +15788,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -15802,7 +15797,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -15828,21 +15823,21 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true @@ -15856,21 +15851,21 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -15882,7 +15877,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -15892,7 +15887,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -15902,7 +15897,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true @@ -15925,14 +15920,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -15942,7 +15937,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true @@ -20404,7 +20399,7 @@ "dependencies": { "asn1.js": { "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "resolved": false, "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "requires": { "bn.js": "^4.0.0", @@ -20414,7 +20409,7 @@ }, "assert": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "resolved": false, "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", "requires": { "util": "0.10.3" @@ -20422,7 +20417,7 @@ "dependencies": { "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": false, "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "requires": { "inherits": "2.0.1" @@ -20432,22 +20427,22 @@ }, "base64-js": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "resolved": false, "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bn.js": { "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "resolved": false, "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "brorand": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "resolved": false, "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": false, "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -20460,7 +20455,7 @@ }, "browserify-cipher": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "resolved": false, "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { "browserify-aes": "^1.0.4", @@ -20470,7 +20465,7 @@ }, "browserify-des": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "resolved": false, "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { "cipher-base": "^1.0.1", @@ -20481,7 +20476,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": false, "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -20490,7 +20485,7 @@ }, "browserify-sign": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "resolved": false, "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "requires": { "bn.js": "^4.1.1", @@ -20504,7 +20499,7 @@ }, "browserify-zlib": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "resolved": false, "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { "pako": "~1.0.5" @@ -20512,7 +20507,7 @@ }, "buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "resolved": false, "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { "base64-js": "^1.0.2", @@ -20521,17 +20516,17 @@ }, "buffer-xor": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "resolved": false, "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, "builtin-status-codes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "resolved": false, "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, "cipher-base": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "resolved": false, "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { "inherits": "^2.0.1", @@ -20540,7 +20535,7 @@ }, "console-browserify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "resolved": false, "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "requires": { "date-now": "^0.1.4" @@ -20548,17 +20543,17 @@ }, "constants-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "resolved": false, "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "requires": { "bn.js": "^4.1.0", @@ -20567,7 +20562,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": false, "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -20579,7 +20574,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": false, "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -20592,7 +20587,7 @@ }, "crypto-browserify": { "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "resolved": false, "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { "browserify-cipher": "^1.0.0", @@ -20610,12 +20605,12 @@ }, "date-now": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "resolved": false, "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" }, "des.js": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "resolved": false, "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "requires": { "inherits": "^2.0.1", @@ -20624,7 +20619,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": false, "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { "bn.js": "^4.1.0", @@ -20634,12 +20629,12 @@ }, "domain-browser": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "resolved": false, "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, "elliptic": { "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "resolved": false, "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "requires": { "bn.js": "^4.4.0", @@ -20653,12 +20648,12 @@ }, "events": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "resolved": false, "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" }, "evp_bytestokey": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "resolved": false, "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { "md5.js": "^1.3.4", @@ -20667,7 +20662,7 @@ }, "hash-base": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "resolved": false, "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "requires": { "inherits": "^2.0.1", @@ -20676,7 +20671,7 @@ }, "hash.js": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "resolved": false, "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { "inherits": "^2.0.3", @@ -20685,14 +20680,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "hmac-drbg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "resolved": false, "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { "hash.js": "^1.0.3", @@ -20702,27 +20697,27 @@ }, "https-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "ieee754": { "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "resolved": false, "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "resolved": false, "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "md5.js": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "resolved": false, "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { "hash-base": "^3.0.0", @@ -20732,7 +20727,7 @@ }, "miller-rabin": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "resolved": false, "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { "bn.js": "^4.0.0", @@ -20741,27 +20736,27 @@ }, "minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "resolved": false, "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "resolved": false, "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "os-browserify": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "resolved": false, "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, "pako": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "resolved": false, "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" }, "parse-asn1": { "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "resolved": false, "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "requires": { "asn1.js": "^4.0.0", @@ -20774,12 +20769,12 @@ }, "path-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.0.tgz", + "resolved": false, "integrity": "sha512-Hkavx/nY4/plImrZPHRk2CL9vpOymZLgEbMNX1U0bjcBL7QN9wODxyx0yaMZURSQaUtSEvDrfAvxa9oPb0at9g==" }, "pbkdf2": { "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "resolved": false, "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "requires": { "create-hash": "^1.1.2", @@ -20791,17 +20786,17 @@ }, "process": { "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "resolved": false, "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "public-encrypt": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "resolved": false, "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { "bn.js": "^4.1.0", @@ -20814,22 +20809,22 @@ }, "punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "resolved": false, "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "querystring": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "resolved": false, "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, "querystring-es3": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "resolved": false, "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "resolved": false, "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { "safe-buffer": "^5.1.0" @@ -20837,7 +20832,7 @@ }, "randomfill": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "resolved": false, "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { "randombytes": "^2.0.5", @@ -20846,7 +20841,7 @@ }, "readable-stream": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "resolved": false, "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "requires": { "inherits": "^2.0.3", @@ -20856,14 +20851,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "ripemd160": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "resolved": false, "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { "hash-base": "^3.0.0", @@ -20872,17 +20867,17 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "resolved": false, "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": false, "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -20891,7 +20886,7 @@ }, "stream-browserify": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "resolved": false, "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { "inherits": "~2.0.1", @@ -20900,7 +20895,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -20914,14 +20909,14 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -20931,7 +20926,7 @@ }, "stream-http": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.0.0.tgz", + "resolved": false, "integrity": "sha512-JELJfd+btL9GHtxU3+XXhg9NLYrKFnhybfvRuDghtyVkOFydz3PKNT1df07AMr88qW03WHF+FSV0PySpXignCA==", "requires": { "builtin-status-codes": "^3.0.0", @@ -20942,7 +20937,7 @@ }, "string_decoder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "resolved": false, "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "requires": { "safe-buffer": "~5.1.0" @@ -20950,7 +20945,7 @@ }, "timers-browserify": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "resolved": false, "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "requires": { "setimmediate": "^1.0.4" @@ -20958,12 +20953,12 @@ }, "tty-browserify": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "resolved": false, "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" }, "url": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "resolved": false, "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "requires": { "punycode": "1.3.2", @@ -20972,14 +20967,14 @@ "dependencies": { "punycode": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "resolved": false, "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" } } }, "util": { "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "resolved": false, "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "requires": { "inherits": "2.0.3" @@ -20987,24 +20982,24 @@ "dependencies": { "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "vm-browserify": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "resolved": false, "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "resolved": false, "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } diff --git a/package.json b/package.json index ed78c8631371..44a87bc90d54 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "@nivo/heatmap": "^0.61.0", "@nivo/line": "^0.61.1", "@nivo/pie": "^0.61.1", - "@rocket.chat/apps-engine": "^1.13.0-beta.2857", + "@rocket.chat/apps-engine": "^1.13.0-beta.2931", "@rocket.chat/fuselage": "^0.6.1", "@rocket.chat/fuselage-hooks": "^0.6.1", "@rocket.chat/fuselage-ui-kit": "^0.6.1", From 8caeae824a91cfa8a523ced7541f7ff4f6c65a6f Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 20:34:10 -0300 Subject: [PATCH 62/64] Final items --- app/ui-sidenav/client/chatRoomItem.js | 2 +- app/ui/client/lib/notification.js | 2 +- server/publications/room/index.js | 3 +++ server/startup/migrations/v179.js | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/ui-sidenav/client/chatRoomItem.js b/app/ui-sidenav/client/chatRoomItem.js index dbb7d0c0e37a..d3c050e2e243 100644 --- a/app/ui-sidenav/client/chatRoomItem.js +++ b/app/ui-sidenav/client/chatRoomItem.js @@ -18,7 +18,7 @@ Template.chatRoomItem.helpers({ const room = Rooms.findOne(this.rid); - const icon = this.t === 'd' ? roomTypes.getIcon(room) : roomTypes.getIcon(this); + const icon = roomTypes.getIcon(this.t === 'd' ? room : this); const roomData = { ...this, diff --git a/app/ui/client/lib/notification.js b/app/ui/client/lib/notification.js index 2d78a4bde333..14e1bebc7381 100644 --- a/app/ui/client/lib/notification.js +++ b/app/ui/client/lib/notification.js @@ -65,7 +65,7 @@ export const KonchatNotification = { window.focus(); switch (notification.payload.type) { case 'd': - return FlowRouter.go('direct', { rid: notification.payload.sender.username }, FlowRouter.current().queryParams); // TODO CHANGE + return FlowRouter.go('direct', { rid: notification.payload.rid }, FlowRouter.current().queryParams); case 'c': return FlowRouter.go('channel', { name: notification.payload.name }, FlowRouter.current().queryParams); case 'p': diff --git a/server/publications/room/index.js b/server/publications/room/index.js index 3f6baf33fa5c..98fd2ea29caf 100644 --- a/server/publications/room/index.js +++ b/server/publications/room/index.js @@ -52,6 +52,9 @@ export const fields = { e2eKeyId: 1, departmentId: 1, servedBy: 1, + + // fields used by DMs + usernames: 1, uids: 1, }; diff --git a/server/startup/migrations/v179.js b/server/startup/migrations/v179.js index b2fef7806cc9..a7e4d81a3b62 100644 --- a/server/startup/migrations/v179.js +++ b/server/startup/migrations/v179.js @@ -57,7 +57,7 @@ async function migrateDMs(models, total, current) { } Migrations.add({ - version: 178, + version: 179, up() { const fut = new Future(); From ebbbd0928396b1a86f71f500adf07db6ac5c436a Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 23:37:30 -0300 Subject: [PATCH 63/64] Fix user info --- app/ui/client/views/app/room.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index 10e86a148aa6..435cfa4ee9db 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -1026,6 +1026,7 @@ Template.room.onCreated(function() { fields: { t: 1, usernames: 1, + uids: 1, }, }); @@ -1033,17 +1034,17 @@ Template.room.onCreated(function() { return c.stop(); } + if (roomTypes.getConfig(room.t).isGroupChat(room)) { + return; + } + this.userDetail.set(room.usernames.filter((username) => username !== user.username)[0]); }); this.autorun(() => { const rid = Template.currentData()._id; - const room = Rooms.findOne({ _id: rid }, { fields: { announcement: 1, usernames: 1, t: 1 } }); + const room = Rooms.findOne({ _id: rid }, { fields: { announcement: 1 } }); this.state.set('announcement', room.announcement); - - if (roomTypes.getConfig(room.t).isGroupChat(room)) { - this.userDetail.set(undefined); - } }); this.autorun(() => { From 61902daaac93433c11d3c3c4395c6f3cea4af902 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Wed, 25 Mar 2020 23:38:00 -0300 Subject: [PATCH 64/64] Deprecate old room _id for DMs --- app/lib/server/functions/createDirectRoom.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/lib/server/functions/createDirectRoom.js b/app/lib/server/functions/createDirectRoom.js index 22ab4282b607..ae1ee8b20c4c 100644 --- a/app/lib/server/functions/createDirectRoom.js +++ b/app/lib/server/functions/createDirectRoom.js @@ -31,13 +31,17 @@ export const createDirectRoom = function(members, roomExtraData = {}, options = const sortedMembers = members.sort((u1, u2) => (u1.name || u1.username).localeCompare(u2.name || u2.username)); const usernames = sortedMembers.map(({ username }) => username); - const uids = sortedMembers.map(({ _id }) => _id); + const uids = members.map(({ _id }) => _id).sort(); - const room = Rooms.findDirectRoomContainingAllUserIDs(uids, { fields: { _id: 1 } }); + // Deprecated: using users' _id to compose the room _id is deprecated + const room = uids.length <= 2 + ? Rooms.findById(uids.join(''), { fields: { _id: 1 } }) + : Rooms.findDirectRoomContainingAllUserIDs(uids, { fields: { _id: 1 } }); const isNewRoom = !room; const rid = room?._id || Rooms.insert({ + ...uids.length <= 2 && { _id: uids.join('') }, // Deprecated: using users' _id to compose the room _id is deprecated t: 'd', usernames, usersCount: members.length,