From d1f2f22cba2d1368294b20deae9e0010419e9c56 Mon Sep 17 00:00:00 2001 From: Nikhil Babu Date: Thu, 21 May 2020 00:30:26 +0530 Subject: [PATCH 01/30] [FIX] Elements of "Personal Access Tokens" section out of alignment and unusable on very small screens (#17129) --- app/theme/client/imports/general/base_old.css | 18 ++++++++++++++++++ .../client/personalAccessTokens.html | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/theme/client/imports/general/base_old.css b/app/theme/client/imports/general/base_old.css index d2b2ace62a9b..0773f4350b3f 100644 --- a/app/theme/client/imports/general/base_old.css +++ b/app/theme/client/imports/general/base_old.css @@ -1314,6 +1314,15 @@ border-bottom: none; } + & .add-token { + display: flex; + + & .rc-select { + width: 40%; + margin: 0 0 0 10px; + } + } + &:first-child { padding-top: 0; } @@ -4147,6 +4156,15 @@ display: none; } } + + .add-token { + display: block !important; + + & .rc-select { + width: auto !important; + margin: 10px 0 !important; + } + } } @media (width <= 500px) { diff --git a/imports/personal-access-tokens/client/personalAccessTokens.html b/imports/personal-access-tokens/client/personalAccessTokens.html index b0e790ecd1c5..9234ee6b4f53 100644 --- a/imports/personal-access-tokens/client/personalAccessTokens.html +++ b/imports/personal-access-tokens/client/personalAccessTokens.html @@ -8,7 +8,7 @@
-
+
@@ -20,8 +20,8 @@ {{> icon block="rc-select__arrow" icon="arrow-down"}}
+
-
From 96552f4fb986bd916e1746e78bf8b39e6be51672 Mon Sep 17 00:00:00 2001 From: ocanema Date: Wed, 20 May 2020 21:07:23 +0200 Subject: [PATCH 02/30] [NEW] Option to remove users from RocketChat if not found in Crowd (#17619) --- app/crowd/server/crowd.js | 8 ++++++++ app/crowd/server/settings.js | 1 + packages/rocketchat-i18n/i18n/en.i18n.json | 1 + packages/rocketchat-i18n/i18n/it.i18n.json | 3 ++- packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/crowd/server/crowd.js b/app/crowd/server/crowd.js index c91d2de399e4..6bbf95614358 100644 --- a/app/crowd/server/crowd.js +++ b/app/crowd/server/crowd.js @@ -9,6 +9,7 @@ import { _setRealName } from '../../lib'; import { Users } from '../../models'; import { settings } from '../../settings'; import { hasRole } from '../../authorization'; +import { deleteUser } from '../../lib/server/functions'; const logger = new Logger('CROWD', {}); @@ -203,6 +204,13 @@ export class CROWD { const response = self.crowdClient.searchSync('user', `email=" ${ email } "`); if (!response || response.users.length === 0) { logger.warn('Could not find user in CROWD with username or email:', crowd_username, email); + if (settings.get('CROWD_Remove_Orphaned_Users') === true) { + logger.info('Removing user:', crowd_username); + Meteor.defer(function() { + deleteUser(user._id); + logger.info('User removed:', crowd_username); + }); + } return; } crowd_username = response.users[0].name; diff --git a/app/crowd/server/settings.js b/app/crowd/server/settings.js index 29307d957a78..b58362967294 100644 --- a/app/crowd/server/settings.js +++ b/app/crowd/server/settings.js @@ -14,6 +14,7 @@ Meteor.startup(function() { this.add('CROWD_APP_PASSWORD', '', { type: 'password', enableQuery, i18nLabel: 'Password', secret: true }); this.add('CROWD_Sync_User_Data', false, { type: 'boolean', enableQuery, i18nLabel: 'Sync_Users' }); this.add('CROWD_Sync_Interval', 'Every 60 mins', { type: 'string', enableQuery: enableSyncQuery, i18nLabel: 'Sync_Interval', i18nDescription: 'Crowd_sync_interval_Description' }); + this.add('CROWD_Remove_Orphaned_Users', false, { type: 'boolean', public: true, i18nLabel: 'Crowd_Remove_Orphaned_Users' }); this.add('CROWD_Clean_Usernames', true, { type: 'boolean', enableQuery, i18nLabel: 'Clean_Usernames', i18nDescription: 'Crowd_clean_usernames_Description' }); this.add('CROWD_Allow_Custom_Username', true, { type: 'boolean', i18nLabel: 'CROWD_Allow_Custom_Username' }); this.add('CROWD_Test_Connection', 'crowd_test_connection', { type: 'action', actionText: 'Test_Connection', i18nLabel: 'Test_Connection' }); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 359c65494b51..c96c4f31b643 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1045,6 +1045,7 @@ "CRM_Integration": "CRM Integration", "CROWD_Allow_Custom_Username": "Allow custom username in Rocket.Chat", "CROWD_Reject_Unauthorized": "Reject Unauthorized", + "Crowd_Remove_Orphaned_Users": "Remove Orphaned Users", "Crowd_sync_interval_Description": "The interval between synchronizations. Example `every 24 hours` or `on the first day of the week`, more examples at [Cron Text Parser](http://bunkat.github.io/later/parsers.html#text)", "Current_Chats": "Current Chats", "Current_File": "Current File", diff --git a/packages/rocketchat-i18n/i18n/it.i18n.json b/packages/rocketchat-i18n/i18n/it.i18n.json index cf93796c15a2..7c96af8a2699 100644 --- a/packages/rocketchat-i18n/i18n/it.i18n.json +++ b/packages/rocketchat-i18n/i18n/it.i18n.json @@ -831,6 +831,7 @@ "Created_at_s_by_s_triggered_by_s": "Creato alle %s da %s scatenato da %s", "CRM_Integration": "Integrazione CRM", "CROWD_Reject_Unauthorized": "Rifiuta non autorizzati", + "Crowd_Remove_Orphaned_Users": "Rimuovi utenti orfani", "Crowd_sync_interval_Description": "L'intervallo tra le sincronizzazioni. Esempio \"ogni 24 ore\" o \"il primo giorno della settimana\", altri esempi su [Cron Text Parser] (http://bunkat.github.io/later/parsers.html#text)", "Current_Chats": "Chat attuali", "Current_Status": "Stato attuale", @@ -2888,4 +2889,4 @@ "Your_push_was_sent_to_s_devices": "La tua richiesta è stata inviata ai %s dispositivi.", "Your_server_link": "Il tuo collegamento al server", "Your_workspace_is_ready": "Il tuo spazio di lavoro è pronto per l'uso 🎉" -} \ No newline at end of file +} diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index 81d4439d78a9..be8eea22939f 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -1000,6 +1000,7 @@ "CRM_Integration": "Integração de CRM", "CROWD_Allow_Custom_Username": "Permitir nome de usuário personalizado no Rocket.Chat", "CROWD_Reject_Unauthorized": "Rejeitar não autorizado", + "Crowd_Remove_Orphaned_Users": "Remover usuários órfãos", "Crowd_sync_interval_Description": "O intervalo entre as sincronizações. Exemplo de \"todas as 24 horas\" ou \"no primeiro dia da semana\", mais exemplos em [Cron Text Parser] (http://bunkat.github.io/later/parsers.html#text)", "Current_Chats": "Bate-papos atuais", "Current_File": "Arquivo atual", From 239e35530aa33b041bb0a48e2c8a8298930c37ba Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 20 May 2020 16:55:34 -0300 Subject: [PATCH 03/30] [IMPROVE] Display status information in the Omnichannel Agents list (#17701) --- app/livechat/client/views/app/livechatAgents.html | 10 +++++++--- app/livechat/client/views/app/livechatAgents.js | 4 ++++ packages/rocketchat-i18n/i18n/en.i18n.json | 1 + packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/livechat/client/views/app/livechatAgents.html b/app/livechat/client/views/app/livechatAgents.html index bb57a86497e9..a32d04763b89 100644 --- a/app/livechat/client/views/app/livechatAgents.html +++ b/app/livechat/client/views/app/livechatAgents.html @@ -51,9 +51,11 @@ {{#table fixed='true' onScroll=onTableScroll}} -
{{_ "Name"}}
-
{{_ "Username"}}
-
{{_ "Email"}}
+
{{_ "Name"}}
+
{{_ "Username"}}
+
{{_ "Email"}}
+
{{_ "Status"}}
+
{{_ "Service"}}
 
@@ -79,6 +81,8 @@ {{username}} {{emailAddress}} + {{status}} + {{statusService}} diff --git a/app/livechat/client/views/app/livechatAgents.js b/app/livechat/client/views/app/livechatAgents.js index 56c45da892ae..af3b68b88854 100644 --- a/app/livechat/client/views/app/livechatAgents.js +++ b/app/livechat/client/views/app/livechatAgents.js @@ -90,6 +90,10 @@ Template.livechatAgents.helpers({ data: Template.instance().tabBarData.get(), }; }, + statusService() { + const { status, statusLivechat } = this; + return statusLivechat === 'available' && status !== 'offline' ? t('Available') : t('Unavailable'); + }, }); const DEBOUNCE_TIME_FOR_SEARCH_AGENTS_IN_MS = 300; diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index c96c4f31b643..4fb371d1b723 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3480,6 +3480,7 @@ "Unarchive": "Unarchive", "unarchive-room": "Unarchive Room", "unarchive-room_description": "Permission to unarchive channels", + "Unavailable": "Unavailable", "Unblock_User": "Unblock User", "Uncheck_All": "Uncheck All", "Undefined": "Undefined", diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index be8eea22939f..f4bdd6bf0d33 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -3123,6 +3123,7 @@ "Unarchive": "Desarquivar", "unarchive-room": "Desarquivar Sala", "unarchive-room_description": "Permissão para desarchivar canais", + "Unavailable": "Indisponível", "Unblock_User": "Desbloquear Usuário", "Undefined": "Não definido", "Unfavorite": "Remover dos Favoritos", From c5016cf2903b252267fd16a6d78d407e9ca9607b Mon Sep 17 00:00:00 2001 From: huzaifahj <52999758+huzaifahj@users.noreply.github.com> Date: Wed, 20 May 2020 23:20:18 +0100 Subject: [PATCH 04/30] Fix typo "You aren't part of any channel yet" (#17498) --- packages/rocketchat-i18n/i18n/en.i18n.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 4fb371d1b723..bc44d4921e89 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -2500,7 +2500,7 @@ "No_Limit": "No Limit", "No_available_agents_to_transfer": "No available agents to transfer", "No_channel_with_name_%s_was_found": "No channel with name \"%s\" was found!", - "No_channels_yet": "You aren't part of any channel yet", + "No_channels_yet": "You aren't part of any channels yet", "No_direct_messages_yet": "No Direct Messages.", "No_emojis_found": "No emojis found", "No_Encryption": "No Encryption", @@ -3815,4 +3815,4 @@ "Your_server_link": "Your server link", "Your_temporary_password_is_password": "Your temporary password is [password].", "Your_workspace_is_ready": "Your workspace is ready to use 🎉" -} \ No newline at end of file +} From 550d08a6e95c0a5e88601392dfac364f2387d714 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 20 May 2020 19:28:41 -0300 Subject: [PATCH 05/30] [NEW] API endpoint to fetch Omnichannel's room transfer history (#17694) --- app/livechat/server/api/lib/transfer.js | 27 +++++++++++++++++++ app/livechat/server/api/rest.js | 1 + app/livechat/server/api/v1/transfer.js | 36 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 app/livechat/server/api/lib/transfer.js create mode 100644 app/livechat/server/api/v1/transfer.js diff --git a/app/livechat/server/api/lib/transfer.js b/app/livechat/server/api/lib/transfer.js new file mode 100644 index 000000000000..60070dfc2645 --- /dev/null +++ b/app/livechat/server/api/lib/transfer.js @@ -0,0 +1,27 @@ +import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; +import { Messages } from '../../../../models/server/raw'; + +const normalizeTransferHistory = ({ transferData }) => transferData; +export async function findLivechatTransferHistory({ userId, rid, pagination: { offset, count, sort } }) { + if (!await hasPermissionAsync(userId, 'view-livechat-rooms')) { + throw new Error('error-not-authorized'); + } + + const cursor = await Messages.find({ rid, t: 'livechat_transfer_history' }, { + fields: { transferData: 1 }, + sort: sort || { ts: 1 }, + skip: offset, + limit: count, + }); + + const total = await cursor.count(); + const messages = await cursor.toArray(); + const history = messages.map(normalizeTransferHistory); + + return { + history, + count: history.length, + offset, + total, + }; +} diff --git a/app/livechat/server/api/rest.js b/app/livechat/server/api/rest.js index 3731e72f6b63..a63794bf1db0 100644 --- a/app/livechat/server/api/rest.js +++ b/app/livechat/server/api/rest.js @@ -8,3 +8,4 @@ import './v1/message.js'; import './v1/customField.js'; import './v1/room.js'; import './v1/videoCall.js'; +import './v1/transfer.js'; diff --git a/app/livechat/server/api/v1/transfer.js b/app/livechat/server/api/v1/transfer.js new file mode 100644 index 000000000000..e38277d5529d --- /dev/null +++ b/app/livechat/server/api/v1/transfer.js @@ -0,0 +1,36 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; + +import { LivechatRooms } from '../../../../models'; +import { API } from '../../../../api'; +import { findLivechatTransferHistory } from '../lib/transfer'; + +API.v1.addRoute('livechat/transfer.history/:rid', { authRequired: true }, { + get() { + check(this.urlParams, { + rid: String, + }); + + const { rid } = this.urlParams; + + const room = LivechatRooms.findOneById(rid, { _id: 1 }); + if (!room) { + throw new Meteor.Error('invalid-room'); + } + + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + + const history = Promise.await(findLivechatTransferHistory({ + userId: this.userId, + rid, + pagination: { + offset, + count, + sort, + }, + })); + + return API.v1.success(history); + }, +}); From 74f087da708b335ffbbe36008d847359ac172b72 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Wed, 20 May 2020 19:30:42 -0300 Subject: [PATCH 06/30] [IMPROVE] Always shows the exact match first on user's and room's autocomplete for mentions and on sidebar search (#16394) --- app/ui-sidenav/client/toolbar.js | 24 +++++++++++++++++++----- server/publications/spotlight.js | 17 ++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/app/ui-sidenav/client/toolbar.js b/app/ui-sidenav/client/toolbar.js index 97b11cfa24f6..3c59a62a7496 100644 --- a/app/ui-sidenav/client/toolbar.js +++ b/app/ui-sidenav/client/toolbar.js @@ -35,19 +35,33 @@ const getFromServer = (cb, type) => { return false; } + let exactUser = null; + let exactRoom = null; + if (results.users[0] && results.users[0].username === currentFilter) { + exactUser = results.users.shift(); + } + if (results.rooms[0] && results.rooms[0].username === currentFilter) { + exactRoom = results.rooms.shift(); + } + const resultsFromServer = []; - resultsFromServer.push(...results.users.map((user) => ({ + const roomFilter = (room) => !resultsFromClient.find((item) => [item.rid, item._id].includes(room._id)); + const userMap = (user) => ({ _id: user._id, t: 'd', name: user.username, fname: user.name, - }))); + }); - resultsFromServer.push(...results.rooms.filter((room) => !resultsFromClient.find((item) => [item.rid, item._id].includes(room._id)))); + resultsFromServer.push(...results.users.map(userMap)); + resultsFromServer.push(...results.rooms.filter(roomFilter)); - if (resultsFromServer.length) { - cb(resultsFromClient.concat(resultsFromServer)); + if (resultsFromServer.length || exactUser || exactRoom) { + exactRoom = exactRoom ? [roomFilter(exactRoom)] : []; + exactUser = exactUser ? [userMap(exactUser)] : []; + const combinedResults = exactUser.concat(exactRoom, resultsFromClient, resultsFromServer); + cb(combinedResults); } }); }; diff --git a/server/publications/spotlight.js b/server/publications/spotlight.js index 0da321b49dfd..702ed843d139 100644 --- a/server/publications/spotlight.js +++ b/server/publications/spotlight.js @@ -19,7 +19,7 @@ function fetchRooms(userId, rooms) { } Meteor.methods({ - spotlight(text, usernames, type = { users: true, rooms: true }, rid) { + spotlight(text, usernames = [], type = { users: true, rooms: true }, rid) { const searchForChannels = text[0] === '#'; const searchForDMs = text[0] === '@'; if (searchForChannels) { @@ -72,7 +72,12 @@ Meteor.methods({ if (hasPermission(userId, 'view-outside-room')) { if (type.users === true && hasPermission(userId, 'view-d-room')) { - result.users = Users.findByActiveUsersExcept(text, usernames, userOptions).fetch(); + const exactUser = Users.findOneByUsernameIgnoringCase(text, userOptions); + if (exactUser && !usernames.includes(exactUser.username)) { + result.users.push(exactUser); + usernames.push(exactUser.username); + } + result.users = result.users.concat(Users.findByActiveUsersExcept(text, usernames, userOptions).fetch()); } if (type.rooms === true && hasPermission(userId, 'view-c-room')) { @@ -81,7 +86,13 @@ Meteor.methods({ .map((roomType) => roomType[0]); const roomIds = Subscriptions.findByUserIdAndTypes(userId, searchableRoomTypes, { fields: { rid: 1 } }).fetch().map((s) => s.rid); - result.rooms = fetchRooms(userId, Rooms.findByNameAndTypesNotInIds(regex, searchableRoomTypes, roomIds, roomOptions).fetch()); + const exactRoom = Rooms.findOneByNameAndType(text, searchableRoomTypes, roomOptions); + if (exactRoom) { + result.exactRoom.push(exactRoom); + roomIds.push(exactRoom.rid); + } + + result.rooms = result.rooms.concat(fetchRooms(userId, Rooms.findByNameAndTypesNotInIds(regex, searchableRoomTypes, roomIds, roomOptions).fetch())); } } else if (type.users === true && rid) { const subscriptions = Subscriptions.find({ From 9029d830fb416696413a09b5077ec16633d35316 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Wed, 20 May 2020 19:41:36 -0300 Subject: [PATCH 07/30] Regression: Click to join button not working (#17705) --- app/action-links/client/init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/action-links/client/init.js b/app/action-links/client/init.js index 2865be4279c9..64b3fc4acb4c 100644 --- a/app/action-links/client/init.js +++ b/app/action-links/client/init.js @@ -8,7 +8,7 @@ import { actionLinks } from '../both/lib/actionLinks'; Template.room.events({ - 'click .action-link'(event, instance) { + 'click [data-actionlink]'(event, instance) { event.preventDefault(); event.stopPropagation(); From 0ab84649877e8feaf5395a89ef281701226317e5 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Wed, 20 May 2020 20:52:48 -0300 Subject: [PATCH 08/30] Update Apps-Engine version (#17706) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7d72f3451d7f..9ec9af78bac7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2797,9 +2797,9 @@ } }, "@rocket.chat/apps-engine": { - "version": "1.15.0-alpha.3394", - "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.15.0-alpha.3394.tgz", - "integrity": "sha512-f1ZrVHqxQS4C/jaM4ES8JIzVU1zgHNGEMuxXVMT1wbk1NnMt40Uw2fEWYV7Ijy3ttEJ35ekMSSV+3ctunsyq1A==", + "version": "1.15.0-beta.3411", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.15.0-beta.3411.tgz", + "integrity": "sha512-e1ddaAfjWXWGyb2tlW8eZHgg6sBHN73n52i8b62GfqSJtf1cIM9VhLA4igq8Anaai5UtcxmmhdAQgmt0xhnNuw==", "requires": { "adm-zip": "^0.4.9", "cryptiles": "^4.1.3", diff --git a/package.json b/package.json index e42509b4fab1..55f6d62ff5cd 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "@nivo/heatmap": "^0.61.0", "@nivo/line": "^0.61.1", "@nivo/pie": "^0.61.1", - "@rocket.chat/apps-engine": "1.15.0-alpha.3394", + "@rocket.chat/apps-engine": "1.15.0-beta.3411", "@rocket.chat/fuselage": "^0.6.3-dev.45", "@rocket.chat/fuselage-hooks": "^0.6.3-dev.35", "@rocket.chat/fuselage-polyfills": "^0.6.3-dev.45", From cb46fb3e3979e57822030af43a084ce29a303e86 Mon Sep 17 00:00:00 2001 From: pierre-lehnen-rc <55164754+pierre-lehnen-rc@users.noreply.github.com> Date: Wed, 20 May 2020 21:37:28 -0300 Subject: [PATCH 09/30] [FIX] Remove a non working setting "Notification Duration" (#15737) --- app/api/server/v1/users.js | 1 - .../server/lib/sendNotificationsOnMessage.js | 2 - app/lib/server/startup/settings.js | 5 -- app/models/server/models/Subscriptions.js | 16 ------ .../views/pushNotificationsFlexTab.html | 14 ------ .../client/views/pushNotificationsFlexTab.js | 50 +------------------ .../methods/saveNotificationSettings.js | 12 ----- app/ui-account/client/accountPreferences.html | 10 ---- app/ui-account/client/accountPreferences.js | 9 ---- app/ui/client/lib/notification.js | 2 +- packages/rocketchat-i18n/i18n/en.i18n.json | 3 -- server/methods/saveUserPreferences.js | 1 - server/publications/subscription/index.js | 1 - server/startup/migrations/index.js | 1 + server/startup/migrations/v105.js | 1 - server/startup/migrations/v190.js | 19 +++++++ tests/cypress/integration/11-admin.js | 9 ---- .../pageobjects/administration.page.js | 4 -- tests/data/user.js | 1 - tests/end-to-end/api/00-miscellaneous.js | 1 - tests/end-to-end/api/09-rooms.js | 1 - 21 files changed, 22 insertions(+), 141 deletions(-) create mode 100644 server/startup/migrations/v190.js diff --git a/app/api/server/v1/users.js b/app/api/server/v1/users.js index 5a8be4493a00..65aee384de9d 100644 --- a/app/api/server/v1/users.js +++ b/app/api/server/v1/users.js @@ -539,7 +539,6 @@ API.v1.addRoute('users.setPreferences', { authRequired: true }, { mobileNotifications: Match.Maybe(String), enableAutoAway: Match.Maybe(Boolean), highlights: Match.Maybe(Array), - desktopNotificationDuration: Match.Maybe(Number), desktopNotificationRequireInteraction: Match.Maybe(Boolean), messageViewMode: Match.Maybe(Number), hideUsernames: Match.Maybe(Boolean), diff --git a/app/lib/server/lib/sendNotificationsOnMessage.js b/app/lib/server/lib/sendNotificationsOnMessage.js index 834eac239b0e..f8db60fc1e77 100644 --- a/app/lib/server/lib/sendNotificationsOnMessage.js +++ b/app/lib/server/lib/sendNotificationsOnMessage.js @@ -112,7 +112,6 @@ export const sendNotification = async ({ user: sender, message, room, - duration: subscription.desktopNotificationDuration, }); } @@ -176,7 +175,6 @@ export const sendNotification = async ({ const project = { $project: { audioNotifications: 1, - desktopNotificationDuration: 1, desktopNotifications: 1, emailNotifications: 1, mobilePushNotifications: 1, diff --git a/app/lib/server/startup/settings.js b/app/lib/server/startup/settings.js index 63241e0b0bed..281206ec273c 100644 --- a/app/lib/server/startup/settings.js +++ b/app/lib/server/startup/settings.js @@ -236,11 +236,6 @@ settings.addGroup('Accounts', function() { public: true, i18nLabel: 'Idle_Time_Limit', }); - this.add('Accounts_Default_User_Preferences_desktopNotificationDuration', 0, { - type: 'int', - public: true, - i18nLabel: 'Notification_Duration', - }); this.add('Accounts_Default_User_Preferences_desktopNotificationRequireInteraction', false, { type: 'boolean', public: true, diff --git a/app/models/server/models/Subscriptions.js b/app/models/server/models/Subscriptions.js index 3442cfcd5a46..e991c1d925a1 100644 --- a/app/models/server/models/Subscriptions.js +++ b/app/models/server/models/Subscriptions.js @@ -180,20 +180,6 @@ export class Subscriptions extends Base { return this.update(query, update); } - updateDesktopNotificationDurationById(_id, value) { - const query = { - _id, - }; - - const update = { - $set: { - desktopNotificationDuration: parseInt(value), - }, - }; - - return this.update(query, update); - } - updateMobilePushNotificationsById(_id, mobilePushNotifications) { const query = { _id, @@ -366,7 +352,6 @@ export class Subscriptions extends Base { ignored: 1, audioNotifications: 1, audioNotificationValue: 1, - desktopNotificationDuration: 1, desktopNotifications: 1, mobilePushNotifications: 1, emailNotifications: 1, @@ -393,7 +378,6 @@ export class Subscriptions extends Base { 'u._id': 1, audioNotifications: 1, audioNotificationValue: 1, - desktopNotificationDuration: 1, desktopNotifications: 1, mobilePushNotifications: 1, emailNotifications: 1, diff --git a/app/push-notifications/client/views/pushNotificationsFlexTab.html b/app/push-notifications/client/views/pushNotificationsFlexTab.html index a32f1b6e9713..f1e3a28162ad 100644 --- a/app/push-notifications/client/views/pushNotificationsFlexTab.html +++ b/app/push-notifications/client/views/pushNotificationsFlexTab.html @@ -101,20 +101,6 @@ {{/with}}
- -
- -
- {{#if desktopNotificationDuration}} - - {{else}} - - {{/if}} -
-
diff --git a/app/ui-account/client/accountPreferences.js b/app/ui-account/client/accountPreferences.js index 099fab32f97a..2d7080102c3f 100644 --- a/app/ui-account/client/accountPreferences.js +++ b/app/ui-account/client/accountPreferences.js @@ -83,13 +83,6 @@ Template.accountPreferences.helpers({ desktopNotificationDisabled() { return KonchatNotification.notificationStatus.get() === 'denied' || (window.Notification && Notification.permission === 'denied'); }, - desktopNotificationDuration() { - const userPref = getUserPreference(Meteor.userId(), 'desktopNotificationDuration', 'undefined'); - return userPref !== 'undefined' ? userPref : undefined; - }, - defaultDesktopNotificationDuration() { - return settings.get('Accounts_Default_User_Preferences_desktopNotificationDuration'); - }, desktopNotificationRequireInteraction() { const userPref = getUserPreference(Meteor.userId(), 'desktopNotificationRequireInteraction', 'undefined'); return userPref !== 'undefined' ? userPref : undefined; @@ -178,7 +171,6 @@ Template.accountPreferences.onCreated(function() { data.sendOnEnter = $('#sendOnEnter').find('select').val(); data.autoImageLoad = JSON.parse($('input[name=autoImageLoad]:checked').val()); data.emailNotificationMode = $('select[name=emailNotificationMode]').val(); - data.desktopNotificationDuration = $('input[name=desktopNotificationDuration]').val() === '' ? settings.get('Accounts_Default_User_Preferences_desktopNotificationDuration') : parseInt($('input[name=desktopNotificationDuration]').val()); data.desktopNotifications = $('#desktopNotifications').find('select').val(); data.mobileNotifications = $('#mobileNotifications').find('select').val(); data.unreadAlert = JSON.parse($('#unreadAlert').find('input:checked').val()); @@ -330,7 +322,6 @@ Template.accountPreferences.events({ 'click .js-test-notifications'(e) { e.preventDefault(); KonchatNotification.notify({ - duration: $('input[name=desktopNotificationDuration]').val(), payload: { sender: { username: 'rocket.cat' }, }, title: TAPi18n.__('Desktop_Notification_Test'), diff --git a/app/ui/client/lib/notification.js b/app/ui/client/lib/notification.js index 2ad74e0a7dd1..98dd113ab002 100644 --- a/app/ui/client/lib/notification.js +++ b/app/ui/client/lib/notification.js @@ -44,7 +44,7 @@ export const KonchatNotification = { requireInteraction: getUserPreference(Meteor.userId(), 'desktopNotificationRequireInteraction'), }); - const notificationDuration = notification.duration - 0 || getUserPreference(Meteor.userId(), 'desktopNotificationDuration') - 0; + const notificationDuration = notification.duration - 0 || 10; if (notificationDuration > 0) { setTimeout(() => n.close(), notificationDuration * 1000); } diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index bc44d4921e89..66795f3b3dd2 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1239,7 +1239,6 @@ "Duplicated_Email_address_will_be_ignored": "Duplicated email address will be ignored.", "Duplicate_file_name_found": "Duplicate file name found.", "Duplicate_private_group_name": "A Private Group with name '%s' exists", - "Duration": "Duration", "E2E Encryption": "E2E Encryption", "E2E_Enabled": "E2E Enabled", "E2E_Enable_alert": "This feature is currently in beta! Please report bugs to github.com/RocketChat/Rocket.Chat/issues and be aware of:
- Encrypted messages of encrypted rooms will not be found by search operations.
- The mobile apps may not support the encypted messages (they are implementing it).
- Bots may not be able to see encrypted messages until they implement support for it.
- Uploads will not be encrypted in this version.", @@ -2537,12 +2536,10 @@ "Nothing_found": "Nothing found", "Not_Imported_Messages_Title": "The following messages were not imported successfully", "Notification_Desktop_Default_For": "Show Desktop Notifications For", - "Notification_Duration": "Notification Duration", "Notification_RequireInteraction": "Require Interaction to Dismiss Desktop Notification", "Notification_RequireInteraction_Description": "Works only with Chrome browser versions > 50. Utilizes the parameter requireInteraction to show the desktop notification to indefinite until the user interacts with it.", "Notification_Mobile_Default_For": "Push Mobile Notifications For", "Notifications": "Notifications", - "Notifications_Duration": "Notifications Duration", "Notifications_Max_Room_Members": "Max Room Members Before Disabling All Message Notifications", "Notifications_Max_Room_Members_Description": "Max number of members in room when notifications for all messages gets disabled. Users can still change per room setting to receive all notifications on an individual basis. (0 to disable)", "Notifications_Muted_Description": "If you choose to mute everything, you won't see the room highlight in the list when there are new messages, except for mentions. Muting notifications will override notifications settings.", diff --git a/server/methods/saveUserPreferences.js b/server/methods/saveUserPreferences.js index 6d24205a6666..4feee329219a 100644 --- a/server/methods/saveUserPreferences.js +++ b/server/methods/saveUserPreferences.js @@ -22,7 +22,6 @@ Meteor.methods({ mobileNotifications: Match.Optional(String), enableAutoAway: Match.Optional(Boolean), highlights: Match.Optional([String]), - desktopNotificationDuration: Match.Optional(Number), messageViewMode: Match.Optional(Number), hideUsernames: Match.Optional(Boolean), hideRoles: Match.Optional(Boolean), diff --git a/server/publications/subscription/index.js b/server/publications/subscription/index.js index 8001eb21eeaf..59a080202fdc 100644 --- a/server/publications/subscription/index.js +++ b/server/publications/subscription/index.js @@ -24,7 +24,6 @@ export const fields = { audioNotifications: 1, audioNotificationValue: 1, desktopNotifications: 1, - desktopNotificationDuration: 1, mobilePushNotifications: 1, emailNotifications: 1, unreadAlert: 1, diff --git a/server/startup/migrations/index.js b/server/startup/migrations/index.js index edee93ea383f..c32aef2646df 100644 --- a/server/startup/migrations/index.js +++ b/server/startup/migrations/index.js @@ -186,4 +186,5 @@ import './v186'; import './v187'; import './v188'; import './v189'; +import './v190'; import './xrun'; diff --git a/server/startup/migrations/v105.js b/server/startup/migrations/v105.js index d68b1bdda5e4..39615b89bf79 100644 --- a/server/startup/migrations/v105.js +++ b/server/startup/migrations/v105.js @@ -15,7 +15,6 @@ Migrations.add({ Desktop_Notifications_Default_Alert: 'Accounts_Default_User_Preferences_desktopNotifications', Mobile_Notifications_Default_Alert: 'Accounts_Default_User_Preferences_mobileNotifications', Audio_Notifications_Default_Alert: 'Accounts_Default_User_Preferences_audioNotifications', - Desktop_Notifications_Duration: 'Accounts_Default_User_Preferences_desktopNotificationDuration', Audio_Notifications_Value: undefined, }; Settings.find({ _id: { $in: Object.keys(settingsMap) } }).forEach((oldSetting) => { diff --git a/server/startup/migrations/v190.js b/server/startup/migrations/v190.js new file mode 100644 index 000000000000..8c4da9b206b2 --- /dev/null +++ b/server/startup/migrations/v190.js @@ -0,0 +1,19 @@ +import { Migrations } from '../../../app/migrations'; +import { Settings, Subscriptions } from '../../../app/models/server/raw'; + +Migrations.add({ + version: 190, + up() { + // Remove unused settings + Promise.await(Settings.col.deleteOne({ _id: 'Accounts_Default_User_Preferences_desktopNotificationDuration' })); + Promise.await(Subscriptions.col.updateMany({ + desktopNotificationDuration: { + $exists: true, + }, + }, { + $unset: { + desktopNotificationDuration: 1, + }, + })); + }, +}); diff --git a/tests/cypress/integration/11-admin.js b/tests/cypress/integration/11-admin.js index 333d54514ed1..51fc46af08e1 100644 --- a/tests/cypress/integration/11-admin.js +++ b/tests/cypress/integration/11-admin.js @@ -683,15 +683,6 @@ describe('[Administration]', () => { admin.accountsidleTimeLimit.should('have.value', '300'); }); - it('it should show the notifications durations field', () => { - admin.accountsNotificationDuration.click(); - admin.accountsNotificationDuration.should('be.visible'); - }); - - it('the notification duration field value should be 0', () => { - admin.accountsNotificationDuration.should('have.value', '0'); - }); - it('it should show the audio notifications select field', () => { admin.accountsAudioNotifications.scrollIntoView(); admin.accountsAudioNotifications.should('be.visible'); diff --git a/tests/cypress/pageobjects/administration.page.js b/tests/cypress/pageobjects/administration.page.js index d2d30530be67..b34f3e83f2b2 100644 --- a/tests/cypress/pageobjects/administration.page.js +++ b/tests/cypress/pageobjects/administration.page.js @@ -231,10 +231,6 @@ class Administration extends Page { get accountsidleTimeLimitReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_idleTimeLimit"]'); } - get accountsNotificationDuration() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - - get accountsNotificationDurationReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_desktopNotificationDuration"]'); } - get accountsAudioNotifications() { return browser.element('[data-qa-setting-id="Accounts_Default_User_Preferences_audioNotifications"]'); } get accountsAudioNotificationsReset() { return browser.element('[data-qa-reset-setting-id="Accounts_Default_User_Preferences_audioNotifications"]'); } diff --git a/tests/data/user.js b/tests/data/user.js index 02d805b138d8..6fb74b9862f7 100644 --- a/tests/data/user.js +++ b/tests/data/user.js @@ -23,7 +23,6 @@ export const preferences = { mobileNotifications: 'default', enableAutoAway: true, highlights: [], - desktopNotificationDuration: 0, desktopNotificationRequireInteraction: false, messageViewMode: 0, hideUsernames: false, diff --git a/tests/end-to-end/api/00-miscellaneous.js b/tests/end-to-end/api/00-miscellaneous.js index a514b3cd7b7c..9ddb510d9704 100644 --- a/tests/end-to-end/api/00-miscellaneous.js +++ b/tests/end-to-end/api/00-miscellaneous.js @@ -126,7 +126,6 @@ describe('miscellaneous', function() { 'mobileNotifications', 'enableAutoAway', // 'highlights', - 'desktopNotificationDuration', 'desktopNotificationRequireInteraction', 'messageViewMode', 'hideUsernames', diff --git a/tests/end-to-end/api/09-rooms.js b/tests/end-to-end/api/09-rooms.js index 841b9b0a4b88..38fa9a246146 100644 --- a/tests/end-to-end/api/09-rooms.js +++ b/tests/end-to-end/api/09-rooms.js @@ -58,7 +58,6 @@ describe('[Rooms]', function() { emailNotifications: 'nothing', audioNotificationValue: 'beep', desktopNotifications: 'nothing', - desktopNotificationDuration: '2', audioNotifications: 'all', mobilePushNotifications: 'mentions', }, From 6ed0e44722b5c5cdbf4a3dbc7e785423c082f7e6 Mon Sep 17 00:00:00 2001 From: Marcos Spessatto Defendi Date: Wed, 20 May 2020 21:38:40 -0300 Subject: [PATCH 10/30] [IMPROVE] Remove index files from action-links, accounts and assets (#17607) --- app/accounts/index.js | 1 - app/action-links/client/index.js | 3 +- app/action-links/client/init.js | 6 +- app/action-links/client/lib/actionLinks.js | 65 ++++++++++++++----- app/action-links/index.js | 8 --- app/action-links/server/actionLinkHandler.js | 2 +- app/action-links/server/index.js | 2 +- .../{both => server}/lib/actionLinks.js | 2 +- app/api/index.js | 1 - app/api/server/v1/assets.js | 2 +- app/assets/index.js | 1 - app/bigbluebutton/index.js | 1 - app/bigbluebutton/server/index.js | 1 + app/blockstack/server/routes.js | 2 +- app/bot-helpers/index.js | 1 - app/integrations/server/api/api.js | 2 +- app/livechat/client/index.js | 1 + app/livechat/client/lib/messageTypes.js | 5 ++ app/livechat/imports/server/rest/agent.js | 2 +- .../imports/server/rest/appearance.js | 2 +- .../imports/server/rest/dashboards.js | 2 +- .../imports/server/rest/departments.js | 2 +- app/livechat/imports/server/rest/facebook.js | 2 +- app/livechat/imports/server/rest/inquiries.js | 2 +- .../imports/server/rest/integrations.js | 2 +- app/livechat/imports/server/rest/messages.js | 2 +- .../imports/server/rest/officeHour.js | 2 +- app/livechat/imports/server/rest/queue.js | 2 +- app/livechat/imports/server/rest/rooms.js | 2 +- app/livechat/imports/server/rest/sms.js | 2 +- app/livechat/imports/server/rest/triggers.js | 2 +- app/livechat/imports/server/rest/upload.js | 2 +- app/livechat/imports/server/rest/users.js | 2 +- app/livechat/imports/server/rest/visitors.js | 2 +- app/livechat/lib/messageTypes.js | 32 --------- app/livechat/server/api/v1/agent.js | 2 +- app/livechat/server/api/v1/config.js | 2 +- app/livechat/server/api/v1/customField.js | 2 +- app/livechat/server/api/v1/message.js | 2 +- app/livechat/server/api/v1/offlineMessage.js | 2 +- app/livechat/server/api/v1/pageVisited.js | 2 +- app/livechat/server/api/v1/room.js | 2 +- app/livechat/server/api/v1/transcript.js | 2 +- app/livechat/server/api/v1/transfer.js | 2 +- app/livechat/server/api/v1/videoCall.js | 2 +- app/livechat/server/api/v1/visitor.js | 2 +- app/livechat/server/index.js | 1 + app/livechat/server/lib/messageTypes.js | 26 ++++++++ app/livestream/server/routes.js | 2 +- .../server/oauth/oauth2-server.js | 2 +- app/videobridge/client/actionLink.js | 2 +- app/videobridge/server/actionLink.js | 2 +- app/videobridge/server/methods/bbb.js | 4 +- client/importPackages.js | 2 +- .../api-enterprise/server/canned-responses.js | 2 +- .../server/api/channels.js | 2 +- .../server/api/messages.js | 2 +- .../engagement-dashboard/server/api/users.js | 2 +- .../imports/server/rest/departments.js | 2 +- .../livechat/imports/server/rest/inquiries.js | 2 +- ee/app/livechat/imports/server/rest/rooms.js | 2 +- ee/app/livechat/imports/server/rest/sms.js | 2 +- ee/app/livechat/imports/server/rest/upload.js | 2 +- server/importPackages.js | 12 ++-- server/startup/migrations/v036.js | 2 +- server/startup/migrations/v042.js | 2 +- 66 files changed, 143 insertions(+), 124 deletions(-) delete mode 100644 app/accounts/index.js delete mode 100644 app/action-links/index.js rename app/action-links/{both => server}/lib/actionLinks.js (93%) delete mode 100644 app/api/index.js delete mode 100644 app/assets/index.js delete mode 100644 app/bigbluebutton/index.js create mode 100644 app/bigbluebutton/server/index.js delete mode 100644 app/bot-helpers/index.js create mode 100644 app/livechat/client/lib/messageTypes.js create mode 100644 app/livechat/server/lib/messageTypes.js diff --git a/app/accounts/index.js b/app/accounts/index.js deleted file mode 100644 index ca39cd0df4b1..000000000000 --- a/app/accounts/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './server/index'; diff --git a/app/action-links/client/index.js b/app/action-links/client/index.js index 34c929c096f9..c09886562a2d 100644 --- a/app/action-links/client/index.js +++ b/app/action-links/client/index.js @@ -1,5 +1,4 @@ -import { actionLinks } from '../both/lib/actionLinks'; -import './lib/actionLinks'; +import { actionLinks } from './lib/actionLinks'; import './init'; import './stylesheets/actionLinks.css'; diff --git a/app/action-links/client/init.js b/app/action-links/client/init.js index 64b3fc4acb4c..b5f218b1ca18 100644 --- a/app/action-links/client/init.js +++ b/app/action-links/client/init.js @@ -1,10 +1,10 @@ import { Blaze } from 'meteor/blaze'; import { Template } from 'meteor/templating'; -import { handleError } from '../../utils'; -import { fireGlobalEvent, Layout } from '../../ui-utils'; +import { handleError } from '../../utils/client'; +import { fireGlobalEvent, Layout } from '../../ui-utils/client'; import { messageArgs } from '../../ui-utils/client/lib/messageArgs'; -import { actionLinks } from '../both/lib/actionLinks'; +import { actionLinks } from './lib/actionLinks'; Template.room.events({ diff --git a/app/action-links/client/lib/actionLinks.js b/app/action-links/client/lib/actionLinks.js index 4391eda94afb..b3d911398dad 100644 --- a/app/action-links/client/lib/actionLinks.js +++ b/app/action-links/client/lib/actionLinks.js @@ -1,27 +1,58 @@ import { Meteor } from 'meteor/meteor'; -import { handleError } from '../../../utils'; -import { actionLinks } from '../../both/lib/actionLinks'; -// Action Links Handler. This method will be called off the client. +import { handleError } from '../../../utils/client'; +import { Messages, Subscriptions } from '../../../models/client'; -actionLinks.run = (name, messageId, instance) => { - const message = actionLinks.getMessage(name, messageId); +// Action Links namespace creation. +export const actionLinks = { + actions: {}, + register(name, funct) { + actionLinks.actions[name] = funct; + }, + getMessage(name, messageId) { + const userId = Meteor.userId(); + if (!userId) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: 'actionLinks.getMessage' }); + } + + const message = Messages.findOne({ _id: messageId }); + if (!message) { + throw new Meteor.Error('error-invalid-message', 'Invalid message', { function: 'actionLinks.getMessage' }); + } + + const subscription = Subscriptions.findOne({ + rid: message.rid, + 'u._id': userId, + }); + if (!subscription) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { function: 'actionLinks.getMessage' }); + } + + if (!message.actionLinks || !message.actionLinks[name]) { + throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { function: 'actionLinks.getMessage' }); + } - const actionLink = message.actionLinks[name]; + return message; + }, + run(name, messageId, instance) { + const message = actionLinks.getMessage(name, messageId); - let ranClient = false; + const actionLink = message.actionLinks[name]; - if (actionLinks && actionLinks.actions && actionLinks.actions[actionLink.method_id]) { - // run just on client side - actionLinks.actions[actionLink.method_id](message, actionLink.params, instance); + let ranClient = false; - ranClient = true; - } + if (actionLinks && actionLinks.actions && actionLinks.actions[actionLink.method_id]) { + // run just on client side + actionLinks.actions[actionLink.method_id](message, actionLink.params, instance); - // and run on server side - Meteor.call('actionLinkHandler', name, messageId, (err) => { - if (err && !ranClient) { - handleError(err); + ranClient = true; } - }); + + // and run on server side + Meteor.call('actionLinkHandler', name, messageId, (err) => { + if (err && !ranClient) { + handleError(err); + } + }); + }, }; diff --git a/app/action-links/index.js b/app/action-links/index.js deleted file mode 100644 index a67eca871efb..000000000000 --- a/app/action-links/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -if (Meteor.isClient) { - module.exports = require('./client/index.js'); -} -if (Meteor.isServer) { - module.exports = require('./server/index.js'); -} diff --git a/app/action-links/server/actionLinkHandler.js b/app/action-links/server/actionLinkHandler.js index 067f727e3dda..7ccd1b05775b 100644 --- a/app/action-links/server/actionLinkHandler.js +++ b/app/action-links/server/actionLinkHandler.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; -import { actionLinks } from '../both/lib/actionLinks'; +import { actionLinks } from './lib/actionLinks'; // Action Links Handler. This method will be called off the client. Meteor.methods({ diff --git a/app/action-links/server/index.js b/app/action-links/server/index.js index b1c484f79888..a6fb9f92b743 100644 --- a/app/action-links/server/index.js +++ b/app/action-links/server/index.js @@ -1,4 +1,4 @@ -import { actionLinks } from '../both/lib/actionLinks'; +import { actionLinks } from './lib/actionLinks'; import './actionLinkHandler'; export { diff --git a/app/action-links/both/lib/actionLinks.js b/app/action-links/server/lib/actionLinks.js similarity index 93% rename from app/action-links/both/lib/actionLinks.js rename to app/action-links/server/lib/actionLinks.js index c87c712e079b..3f7b2f2e5775 100644 --- a/app/action-links/both/lib/actionLinks.js +++ b/app/action-links/server/lib/actionLinks.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; -import { Messages, Subscriptions } from '../../../models'; +import { Messages, Subscriptions } from '../../../models/server'; // Action Links namespace creation. export const actionLinks = { diff --git a/app/api/index.js b/app/api/index.js deleted file mode 100644 index ca39cd0df4b1..000000000000 --- a/app/api/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './server/index'; diff --git a/app/api/server/v1/assets.js b/app/api/server/v1/assets.js index eacf92ae31cd..108f9649ffe6 100644 --- a/app/api/server/v1/assets.js +++ b/app/api/server/v1/assets.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import Busboy from 'busboy'; -import { RocketChatAssets } from '../../../assets'; +import { RocketChatAssets } from '../../../assets/server'; import { API } from '../api'; API.v1.addRoute('assets.setAsset', { authRequired: true }, { diff --git a/app/assets/index.js b/app/assets/index.js deleted file mode 100644 index ca39cd0df4b1..000000000000 --- a/app/assets/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './server/index'; diff --git a/app/bigbluebutton/index.js b/app/bigbluebutton/index.js deleted file mode 100644 index ba58589ba3d7..000000000000 --- a/app/bigbluebutton/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './server/bigbluebutton-api'; diff --git a/app/bigbluebutton/server/index.js b/app/bigbluebutton/server/index.js new file mode 100644 index 000000000000..b6be696a20bd --- /dev/null +++ b/app/bigbluebutton/server/index.js @@ -0,0 +1 @@ +export { default } from './bigbluebutton-api'; diff --git a/app/blockstack/server/routes.js b/app/blockstack/server/routes.js index ee4c7cc087df..81902030e426 100644 --- a/app/blockstack/server/routes.js +++ b/app/blockstack/server/routes.js @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; import { settings } from '../../settings'; -import { RocketChatAssets } from '../../assets'; +import { RocketChatAssets } from '../../assets/server'; WebApp.connectHandlers.use('/_blockstack/manifest', Meteor.bindEnvironment(function(req, res) { const name = settings.get('Site_Name'); diff --git a/app/bot-helpers/index.js b/app/bot-helpers/index.js deleted file mode 100644 index f5778a23b606..000000000000 --- a/app/bot-helpers/index.js +++ /dev/null @@ -1 +0,0 @@ -import './server/index'; diff --git a/app/integrations/server/api/api.js b/app/integrations/server/api/api.js index db79dc0943bd..aa55b3bd1fad 100644 --- a/app/integrations/server/api/api.js +++ b/app/integrations/server/api/api.js @@ -12,7 +12,7 @@ import moment from 'moment'; import { logger } from '../logger'; import { processWebhookMessage } from '../../../lib'; -import { API, APIClass, defaultRateLimiterOptions } from '../../../api'; +import { API, APIClass, defaultRateLimiterOptions } from '../../../api/server'; import * as Models from '../../../models'; import { settings } from '../../../settings/server'; diff --git a/app/livechat/client/index.js b/app/livechat/client/index.js index 26013edf70a5..0174884f532f 100644 --- a/app/livechat/client/index.js +++ b/app/livechat/client/index.js @@ -9,3 +9,4 @@ import './stylesheets/livechat.css'; import './views/sideNav/livechat'; import './views/sideNav/livechatFlex'; import './externalFrame'; +import './lib/messageTypes'; diff --git a/app/livechat/client/lib/messageTypes.js b/app/livechat/client/lib/messageTypes.js new file mode 100644 index 000000000000..0e3353f31366 --- /dev/null +++ b/app/livechat/client/lib/messageTypes.js @@ -0,0 +1,5 @@ +import { actionLinks } from '../../../action-links/client'; + +actionLinks.register('createLivechatCall', function(message, params, instance) { + instance.tabBar.open('video'); +}); diff --git a/app/livechat/imports/server/rest/agent.js b/app/livechat/imports/server/rest/agent.js index b928501dc2c1..170af7636ff2 100644 --- a/app/livechat/imports/server/rest/agent.js +++ b/app/livechat/imports/server/rest/agent.js @@ -1,6 +1,6 @@ import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findAgentDepartments } from '../../../server/api/lib/agents'; API.v1.addRoute('livechat/agents/:agentId/departments', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/appearance.js b/app/livechat/imports/server/rest/appearance.js index f8345f7d31dc..c7fe16243a78 100644 --- a/app/livechat/imports/server/rest/appearance.js +++ b/app/livechat/imports/server/rest/appearance.js @@ -1,4 +1,4 @@ -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findAppearance } from '../../../server/api/lib/appearance'; API.v1.addRoute('livechat/appearance', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/dashboards.js b/app/livechat/imports/server/rest/dashboards.js index 2537942e74dc..af8972296b20 100644 --- a/app/livechat/imports/server/rest/dashboards.js +++ b/app/livechat/imports/server/rest/dashboards.js @@ -1,6 +1,6 @@ import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { hasPermission } from '../../../../authorization/server'; import { findAllChatsStatus, diff --git a/app/livechat/imports/server/rest/departments.js b/app/livechat/imports/server/rest/departments.js index 8a255185f86f..9ec4113ba66a 100644 --- a/app/livechat/imports/server/rest/departments.js +++ b/app/livechat/imports/server/rest/departments.js @@ -1,6 +1,6 @@ import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { hasPermission } from '../../../../authorization'; import { LivechatDepartment, LivechatDepartmentAgents } from '../../../../models'; import { Livechat } from '../../../server/lib/Livechat'; diff --git a/app/livechat/imports/server/rest/facebook.js b/app/livechat/imports/server/rest/facebook.js index cce8c53a7165..b4b8efa55034 100644 --- a/app/livechat/imports/server/rest/facebook.js +++ b/app/livechat/imports/server/rest/facebook.js @@ -2,7 +2,7 @@ import crypto from 'crypto'; import { Random } from 'meteor/random'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { LivechatRooms, LivechatVisitors } from '../../../../models'; import { settings } from '../../../../settings'; import { Livechat } from '../../../server/lib/Livechat'; diff --git a/app/livechat/imports/server/rest/inquiries.js b/app/livechat/imports/server/rest/inquiries.js index a553c875fe84..3abfc5eee735 100644 --- a/app/livechat/imports/server/rest/inquiries.js +++ b/app/livechat/imports/server/rest/inquiries.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { hasPermission } from '../../../../authorization'; import { Users, LivechatDepartment, LivechatInquiry } from '../../../../models'; import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; diff --git a/app/livechat/imports/server/rest/integrations.js b/app/livechat/imports/server/rest/integrations.js index 08d9d064892a..6b7aed33d89f 100644 --- a/app/livechat/imports/server/rest/integrations.js +++ b/app/livechat/imports/server/rest/integrations.js @@ -1,4 +1,4 @@ -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findIntegrationSettings } from '../../../server/api/lib/integrations'; API.v1.addRoute('livechat/integrations.settings', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/messages.js b/app/livechat/imports/server/rest/messages.js index a40557231b53..f5ad166c8c70 100644 --- a/app/livechat/imports/server/rest/messages.js +++ b/app/livechat/imports/server/rest/messages.js @@ -1,7 +1,7 @@ import { check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findExternalMessages } from '../../../server/api/lib/messages'; API.v1.addRoute('livechat/messages.external/:roomId', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/officeHour.js b/app/livechat/imports/server/rest/officeHour.js index f321a31ea5a3..7b2cd02497ee 100644 --- a/app/livechat/imports/server/rest/officeHour.js +++ b/app/livechat/imports/server/rest/officeHour.js @@ -1,4 +1,4 @@ -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findLivechatOfficeHours } from '../../../server/api/lib/officeHour'; API.v1.addRoute('livechat/office-hours', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/queue.js b/app/livechat/imports/server/rest/queue.js index d5f319f2e3c0..43b586431ea2 100644 --- a/app/livechat/imports/server/rest/queue.js +++ b/app/livechat/imports/server/rest/queue.js @@ -1,4 +1,4 @@ -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findQueueMetrics } from '../../../server/api/lib/queue'; API.v1.addRoute('livechat/queue', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/rooms.js b/app/livechat/imports/server/rest/rooms.js index d7556006597a..052da5db3963 100644 --- a/app/livechat/imports/server/rest/rooms.js +++ b/app/livechat/imports/server/rest/rooms.js @@ -1,7 +1,7 @@ import { Match, check } from 'meteor/check'; import { hasPermission } from '../../../../authorization/server'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findRooms } from '../../../server/api/lib/rooms'; const validateDateParams = (property, date) => { diff --git a/app/livechat/imports/server/rest/sms.js b/app/livechat/imports/server/rest/sms.js index edebecb583a7..f813e7def804 100644 --- a/app/livechat/imports/server/rest/sms.js +++ b/app/livechat/imports/server/rest/sms.js @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor'; import { Random } from 'meteor/random'; import { LivechatRooms, LivechatVisitors, LivechatDepartment } from '../../../../models'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { SMS } from '../../../../sms'; import { Livechat } from '../../../server/lib/Livechat'; diff --git a/app/livechat/imports/server/rest/triggers.js b/app/livechat/imports/server/rest/triggers.js index ca6ebe7a12a0..de3d0b57f27b 100644 --- a/app/livechat/imports/server/rest/triggers.js +++ b/app/livechat/imports/server/rest/triggers.js @@ -1,6 +1,6 @@ import { check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findTriggers, findTriggerById } from '../../../server/api/lib/triggers'; API.v1.addRoute('livechat/triggers', { authRequired: true }, { diff --git a/app/livechat/imports/server/rest/upload.js b/app/livechat/imports/server/rest/upload.js index 3d28f420402e..4c27811749a6 100644 --- a/app/livechat/imports/server/rest/upload.js +++ b/app/livechat/imports/server/rest/upload.js @@ -6,7 +6,7 @@ import { settings } from '../../../../settings'; import { Settings, LivechatRooms, LivechatVisitors } from '../../../../models'; import { fileUploadIsValidContentType } from '../../../../utils'; import { FileUpload } from '../../../../file-upload'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; let maxFileSize; diff --git a/app/livechat/imports/server/rest/users.js b/app/livechat/imports/server/rest/users.js index 04e1815b4f07..f0c88aa25c59 100644 --- a/app/livechat/imports/server/rest/users.js +++ b/app/livechat/imports/server/rest/users.js @@ -2,7 +2,7 @@ import { check } from 'meteor/check'; import _ from 'underscore'; import { hasPermission } from '../../../../authorization'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { Users } from '../../../../models'; import { Livechat } from '../../../server/lib/Livechat'; import { findAgents, findManagers } from '../../../server/api/lib/users'; diff --git a/app/livechat/imports/server/rest/visitors.js b/app/livechat/imports/server/rest/visitors.js index 42b5a20b25d7..c828e9552e58 100644 --- a/app/livechat/imports/server/rest/visitors.js +++ b/app/livechat/imports/server/rest/visitors.js @@ -1,7 +1,7 @@ import { check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findVisitorInfo, findVisitedPages, findChatHistory } from '../../../server/api/lib/visitors'; API.v1.addRoute('livechat/visitors.info', { authRequired: true }, { diff --git a/app/livechat/lib/messageTypes.js b/app/livechat/lib/messageTypes.js index c68e120f0542..8f870923bd28 100644 --- a/app/livechat/lib/messageTypes.js +++ b/app/livechat/lib/messageTypes.js @@ -1,12 +1,6 @@ -import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Livechat } from 'meteor/rocketchat:livechat'; import { MessageTypes } from '../../ui-utils'; -import { actionLinks } from '../../action-links'; -import { Notifications } from '../../notifications'; -import { Messages, LivechatRooms } from '../../models'; -import { settings } from '../../settings'; MessageTypes.registerType({ id: 'livechat_navigation_history', @@ -60,29 +54,3 @@ MessageTypes.registerType({ system: true, message: 'New_videocall_request', }); - -actionLinks.register('createLivechatCall', function(message, params, instance) { - if (Meteor.isClient) { - instance.tabBar.open('video'); - } -}); - -actionLinks.register('denyLivechatCall', function(message/* , params*/) { - if (Meteor.isServer) { - const user = Meteor.user(); - - Messages.createWithTypeRoomIdMessageAndUser('command', message.rid, 'endCall', user); - Notifications.notifyRoom(message.rid, 'deleteMessage', { _id: message._id }); - - const language = user.language || settings.get('Language') || 'en'; - - Livechat.closeRoom({ - user, - room: LivechatRooms.findOneById(message.rid), - comment: TAPi18n.__('Videocall_declined', { lng: language }), - }); - Meteor.defer(() => { - Messages.setHiddenById(message._id); - }); - } -}); diff --git a/app/livechat/server/api/v1/agent.js b/app/livechat/server/api/v1/agent.js index 68ceef87da14..7e2329058542 100644 --- a/app/livechat/server/api/v1/agent.js +++ b/app/livechat/server/api/v1/agent.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findRoom, findGuest, findAgent, findOpenRoom } from '../lib/livechat'; import { Livechat } from '../../lib/Livechat'; diff --git a/app/livechat/server/api/v1/config.js b/app/livechat/server/api/v1/config.js index a1f4bab03405..50e4229fa40e 100644 --- a/app/livechat/server/api/v1/config.js +++ b/app/livechat/server/api/v1/config.js @@ -1,6 +1,6 @@ import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findGuest, settings, online, findOpenRoom, getExtraConfigInfo, findAgent } from '../lib/livechat'; API.v1.addRoute('livechat/config', { diff --git a/app/livechat/server/api/v1/customField.js b/app/livechat/server/api/v1/customField.js index f64266d3be6c..3b19e832bc65 100644 --- a/app/livechat/server/api/v1/customField.js +++ b/app/livechat/server/api/v1/customField.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findGuest } from '../lib/livechat'; import { Livechat } from '../../lib/Livechat'; import { findLivechatCustomFields, findCustomFieldById } from '../lib/customFields'; diff --git a/app/livechat/server/api/v1/message.js b/app/livechat/server/api/v1/message.js index e2362baf6d32..0811bc8324fb 100644 --- a/app/livechat/server/api/v1/message.js +++ b/app/livechat/server/api/v1/message.js @@ -4,7 +4,7 @@ import { Random } from 'meteor/random'; import { Messages, LivechatRooms, LivechatVisitors } from '../../../../models'; import { hasPermission } from '../../../../authorization'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { loadMessageHistory } from '../../../../lib'; import { findGuest, findRoom, normalizeHttpHeaderData } from '../lib/livechat'; import { Livechat } from '../../lib/Livechat'; diff --git a/app/livechat/server/api/v1/offlineMessage.js b/app/livechat/server/api/v1/offlineMessage.js index 6788c30e3d86..8264228c97e7 100644 --- a/app/livechat/server/api/v1/offlineMessage.js +++ b/app/livechat/server/api/v1/offlineMessage.js @@ -1,7 +1,7 @@ import { Match, check } from 'meteor/check'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { Livechat } from '../../lib/Livechat'; API.v1.addRoute('livechat/offline.message', { diff --git a/app/livechat/server/api/v1/pageVisited.js b/app/livechat/server/api/v1/pageVisited.js index e5ef7c42ba64..4f8c638e6146 100644 --- a/app/livechat/server/api/v1/pageVisited.js +++ b/app/livechat/server/api/v1/pageVisited.js @@ -1,7 +1,7 @@ import { Match, check } from 'meteor/check'; import _ from 'underscore'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { Livechat } from '../../lib/Livechat'; API.v1.addRoute('livechat/page.visited', { diff --git a/app/livechat/server/api/v1/room.js b/app/livechat/server/api/v1/room.js index 83af5ffe1b61..5ec9ef1cf06e 100644 --- a/app/livechat/server/api/v1/room.js +++ b/app/livechat/server/api/v1/room.js @@ -5,7 +5,7 @@ import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { settings as rcSettings } from '../../../../settings'; import { Messages, LivechatRooms } from '../../../../models'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findGuest, findRoom, getRoom, settings, findAgent, onCheckRoomParams } from '../lib/livechat'; import { Livechat } from '../../lib/Livechat'; import { normalizeTransferredByData } from '../../lib/Helper'; diff --git a/app/livechat/server/api/v1/transcript.js b/app/livechat/server/api/v1/transcript.js index 02c0d9d27561..f8f3c923d25e 100644 --- a/app/livechat/server/api/v1/transcript.js +++ b/app/livechat/server/api/v1/transcript.js @@ -1,7 +1,7 @@ import { check } from 'meteor/check'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { Livechat } from '../../lib/Livechat'; API.v1.addRoute('livechat/transcript', { diff --git a/app/livechat/server/api/v1/transfer.js b/app/livechat/server/api/v1/transfer.js index e38277d5529d..aa3fb7facd0e 100644 --- a/app/livechat/server/api/v1/transfer.js +++ b/app/livechat/server/api/v1/transfer.js @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import { LivechatRooms } from '../../../../models'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findLivechatTransferHistory } from '../lib/transfer'; API.v1.addRoute('livechat/transfer.history/:rid', { authRequired: true }, { diff --git a/app/livechat/server/api/v1/videoCall.js b/app/livechat/server/api/v1/videoCall.js index 0aaa231da654..56159d8c349c 100644 --- a/app/livechat/server/api/v1/videoCall.js +++ b/app/livechat/server/api/v1/videoCall.js @@ -4,7 +4,7 @@ import { Random } from 'meteor/random'; import { Messages } from '../../../../models'; import { settings as rcSettings } from '../../../../settings'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findGuest, getRoom, settings } from '../lib/livechat'; API.v1.addRoute('livechat/video.call/:token', { diff --git a/app/livechat/server/api/v1/visitor.js b/app/livechat/server/api/v1/visitor.js index f34930a1b9c3..98007540876c 100644 --- a/app/livechat/server/api/v1/visitor.js +++ b/app/livechat/server/api/v1/visitor.js @@ -3,7 +3,7 @@ import { Match, check } from 'meteor/check'; import { LivechatRooms, LivechatVisitors, LivechatCustomField } from '../../../../models'; import { hasPermission } from '../../../../authorization'; -import { API } from '../../../../api'; +import { API } from '../../../../api/server'; import { findGuest, normalizeHttpHeaderData } from '../lib/livechat'; import { Livechat } from '../../lib/Livechat'; diff --git a/app/livechat/server/index.js b/app/livechat/server/index.js index 72632b50670e..527bc59802d6 100644 --- a/app/livechat/server/index.js +++ b/app/livechat/server/index.js @@ -84,5 +84,6 @@ import './sendMessageBySMS'; import './api'; import './api/rest'; import './externalFrame'; +import './lib/messageTypes'; export { Livechat } from './lib/Livechat'; diff --git a/app/livechat/server/lib/messageTypes.js b/app/livechat/server/lib/messageTypes.js new file mode 100644 index 000000000000..3d32da6f401f --- /dev/null +++ b/app/livechat/server/lib/messageTypes.js @@ -0,0 +1,26 @@ +import { Meteor } from 'meteor/meteor'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; + +import { actionLinks } from '../../../action-links/server'; +import { Notifications } from '../../../notifications/server'; +import { Messages, LivechatRooms } from '../../../models/server'; +import { settings } from '../../../settings/server'; +import { Livechat } from './Livechat'; + +actionLinks.register('denyLivechatCall', function(message/* , params*/) { + const user = Meteor.user(); + + Messages.createWithTypeRoomIdMessageAndUser('command', message.rid, 'endCall', user); + Notifications.notifyRoom(message.rid, 'deleteMessage', { _id: message._id }); + + const language = user.language || settings.get('Language') || 'en'; + + Livechat.closeRoom({ + user, + room: LivechatRooms.findOneById(message.rid), + comment: TAPi18n.__('Videocall_declined', { lng: language }), + }); + Meteor.defer(() => { + Messages.setHiddenById(message._id); + }); +}); diff --git a/app/livestream/server/routes.js b/app/livestream/server/routes.js index 8668217d19a5..3a52aec6031c 100644 --- a/app/livestream/server/routes.js +++ b/app/livestream/server/routes.js @@ -3,7 +3,7 @@ import google from 'googleapis'; import { settings } from '../../settings'; import { Users } from '../../models'; -import { API } from '../../api'; +import { API } from '../../api/server'; const { OAuth2 } = google.auth; diff --git a/app/oauth2-server-config/server/oauth/oauth2-server.js b/app/oauth2-server-config/server/oauth/oauth2-server.js index ff813497bc5a..f1c51982c760 100644 --- a/app/oauth2-server-config/server/oauth/oauth2-server.js +++ b/app/oauth2-server-config/server/oauth/oauth2-server.js @@ -3,7 +3,7 @@ import { WebApp } from 'meteor/webapp'; import { OAuth2Server } from 'meteor/rocketchat:oauth2-server'; import { OAuthApps, Users } from '../../../models'; -import { API } from '../../../api'; +import { API } from '../../../api/server'; const oauth2server = new OAuth2Server({ accessTokensCollectionName: 'rocketchat_oauth_access_tokens', diff --git a/app/videobridge/client/actionLink.js b/app/videobridge/client/actionLink.js index 666059649d32..c1955690ddfb 100644 --- a/app/videobridge/client/actionLink.js +++ b/app/videobridge/client/actionLink.js @@ -2,7 +2,7 @@ import { Session } from 'meteor/session'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import toastr from 'toastr'; -import { actionLinks } from '../../action-links'; +import { actionLinks } from '../../action-links/client'; import { Rooms } from '../../models'; actionLinks.register('joinJitsiCall', function(message, params, instance) { diff --git a/app/videobridge/server/actionLink.js b/app/videobridge/server/actionLink.js index 01d5baa2ff4f..e3e42bee4c33 100644 --- a/app/videobridge/server/actionLink.js +++ b/app/videobridge/server/actionLink.js @@ -1,4 +1,4 @@ -import { actionLinks } from '../../action-links'; +import { actionLinks } from '../../action-links/server'; actionLinks.register('joinJitsiCall', function(/* message, params*/) { diff --git a/app/videobridge/server/methods/bbb.js b/app/videobridge/server/methods/bbb.js index 04b1d6030ed1..b06045271d54 100644 --- a/app/videobridge/server/methods/bbb.js +++ b/app/videobridge/server/methods/bbb.js @@ -2,11 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { HTTP } from 'meteor/http'; import xml2js from 'xml2js'; -import BigBlueButtonApi from '../../../bigbluebutton'; +import BigBlueButtonApi from '../../../bigbluebutton/server'; import { settings } from '../../../settings'; import { Rooms, Users } from '../../../models'; import { saveStreamingOptions } from '../../../channel-settings'; -import { API } from '../../../api'; +import { API } from '../../../api/server'; const parser = new xml2js.Parser({ explicitRoot: true, diff --git a/client/importPackages.js b/client/importPackages.js index 183ed71b41fc..7d95bc6f83e7 100644 --- a/client/importPackages.js +++ b/client/importPackages.js @@ -102,7 +102,7 @@ import '../app/notifications'; import '../app/promises/client'; import '../app/ui-utils'; import '../app/ui-cached-collection'; -import '../app/action-links'; +import '../app/action-links/client'; import '../app/reactions/client'; import '../app/livechat/client'; import '../app/meteor-autocomplete/client'; diff --git a/ee/app/api-enterprise/server/canned-responses.js b/ee/app/api-enterprise/server/canned-responses.js index 36b1175406a1..99f41f2709c6 100644 --- a/ee/app/api-enterprise/server/canned-responses.js +++ b/ee/app/api-enterprise/server/canned-responses.js @@ -1,4 +1,4 @@ -import { API } from '../../../../app/api'; +import { API } from '../../../../app/api/server'; import { findAllCannedResponses } from './lib/canned-responses'; API.v1.addRoute('canned-responses.get', { authRequired: true }, { diff --git a/ee/app/engagement-dashboard/server/api/channels.js b/ee/app/engagement-dashboard/server/api/channels.js index 405161d3e0c6..e97dd3995df0 100644 --- a/ee/app/engagement-dashboard/server/api/channels.js +++ b/ee/app/engagement-dashboard/server/api/channels.js @@ -1,6 +1,6 @@ import { check } from 'meteor/check'; -import { API } from '../../../../../app/api'; +import { API } from '../../../../../app/api/server'; import { findAllChannelsWithNumberOfMessages } from '../lib/channels'; import { transformDatesForAPI } from './helpers/date'; diff --git a/ee/app/engagement-dashboard/server/api/messages.js b/ee/app/engagement-dashboard/server/api/messages.js index b51f393e0091..94b6428c011e 100644 --- a/ee/app/engagement-dashboard/server/api/messages.js +++ b/ee/app/engagement-dashboard/server/api/messages.js @@ -1,6 +1,6 @@ import { check } from 'meteor/check'; -import { API } from '../../../../../app/api'; +import { API } from '../../../../../app/api/server'; import { findWeeklyMessagesSentData, findMessagesSentOrigin, findTopFivePopularChannelsByMessageSentQuantity } from '../lib/messages'; import { transformDatesForAPI } from './helpers/date'; diff --git a/ee/app/engagement-dashboard/server/api/users.js b/ee/app/engagement-dashboard/server/api/users.js index aaf33b4c0f28..8a675146237a 100644 --- a/ee/app/engagement-dashboard/server/api/users.js +++ b/ee/app/engagement-dashboard/server/api/users.js @@ -1,6 +1,6 @@ import { check } from 'meteor/check'; -import { API } from '../../../../../app/api'; +import { API } from '../../../../../app/api/server'; import { findWeeklyUsersRegisteredData, findActiveUsersMonthlyData, diff --git a/ee/app/livechat/imports/server/rest/departments.js b/ee/app/livechat/imports/server/rest/departments.js index 4ec594c9051e..1521dc7656a9 100644 --- a/ee/app/livechat/imports/server/rest/departments.js +++ b/ee/app/livechat/imports/server/rest/departments.js @@ -1,4 +1,4 @@ -import { API } from '../../../../../../app/api'; +import { API } from '../../../../../../app/api/server'; import { runEndpointsAsUser } from '../../../../livechat-enterprise/server/lib/runEndpointsAsUser'; const endpointsToRunAsUser = { diff --git a/ee/app/livechat/imports/server/rest/inquiries.js b/ee/app/livechat/imports/server/rest/inquiries.js index 3c9e6c314414..cab34ca9b355 100644 --- a/ee/app/livechat/imports/server/rest/inquiries.js +++ b/ee/app/livechat/imports/server/rest/inquiries.js @@ -1,4 +1,4 @@ -import { API } from '../../../../../../app/api'; +import { API } from '../../../../../../app/api/server'; import { runEndpointsAsUser } from '../../../../livechat-enterprise/server/lib/runEndpointsAsUser'; const endpointsToRunAsUser = { diff --git a/ee/app/livechat/imports/server/rest/rooms.js b/ee/app/livechat/imports/server/rest/rooms.js index 7d15bf85e2f9..76578268b288 100644 --- a/ee/app/livechat/imports/server/rest/rooms.js +++ b/ee/app/livechat/imports/server/rest/rooms.js @@ -1,4 +1,4 @@ -import { API } from '../../../../../../app/api'; +import { API } from '../../../../../../app/api/server'; import { runEndpointsAsUser } from '../../../../livechat-enterprise/server/lib/runEndpointsAsUser'; const endpointsToRunAsUser = { diff --git a/ee/app/livechat/imports/server/rest/sms.js b/ee/app/livechat/imports/server/rest/sms.js index 982ddd7b2438..211f5e444a40 100644 --- a/ee/app/livechat/imports/server/rest/sms.js +++ b/ee/app/livechat/imports/server/rest/sms.js @@ -1,4 +1,4 @@ -import { API } from '../../../../../../app/api'; +import { API } from '../../../../../../app/api/server'; import { runEndpointsAsUser } from '../../../../livechat-enterprise/server/lib/runEndpointsAsUser'; const endpointsToRunAsUser = { diff --git a/ee/app/livechat/imports/server/rest/upload.js b/ee/app/livechat/imports/server/rest/upload.js index 8f87096af200..e8c4ad4e81ba 100644 --- a/ee/app/livechat/imports/server/rest/upload.js +++ b/ee/app/livechat/imports/server/rest/upload.js @@ -1,4 +1,4 @@ -import { API } from '../../../../../../app/api'; +import { API } from '../../../../../../app/api/server'; import { runEndpointsAsUser } from '../../../../livechat-enterprise/server/lib/runEndpointsAsUser'; const endpointsToRunAsUser = { diff --git a/server/importPackages.js b/server/importPackages.js index 96073ce4fa3f..aa56233f2bf5 100644 --- a/server/importPackages.js +++ b/server/importPackages.js @@ -1,14 +1,14 @@ import '../app/cors/server'; import '../app/sms'; import '../app/2fa/server'; -import '../app/accounts'; +import '../app/accounts/server'; import '../app/analytics/server'; -import '../app/api'; -import '../app/assets'; +import '../app/api/server'; +import '../app/assets/server'; import '../app/authorization'; import '../app/autolinker/server'; import '../app/autotranslate/server'; -import '../app/bot-helpers'; +import '../app/bot-helpers/server'; import '../app/cas/server'; import '../app/channel-settings'; import '../app/channel-settings-mail-messages/server'; @@ -98,7 +98,7 @@ import '../app/version-check/server'; import '../app/search/server'; import '../app/chatpal-search/server'; import '../app/discussion/server'; -import '../app/bigbluebutton'; +import '../app/bigbluebutton/server'; import '../app/mail-messages/server'; import '../app/user-status'; import '../app/utils'; @@ -109,6 +109,6 @@ import '../app/callbacks'; import '../app/notifications'; import '../app/promises/server'; import '../app/ui-utils'; -import '../app/action-links'; +import '../app/action-links/server'; import '../app/reactions/server'; import '../app/livechat/server'; diff --git a/server/startup/migrations/v036.js b/server/startup/migrations/v036.js index a4f97e7bf80f..ba22dbdfa8db 100644 --- a/server/startup/migrations/v036.js +++ b/server/startup/migrations/v036.js @@ -5,7 +5,7 @@ import { HTTP } from 'meteor/http'; import { Migrations } from '../../../app/migrations'; import { Settings } from '../../../app/models'; -import { RocketChatAssets } from '../../../app/assets'; +import { RocketChatAssets } from '../../../app/assets/server'; Migrations.add({ version: 36, diff --git a/server/startup/migrations/v042.js b/server/startup/migrations/v042.js index dc95a49cbae2..d17a90026692 100644 --- a/server/startup/migrations/v042.js +++ b/server/startup/migrations/v042.js @@ -2,7 +2,7 @@ import { Mongo } from 'meteor/mongo'; import { Migrations } from '../../../app/migrations'; import { settings } from '../../../app/settings'; -import { RocketChatAssets } from '../../../app/assets'; +import { RocketChatAssets } from '../../../app/assets/server'; Migrations.add({ version: 42, From 5a6a084ccfb41a95a5c6e1280141846e45af9509 Mon Sep 17 00:00:00 2001 From: Maria Eduarda Cunha <42151808+mariaeduardacunha@users.noreply.github.com> Date: Wed, 20 May 2020 23:29:20 -0300 Subject: [PATCH 11/30] Regression: Status presence color (#17707) Co-authored-by: Guilherme Gazzo --- .../client/imports/components/header.css | 10 +++--- .../imports/components/main-content.css | 8 ++--- .../client/imports/components/memberlist.css | 8 ++--- .../client/imports/components/popover.css | 8 ++--- .../components/sidebar/sidebar-header.css | 18 +++++------ .../components/sidebar/sidebar-item.css | 14 ++++---- .../client/imports/general/theme_old.css | 32 +++++++++---------- .../client/imports/general/variables.css | 17 +++++----- .../client/models/CachedCollection.js | 2 +- app/ui/client/views/app/editStatus.css | 16 +++++----- server/startup/migrations/index.js | 1 + server/startup/migrations/v191.js | 9 ++++++ 12 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 server/startup/migrations/v191.js diff --git a/app/theme/client/imports/components/header.css b/app/theme/client/imports/components/header.css index d5b0a05cf493..3dfa4f441492 100644 --- a/app/theme/client/imports/components/header.css +++ b/app/theme/client/imports/components/header.css @@ -225,23 +225,23 @@ border-radius: var(--header-title-status-bullet-radius); &--online { - background-color: var(--status-online); + background-color: var(--rc-status-online); } &--away { - background-color: var(--status-away); + background-color: var(--rc-status-away); } &--busy { - background-color: var(--status-busy); + background-color: var(--rc-status-busy); } &--invisible { - background-color: var(--status-invisible); + background-color: var(--rc-status-invisible); } &--offline { - background-color: var(--status-invisible); + background-color: var(--rc-status-invisible); } } } diff --git a/app/theme/client/imports/components/main-content.css b/app/theme/client/imports/components/main-content.css index bda5cf955e32..04f7cb05d970 100644 --- a/app/theme/client/imports/components/main-content.css +++ b/app/theme/client/imports/components/main-content.css @@ -15,18 +15,18 @@ .messages-container .room-icon { &.online { - color: var(--status-online); + color: var(--rc-status-online); } &.away { - color: var(--status-away); + color: var(--rc-status-away); } &.busy { - color: var(--status-busy); + color: var(--rc-status-busy); } &.offline { - color: var(--status-invisible); + color: var(--rc-status-invisible); } } diff --git a/app/theme/client/imports/components/memberlist.css b/app/theme/client/imports/components/memberlist.css index 6d78136b841f..0da2ebec46e8 100644 --- a/app/theme/client/imports/components/memberlist.css +++ b/app/theme/client/imports/components/memberlist.css @@ -61,19 +61,19 @@ border-radius: var(--sidebar-item-user-status-radius); &--online { - background-color: var(--status-online); + background-color: var(--rc-status-online); } &--away { - background-color: var(--status-away); + background-color: var(--rc-status-away); } &--busy { - background-color: var(--status-busy); + background-color: var(--rc-status-busy); } &--offline { - background-color: var(--status-invisible-sidebar); + background-color: var(--rc-status-invisible-sidebar); } } diff --git a/app/theme/client/imports/components/popover.css b/app/theme/client/imports/components/popover.css index 551c02e9dd40..807bdd7c88d2 100644 --- a/app/theme/client/imports/components/popover.css +++ b/app/theme/client/imports/components/popover.css @@ -127,25 +127,25 @@ &--online { & .rc-popover__icon { - color: var(--status-online); + color: var(--rc-status-online); } } &--away { & .rc-popover__icon { - color: var(--status-away); + color: var(--rc-status-away); } } &--busy { & .rc-popover__icon { - color: var(--status-busy); + color: var(--rc-status-busy); } } &--offline { & .rc-popover__icon { - color: var(--status-invisible); + color: var(--rc-status-invisible); } } } diff --git a/app/theme/client/imports/components/sidebar/sidebar-header.css b/app/theme/client/imports/components/sidebar/sidebar-header.css index de54cba02ae4..fc963c5eda02 100644 --- a/app/theme/client/imports/components/sidebar/sidebar-header.css +++ b/app/theme/client/imports/components/sidebar/sidebar-header.css @@ -40,23 +40,23 @@ border-radius: var(--sidebar-account-status-bullet-radius); &--online { - background-color: var(--status-online); + background-color: var(--rc-status-online); } &--away { - background-color: var(--status-away); + background-color: var(--rc-status-away); } &--busy { - background-color: var(--status-busy); + background-color: var(--rc-status-busy); } &--invisible { - background-color: var(--status-invisible); + background-color: var(--rc-status-invisible); } &--offline { - background-color: var(--status-invisible); + background-color: var(--rc-status-invisible); } } } @@ -109,25 +109,25 @@ & .rc-popover__item { &--online { & .rc-icon { - color: var(--status-online); + color: var(--rc-status-online); } } &--away { & .rc-icon { - color: var(--status-away); + color: var(--rc-status-away); } } &--busy { & .rc-icon { - color: var(--status-busy); + color: var(--rc-status-busy); } } &--offline { & .rc-icon { - color: var(--status-invisible); + color: var(--rc-status-invisible); } } } diff --git a/app/theme/client/imports/components/sidebar/sidebar-item.css b/app/theme/client/imports/components/sidebar/sidebar-item.css index 125ed7283f45..17771d9a3081 100644 --- a/app/theme/client/imports/components/sidebar/sidebar-item.css +++ b/app/theme/client/imports/components/sidebar/sidebar-item.css @@ -137,15 +137,15 @@ &-status { &--online { - color: var(--status-online); + color: var(--rc-status-online); } &--away { - color: var(--status-away); + color: var(--rc-status-away); } &--busy { - color: var(--status-busy); + color: var(--rc-status-busy); } } } @@ -175,19 +175,19 @@ border-radius: var(--sidebar-item-user-status-radius); &--online { - background-color: var(--status-online); + background-color: var(--rc-status-online); } &--away { - background-color: var(--status-away); + background-color: var(--rc-status-away); } &--busy { - background-color: var(--status-busy); + background-color: var(--rc-status-busy); } &--offline { - background-color: var(--status-invisible-sidebar); + background-color: var(--rc-status-invisible-sidebar); } } diff --git a/app/theme/client/imports/general/theme_old.css b/app/theme/client/imports/general/theme_old.css index 657ebb4f3c41..2f88a849dfef 100644 --- a/app/theme/client/imports/general/theme_old.css +++ b/app/theme/client/imports/general/theme_old.css @@ -411,19 +411,19 @@ textarea { } i.status-online { - color: var(--status-online); + color: var(--rc-status-online); } .status-bg-online { - background-color: var(--status-online); + background-color: var(--rc-status-online); } .account-box .status-online .thumb::after, .account-box .status.online::after, .popup-user-status-online, .status-online::after { - border-color: var(--status-online-darken-10); - background-color: var(--status-online); + border-color: var(--rc-status-online-darken-10); + background-color: var(--rc-status-online); } .account-box .status-offline .thumb::after, @@ -432,11 +432,11 @@ i.status-online { } i.status-away { - color: var(--status-away); + color: var(--rc-status-away); } .status-bg-away { - background-color: var(--status-away); + background-color: var(--rc-status-away); } .account-box .status-away .thumb::after, @@ -444,38 +444,38 @@ i.status-away { .popup-user-status-away, .status-away::after, .status-pending::after { - border-color: var(--status-away-darken-10); - background-color: var(--status-away); + border-color: var(--rc-status-away-darken-10); + background-color: var(--rc-status-away); } i.status-busy { - color: var(--status-busy); + color: var(--rc-status-busy); } .status-bg-busy { - background-color: var(--status-busy); + background-color: var(--rc-status-busy); } .account-box .status-busy .thumb::after, .account-box .status.busy::after, .popup-user-status-busy, .status-busy::after { - border-color: var(--status-busy-darken-10); - background-color: var(--status-busy); + border-color: var(--rc-status-busy-darken-10); + background-color: var(--rc-status-busy); } i.status-offline { - color: var(--status-offline); + color: var(--rc-status-offline); } .status-bg-offline { - background-color: var(--status-offline); + background-color: var(--rc-status-offline); } .popup-user-status-offline, .status-offline::after { - border-color: var(--status-offline-darken-10); - background-color: var(--status-offline); + border-color: var(--rc-status-offline-darken-10); + background-color: var(--rc-status-offline); } .alert-warning { diff --git a/app/theme/client/imports/general/variables.css b/app/theme/client/imports/general/variables.css index d44f21266256..fb317250592e 100644 --- a/app/theme/client/imports/general/variables.css +++ b/app/theme/client/imports/general/variables.css @@ -17,7 +17,7 @@ --color-purple: #861da8; --color-red: #f5455c; --color-dark-red: #e0364d; - --color-orange: #f59547; + --color-orange: #f38c39; --color-yellow: #ffd21f; --color-dark-yellow: #f6c502; --color-green: #2de0a5; @@ -40,7 +40,7 @@ /* #region colors Colors */ --rc-color-error: var(--color-red); --rc-color-error-light: #e1364c; - --rc-color-alert: var(--color-yellow); + --rc-color-alert: var(--color-orange); --rc-color-alert-light: var(--color-dark-yellow); --rc-color-success: var(--color-green); --rc-color-success-light: #25d198; @@ -75,6 +75,7 @@ --component-color: #f2f3f5; --pending-color: #fcb316; --error-color: #bc2031; + --success-color: #2de0a5; --selection-color: #02acec; --attention-color: #9c27b0; @@ -86,7 +87,6 @@ --link-font-color: var(--primary-action-color); --info-font-color: var(--secondary-font-color); --custom-scrollbar-color: var(--transparent-darker); - --status-offline: var(--transparent-darker); /* #endregion */ @@ -108,11 +108,12 @@ --flex-tab-webrtc-2-width: 850px; --border: 2px; --border-radius: 2px; - --status-online: var(--rc-color-success); - --status-away: var(--rc-color-alert); - --status-busy: var(--rc-color-error); - --status-invisible: var(--color-gray-medium); - --status-invisible-sidebar: var(--rc-color-primary-darkest); + --rc-status-online: var(--rc-color-success); + --rc-status-away: var(--rc-color-alert); + --rc-status-busy: var(--rc-color-error); + --rc-status-invisible: var(--color-gray-medium); + --rc-status-offline: var(--transparent-darker); + --rc-status-invisible-sidebar: var(--rc-color-primary-darkest); --default-padding: 1.5rem; --default-small-padding: 1rem; --status-bullet-size: 10px; diff --git a/app/ui-cached-collection/client/models/CachedCollection.js b/app/ui-cached-collection/client/models/CachedCollection.js index bcd1ffc5b6bb..26dece4ccc93 100644 --- a/app/ui-cached-collection/client/models/CachedCollection.js +++ b/app/ui-cached-collection/client/models/CachedCollection.js @@ -129,7 +129,7 @@ export class CachedCollection extends EventEmitter { userRelated = true, listenChangesForLoggedUsersOnly = false, useSync = true, - version = 10, + version = 11, maxCacheTime = 60 * 60 * 24 * 30, onSyncData = (/* action, record */) => {}, }) { diff --git a/app/ui/client/views/app/editStatus.css b/app/ui/client/views/app/editStatus.css index ab2170f62c88..a7b92dc5d7a8 100644 --- a/app/ui/client/views/app/editStatus.css +++ b/app/ui/client/views/app/editStatus.css @@ -1,19 +1,19 @@ .edit-status-type.rc-popover { &__item { &--online { - color: var(--status-online); + color: var(--rc-status-online); } &--away { - color: var(--status-away); + color: var(--rc-status-away); } &--busy { - color: var(--status-busy); + color: var(--rc-status-busy); } &--offline { - color: var(--status-invisible); + color: var(--rc-status-invisible); } } } @@ -21,25 +21,25 @@ .edit-status-type-icon { &--online { & .rc-icon { - color: var(--status-online); + color: var(--rc-status-online); } } &--away { & .rc-icon { - color: var(--status-away); + color: var(--rc-status-away); } } &--busy { & .rc-icon { - color: var(--status-busy); + color: var(--rc-status-busy); } } &--offline { & .rc-icon { - color: var(--status-invisible); + color: var(--rc-status-invisible); } } } diff --git a/server/startup/migrations/index.js b/server/startup/migrations/index.js index c32aef2646df..d4353ab9d79c 100644 --- a/server/startup/migrations/index.js +++ b/server/startup/migrations/index.js @@ -187,4 +187,5 @@ import './v187'; import './v188'; import './v189'; import './v190'; +import './v191'; import './xrun'; diff --git a/server/startup/migrations/v191.js b/server/startup/migrations/v191.js new file mode 100644 index 000000000000..10f5af6a62ce --- /dev/null +++ b/server/startup/migrations/v191.js @@ -0,0 +1,9 @@ +import { Migrations } from '../../../app/migrations/server'; +import { Settings } from '../../../app/models/server'; + +Migrations.add({ + version: 191, + up() { + Settings.remove({ _id: /theme-color-status/ }, { multi: true }); + }, +}); From 9cde69f555156297826f9ff751884b3a8cd31c49 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Thu, 21 May 2020 00:45:09 -0300 Subject: [PATCH 12/30] [NEW][ENTERPRISE] Omnichannel Last-Chatted Agent Preferred option (#17666) --- app/livechat/server/lib/Livechat.js | 5 +- app/livechat/server/lib/RoutingManager.js | 2 +- app/models/server/models/LivechatInquiry.js | 16 +++- app/models/server/models/LivechatRooms.js | 14 +++ app/models/server/models/LivechatVisitors.js | 14 +++ app/models/server/models/Rooms.js | 3 - app/models/server/models/Users.js | 4 +- .../server/hooks/beforeRoutingChat.js | 4 +- .../hooks/checkAgentBeforeTakeInquiry.js | 3 + .../handleLastChattedAgentPreferredEvents.js | 96 +++++++++++++++++++ ee/app/livechat-enterprise/server/index.js | 1 + .../livechat-enterprise/server/lib/Helper.js | 3 +- ee/app/livechat-enterprise/server/settings.js | 7 ++ ee/i18n/en.i18n.json | 2 + ee/i18n/pt-BR.i18n.json | 2 + 15 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 ee/app/livechat-enterprise/server/hooks/handleLastChattedAgentPreferredEvents.js diff --git a/app/livechat/server/lib/Livechat.js b/app/livechat/server/lib/Livechat.js index b57571205fa4..ae5004a84500 100644 --- a/app/livechat/server/lib/Livechat.js +++ b/app/livechat/server/lib/Livechat.js @@ -117,8 +117,9 @@ export const Livechat = { } if (room == null) { + const defaultAgent = callbacks.run('livechat.checkDefaultAgentOnNewRoom', agent, guest); // if no department selected verify if there is at least one active and pick the first - if (!agent && !guest.department) { + if (!defaultAgent && !guest.department) { const department = this.getRequiredDepartment(); if (department) { @@ -127,7 +128,7 @@ export const Livechat = { } // delegate room creation to QueueManager - room = await QueueManager.requestRoom({ guest, message, roomInfo, agent, extraData }); + room = await QueueManager.requestRoom({ guest, message, roomInfo, agent: defaultAgent, extraData }); newRoom = true; } diff --git a/app/livechat/server/lib/RoutingManager.js b/app/livechat/server/lib/RoutingManager.js index f654415af4a8..5558d1be5d0e 100644 --- a/app/livechat/server/lib/RoutingManager.js +++ b/app/livechat/server/lib/RoutingManager.js @@ -145,7 +145,7 @@ export const RoutingManager = { LivechatInquiry.takeInquiry(_id); const inq = this.assignAgent(inquiry, agent); - callbacks.run('livechat.afterTakeInquiry', inq); + callbacks.runAsync('livechat.afterTakeInquiry', inq, agent); return LivechatRooms.findOneById(rid); }, diff --git a/app/models/server/models/LivechatInquiry.js b/app/models/server/models/LivechatInquiry.js index 954c7083ab6a..9dc6251a17cb 100644 --- a/app/models/server/models/LivechatInquiry.js +++ b/app/models/server/models/LivechatInquiry.js @@ -45,6 +45,7 @@ export class LivechatInquiry extends Base { _id: inquiryId, }, { $set: { status: 'taken' }, + $unset: { defaultAgent: 1 }, }); } @@ -62,11 +63,14 @@ export class LivechatInquiry extends Base { /* * mark inquiry as queued */ - queueInquiry(inquiryId) { + queueInquiry(inquiryId, defaultAgent) { return this.update({ _id: inquiryId, }, { - $set: { status: 'queued' }, + $set: { + status: 'queued', + ...defaultAgent && { defaultAgent }, + }, }); } @@ -180,6 +184,14 @@ export class LivechatInquiry extends Base { return collectionObj.aggregate(aggregate).toArray(); } + removeDefaultAgentById(inquiryId) { + return this.update({ + _id: inquiryId, + }, { + $unset: { defaultAgent: 1 }, + }); + } + /* * remove the inquiry by roomId */ diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index 25e2e51c6be2..49823c11f896 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -16,6 +16,8 @@ export class LivechatRooms extends Base { this.tryEnsureIndex({ 'metrics.serviceTimeDuration': 1 }, { sparse: true }); this.tryEnsureIndex({ 'metrics.visitorInactivity': 1 }, { sparse: true }); this.tryEnsureIndex({ 'omnichannel.predictedVisitorAbandonmentAt': 1 }, { sparse: true }); + this.tryEnsureIndex({ closedAt: 1 }, { sparse: true }); + this.tryEnsureIndex({ servedBy: 1 }, { sparse: true }); } findLivechat(filter = {}, offset = 0, limit = 20) { @@ -164,6 +166,18 @@ export class LivechatRooms extends Base { return this.findOne(query, options); } + findOneLastServedAndClosedByVisitorToken(visitorToken, options = {}) { + const query = { + t: 'l', + 'v.token': visitorToken, + closedAt: { $exists: true }, + servedBy: { $exists: true }, + }; + + options.sort = { closedAt: -1 }; + return this.findOne(query, options); + } + findOneByVisitorToken(visitorToken, fields) { const options = {}; diff --git a/app/models/server/models/LivechatVisitors.js b/app/models/server/models/LivechatVisitors.js index 803ecf2dc56f..571d950b0fee 100644 --- a/app/models/server/models/LivechatVisitors.js +++ b/app/models/server/models/LivechatVisitors.js @@ -78,6 +78,20 @@ export class LivechatVisitors extends Base { return this.update(query, update); } + updateLastAgentByToken(token, lastAgent) { + const query = { + token, + }; + + const update = { + $set: { + lastAgent, + }, + }; + + return this.update(query, update); + } + /** * Find a visitor by their phone number * @return {object} User from db diff --git a/app/models/server/models/Rooms.js b/app/models/server/models/Rooms.js index 0f038458b700..6e5007cabf90 100644 --- a/app/models/server/models/Rooms.js +++ b/app/models/server/models/Rooms.js @@ -20,9 +20,6 @@ export class Rooms extends Base { // discussions this.tryEnsureIndex({ prid: 1 }, { sparse: true }); this.tryEnsureIndex({ fname: 1 }, { sparse: true }); - // Livechat - statistics - this.tryEnsureIndex({ closedAt: 1 }, { sparse: true }); - // field used for DMs only this.tryEnsureIndex({ uids: 1 }, { sparse: true }); } diff --git a/app/models/server/models/Users.js b/app/models/server/models/Users.js index c9515a3b03e7..5f9374fac4a6 100644 --- a/app/models/server/models/Users.js +++ b/app/models/server/models/Users.js @@ -124,10 +124,10 @@ export class Users extends Base { return this.findOne(query); } - findOneOnlineAgentByUsername(username) { + findOneOnlineAgentByUsername(username, options) { const query = queryStatusAgentOnline({ username }); - return this.findOne(query); + return this.findOne(query, options); } findOneOnlineAgentById(_id) { diff --git a/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js b/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js index dd5cefce1bfa..4a9701648b91 100644 --- a/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js +++ b/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js @@ -3,7 +3,7 @@ import { settings } from '../../../../../app/settings'; import { LivechatInquiry } from '../../../../../app/models/server'; import { dispatchInquiryPosition, checkWaitingQueue } from '../lib/Helper'; -callbacks.add('livechat.beforeRouteChat', async (inquiry) => { +callbacks.add('livechat.beforeRouteChat', async (inquiry, agent) => { if (!settings.get('Livechat_waiting_queue')) { return inquiry; } @@ -18,7 +18,7 @@ callbacks.add('livechat.beforeRouteChat', async (inquiry) => { return inquiry; } - LivechatInquiry.queueInquiry(_id); + LivechatInquiry.queueInquiry(_id, agent); const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ _id }); if (inq) { diff --git a/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.js b/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.js index 4cbdd304f043..513f07d8a3e9 100644 --- a/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.js +++ b/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.js @@ -34,9 +34,12 @@ callbacks.add('livechat.checkAgentBeforeTakeInquiry', async (agent, inquiry) => const { queueInfo: { chats = 0 } = {} } = user; if (maxNumberSimultaneousChat <= chats) { + callbacks.run('livechat.onMaxNumberSimultaneousChatsReached', inquiry, agent); + if (!RoutingManager.getConfig().autoAssignAgent) { throw new Meteor.Error('error-max-number-simultaneous-chats-reached', 'Not allowed'); } + return null; } return agent; diff --git a/ee/app/livechat-enterprise/server/hooks/handleLastChattedAgentPreferredEvents.js b/ee/app/livechat-enterprise/server/hooks/handleLastChattedAgentPreferredEvents.js new file mode 100644 index 000000000000..9bdc2bc8de66 --- /dev/null +++ b/ee/app/livechat-enterprise/server/hooks/handleLastChattedAgentPreferredEvents.js @@ -0,0 +1,96 @@ +import { callbacks } from '../../../../../app/callbacks/server'; +import { RoutingManager } from '../../../../../app/livechat/server/lib/RoutingManager'; +import { settings } from '../../../../../app/settings/server'; +import { LivechatRooms, LivechatInquiry, LivechatVisitors, Users } from '../../../../../app/models/server'; +import { checkWaitingQueue } from '../lib/Helper'; + +const normalizeDefaultAgent = (agent) => { + if (!agent) { + return; + } + + const { _id: agentId, username } = agent; + return { agentId, username }; +}; + +const checkDefaultAgentOnNewRoom = (defaultAgent, defaultGuest) => { + if (defaultAgent || !defaultGuest) { + return defaultAgent; + } + + if (!RoutingManager.getConfig().autoAssignAgent) { + return defaultAgent; + } + + const { _id: guestId } = defaultGuest; + const guest = LivechatVisitors.findOneById(guestId, { fields: { lastAgent: 1, token: 1 } }); + const { lastAgent: { username: usernameByVisitor } = {}, token } = guest; + + const lastGuestAgent = usernameByVisitor && normalizeDefaultAgent(Users.findOneOnlineAgentByUsername(usernameByVisitor, { fields: { _id: 1, username: 1 } })); + if (lastGuestAgent) { + return lastGuestAgent; + } + + const room = LivechatRooms.findOneLastServedAndClosedByVisitorToken(token, { fields: { servedBy: 1 } }); + if (!room || !room.servedBy) { + return defaultAgent; + } + + const { servedBy: { username: usernameByRoom } } = room; + const lastRoomAgent = normalizeDefaultAgent(Users.findOneOnlineAgentByUsername(usernameByRoom, { fields: { _id: 1, username: 1 } })); + return lastRoomAgent || defaultAgent; +}; + +const onMaxNumberSimultaneousChatsReached = (inquiry, agent) => { + if (!inquiry || !inquiry.defaultAgent) { + return inquiry; + } + + if (!RoutingManager.getConfig().autoAssignAgent) { + return inquiry; + } + + const { _id, defaultAgent, department } = inquiry; + + LivechatInquiry.removeDefaultAgentById(_id); + + const { _id: defaultAgentId } = defaultAgent; + const { agentId } = agent; + + if (defaultAgentId === agentId) { + checkWaitingQueue(department); + } + + return LivechatInquiry.findOneById(_id); +}; + +const afterTakeInquiry = (inquiry, agent) => { + if (!inquiry || !agent) { + return inquiry; + } + + if (!RoutingManager.getConfig().autoAssignAgent) { + return inquiry; + } + + const { v: { token } = {} } = inquiry; + if (!token) { + return inquiry; + } + + LivechatVisitors.updateLastAgentByToken(token, { ...agent, ts: new Date() }); + + return inquiry; +}; +settings.get('Livechat_last_chatted_agent_routing', function(key, value) { + if (!value) { + callbacks.remove('livechat.checkDefaultAgentOnNewRoom', 'livechat-check-default-agent-new-room'); + callbacks.remove('livechat.onMaxNumberSimultaneousChatsReached', 'livechat-on-max-number-simultaneous-chats-reached'); + callbacks.remove('livechat.afterTakeInquiry', 'livechat-save-default-agent-after-take-inquiry'); + return; + } + + callbacks.add('livechat.checkDefaultAgentOnNewRoom', checkDefaultAgentOnNewRoom, callbacks.priority.MEDIUM, 'livechat-check-default-agent-new-room'); + callbacks.add('livechat.onMaxNumberSimultaneousChatsReached', onMaxNumberSimultaneousChatsReached, callbacks.priority.MEDIUM, 'livechat-on-max-number-simultaneous-chats-reached'); + callbacks.add('livechat.afterTakeInquiry', afterTakeInquiry, callbacks.priority.MEDIUM, 'livechat-save-default-agent-after-take-inquiry'); +}); diff --git a/ee/app/livechat-enterprise/server/index.js b/ee/app/livechat-enterprise/server/index.js index 63f36630a18c..f18d76223f40 100644 --- a/ee/app/livechat-enterprise/server/index.js +++ b/ee/app/livechat-enterprise/server/index.js @@ -27,6 +27,7 @@ import './hooks/beforeNewInquiry'; import './hooks/beforeNewRoom'; import './hooks/beforeRoutingChat'; import './hooks/checkAgentBeforeTakeInquiry'; +import './hooks/handleLastChattedAgentPreferredEvents'; import './hooks/onCheckRoomParamsApi'; import './hooks/onLoadConfigApi'; import './hooks/onSetUserStatusLivechat'; diff --git a/ee/app/livechat-enterprise/server/lib/Helper.js b/ee/app/livechat-enterprise/server/lib/Helper.js index d3c525e85066..dd3318c8e678 100644 --- a/ee/app/livechat-enterprise/server/lib/Helper.js +++ b/ee/app/livechat-enterprise/server/lib/Helper.js @@ -100,7 +100,8 @@ const processWaitingQueue = async (department) => { return; } - const room = await RoutingManager.delegateInquiry(inquiry); + const { defaultAgent } = inquiry; + const room = await RoutingManager.delegateInquiry(inquiry, defaultAgent); const propagateAgentDelegated = Meteor.bindEnvironment((rid, agentId) => { dispatchAgentDelegated(rid, agentId); diff --git a/ee/app/livechat-enterprise/server/settings.js b/ee/app/livechat-enterprise/server/settings.js index 8d91cb92f6c2..118fe5967a54 100644 --- a/ee/app/livechat-enterprise/server/settings.js +++ b/ee/app/livechat-enterprise/server/settings.js @@ -51,5 +51,12 @@ export const createSettings = () => { enableQuery: { _id: 'Livechat_auto_close_abandoned_rooms', value: true }, }); + settings.add('Livechat_last_chatted_agent_routing', false, { + type: 'boolean', + group: 'Omnichannel', + section: 'Routing', + enableQuery: { _id: 'Livechat_Routing_Method', value: { $ne: 'Manual_Selection' } }, + }); + Settings.addOptionValueById('Livechat_Routing_Method', { key: 'Load_Balancing', i18nLabel: 'Load_Balancing' }); }; diff --git a/ee/i18n/en.i18n.json b/ee/i18n/en.i18n.json index 09f587ee2297..0c44d3332954 100644 --- a/ee/i18n/en.i18n.json +++ b/ee/i18n/en.i18n.json @@ -34,6 +34,8 @@ "List_of_departments_for_forward": "List of departments allowed for forwarding (Optional)", "List_of_departments_for_forward_description": "Allow to set a restricted list of departments that can receive chats from this department", "Livechat_abandoned_rooms_closed_custom_message": "Custom message when room is automatically closed by visitor inactivity", + "Livechat_last_chatted_agent_routing": "Last-Chatted Agent Preferred", + "Livechat_last_chatted_agent_routing_Description": "The Last-Chatted Agent setting allocates chats to the agent who previously interacted with the same visitor if the agent is available when the chat starts.", "Livechat_Monitors": "Monitors", "Livechat_monitors": "Livechat monitors", "Max_number_of_chats_per_agent": "Max. number of simultaneous chats", diff --git a/ee/i18n/pt-BR.i18n.json b/ee/i18n/pt-BR.i18n.json index 892daf29eed0..e7ebff498eae 100644 --- a/ee/i18n/pt-BR.i18n.json +++ b/ee/i18n/pt-BR.i18n.json @@ -26,6 +26,8 @@ "List_of_departments_for_forward": "Lista de departamentos permitidos para o encaminhamento(Opcional).", "List_of_departments_for_forward_description": "Permite definir uma lista restrita de departamentos que podem receber conversas desse departamento.", "Livechat_abandoned_rooms_closed_custom_message": "Mensagem customizada para usar quando a sala for automaticamente fechada por abandono do visitante", + "Livechat_last_chatted_agent_routing": "Agente preferido pela última conversa", + "Livechat_last_chatted_agent_routing_Description": "Agente preferido pela última conversa aloca bate-papos para o agente que interagiu anteriormente com o mesmo visitante, caso o agente esteja disponível quando o bate-papo for iniciado.", "Livechat_Monitors": "Monitores", "Livechat_monitors": "Monitores de Livechat", "Max_number_of_chats_per_agent": "Número máximo de atendimentos simultâneos", From bf5af0da0bae06212e91e8b4b1ac9bc509d09bc9 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 21 May 2020 00:48:01 -0300 Subject: [PATCH 13/30] Update Fuselage version (#17708) --- package-lock.json | 56 +++++++++++++++++++++++------------------------ package.json | 8 +++---- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ec9af78bac7..e43bcec27d6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2818,9 +2818,9 @@ } }, "@rocket.chat/css-in-js": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.8.0.tgz", - "integrity": "sha512-G6RlTlzUwJR/ske8PjY1CsE2ktnA7YOkErkEBp5+FpXMGxCpNb8zqLqx3jrxJqyRKwXIBnX/6PO7dWPFMHTPpw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/css-in-js/-/css-in-js-0.9.0.tgz", + "integrity": "sha512-CK7WAPAG+Vi8yX73cPIGNU5j/zRMbbXqKYrz7qrAY66qXlsFtz+K1Cj2ntownzi9R1wz4wxHmM89/6wN23WKAg==", "requires": { "@emotion/hash": "^0.8.0", "@emotion/stylis": "^0.8.5" @@ -2836,32 +2836,32 @@ } }, "@rocket.chat/fuselage": { - "version": "0.6.3-dev.45", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.45.tgz", - "integrity": "sha512-ZcIYh29PQdSMLEo35D1RgGkRLZ5dIbZcBadJ5aN/QYCBx666i5CSIVOMNlbST1nEN8AKk79FWlBjNhMY8npLtw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.9.0.tgz", + "integrity": "sha512-BRmKElhuf0NwOz3vJdDIwOoGPYm0FZF978ve9kYidCJQevPVY4Th9ptOfD3YCtZjWPWGVqqpbtwbocabPQjurw==", "requires": { - "@rocket.chat/css-in-js": "^0.8.0", - "@rocket.chat/fuselage-tokens": "^0.8.0", - "@rocket.chat/icons": "^0.8.0", + "@rocket.chat/css-in-js": "^0.9.0", + "@rocket.chat/fuselage-tokens": "^0.9.0", + "@rocket.chat/icons": "^0.9.0", "invariant": "^2.2.4" }, "dependencies": { "@rocket.chat/icons": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.8.0.tgz", - "integrity": "sha512-5GGgIeIwK3QdtsalNuhtrzGr2iYDbkYnhjHaABo2j6hENB+xIn1p3AkkrKaYQXLqGvIlzwuTMyTGn9b49HzNPg==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/icons/-/icons-0.9.0.tgz", + "integrity": "sha512-Yfzz19+LoD6OpP57Y7W6E4ctiBP1RfG1LvTC+9/FNPpvWRnlQDySZHpUVn+TGrfuvBQ5YH5XqeHIKWZw+YiWEg==" } } }, "@rocket.chat/fuselage-hooks": { - "version": "0.6.3-dev.35", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.6.3-dev.35.tgz", - "integrity": "sha512-hvnNmiDBYhFGa1rvzuZAuPm1gI79YdJAIy9PZDQ77+deYzTpcR8aTCYsTa4p3hHc3RwflmqrXHDbRAjTiHR/1Q==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-hooks/-/fuselage-hooks-0.9.0.tgz", + "integrity": "sha512-15uw1Z63Q8XLr6Or4YoJdReyYozbp6NFYTIDSe3Dz44gp5oDmXzS+Uwmn2iQPxF3qEbxPEMnt/CcVux/Pv3MNw==" }, "@rocket.chat/fuselage-polyfills": { - "version": "0.6.3-dev.45", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-polyfills/-/fuselage-polyfills-0.6.3-dev.45.tgz", - "integrity": "sha512-h+S+FsfeO6VQVSq98SM1flHdM0Zffeqj790RiZdQzOUHEYbCds+yFYGFIrbS/4UnGnn2rgxpqeuDUtFWT7TRaw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-polyfills/-/fuselage-polyfills-0.9.0.tgz", + "integrity": "sha512-or8zQQAZg9bXWpQD9074PuqtiC1Xoy41Z3syS8ABU0NeDS4llJ2EScSt/ksZz+2y7uh3c3MxrZIZLUAMrbup0g==", "requires": { "@juggle/resize-observer": "^3.1.2", "clipboard-polyfill": "^2.8.6", @@ -2869,22 +2869,22 @@ } }, "@rocket.chat/fuselage-tokens": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.8.0.tgz", - "integrity": "sha512-TVPEckSbzHr+Ix3h4OuEd5OyDVAVnviSQRqwYzAbfRvb4B9riZwqUlvdNKgRofy1og5ovRMZUL9CqduGbsdhsA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-tokens/-/fuselage-tokens-0.9.0.tgz", + "integrity": "sha512-ZiCIDtNsPj7icJLr9iK/Dn0vN+mrUy/blQlrFn0pKznET2ARPAvjWPsAAk/JJu3rlCnD7u4Fd15oI6BJllh+4A==" }, "@rocket.chat/fuselage-ui-kit": { - "version": "0.6.3-dev.39", - "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.6.3-dev.39.tgz", - "integrity": "sha512-ll9lYOM2mEAsKtHiPdxDwVO2YGkarZMCLl7UK6yT71BFVuDY7hJXm14+aj+JBTKc9B2J0CFIo+MfO1cDuqYc+A==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage-ui-kit/-/fuselage-ui-kit-0.9.0.tgz", + "integrity": "sha512-rVp+gaR3L9tJEBx5onjajPi9aNw8cdqUBtuRxgTwpHUPGxZVxadgJo9OXvFGfB0bt8d9DcXMW+ouRJp+LRfLtg==", "requires": { - "@rocket.chat/ui-kit": "^0.8.0" + "@rocket.chat/ui-kit": "^0.9.0" }, "dependencies": { "@rocket.chat/ui-kit": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.8.0.tgz", - "integrity": "sha512-JNpwGcVQfBHjfG/sLJmMwau0BNvUWx210UAji4MnARAvfxBUslUYWzTRDkvxryKX0223dbTC91HOMt1HZDNNLQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/ui-kit/-/ui-kit-0.9.0.tgz", + "integrity": "sha512-BBqLT1vbZjUzG4xzUMo56O0EsnH0sLNaESmBy0YYIAzBYkpxwQcVLY0XWq3w7gcLYEUhFvLVvKCis5zPHkZrqQ==" } } }, diff --git a/package.json b/package.json index 55f6d62ff5cd..99750b95786a 100644 --- a/package.json +++ b/package.json @@ -126,10 +126,10 @@ "@nivo/line": "^0.61.1", "@nivo/pie": "^0.61.1", "@rocket.chat/apps-engine": "1.15.0-beta.3411", - "@rocket.chat/fuselage": "^0.6.3-dev.45", - "@rocket.chat/fuselage-hooks": "^0.6.3-dev.35", - "@rocket.chat/fuselage-polyfills": "^0.6.3-dev.45", - "@rocket.chat/fuselage-ui-kit": "^0.6.3-dev.39", + "@rocket.chat/fuselage": "^0.9.0", + "@rocket.chat/fuselage-hooks": "^0.9.0", + "@rocket.chat/fuselage-polyfills": "^0.9.0", + "@rocket.chat/fuselage-ui-kit": "^0.9.0", "@rocket.chat/icons": "^0.6.3-dev.23", "@rocket.chat/ui-kit": "^0.6.3-dev.23", "@slack/client": "^4.8.0", From 4aed76deba9bad4cc6b33eaff98e0749caf72af3 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Thu, 21 May 2020 01:20:44 -0300 Subject: [PATCH 14/30] [NEW][ENTERPRISE] Support for custom Livechat registration form fields (#17581) Co-authored-by: Guilherme Gazzo --- .../views/app/livechatCustomFieldForm.html | 15 ++++--- .../views/app/livechatCustomFieldForm.js | 29 +++++++++++++ .../client/views/app/tabbar/visitorEdit.html | 23 ++-------- .../client/views/app/tabbar/visitorEdit.js | 34 ++++++--------- .../app/tabbar/visitorEditCustomField.html | 22 ++++++++++ .../app/tabbar/visitorEditCustomField.js | 17 ++++++++ app/livechat/client/views/regular.js | 1 + app/livechat/server/api/lib/livechat.js | 2 +- app/livechat/server/api/v1/config.js | 5 ++- .../server/methods/saveCustomField.js | 6 ++- .../livechatCustomFieldsAdditionalForm.html | 42 ++++++++++++++++++ .../livechatCustomFieldsAdditionalForm.js | 37 ++++++++++++++++ .../views/app/registerCustomTemplates.js | 4 +- .../livechat-enterprise/server/hooks/index.js | 17 ++++++++ .../server/hooks/onLoadConfigApi.js | 39 +++++------------ ee/app/livechat-enterprise/server/index.js | 8 +--- .../livechat-enterprise/server/lib/Helper.js | 43 ++++++++++++++++++- ee/i18n/en.i18n.json | 3 ++ ee/i18n/pt-BR.i18n.json | 3 ++ packages/rocketchat-i18n/i18n/en.i18n.json | 4 +- packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 2 + packages/rocketchat-i18n/i18n/pt.i18n.json | 1 + 22 files changed, 266 insertions(+), 91 deletions(-) create mode 100644 app/livechat/client/views/app/tabbar/visitorEditCustomField.html create mode 100644 app/livechat/client/views/app/tabbar/visitorEditCustomField.js create mode 100644 ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.html create mode 100644 ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.js create mode 100644 ee/app/livechat-enterprise/server/hooks/index.js diff --git a/app/livechat/client/views/app/livechatCustomFieldForm.html b/app/livechat/client/views/app/livechatCustomFieldForm.html index d879ce74218c..0dcf4e1ae792 100644 --- a/app/livechat/client/views/app/livechatCustomFieldForm.html +++ b/app/livechat/client/views/app/livechatCustomFieldForm.html @@ -7,19 +7,19 @@
- +
- +
- @@ -28,18 +28,21 @@
-
- +
- +
+ {{#if customFieldsTemplate}} + {{> Template.dynamic template=customFieldsTemplate data=dataContext }} + {{/if}}
diff --git a/app/livechat/client/views/app/livechatCustomFieldForm.js b/app/livechat/client/views/app/livechatCustomFieldForm.js index b768a5babeae..9f8944dfdd7a 100644 --- a/app/livechat/client/views/app/livechatCustomFieldForm.js +++ b/app/livechat/client/views/app/livechatCustomFieldForm.js @@ -5,6 +5,7 @@ import { Template } from 'meteor/templating'; import toastr from 'toastr'; import { t, handleError } from '../../../../utils'; +import { getCustomFormTemplate } from './customTemplates/register'; import './livechatCustomFieldForm.html'; import { APIClient } from '../../../../utils/client'; @@ -12,6 +13,16 @@ Template.livechatCustomFieldForm.helpers({ customField() { return Template.instance().customField.get(); }, + + customFieldsTemplate() { + return getCustomFormTemplate('livechatCustomFieldsAdditionalForm'); + }, + + dataContext() { + // To make the dynamic template reactive we need to pass a ReactiveVar through the data property + // because only the dynamic template data will be reloaded + return Template.instance().localFields; + }, }); Template.livechatCustomFieldForm.events({ @@ -45,6 +56,16 @@ Template.livechatCustomFieldForm.events({ regexp: regexp.trim(), }; + instance.$('.additional-field').each((i, el) => { + const elField = instance.$(el); + const name = elField.attr('name'); + let value = elField.val(); + if (['true', 'false'].includes(value) && el.tagName === 'SELECT') { + value = value === 'true'; + } + customFieldData[name] = value; + }); + Meteor.call('livechat:saveCustomField', _id, customFieldData, function(error) { $btn.html(oldBtnValue); if (error) { @@ -60,12 +81,20 @@ Template.livechatCustomFieldForm.events({ e.preventDefault(); FlowRouter.go('livechat-customfields'); }, + + 'change .custom-field-input'(e, instance) { + const { target: { name, value } } = e; + instance.localFields.set({ ...instance.localFields.get(), [name]: value }); + }, }); Template.livechatCustomFieldForm.onCreated(async function() { this.customField = new ReactiveVar({}); + this.localFields = new ReactiveVar({}); + const { customField } = await APIClient.v1.get(`livechat/custom-fields/${ FlowRouter.getParam('_id') }`); if (customField) { this.customField.set(customField); + this.localFields.set({ ...customField }); } }); diff --git a/app/livechat/client/views/app/tabbar/visitorEdit.html b/app/livechat/client/views/app/tabbar/visitorEdit.html index a83fcfd5e766..778b28a7e1f5 100644 --- a/app/livechat/client/views/app/tabbar/visitorEdit.html +++ b/app/livechat/client/views/app/tabbar/visitorEdit.html @@ -30,17 +30,9 @@

{{username}}

- {{#if canViewCustomFields }} - {{#each visitorCustomFields}} -
- -
+ {{#each field in visitorCustomFields}} + {{> visitorEditCustomField field }} {{/each}} {{/if}} {{/with}} @@ -94,15 +86,8 @@

{{_ "Conversation" }}

{{#if canViewCustomFields }} - {{#each roomCustomFields}} -
- -
+ {{#each field in roomCustomFields}} + {{> visitorEditCustomField field }} {{/each}} {{/if}} {{/with}} diff --git a/app/livechat/client/views/app/tabbar/visitorEdit.js b/app/livechat/client/views/app/tabbar/visitorEdit.js index 3f9cf9b3e768..536d0b77e275 100644 --- a/app/livechat/client/views/app/tabbar/visitorEdit.js +++ b/app/livechat/client/views/app/tabbar/visitorEdit.js @@ -11,6 +11,16 @@ import { getCustomFormTemplate } from '../customTemplates/register'; const CUSTOM_FIELDS_COUNT = 100; +const getCustomFieldsByScope = (customFields = [], data = {}, filter, disabled) => + customFields + .filter(({ visibility, scope }) => visibility !== 'hidden' && scope === filter) + .map(({ _id: name, scope, label, ...extraData }) => { + const value = data[name] ? data[name] : ''; + return { name, label, scope, value, disabled, ...extraData }; + }); + +const isCustomFieldDisabled = () => !hasPermission('edit-livechat-room-customfields'); + Template.visitorEdit.helpers({ visitor() { return Template.instance().visitor.get(); @@ -20,28 +30,16 @@ Template.visitorEdit.helpers({ return hasAtLeastOnePermission(['view-livechat-room-customfields', 'edit-livechat-room-customfields']); }, - canOnlyViewCustomFields() { - return hasPermission('view-livechat-room-customfields') && !hasPermission('edit-livechat-room-customfields'); - }, - visitorCustomFields() { const customFields = Template.instance().customFields.get(); if (!customFields || customFields.length === 0) { return []; } - const fields = []; const visitor = Template.instance().visitor.get(); const { livechatData = {} } = visitor || {}; - customFields.forEach((field) => { - if (field.visibility !== 'hidden' && field.scope === 'visitor') { - const value = livechatData[field._id] ? livechatData[field._id] : ''; - fields.push({ name: field._id, label: field.label, value }); - } - }); - - return fields; + return getCustomFieldsByScope(customFields, livechatData, 'visitor', isCustomFieldDisabled()); }, room() { @@ -54,18 +52,10 @@ Template.visitorEdit.helpers({ return []; } - const fields = []; const room = Template.instance().room.get(); const { livechatData = {} } = room || {}; - customFields.forEach((field) => { - if (field.visibility !== 'hidden' && field.scope === 'room') { - const value = livechatData[field._id] ? livechatData[field._id] : ''; - fields.push({ name: field._id, label: field.label, value }); - } - }); - - return fields; + return getCustomFieldsByScope(customFields, livechatData, 'room', isCustomFieldDisabled()); }, email() { diff --git a/app/livechat/client/views/app/tabbar/visitorEditCustomField.html b/app/livechat/client/views/app/tabbar/visitorEditCustomField.html new file mode 100644 index 000000000000..bf85704e4b26 --- /dev/null +++ b/app/livechat/client/views/app/tabbar/visitorEditCustomField.html @@ -0,0 +1,22 @@ + diff --git a/app/livechat/client/views/app/tabbar/visitorEditCustomField.js b/app/livechat/client/views/app/tabbar/visitorEditCustomField.js new file mode 100644 index 000000000000..f0024c0725dd --- /dev/null +++ b/app/livechat/client/views/app/tabbar/visitorEditCustomField.js @@ -0,0 +1,17 @@ +import { Template } from 'meteor/templating'; + +import './visitorEditCustomField.html'; + +Template.visitorEditCustomField.helpers({ + optionsList() { + if (!this.options) { + return []; + } + + return this.options.split(','); + }, + selectedField(current) { + const { fieldData: { value } } = Template.currentData(); + return value.trim() === current.trim(); + }, +}); diff --git a/app/livechat/client/views/regular.js b/app/livechat/client/views/regular.js index 30f1a72c3e14..e2a3f3b8b6fd 100644 --- a/app/livechat/client/views/regular.js +++ b/app/livechat/client/views/regular.js @@ -6,6 +6,7 @@ import './app/livechatRoomTagSelector'; import './app/tabbar/agentEdit'; import './app/tabbar/agentInfo'; import './app/tabbar/visitorEdit'; +import './app/tabbar/visitorEditCustomField'; import './app/tabbar/visitorForward'; import './app/tabbar/visitorHistory'; import './app/tabbar/visitorInfo'; diff --git a/app/livechat/server/api/lib/livechat.js b/app/livechat/server/api/lib/livechat.js index b1893f9a0f84..4626ce819b35 100644 --- a/app/livechat/server/api/lib/livechat.js +++ b/app/livechat/server/api/lib/livechat.js @@ -146,7 +146,7 @@ export function settings() { } export async function getExtraConfigInfo(room) { - return callbacks.run('livechat.onLoadConfigApi', room); + return callbacks.run('livechat.onLoadConfigApi', { room }); } export function onCheckRoomParams(params) { diff --git a/app/livechat/server/api/v1/config.js b/app/livechat/server/api/v1/config.js index 50e4229fa40e..85ef7a10a865 100644 --- a/app/livechat/server/api/v1/config.js +++ b/app/livechat/server/api/v1/config.js @@ -27,8 +27,9 @@ API.v1.addRoute('livechat/config', { room = findOpenRoom(token); agent = room && room.servedBy && findAgent(room.servedBy._id); } - const extraConfig = room && Promise.await(getExtraConfigInfo(room)); - Object.assign(config, { online: status, guest, room, agent }, extraConfig); + const extra = Promise.await(getExtraConfigInfo(room)); + const { config: extraConfig = {} } = extra || {}; + Object.assign(config, { online: status, guest, room, agent }, { ...extraConfig }); return API.v1.success({ config }); } catch (e) { diff --git a/app/livechat/server/methods/saveCustomField.js b/app/livechat/server/methods/saveCustomField.js index 4630b967cd26..772ca03cfae5 100644 --- a/app/livechat/server/methods/saveCustomField.js +++ b/app/livechat/server/methods/saveCustomField.js @@ -17,7 +17,7 @@ Meteor.methods({ check(customFieldData, Match.ObjectIncluding({ field: String, label: String, scope: String, visibility: String, regexp: String })); if (!/^[0-9a-zA-Z-_]+$/.test(customFieldData.field)) { - throw new Meteor.Error('error-invalid-custom-field-nmae', 'Invalid custom field name. Use only letters, numbers, hyphens and underscores.', { method: 'livechat:saveCustomField' }); + throw new Meteor.Error('error-invalid-custom-field-name', 'Invalid custom field name. Use only letters, numbers, hyphens and underscores.', { method: 'livechat:saveCustomField' }); } if (_id) { @@ -26,6 +26,8 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-custom-field', 'Custom Field Not found', { method: 'livechat:saveCustomField' }); } } - return LivechatCustomField.createOrUpdateCustomField(_id, customFieldData.field, customFieldData.label, customFieldData.scope, customFieldData.visibility, { regexp: customFieldData.regexp }); + + const { field, label, scope, visibility, ...extraData } = customFieldData; + return LivechatCustomField.createOrUpdateCustomField(_id, field, label, scope, visibility, { ...extraData }); }, }); diff --git a/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.html b/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.html new file mode 100644 index 000000000000..e25cb8f98f8f --- /dev/null +++ b/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.html @@ -0,0 +1,42 @@ + diff --git a/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.js b/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.js new file mode 100644 index 000000000000..2632bd883440 --- /dev/null +++ b/ee/app/livechat-enterprise/client/views/app/customTemplates/livechatCustomFieldsAdditionalForm.js @@ -0,0 +1,37 @@ +import { ReactiveVar } from 'meteor/reactive-var'; +import { Template } from 'meteor/templating'; +import toastr from 'toastr'; + +import './livechatCustomFieldsAdditionalForm.html'; +import { t } from '../../../../../../../app/utils/client'; + +Template.livechatCustomFieldsAdditionalForm.helpers({ + customField() { + return Template.instance().customField.get(); + }, +}); + +Template.livechatCustomFieldsAdditionalForm.onCreated(function() { + this.customField = new ReactiveVar({}); + + this.autorun(() => { + // To make this template reactive we expect a ReactiveVar through the data property, + // because the parent form may not be rerender, only the dynamic template data + this.customField.set({ ...this.data.get() }); + }); +}); + +Template.livechatCustomFieldsAdditionalForm.events({ + 'change .additional-field'(e, instance) { + const { target: { name, value } } = e; + instance.customField.set({ ...instance.customField.get(), [name]: value }); + }, + + 'blur [name="options"]'(e) { + const { currentTarget: { value } } = e; + if (value.trim() !== '' && !/^([a-zA-Z0-9-_ ]+)(,\s*[a-zA-Z0-9-_ ]+)*$/i.test(value)) { + toastr.error(t('error-invalid-value')); + e.currentTarget.focus(); + } + }, +}); diff --git a/ee/app/livechat-enterprise/client/views/app/registerCustomTemplates.js b/ee/app/livechat-enterprise/client/views/app/registerCustomTemplates.js index de436419e742..6a655f1b1ae4 100644 --- a/ee/app/livechat-enterprise/client/views/app/registerCustomTemplates.js +++ b/ee/app/livechat-enterprise/client/views/app/registerCustomTemplates.js @@ -1,12 +1,14 @@ import { addCustomFormTemplate } from '../../../../../../app/livechat/client/views/app/customTemplates/register'; +import './customTemplates/livechatCustomFieldsAdditionalForm'; import './customTemplates/livechatDepartmentCustomFieldsForm'; import './customTemplates/livechatAgentEditCustomFieldsForm'; import './customTemplates/livechatAgentInfoCustomFieldsForm'; import './customTemplates/visitorEditCustomFieldsForm'; import './customTemplates/visitorInfoCustomForm'; -addCustomFormTemplate('livechatDepartmentForm', 'livechatDepartmentCustomFieldsForm'); addCustomFormTemplate('livechatAgentEditForm', 'livechatAgentEditCustomFieldsForm'); addCustomFormTemplate('livechatAgentInfoForm', 'livechatAgentInfoCustomFieldsForm'); +addCustomFormTemplate('livechatCustomFieldsAdditionalForm', 'livechatCustomFieldsAdditionalForm'); +addCustomFormTemplate('livechatDepartmentForm', 'livechatDepartmentCustomFieldsForm'); addCustomFormTemplate('livechatVisitorEditForm', 'visitorEditCustomFieldsForm'); addCustomFormTemplate('livechatVisitorInfo', 'visitorInfoCustomForm'); diff --git a/ee/app/livechat-enterprise/server/hooks/index.js b/ee/app/livechat-enterprise/server/hooks/index.js new file mode 100644 index 000000000000..4877aa007de0 --- /dev/null +++ b/ee/app/livechat-enterprise/server/hooks/index.js @@ -0,0 +1,17 @@ +import './addDepartmentAncestors'; +import './afterForwardChatToDepartment'; +import './beforeListTags'; +import './setPredictedVisitorAbandonmentTime'; +import './beforeForwardRoomToDepartment'; +import './afterRemoveDepartment'; +import './onLoadForwardDepartmentRestrictions'; +import './afterTakeInquiry'; +import './beforeNewInquiry'; +import './beforeNewRoom'; +import './beforeRoutingChat'; +import './checkAgentBeforeTakeInquiry'; +import './onCheckRoomParamsApi'; +import './onLoadConfigApi'; +import './onSetUserStatusLivechat'; +import './onCloseLivechat'; +import './onSaveVisitorInfo'; diff --git a/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js b/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js index b05a0a2b5a6b..7bf3f416c6ce 100644 --- a/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js +++ b/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js @@ -1,35 +1,16 @@ import { callbacks } from '../../../../../app/callbacks'; -import { settings } from '../../../../../app/settings'; -import { LivechatInquiry } from '../../../../../app/models/server'; -import { normalizeQueueInfo } from '../lib/Helper'; +import { getLivechatQueueInfo, getLivechatCustomFields } from '../lib/Helper'; -callbacks.add('livechat.onLoadConfigApi', async (room) => { - if (!room) { - return null; - } +callbacks.add('livechat.onLoadConfigApi', async (options = {}) => { + const { room } = options; - if (!settings.get('Livechat_waiting_queue')) { - return null; - } + const queueInfo = await getLivechatQueueInfo(room); + const customFields = getLivechatCustomFields(); - const { _id: rid } = room; - const inquiry = LivechatInquiry.findOneByRoomId(rid); - if (!inquiry) { - return null; - } + const config = { + ...queueInfo && { queueInfo }, + ...customFields && { customFields }, + }; - const { _id, status } = inquiry; - if (status !== 'queued') { - return null; - } - - const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ _id }); - - let queueInfo; - if (inq) { - const { position, department } = inq; - queueInfo = await normalizeQueueInfo({ position, department }); - } - - return { queueInfo }; + return Object.assign({ config }, options); }, callbacks.priority.MEDIUM, 'livechat-on-load-config-api'); diff --git a/ee/app/livechat-enterprise/server/index.js b/ee/app/livechat-enterprise/server/index.js index f18d76223f40..890418ef567c 100644 --- a/ee/app/livechat-enterprise/server/index.js +++ b/ee/app/livechat-enterprise/server/index.js @@ -1,13 +1,6 @@ import { Meteor } from 'meteor/meteor'; import '../lib/messageTypes'; -import './hooks/addDepartmentAncestors'; -import './hooks/afterForwardChatToDepartment'; -import './hooks/beforeListTags'; -import './hooks/setPredictedVisitorAbandonmentTime'; -import './hooks/beforeForwardRoomToDepartment'; -import './hooks/afterRemoveDepartment'; -import './hooks/onLoadForwardDepartmentRestrictions'; import './methods/addMonitor'; import './methods/getUnitsFromUserRoles'; import './methods/removeMonitor'; @@ -38,6 +31,7 @@ import { onLicense } from '../../license/server'; onLicense('livechat-enterprise', () => { require('./api'); + require('./hooks'); const { createPermissions } = require('./permissions'); const { createSettings } = require('./settings'); diff --git a/ee/app/livechat-enterprise/server/lib/Helper.js b/ee/app/livechat-enterprise/server/lib/Helper.js index dd3318c8e678..af42c8fce807 100644 --- a/ee/app/livechat-enterprise/server/lib/Helper.js +++ b/ee/app/livechat-enterprise/server/lib/Helper.js @@ -3,7 +3,14 @@ import { Match, check } from 'meteor/check'; import moment from 'moment'; import { hasRole } from '../../../../../app/authorization'; -import { LivechatDepartment, Users, LivechatInquiry, LivechatRooms, Messages } from '../../../../../app/models/server'; +import { + LivechatDepartment, + Users, + LivechatInquiry, + LivechatRooms, + Messages, + LivechatCustomField, +} from '../../../../../app/models/server'; import { Rooms as RoomRaw } from '../../../../../app/models/server/raw'; import { settings } from '../../../../../app/settings'; import { Livechat } from '../../../../../app/livechat/server/lib/Livechat'; @@ -217,3 +224,37 @@ export const updatePriorityInquiries = (priority) => { updateInquiryQueuePriority(room._id, priority); }); }; + +export const getLivechatCustomFields = () => { + const customFields = LivechatCustomField.find({ visibility: 'visible', scope: 'visitor', public: true }).fetch(); + return customFields.map(({ _id, label, regexp, required = false, type, defaultValue = null, options }) => ({ _id, label, regexp, required, type, defaultValue, ...options && options !== '' && { options: options.split(',') } })); +}; + +export const getLivechatQueueInfo = async (room) => { + if (!room) { + return null; + } + + if (!settings.get('Livechat_waiting_queue')) { + return null; + } + + const { _id: rid } = room; + const inquiry = LivechatInquiry.findOneByRoomId(rid, { fields: { _id: 1, status: 1 } }); + if (!inquiry) { + return null; + } + + const { _id, status } = inquiry; + if (status !== 'queued') { + return null; + } + + const [inq] = await LivechatInquiry.getCurrentSortedQueueAsync({ _id }); + + if (!inq) { + return null; + } + + return normalizeQueueInfo(inq); +}; diff --git a/ee/i18n/en.i18n.json b/ee/i18n/en.i18n.json index 0c44d3332954..a94242a2d03c 100644 --- a/ee/i18n/en.i18n.json +++ b/ee/i18n/en.i18n.json @@ -11,6 +11,7 @@ "Canned_Response_Removed": "Canned Response Removed", "Canned_Responses_Enable": "Enable Canned Responses", "Closed_automatically": "Closed automatically by the system", + "Default_value": "Default value", "Edit_Tag": "Edit Tag", "Edit_Unit": "Edit Unit", "Edit_Priority": "Edit Priority", @@ -34,6 +35,8 @@ "List_of_departments_for_forward": "List of departments allowed for forwarding (Optional)", "List_of_departments_for_forward_description": "Allow to set a restricted list of departments that can receive chats from this department", "Livechat_abandoned_rooms_closed_custom_message": "Custom message when room is automatically closed by visitor inactivity", + "Livechat_custom_fields_options_placeholder": "Comma-separated list used to select a pre-configured value. Spaces between elements are not accepted.", + "Livechat_custom_fields_public_description": "Public custom fields will be displayed in external applications, such as Livechat, etc.", "Livechat_last_chatted_agent_routing": "Last-Chatted Agent Preferred", "Livechat_last_chatted_agent_routing_Description": "The Last-Chatted Agent setting allocates chats to the agent who previously interacted with the same visitor if the agent is available when the chat starts.", "Livechat_Monitors": "Monitors", diff --git a/ee/i18n/pt-BR.i18n.json b/ee/i18n/pt-BR.i18n.json index e7ebff498eae..2d772e4be909 100644 --- a/ee/i18n/pt-BR.i18n.json +++ b/ee/i18n/pt-BR.i18n.json @@ -5,6 +5,7 @@ "Add_monitor": "Adicionar Monitor", "Available_departments": "Departamentos disponíveis", "Closed_automatically": "Fechado automaticamente pelo sistema", + "Default_value": "Default value", "Edit_Tag": "Editar Tag", "Edit_Unit": "Editar Unidade", "Edit_Priority": "Editar Prioridade", @@ -26,6 +27,8 @@ "List_of_departments_for_forward": "Lista de departamentos permitidos para o encaminhamento(Opcional).", "List_of_departments_for_forward_description": "Permite definir uma lista restrita de departamentos que podem receber conversas desse departamento.", "Livechat_abandoned_rooms_closed_custom_message": "Mensagem customizada para usar quando a sala for automaticamente fechada por abandono do visitante", + "Livechat_custom_fields_options_placeholder": "Lista separada por vírgula usada para selecionar um valor pré-configurado. Espaços entre elementos não são aceitos.", + "Livechat_custom_fields_public_description": "Os custom fields públicos serão exibidos nos aplicativos externos, como o Livechat etc.", "Livechat_last_chatted_agent_routing": "Agente preferido pela última conversa", "Livechat_last_chatted_agent_routing_Description": "Agente preferido pela última conversa aloca bate-papos para o agente que interagiu anteriormente com o mesmo visitante, caso o agente esteja disponível quando o bate-papo for iniciado.", "Livechat_Monitors": "Monitores", diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 66795f3b3dd2..d6210569d3bf 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1406,6 +1406,7 @@ "error-invalid-urls": "Invalid URLs", "error-invalid-user": "Invalid user", "error-invalid-username": "Invalid username", + "error-invalid-value": "Invalid valid", "error-invalid-webhook-response": "The webhook URL responded with a status other than 200", "error-message-deleting-blocked": "Message deleting is blocked", "error-message-editing-blocked": "Message editing is blocked", @@ -2802,7 +2803,7 @@ "Refresh_oauth_services": "Refresh OAuth Services", "Refresh_your_page_after_install_to_enable_screen_sharing": "Refresh your page after install to enable screen sharing", "Regenerate_codes": "Regenerate codes", - "Regexp_validation": "Validation by RegExp", + "Regexp_validation": "Validation by regular expression", "Register": "Register a new account", "Register_Server": "Register Server", "Register_Server_Info": "Use the preconfigured gateways and proxies provided by Rocket.Chat Technologies Corp.", @@ -3634,6 +3635,7 @@ "UTF8_Names_Slugify": "UTF8 Names Slugify", "UTF8_Names_Validation": "UTF8 Names Validation", "UTF8_Names_Validation_Description": "RegExp that will be used to validate usernames and channel names", + "Validation": "Validation", "Value_messages": "__value__ messages", "Value_users": "__value__ users", "Validate_email_address": "Validate Email Address", diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index f4bdd6bf0d33..5c293c319b42 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -2541,6 +2541,7 @@ "Refresh_oauth_services": "Atualize os Serviços OAuth", "Refresh_your_page_after_install_to_enable_screen_sharing": "Atualize sua página após a instalação para permitir o compartilhamento de tela", "Regenerate_codes": "Regenerar códigos", + "Regexp_validation": "Validação por expressão regular", "Register": "Registrar-se", "Register_Server": "Registrar Servidor", "Register_Server_Info": "Use os gateways e proxies pré-configurados fornecidos pela Rocket.Chat Technologies Corp.", @@ -3272,6 +3273,7 @@ "UTF8_Names_Validation": "Validação de Nomes UTF8", "UTF8_Names_Validation_Description": "Não permitir caracteres especiais e espaços. Você pode usar - _ e. mas não no final do nome", "Validate_email_address": "Validar endereço de e-mail", + "Validation": "Validação", "Verification_email_body": "Você criou uma conta com sucesso em [Site_Name]. Por favor, clique no botão abaixo para confirmar seu endereço de e-mail e finalizar o registro.", "Verification": "Verificação", "Verification_Description": "Você pode usar os seguintes placeholders:
  • [Verification_Url] para o URL de verificação.
  • [nome], [fname], [lname] para o nome completo, primeiro nome ou sobrenome do usuário, respectivamente.
  • [email] para o email do usuário.
  • [Site_Name] e [Site_URL] para o Nome da Aplicação e o URL, respectivamente.
", diff --git a/packages/rocketchat-i18n/i18n/pt.i18n.json b/packages/rocketchat-i18n/i18n/pt.i18n.json index 6cce50aa8e08..a227f8e0c9ac 100644 --- a/packages/rocketchat-i18n/i18n/pt.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt.i18n.json @@ -1256,6 +1256,7 @@ "error-invalid-triggerWords": "Gerador de palavras inválido", "error-invalid-urls": "URLs inválidas", "error-invalid-user": "Utilizador inválido", + "error-invalid-value": "Valor inválido", "error-invalid-username": "Nome de utilizador Inválido", "error-invalid-webhook-response": "O URL do webhook respondeu com um status diferente de 200", "error-message-deleting-blocked": "Exclusão de mensagens está bloqueada", From c35811ddf5d34d5ac1e2c0b0b76131049ae75cbb Mon Sep 17 00:00:00 2001 From: Ritvik jain <34532173+ritvikjain99@users.noreply.github.com> Date: Thu, 21 May 2020 09:52:37 +0530 Subject: [PATCH 15/30] [FIX] Can't click on room's actions menu of sidebar list when in search mode (#16548) --- app/ui-message/client/popup/messagePopup.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/ui-message/client/popup/messagePopup.js b/app/ui-message/client/popup/messagePopup.js index 7ac6a7d785f2..f948dd6d4ffb 100644 --- a/app/ui-message/client/popup/messagePopup.js +++ b/app/ui-message/client/popup/messagePopup.js @@ -288,12 +288,16 @@ Template.messagePopup.events({ const template = Template.instance(); template.clickingItem = true; }, - 'mouseup .popup-item, touchend .popup-item'() { + 'mouseup .popup-item, touchend .popup-item'(e) { + e.stopPropagation(); const template = Template.instance(); + const wasMenuIconClicked = e.target.classList.contains('sidebar-item__menu-icon'); template.clickingItem = false; - template.value.set(this._id); - template.enterValue(); - template.open.set(false); + if (!wasMenuIconClicked) { + template.value.set(this._id); + template.enterValue(); + template.open.set(false); + } }, }); From 9826434e2c7bc4a716cd8db2302c4e30901dd518 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Thu, 21 May 2020 01:24:00 -0300 Subject: [PATCH 16/30] Upgrade Livechat Widget version to 1.5.0 (#17710) --- package-lock.json | 47 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index e43bcec27d6f..f73e245f0d76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2810,6 +2810,11 @@ "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", @@ -2894,9 +2899,9 @@ "integrity": "sha512-MGljJJkGVe9g3UnKq2tSnfFq1gI6nIFociIXmOx9h/ZISeRc+xL6HpJ9pnbLXubFTPppNYn8JiVDlVB8Mm0flw==" }, "@rocket.chat/livechat": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@rocket.chat/livechat/-/livechat-1.4.0.tgz", - "integrity": "sha512-jOUy49njPMW0ZmL9Gk6lRv4X0WTSS9N78iSzR/p3pSV4ivEQk1LRXCi6QLknZmxEXIpe6MTJgUY/ggsORfxrDQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/livechat/-/livechat-1.5.0.tgz", + "integrity": "sha512-Qq+kMRdY6RpZlzl5q3uM7hpAQF5tFFw+v7ON1IqBlFhkX5JA1mzpXnRWzb0si1LtuJ4NjdK2CS4xqvlaVn4A8Q==", "dev": true, "requires": { "@kossnocorp/desvg": "^0.2.0", @@ -2936,12 +2941,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, "query-string": { "version": "6.8.3", "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.3.tgz", @@ -12975,9 +12974,9 @@ } }, "date-fns": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.11.0.tgz", - "integrity": "sha512-8P1cDi8ebZyDxUyUprBXwidoEtiQAawYPGvpfb+Dg0G6JrQ+VozwOmm91xYC0vAv1+0VmLehEPb+isg4BGUFfA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.14.0.tgz", + "integrity": "sha512-1zD+68jhFgDIM0rF05rcwYO8cExdNqxjq4xP1QKM60Q45mnO6zaMWB4tOzrIr4M4GSLntsKeE4c9Bdl2jhL/yw==", "dev": true }, "date-now": { @@ -20965,9 +20964,9 @@ "dev": true }, "make-plural": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.1.0.tgz", - "integrity": "sha512-0ekbPHqxcdRcmjZ43TkRuejK5rXgMF1OjG4FVnVHgCvOcjrexaSX7a0dfAvqhOm1qWPgjYnXtmz3cHpHW5ZewA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.2.1.tgz", + "integrity": "sha512-AmkruwJ9EjvyTv6AM8MBMK3TAeOJvhgTv5YQXzF0EP2qawhpvMjDpHvsdOIIT0Vn+BB0+IogmYZ1z+Ulm/m0Fg==", "dev": true }, "map-age-cleaner": { @@ -21025,9 +21024,9 @@ }, "dependencies": { "entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz", + "integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==", "dev": true } } @@ -21388,9 +21387,9 @@ "dev": true }, "messageformat-parser": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.2.tgz", - "integrity": "sha512-7dWuifeyldz7vhEuL96Kwq1fhZXBW+TUfbnHN4UCrCxoXQTYjHnR78eI66Gk9LaLLsAvzPNVJBaa66DRfFNaiA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz", + "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==", "dev": true }, "meteor-blaze-tools": { @@ -22772,9 +22771,9 @@ }, "dependencies": { "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", "dev": true } } diff --git a/package.json b/package.json index 99750b95786a..96e3934081e9 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@babel/preset-react": "^7.0.0", "@octokit/rest": "^16.1.0", "@rocket.chat/eslint-config": "^0.3.0", - "@rocket.chat/livechat": "^1.4.0", + "@rocket.chat/livechat": "^1.5.0", "@settlin/spacebars-loader": "^1.0.7", "@storybook/addon-actions": "^5.3.18", "@storybook/addon-knobs": "^5.3.18", From d46c864f5ef792eafff27d634c4a32bb7486c85e Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Thu, 21 May 2020 01:32:13 -0300 Subject: [PATCH 17/30] [NEW][ENTERPRISE] Support Omnichannel conversations auditing (#17692) Co-authored-by: Rodrigo Nascimento --- app/livechat/imports/server/rest/visitors.js | 16 +++++++- app/livechat/server/api/lib/visitors.js | 24 +++++++++++ app/models/server/models/LivechatRooms.js | 10 +++++ app/models/server/raw/LivechatVisitors.js | 41 +++++++++++++++++++ app/ui/client/components/popupList.html | 9 ++++ .../client/templates/audit/audit.html | 7 +++- .../auditing/client/templates/audit/audit.js | 36 ++++++++++++---- ee/app/auditing/client/utils.js | 13 +----- ee/app/auditing/server/methods.js | 34 +++++++++++---- packages/rocketchat-i18n/i18n/en.i18n.json | 2 + packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 2 + 11 files changed, 163 insertions(+), 31 deletions(-) diff --git a/app/livechat/imports/server/rest/visitors.js b/app/livechat/imports/server/rest/visitors.js index c828e9552e58..cc38c3bc4008 100644 --- a/app/livechat/imports/server/rest/visitors.js +++ b/app/livechat/imports/server/rest/visitors.js @@ -2,7 +2,7 @@ import { check } from 'meteor/check'; import { API } from '../../../../api/server'; -import { findVisitorInfo, findVisitedPages, findChatHistory } from '../../../server/api/lib/visitors'; +import { findVisitorInfo, findVisitedPages, findChatHistory, findVisitorsToAutocomplete } from '../../../server/api/lib/visitors'; API.v1.addRoute('livechat/visitors.info', { authRequired: true }, { get() { @@ -62,3 +62,17 @@ API.v1.addRoute('livechat/visitors.chatHistory/room/:roomId/visitor/:visitorId', return API.v1.success(history); }, }); + +API.v1.addRoute('livechat/visitors.autocomplete', { authRequired: true }, { + get() { + const { selector } = this.queryParams; + if (!selector) { + return API.v1.failure('The \'selector\' param is required'); + } + + return API.v1.success(Promise.await(findVisitorsToAutocomplete({ + userId: this.userId, + selector: JSON.parse(selector), + }))); + }, +}); diff --git a/app/livechat/server/api/lib/visitors.js b/app/livechat/server/api/lib/visitors.js index ad7cb3da93e5..d1c7477fdd56 100644 --- a/app/livechat/server/api/lib/visitors.js +++ b/app/livechat/server/api/lib/visitors.js @@ -72,3 +72,27 @@ export async function findChatHistory({ userId, roomId, visitorId, pagination: { total, }; } + +export async function findVisitorsToAutocomplete({ userId, selector }) { + if (!await hasPermissionAsync(userId, 'view-l-room')) { + return { items: [] }; + } + const { exceptions = [], conditions = {} } = selector; + + const options = { + fields: { + _id: 1, + name: 1, + username: 1, + }, + limit: 10, + sort: { + name: 1, + }, + }; + + const items = await LivechatVisitors.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray(); + return { + items, + }; +} diff --git a/app/models/server/models/LivechatRooms.js b/app/models/server/models/LivechatRooms.js index 49823c11f896..6f9e1957c491 100644 --- a/app/models/server/models/LivechatRooms.js +++ b/app/models/server/models/LivechatRooms.js @@ -252,6 +252,16 @@ export class LivechatRooms extends Base { return this.find(query); } + findByVisitorIdAndAgentId(visitorId, agentId, options) { + const query = { + t: 'l', + ...visitorId && { 'v._id': visitorId }, + ...agentId && { 'servedBy._id': agentId }, + }; + + return this.find(query, options); + } + findByVisitorId(visitorId) { const query = { t: 'l', diff --git a/app/models/server/raw/LivechatVisitors.js b/app/models/server/raw/LivechatVisitors.js index 7ee3f02f2cca..8be6eccd5d49 100644 --- a/app/models/server/raw/LivechatVisitors.js +++ b/app/models/server/raw/LivechatVisitors.js @@ -1,3 +1,5 @@ +import s from 'underscore.string'; + import { BaseRaw } from './BaseRaw'; export class LivechatVisitorsRaw extends BaseRaw { @@ -12,4 +14,43 @@ export class LivechatVisitorsRaw extends BaseRaw { return this.find(query, { fields: { _id: 1 } }); } + + findByNameRegexWithExceptionsAndConditions(searchTerm, exceptions = [], conditions = {}, options = {}) { + if (!Array.isArray(exceptions)) { + exceptions = [exceptions]; + } + + const nameRegex = new RegExp(`^${ s.escapeRegExp(searchTerm).trim() }`, 'i'); + + const match = { + $match: { + name: nameRegex, + _id: { + $nin: exceptions, + }, + ...conditions, + }, + }; + + const { fields, sort, offset, count } = options; + const project = { + $project: { + custom_name: { $concat: ['$username', ' - ', '$name'] }, + ...fields, + }, + }; + + const order = { $sort: sort || { name: 1 } }; + const params = [match, project, order]; + + if (offset) { + params.push({ $skip: offset }); + } + + if (count) { + params.push({ $limit: count }); + } + + return this.col.aggregate(params); + } } diff --git a/app/ui/client/components/popupList.html b/app/ui/client/components/popupList.html index 49318e3aea9e..135554197510 100644 --- a/app/ui/client/components/popupList.html +++ b/app/ui/client/components/popupList.html @@ -43,3 +43,12 @@ {{{modifier item.name}}} + + diff --git a/ee/app/auditing/client/templates/audit/audit.html b/ee/app/auditing/client/templates/audit/audit.html index 1493064c8eed..b5247322ce60 100644 --- a/ee/app/auditing/client/templates/audit/audit.html +++ b/ee/app/auditing/client/templates/audit/audit.html @@ -18,12 +18,15 @@ {{> icon block="rc-select__arrow" icon="arrow-down" }} - {{> auditAutocomplete key='room' hide=typeD onChange=onChange prepare=prepareRoom field='name' term='name' icon='hashtag' label="room_name" placeholder='Channel_Name_Placeholder'}} - {{> auditAutocompleteDirectMessage key='users' hide=nTypeD onChange=onChange collection='UserAndRoom' modifier=modifierUser endpoint='users.autocomplete' field='username' icon='at' label="From" placeholder='Username_Placeholder'}} + {{> auditAutocomplete key='room' hide=nTypeOthers onChange=onChange prepare=prepareRoom field='name' term='name' icon='hashtag' label="room_name" placeholder='Channel_Name_Placeholder'}} + {{> auditAutocompleteDirectMessage key='users' hide=nTypeDM onChange=onChange collection='UserAndRoom' modifier=modifierUser endpoint='users.autocomplete' field='username' icon='at' label="From" placeholder='Username_Placeholder'}} + {{> auditAutocomplete key='visitor' hide=nTypeOmni onChange=onChange collection='CachedVisitorsList' modifier=modifierUser endpoint='livechat/visitors.autocomplete' field='custom_name' term='custom_name' icon='omnichannel' label="Visitor" templateItem="popupList_item_custom" placeholder='Visitor_Name_Placeholder'}} + {{> auditAutocomplete key='agent' hide=nTypeOmni onChange=onChange collection='CachedAgentsList' conditions=agentConditions modifier=modifierUser endpoint='users.autocomplete' field='username' icon='omnichannel' label="Agent" placeholder='Agent_Name_Placeholder'}}