diff --git a/client/routes/router.js b/client/routes/router.js index d75f07595f0b..67d0f4870e5e 100644 --- a/client/routes/router.js +++ b/client/routes/router.js @@ -95,19 +95,6 @@ FlowRouter.route('/account/:group?', { }] }); -FlowRouter.route('/history/private', { - name: 'privateHistory', - - subscriptions(/*params, queryParams*/) { - this.register('privateHistory', Meteor.subscribe('privateHistory')); - }, - - action() { - Session.setDefault('historyFilter', ''); - BlazeLayout.render('main', {center: 'privateHistory'}); - } -}); - FlowRouter.route('/terms-of-service', { name: 'terms-of-service', diff --git a/packages/rocketchat-api/server/v1/channels.js b/packages/rocketchat-api/server/v1/channels.js index 07077bd786d1..ef07da8d1df7 100644 --- a/packages/rocketchat-api/server/v1/channels.js +++ b/packages/rocketchat-api/server/v1/channels.js @@ -847,4 +847,42 @@ RocketChat.API.v1.addRoute('channels.getAllUserMentionsByChannel', { authRequire } }); +RocketChat.API.v1.addRoute('channels.notifications', { authRequired: true }, { + get() { + const { roomId } = this.requestParams(); + + if (!roomId) { + return RocketChat.API.v1.failure('The \'roomId\' param is required'); + } + + const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, this.userId, { + fields: { + _room: 0, + _user: 0, + $loki: 0 + } + }); + + return RocketChat.API.v1.success({ + subscription + }); + }, + post() { + const saveNotifications = (notifications, roomId) => { + Object.keys(notifications).map((notificationKey) => { + Meteor.runAsUser(this.userId, () => Meteor.call('saveNotificationSettings', roomId, notificationKey, notifications[notificationKey])); + }); + }; + const { roomId, notifications } = this.bodyParams; + if (!roomId) { + return RocketChat.API.v1.failure('The \'roomId\' param is required'); + } + + if (!notifications || Object.keys(notifications).length === 0) { + return RocketChat.API.v1.failure('The \'notifications\' param is required'); + } + + saveNotifications(notifications, roomId); + } +}); diff --git a/packages/rocketchat-autolinker/client/client.js b/packages/rocketchat-autolinker/client/client.js index 60c18123d007..4846ff16e25d 100644 --- a/packages/rocketchat-autolinker/client/client.js +++ b/packages/rocketchat-autolinker/client/client.js @@ -7,7 +7,14 @@ import s from 'underscore.string'; import Autolinker from 'autolinker'; +function htmlDecode(input) { + const e = document.createElement('div'); + e.innerHTML = input; + return e.childNodes.length === 0 ? '' : e.childNodes[0].nodeValue; +} + function AutoLinker(message) { + message.html = htmlDecode(message.html); if (RocketChat.settings.get('AutoLinker') !== true) { return message; } diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 50b23379e4a9..434bf04b1d1b 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -553,6 +553,7 @@ "Display_offline_form": "Display Offline Form", "Displays_action_text": "Displays action text", "Do_not_display_unread_counter": "Do not display any counter of this channel", + "Do_you_want_to_accept": "Do you want to accept?", "Do_you_want_to_change_to_s_question": "Do you want to change to %s?", "Domain": "Domain", "Domain_added": "domain Added", @@ -1429,6 +1430,7 @@ "Offline_unavailable": "Offline unavailable", "On": "On", "Online": "Online", + "online": "online", "Only_authorized_users_can_write_new_messages": "Only authorized users can write new messages", "Only_On_Desktop": "Desktop mode (only sends with enter on desktop)", "Only_you_can_see_this_message": "Only you can see this message", @@ -2167,6 +2169,11 @@ "We_have_sent_registration_email": "We have sent you an email to confirm your registration. If you do not receive an email shortly, please come back and try again.", "Webhook_URL": "Webhook URL", "Webhooks": "Webhooks", + "WebRTC_direct_audio_call_from_%s": "Direct audio call from %s", + "WebRTC_direct_video_call_from_%s": "Direct video call from %s", + "WebRTC_group_audio_call_from_%s": "Group audio call from %s", + "WebRTC_group_video_call_from_%s": "Group video call from %s", + "WebRTC_monitor_call_from_%s": "Monitor call from %s", "WebRTC_Enable_Channel": "Enable for Public Channels", "WebRTC_Enable_Direct": "Enable for Direct Messages", "WebRTC_Enable_Private": "Enable for Private Channels", diff --git a/packages/rocketchat-lib/client/MessageAction.js b/packages/rocketchat-lib/client/MessageAction.js index c473d2de4383..79747da1631d 100644 --- a/packages/rocketchat-lib/client/MessageAction.js +++ b/packages/rocketchat-lib/client/MessageAction.js @@ -103,25 +103,10 @@ Meteor.startup(function() { action() { const message = this._arguments[1]; const {input} = chatMessages[message.rid]; - const url = RocketChat.MessageAction.getPermaLink(message._id); - const roomInfo = RocketChat.models.Rooms.findOne(message.rid, { fields: { t: 1 } }); - let text = `[ ](${ url }) `; - let inputValue = ''; - - if (roomInfo.t !== 'd' && message.u.username !== Meteor.user().username) { - text += `@${ message.u.username } `; - } - - if (input.value && !input.value.endsWith(' ')) { - inputValue += ' '; - } - inputValue += text; - $(input) .focus() - .val(inputValue) - .trigger('change') - .trigger('input'); + .data('reply', message) + .trigger('dataChange'); }, condition(message) { if (RocketChat.models.Subscriptions.findOne({rid: message.rid}) == null) { diff --git a/packages/rocketchat-lib/server/models/Subscriptions.js b/packages/rocketchat-lib/server/models/Subscriptions.js index 726a0b4299c2..9e585150bf01 100644 --- a/packages/rocketchat-lib/server/models/Subscriptions.js +++ b/packages/rocketchat-lib/server/models/Subscriptions.js @@ -30,16 +30,16 @@ class ModelSubscriptions extends RocketChat.models._Base { // FIND ONE - findOneByRoomIdAndUserId(roomId, userId) { + findOneByRoomIdAndUserId(roomId, userId, options) { if (this.useCache) { - return this.cache.findByIndex('rid,u._id', [roomId, userId]).fetch(); + return this.cache.findByIndex('rid,u._id', [roomId, userId], options).fetch(); } const query = { rid: roomId, 'u._id': userId }; - return this.findOne(query); + return this.findOne(query, options); } findOneByRoomNameAndUserId(roomName, userId) { @@ -61,7 +61,7 @@ class ModelSubscriptions extends RocketChat.models._Base { } const query = - {'u._id': userId}; + { 'u._id': userId }; return this.find(query, options); } @@ -123,7 +123,7 @@ class ModelSubscriptions extends RocketChat.models._Base { } const query = - {rid: roomId}; + { rid: roomId }; return this.find(query, options); } @@ -140,7 +140,9 @@ class ModelSubscriptions extends RocketChat.models._Base { } getLastSeen(options) { - if (options == null) { options = {}; } + if (options == null) { + options = {}; + } const query = { ls: { $exists: 1 } }; options.sort = { ls: -1 }; options.limit = 1; @@ -198,7 +200,7 @@ class ModelSubscriptions extends RocketChat.models._Base { // UPDATE archiveByRoomId(roomId) { const query = - {rid: roomId}; + { rid: roomId }; const update = { $set: { @@ -213,7 +215,7 @@ class ModelSubscriptions extends RocketChat.models._Base { unarchiveByRoomId(roomId) { const query = - {rid: roomId}; + { rid: roomId }; const update = { $set: { @@ -311,7 +313,9 @@ class ModelSubscriptions extends RocketChat.models._Base { } setFavoriteByRoomIdAndUserId(roomId, userId, favorite) { - if (favorite == null) { favorite = true; } + if (favorite == null) { + favorite = true; + } const query = { rid: roomId, 'u._id': userId @@ -328,7 +332,7 @@ class ModelSubscriptions extends RocketChat.models._Base { updateNameAndAlertByRoomId(roomId, name, fname) { const query = - {rid: roomId}; + { rid: roomId }; const update = { $set: { @@ -343,7 +347,7 @@ class ModelSubscriptions extends RocketChat.models._Base { updateNameByRoomId(roomId, name) { const query = - {rid: roomId}; + { rid: roomId }; const update = { $set: { @@ -356,7 +360,7 @@ class ModelSubscriptions extends RocketChat.models._Base { setUserUsernameByUserId(userId, username) { const query = - {'u._id': userId}; + { 'u._id': userId }; const update = { $set: { @@ -383,7 +387,9 @@ class ModelSubscriptions extends RocketChat.models._Base { } incUnreadForRoomIdExcludingUserId(roomId, userId, inc) { - if (inc == null) { inc = 1; } + if (inc == null) { + inc = 1; + } const query = { rid: roomId, 'u._id': { @@ -447,6 +453,7 @@ class ModelSubscriptions extends RocketChat.models._Base { return this.update(query, update, { multi: true }); } + setAlertForRoomIdExcludingUserId(roomId, userId) { const query = { rid: roomId, @@ -522,7 +529,7 @@ class ModelSubscriptions extends RocketChat.models._Base { updateTypeByRoomId(roomId, type) { const query = - {rid: roomId}; + { rid: roomId }; const update = { $set: { @@ -535,7 +542,7 @@ class ModelSubscriptions extends RocketChat.models._Base { addRoleById(_id, role) { const query = - {_id}; + { _id }; const update = { $addToSet: { @@ -548,7 +555,7 @@ class ModelSubscriptions extends RocketChat.models._Base { removeRoleById(_id, role) { const query = - {_id}; + { _id }; const update = { $pull: { @@ -604,14 +611,14 @@ class ModelSubscriptions extends RocketChat.models._Base { // REMOVE removeByUserId(userId) { const query = - {'u._id': userId}; + { 'u._id': userId }; return this.remove(query); } removeByRoomId(roomId) { const query = - {rid: roomId}; + { rid: roomId }; return this.remove(query); } diff --git a/packages/rocketchat-livechat/.app/client/views/messages.js b/packages/rocketchat-livechat/.app/client/views/messages.js index 9d298fa207cf..f27e7d00f2d3 100644 --- a/packages/rocketchat-livechat/.app/client/views/messages.js +++ b/packages/rocketchat-livechat/.app/client/views/messages.js @@ -79,7 +79,9 @@ Template.messages.helpers({ agentData.email = agent.emails[0].address; } - if (agent.customFields && agent.customFields.phone) { + if (agent.phone && agent.phone.length > 0) { + agentData.phone = agent.phone[0].phoneNumber; + } else if (agent.customFields && agent.customFields.phone) { agentData.phone = agent.customFields.phone; } diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index 65a8142a1b75..55f7c8799c07 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -167,6 +167,7 @@ RocketChat.models.Users.getAgentInfo = function(agentId) { fields: { name: 1, username: 1, + phone: 1, customFields: 1 } }; diff --git a/packages/rocketchat-push-notifications/server/methods/saveNotificationSettings.js b/packages/rocketchat-push-notifications/server/methods/saveNotificationSettings.js index 365d0b3f6c52..1bf4ec2ac844 100644 --- a/packages/rocketchat-push-notifications/server/methods/saveNotificationSettings.js +++ b/packages/rocketchat-push-notifications/server/methods/saveNotificationSettings.js @@ -1,49 +1,59 @@ Meteor.methods({ - saveNotificationSettings(rid, field, value) { + saveNotificationSettings(roomId, field, value) { if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'saveNotificationSettings' }); } - - check(rid, String); + check(roomId, String); check(field, String); check(value, String); - if (['audioNotifications', 'desktopNotifications', 'mobilePushNotifications', 'emailNotifications', 'unreadAlert', 'disableNotifications', 'hideUnreadStatus'].indexOf(field) === -1) { + const notifications = { + 'audioNotifications': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateAudioNotificationsById(subscription._id, value) + }, + 'desktopNotifications': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateDesktopNotificationsById(subscription._id, value) + }, + 'mobilePushNotifications': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateMobilePushNotificationsById(subscription._id, value) + }, + 'emailNotifications': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateEmailNotificationsById(subscription._id, value) + }, + 'unreadAlert': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateUnreadAlertById(subscription._id, value) + }, + 'disableNotifications': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateDisableNotificationsById(subscription._id, value === '1') + }, + 'hideUnreadStatus': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateHideUnreadStatusById(subscription._id, value === '1') + }, + 'desktopNotificationDuration': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateDesktopNotificationDurationById(subscription._id, value) + }, + 'audioNotificationValue': { + updateMethod: (subscription, value) => RocketChat.models.Subscriptions.updateAudioNotificationValueById(subscription._id, value) + } + }; + const isInvalidNotification = !Object.keys(notifications).includes(field); + const basicValuesForNotifications = ['all', 'mentions', 'nothing', 'default']; + const fieldsMustHaveBasicValues = ['emailNotifications', 'audioNotifications', 'mobilePushNotifications', 'desktopNotifications']; + + if (isInvalidNotification) { throw new Meteor.Error('error-invalid-settings', 'Invalid settings field', { method: 'saveNotificationSettings' }); } - if (field !== 'hideUnreadStatus' && field !== 'disableNotifications' && ['all', 'mentions', 'nothing', 'default'].indexOf(value) === -1) { + if (fieldsMustHaveBasicValues.includes(field) && !basicValuesForNotifications.includes(value)) { throw new Meteor.Error('error-invalid-settings', 'Invalid settings value', { method: 'saveNotificationSettings' }); } - const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(rid, Meteor.userId()); + const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, Meteor.userId()); if (!subscription) { throw new Meteor.Error('error-invalid-subscription', 'Invalid subscription', { method: 'saveNotificationSettings' }); } - switch (field) { - case 'audioNotifications': - RocketChat.models.Subscriptions.updateAudioNotificationsById(subscription._id, value); - break; - case 'desktopNotifications': - RocketChat.models.Subscriptions.updateDesktopNotificationsById(subscription._id, value); - break; - case 'mobilePushNotifications': - RocketChat.models.Subscriptions.updateMobilePushNotificationsById(subscription._id, value); - break; - case 'emailNotifications': - RocketChat.models.Subscriptions.updateEmailNotificationsById(subscription._id, value); - break; - case 'unreadAlert': - RocketChat.models.Subscriptions.updateUnreadAlertById(subscription._id, value); - break; - case 'disableNotifications': - RocketChat.models.Subscriptions.updateDisableNotificationsById(subscription._id, value === '1' ? true : false); - break; - case 'hideUnreadStatus': - RocketChat.models.Subscriptions.updateHideUnreadStatusById(subscription._id, value === '1' ? true : false); - break; - } + notifications[field].updateMethod(subscription, value); return true; }, diff --git a/packages/rocketchat-reactions/client/init.js b/packages/rocketchat-reactions/client/init.js index 040caa413e9a..115cb80b8266 100644 --- a/packages/rocketchat-reactions/client/init.js +++ b/packages/rocketchat-reactions/client/init.js @@ -45,13 +45,8 @@ Meteor.startup(function() { 'message-mobile' ], action(event) { - const data = Blaze.getData(event.currentTarget); - event.stopPropagation(); - - RocketChat.EmojiPicker.open(event.currentTarget, (emoji) => { - Meteor.call('setReaction', `:${ emoji }:`, data._arguments[1]._id); - }); + RocketChat.EmojiPicker.open(event.currentTarget, emoji => Meteor.call('setReaction', `:${ emoji }:`, this._arguments[1]._id)); }, condition(message) { const room = RocketChat.models.Rooms.findOne({ _id: message.rid }); diff --git a/packages/rocketchat-theme/client/imports/components/file-list.css b/packages/rocketchat-theme/client/imports/components/file-list.css new file mode 100644 index 000000000000..b2a7178a7d7f --- /dev/null +++ b/packages/rocketchat-theme/client/imports/components/file-list.css @@ -0,0 +1,3 @@ +.attachments__content .attachments__name { + overflow: unset; +} diff --git a/packages/rocketchat-theme/client/imports/components/popover.css b/packages/rocketchat-theme/client/imports/components/popover.css index d75c9f6685a7..dc0c207624a9 100644 --- a/packages/rocketchat-theme/client/imports/components/popover.css +++ b/packages/rocketchat-theme/client/imports/components/popover.css @@ -65,6 +65,13 @@ } } + &__content-scroll { + + .rc-popover__item { + display:block; + } + } + &__title { flex: 1; diff --git a/packages/rocketchat-theme/client/imports/forms/switch.css b/packages/rocketchat-theme/client/imports/forms/switch.css index bbed3cf53909..503f7cceb0c7 100644 --- a/packages/rocketchat-theme/client/imports/forms/switch.css +++ b/packages/rocketchat-theme/client/imports/forms/switch.css @@ -18,7 +18,7 @@ & .rc-switch__input { &:checked { & + .rc-switch__button { - border-color: #1757B7; + border-color: var(--button-primary-background); background-color: var(--button-primary-background); } } diff --git a/packages/rocketchat-theme/client/imports/general/base_old.css b/packages/rocketchat-theme/client/imports/general/base_old.css index 50df7449b4c6..6ec7acebce0b 100644 --- a/packages/rocketchat-theme/client/imports/general/base_old.css +++ b/packages/rocketchat-theme/client/imports/general/base_old.css @@ -2608,6 +2608,44 @@ position: relative; } +.rc-old .rc-message-box .reply-preview { + display: flex; + position: relative; + background-color:#fff; + padding-left: 15px; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + align-items: center; + justify-content: space-between; +} + +.rc-old .rc-message-box .reply-preview-with-popup { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 5px; + border-bottom-left-radius: 5px; + box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2), 0 1px 1px rgba(0, 0, 0, 0.16);; +} + +.rc-old .reply-preview .cancel-reply { + padding: 10px; +} + +.rc-old .reply-preview .mention-link.mention-link-all { + color: #fff; +} + +.rc-old .reply-preview .mention-link.mention-link-me { + color: #fff; +} + +.rc-old .message-popup.popup-with-reply-preview { + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + .rc-old .message-popup { position: absolute; z-index: 101; diff --git a/packages/rocketchat-theme/client/main.css b/packages/rocketchat-theme/client/main.css index ad0867b2a50d..95577ddd1e4b 100644 --- a/packages/rocketchat-theme/client/main.css +++ b/packages/rocketchat-theme/client/main.css @@ -42,6 +42,7 @@ @import 'imports/components/contextual-bar.css'; @import 'imports/components/emojiPicker.css'; @import 'imports/components/table.css'; +@import 'imports/components/file-list.css'; /* Modal */ @import 'imports/components/modal/full-modal.css'; diff --git a/packages/rocketchat-ui-flextab/client/tabs/userInfo.html b/packages/rocketchat-ui-flextab/client/tabs/userInfo.html index 538d89b12a6e..4a8691bc2090 100644 --- a/packages/rocketchat-ui-flextab/client/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/client/tabs/userInfo.html @@ -25,6 +25,10 @@

{{_ "User_Info"}}

{{name}}

{{#if username}}

@{{username}}

{{/if}} + +
+
{{userStatus}}
+
diff --git a/packages/rocketchat-ui-flextab/client/tabs/userInfo.js b/packages/rocketchat-ui-flextab/client/tabs/userInfo.js index 895f0a984a96..25fa6d560315 100644 --- a/packages/rocketchat-ui-flextab/client/tabs/userInfo.js +++ b/packages/rocketchat-ui-flextab/client/tabs/userInfo.js @@ -62,6 +62,12 @@ Template.userInfo.helpers({ return user && user.username; }, + userStatus() { + const user = Template.instance().user.get(); + const userStatus = Session.get(`user_${ user.username }_status`); + return userStatus; + }, + email() { const user = Template.instance().user.get(); return user && user.emails && user.emails[0] && user.emails[0].address; diff --git a/packages/rocketchat-ui-message/client/messageBox.html b/packages/rocketchat-ui-message/client/messageBox.html index 37ec7b476fd0..141e31336f1b 100644 --- a/packages/rocketchat-ui-message/client/messageBox.html +++ b/packages/rocketchat-ui-message/client/messageBox.html @@ -21,6 +21,16 @@ {{/with}} {{#if allowedToSend}} {{> messagePopupConfig getPopupConfig}} + {{#if dataReply}} + {{#with dataReply}} +
+ {{> messageAttachment text=msg author_name=u.username}} +
+ {{> icon block="rc-input__icon-svg" icon="cross"}} +
+
+ {{/with}} + {{/if}}