diff --git a/packages/rocketchat-api/server/v1/groups.js b/packages/rocketchat-api/server/v1/groups.js index 73fa7d3cc1133..ffeb3cf4434a3 100644 --- a/packages/rocketchat-api/server/v1/groups.js +++ b/packages/rocketchat-api/server/v1/groups.js @@ -348,16 +348,24 @@ RocketChat.API.v1.addRoute('groups.info', { authRequired: true }, { RocketChat.API.v1.addRoute('groups.invite', { authRequired: true }, { post() { - const findResult = findPrivateGroupByIdOrName({ params: this.requestParams(), userId: this.userId }); + const { roomId = '', roomName = '' } = this.requestParams(); + const idOrName = roomId || roomName; + if (!idOrName.trim()) { + throw new Meteor.Error('error-room-param-not-provided', 'The parameter "roomId" or "roomName" is required'); + } - const user = this.getUserFromParams(); + const { _id: rid, t: type } = RocketChat.models.Rooms.findOneByIdOrName(idOrName) || {}; - Meteor.runAsUser(this.userId, () => { - Meteor.call('addUserToRoom', { rid: findResult.rid, username: user.username }); - }); + if (!rid || type !== 'p') { + throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group'); + } + + const { username } = this.getUserFromParams(); + + Meteor.runAsUser(this.userId, () => Meteor.call('addUserToRoom', { rid, username })); return RocketChat.API.v1.success({ - group: RocketChat.models.Rooms.findOneById(findResult.rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }) + group: RocketChat.models.Rooms.findOneById(rid, { fields: RocketChat.API.v1.defaultFieldsToExclude }) }); } }); diff --git a/packages/rocketchat-assets/server/assets.js b/packages/rocketchat-assets/server/assets.js index 297efb79ea473..9d2892b1586b8 100644 --- a/packages/rocketchat-assets/server/assets.js +++ b/packages/rocketchat-assets/server/assets.js @@ -396,7 +396,7 @@ Meteor.methods({ const hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'manage-assets'); if (!hasPermission) { - throw new Meteor.Error('error-action-now-allowed', 'Managing assets not allowed', { + throw new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', { method: 'refreshClients', action: 'Managing_assets' }); @@ -414,7 +414,7 @@ Meteor.methods({ const hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'manage-assets'); if (!hasPermission) { - throw new Meteor.Error('error-action-now-allowed', 'Managing assets not allowed', { + throw new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', { method: 'unsetAsset', action: 'Managing_assets' }); @@ -432,7 +432,7 @@ Meteor.methods({ const hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'manage-assets'); if (!hasPermission) { - throw new Meteor.Error('error-action-now-allowed', 'Managing assets not allowed', { + throw new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', { method: 'setAsset', action: 'Managing_assets' }); diff --git a/packages/rocketchat-autotranslate/server/methods/getSupportedLanguages.js b/packages/rocketchat-autotranslate/server/methods/getSupportedLanguages.js index 841a30268f854..e312e6ed51cae 100644 --- a/packages/rocketchat-autotranslate/server/methods/getSupportedLanguages.js +++ b/packages/rocketchat-autotranslate/server/methods/getSupportedLanguages.js @@ -1,7 +1,7 @@ Meteor.methods({ 'autoTranslate.getSupportedLanguages'(targetLanguage) { if (!RocketChat.authz.hasPermission(Meteor.userId(), 'auto-translate')) { - throw new Meteor.Error('error-action-now-allowed', 'Auto-Translate is not allowed', { method: 'autoTranslate.saveSettings'}); + throw new Meteor.Error('error-action-not-allowed', 'Auto-Translate is not allowed', { method: 'autoTranslate.saveSettings'}); } return RocketChat.AutoTranslate.getSupportedLanguages(targetLanguage); diff --git a/packages/rocketchat-autotranslate/server/methods/saveSettings.js b/packages/rocketchat-autotranslate/server/methods/saveSettings.js index 1030436bcddad..e9ed6dd6fb574 100644 --- a/packages/rocketchat-autotranslate/server/methods/saveSettings.js +++ b/packages/rocketchat-autotranslate/server/methods/saveSettings.js @@ -5,7 +5,7 @@ Meteor.methods({ } if (!RocketChat.authz.hasPermission(Meteor.userId(), 'auto-translate')) { - throw new Meteor.Error('error-action-now-allowed', 'Auto-Translate is not allowed', { method: 'autoTranslate.saveSettings'}); + throw new Meteor.Error('error-action-not-allowed', 'Auto-Translate is not allowed', { method: 'autoTranslate.saveSettings'}); } check(rid, String); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 46d3aebac22a0..8b65d06cd259c 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -534,6 +534,7 @@ "Common_Access": "Common Access", "Community": "Community", "Compact": "Compact", + "Condensed": "Condensed", "Computer": "Computer", "Confirm_password": "Confirm your password", "Consulting": "Consulting", @@ -1063,7 +1064,9 @@ "error-remove-last-owner": "This is the last owner. Please set a new owner before removing this one.", "error-role-in-use": "Cannot delete role because it's in use", "error-role-name-required": "Role name is required", + "error-room-is-not-closed": "Room is not closed", "error-the-field-is-required": "The field __field__ is required.", + "error-this-is-not-a-livechat-room": "This is not a Livechat room", "error-too-many-requests": "Error, too many requests. Please slow down. You must wait __seconds__ seconds before trying again.", "error-user-has-no-roles": "User has no roles", "error-user-is-not-activated": "User is not activated", @@ -1652,6 +1655,7 @@ "Markdown_SupportSchemesForLink_Description": "Comma-separated list of allowed schemes", "Max_length_is": "Max length is %s", "Media": "Media", + "Medium": "Medium", "Members_List": "Members List", "mention-all": "Mention All", "mention-all_description": "Permission to use the @all mention", diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index 30e1105566fd9..3c33b5ba9d8c9 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -1059,7 +1059,9 @@ "error-remove-last-owner": "Este é o último proprietário. Por favor, defina um novo proprietário antes de remover este.", "error-role-in-use": "Não é possível remover o papel pois ele está em uso", "error-role-name-required": "Nome do papel é obrigatório", + "error-room-is-not-closed": "Sala não está fechada", "error-the-field-is-required": "O campo __field__ é obrigatório.", + "error-this-is-not-a-livechat-room": "Esta não é uma sala de Livechat", "error-too-many-requests": "Erro, muitas solicitações. Por favor, diminua a velocidade. Você deve esperar __seconds__ segundos antes de tentar novamente.", "error-user-has-no-roles": "O usuário não possui permissões", "error-user-is-not-activated": "O usuário não está ativo", diff --git a/packages/rocketchat-i18n/i18n/pt.i18n.json b/packages/rocketchat-i18n/i18n/pt.i18n.json index bf32a1263dd1e..598fdcd3af063 100644 --- a/packages/rocketchat-i18n/i18n/pt.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt.i18n.json @@ -1059,7 +1059,9 @@ "error-remove-last-owner": "Este é o último proprietário. Por favor, defina um novo proprietário antes de remover este.", "error-role-in-use": "Não é possível remover o papel pois ele está em uso", "error-role-name-required": "Nome do papel é obrigatório", + "error-room-is-not-closed": "Sala não está fechada", "error-the-field-is-required": "O campo __field__ é obrigatório.", + "error-this-is-not-a-livechat-room": "Esta não é uma sala de Livechat", "error-too-many-requests": "Erro, muitas solicitações. Por favor, diminua a velocidade. Você deve esperar __seconds__ segundos antes de tentar novamente.", "error-user-has-no-roles": "O usuário não possui papéis", "error-user-is-not-activated": "O usuário não está ativo", diff --git a/packages/rocketchat-i18n/i18n/ru.i18n.json b/packages/rocketchat-i18n/i18n/ru.i18n.json index 4dd9294a89692..1430a6287bf28 100644 --- a/packages/rocketchat-i18n/i18n/ru.i18n.json +++ b/packages/rocketchat-i18n/i18n/ru.i18n.json @@ -181,7 +181,7 @@ "Accounts_UserAddedEmail_Description": "Вы можете использовать следующие подстановки:
", "Accounts_UserAddedEmailSubject_Default": "Вы были добавлены в [Site_Name]", "Activate": "Активировать", - "Activity": "Активность", + "Activity": "По активности", "Add": "Добавить", "add-oauth-service": "Добавить сервис Oauth", "add-oauth-service_description": "Разрешение на добавление новых сервисов Oauth", @@ -533,6 +533,7 @@ "Community": "Сообщество", "Compact": "Компактный", "Computer": "Компьютер", + "Condensed": "Компактный", "Confirm_password": "Подтвердить пароль", "Consulting": "Консалтинг", "Consumer_Goods": "Потребительские товары", @@ -1235,6 +1236,7 @@ "Idle_Time_Limit": "Предел времени ожидания", "Idle_Time_Limit_Description": "Период времени, пока статус не изменится. Значение должно быть в секундах.", "If_this_email_is_registered": "Если этот адрес электронной почты зарегистрирован, мы отправим на него инструкцию по сбросу пароля. Если вы не получили электронное сообщение, попробуйте снова позже.", + "Idle_Time_Limit": "Время ожидания", "If_you_are_sure_type_in_your_password": "Если вы уверены, введите пароль:", "If_you_are_sure_type_in_your_username": "Если вы уверены, введите ваш логин:", "If_you_dont_have_one_send_an_email_to_omni_rocketchat_to_get_yours": "Если у вас нет одного, отправьте электронное сообщение на адрес [omni@rocket.chat] (mailto: omni@rocket.chat), чтобы получить свой.", @@ -1632,6 +1634,7 @@ "Markdown_SupportSchemesForLink_Description": "Разрешённые Markdown системы через запятую", "Max_length_is": "Максимальная длина %s", "Media": "СМИ", + "Medium": "Обычный", "Members_List": "Пользователи", "mention-all": "Упоминать всех", "mention-all_description": "Разрешение на использование упоминания @all", @@ -2024,7 +2027,7 @@ "Require_all_tokens": "Требовать все токены", "Require_any_token": "Требовать любой токен", "Require_password_change": "Требуется смена пароля", - "Resend_verification_email": "Отправить проверочное электронное письмо ещё раз", + "Resend_verification_email": "Отправить проверочный e-mail снова", "Reset": "Восстановить", "Reset_password": "Восстановить пароль", "Reset_section_settings": "Восстановить значения по умолчанию", @@ -2184,7 +2187,7 @@ "Show_only_online": "Показать только подключенных", "Show_preregistration_form": "Показать предварительную регистрационную форму", "Show_queue_list_to_all_agents": "Показывать список очередей всем представителям", - "Show_room_counter_on_sidebar": "Показывать число комнат на боковой панели", + "Show_room_counter_on_sidebar": "Показывать количество чатов на боковой панели", "Show_the_keyboard_shortcut_list": "Показывать список горячих клавиш", "Showing_archived_results": "

Показано %s архивных результатов

", "Showing_online_users": "Показано: __total_showing__. Подключенных: __online__. Всего: __total__ пользователей", @@ -2450,7 +2453,7 @@ "Unread_Count": "Количество непрочитанных", "Unread_Count_DM": "Количество непрочитанных сообщений для личных переписки", "Unread_Messages": "Непрочитанные сообщения", - "Unread_on_top": "Непрочитанное наверх", + "Unread_on_top" : "Непрочитанные сверху", "Unread_Rooms": "Непрочитанные комнаты", "Unread_Rooms_Mode": "Режим непрочитанные комнаты", "Unread_Tray_Icon_Alert": "Иконка уведомлений о непрочитанных сообщениях в трее", diff --git a/packages/rocketchat-lib/server/functions/sendMessage.js b/packages/rocketchat-lib/server/functions/sendMessage.js index 89c58881ac175..321d085641f02 100644 --- a/packages/rocketchat-lib/server/functions/sendMessage.js +++ b/packages/rocketchat-lib/server/functions/sendMessage.js @@ -20,7 +20,7 @@ const validateAttachmentsFields = attachmentFields => { short: Boolean })); - check(attachmentFields, Match.ObjectIncluding({ + check(attachmentFields, objectMaybeIncluding({ title: String, value: String })); @@ -30,7 +30,7 @@ const validateAttachment = attachment => { check(attachment, objectMaybeIncluding({ color: String, text: String, - ts: String, + ts: Match.OneOf(String, Match.Integer), thumb_url: String, message_link: String, collapsed: Boolean, diff --git a/packages/rocketchat-lib/server/lib/metrics.js b/packages/rocketchat-lib/server/lib/metrics.js index 364d19c238596..1ee228dcda3cd 100644 --- a/packages/rocketchat-lib/server/lib/metrics.js +++ b/packages/rocketchat-lib/server/lib/metrics.js @@ -147,7 +147,7 @@ let timer; RocketChat.settings.get('Prometheus_Enabled', (key, value) => { if (value === true) { server.listen({ - port: 9100, + port: RocketChat.settings.get('Prometheus_Port'), host: process.env.BIND_IP || '0.0.0.0' }); timer = Meteor.setInterval(setPrometheusData, 5000); diff --git a/packages/rocketchat-lib/server/startup/settings.js b/packages/rocketchat-lib/server/startup/settings.js index e2a11e42e8f69..b32e470a5bd9a 100644 --- a/packages/rocketchat-lib/server/startup/settings.js +++ b/packages/rocketchat-lib/server/startup/settings.js @@ -1714,6 +1714,10 @@ RocketChat.settings.addGroup('Logs', function() { type: 'boolean', i18nLabel: 'Enabled' }); + this.add('Prometheus_Port', 9100, { + type: 'string', + i18nLabel: 'Port' + }); }); }); diff --git a/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.html b/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.html index 6e3dda88d2e17..4606ad8e4f095 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.html +++ b/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.html @@ -41,7 +41,8 @@ {{_ "Served_By"}} {{_ "Started_At"}} {{_ "Last_Message_At"}} - {{_ "Status"}} + {{_ "Status"}} +   @@ -52,6 +53,15 @@ {{startedAt}} {{lastMessage}} {{status}} + {{#requiresPermission 'remove-closed-livechat-rooms'}} + {{#if isClosed}} + + {{else}} +   + {{/if}} + {{else}} +   + {{/requiresPermission}} {{/each}} diff --git a/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.js b/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.js index 659784c4f33ad..f726f14381d26 100644 --- a/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.js +++ b/packages/rocketchat-livechat/client/views/app/livechatCurrentChats.js @@ -21,6 +21,9 @@ Template.livechatCurrentChats.helpers({ }, agents() { return AgentUsers.find({}, { sort: { name: 1 } }); + }, + isClosed() { + return !this.open; } }); @@ -55,6 +58,34 @@ Template.livechatCurrentChats.events({ instance.filter.set(filter); instance.limit.set(20); + }, + 'click .remove-livechat-room'(event) { + event.preventDefault(); + event.stopPropagation(); + + modal.open({ + title: t('Are_you_sure'), + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#DD6B55', + confirmButtonText: t('Yes'), + cancelButtonText: t('Cancel'), + closeOnConfirm: false, + html: false + }, () => { + Meteor.call('livechat:removeRoom', this._id, function(error/*, result*/) { + if (error) { + return handleError(error); + } + modal.open({ + title: t('Deleted'), + text: t('Room_has_been_deleted'), + type: 'success', + timer: 1000, + showConfirmButton: false + }); + }); + }); } }); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 537db759cac55..85745d4c6e9eb 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -160,6 +160,7 @@ Package.onUse(function(api) { api.addFiles('server/methods/removeDepartment.js', 'server'); api.addFiles('server/methods/removeManager.js', 'server'); api.addFiles('server/methods/removeTrigger.js', 'server'); + api.addFiles('server/methods/removeRoom.js', 'server'); api.addFiles('server/methods/saveAppearance.js', 'server'); api.addFiles('server/methods/saveCustomField.js', 'server'); api.addFiles('server/methods/saveDepartment.js', 'server'); diff --git a/packages/rocketchat-livechat/server/methods/removeRoom.js b/packages/rocketchat-livechat/server/methods/removeRoom.js new file mode 100644 index 0000000000000..a91f4309de7c3 --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/removeRoom.js @@ -0,0 +1,31 @@ +Meteor.methods({ + 'livechat:removeRoom'(rid) { + if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'remove-closed-livechat-rooms')) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeRoom' }); + } + + const room = RocketChat.models.Rooms.findOneById(rid); + + if (!room) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { + method: 'livechat:removeRoom' + }); + } + + if (room.t !== 'l') { + throw new Meteor.Error('error-this-is-not-a-livechat-room', 'This is not a Livechat room', { + method: 'livechat:removeRoom' + }); + } + + if (room.open) { + throw new Meteor.Error('error-room-is-not-closed', 'Room is not closed', { + method: 'livechat:removeRoom' + }); + } + + RocketChat.models.Messages.removeByRoomId(rid); + RocketChat.models.Subscriptions.removeByRoomId(rid); + return RocketChat.models.Rooms.removeById(rid); + } +}); diff --git a/packages/rocketchat-theme/client/imports/components/header.css b/packages/rocketchat-theme/client/imports/components/header.css index aa800c121d093..af2f21c43f1ad 100644 --- a/packages/rocketchat-theme/client/imports/components/header.css +++ b/packages/rocketchat-theme/client/imports/components/header.css @@ -278,6 +278,14 @@ font-size: 12px; font-weight: 600; } + & + & { + border-left: 1px var(--color-gray) solid; + + .rtl & { + border-left: 0; + border-right: 1px var(--color-gray) solid; + } + } } .tab-button-icon--star { diff --git a/packages/rocketchat-ui-flextab/client/flexTabBar.html b/packages/rocketchat-ui-flextab/client/flexTabBar.html index 40797a795322f..4db9b5f805af4 100644 --- a/packages/rocketchat-ui-flextab/client/flexTabBar.html +++ b/packages/rocketchat-ui-flextab/client/flexTabBar.html @@ -31,6 +31,17 @@

{{_ label}}