diff --git a/apps/meteor/app/livechat/imports/server/rest/departments.ts b/apps/meteor/app/livechat/imports/server/rest/departments.ts index e501782744d4..ce0d9e83143e 100644 --- a/apps/meteor/app/livechat/imports/server/rest/departments.ts +++ b/apps/meteor/app/livechat/imports/server/rest/departments.ts @@ -2,7 +2,7 @@ import { isLivechatDepartmentProps } from '@rocket.chat/rest-typings'; import { Match, check } from 'meteor/check'; import { API } from '../../../../api/server'; -import { hasPermission } from '../../../../authorization/server'; +import { hasPermission, hasAtLeastOnePermission } from '../../../../authorization/server'; import { LivechatDepartment, LivechatDepartmentAgents } from '../../../../models/server'; import { Livechat } from '../../../server/lib/Livechat'; import { @@ -18,6 +18,10 @@ API.v1.addRoute( { authRequired: true, validateParams: isLivechatDepartmentProps }, { async get() { + if (!hasAtLeastOnePermission(this.userId, ['view-livechat-departments', 'view-l-room'])) { + return API.v1.unauthorized(); + } + const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); @@ -76,6 +80,10 @@ API.v1.addRoute( { authRequired: true }, { async get() { + if (!hasAtLeastOnePermission(this.userId, ['view-livechat-departments', 'view-l-room'])) { + return API.v1.unauthorized(); + } + check(this.urlParams, { _id: String, }); diff --git a/apps/meteor/app/livechat/imports/server/rest/officeHour.js b/apps/meteor/app/livechat/imports/server/rest/officeHour.js deleted file mode 100644 index 1dcb2827f63b..000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/officeHour.js +++ /dev/null @@ -1,21 +0,0 @@ -import { API } from '../../../../api/server'; -import { findLivechatOfficeHours } from '../../../server/api/lib/officeHour'; - -API.v1.addRoute( - 'livechat/office-hours', - { authRequired: true }, - { - get() { - const { officeHours } = Promise.await(findLivechatOfficeHours({ userId: this.userId })); - return API.v1.success( - this.deprecationWarning({ - endpoint: 'livechat/office-hours', - versionWillBeRemoved: '4.0.0', - response: { - officeHours, - }, - }), - ); - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api.js b/apps/meteor/app/livechat/server/api.js index 9e2902ad30b3..55f2768a0941 100644 --- a/apps/meteor/app/livechat/server/api.js +++ b/apps/meteor/app/livechat/server/api.js @@ -13,5 +13,4 @@ import '../imports/server/rest/visitors.js'; import '../imports/server/rest/visitors.ts'; import '../imports/server/rest/dashboards.js'; import '../imports/server/rest/queue.js'; -import '../imports/server/rest/officeHour.js'; import '../imports/server/rest/businessHours.js'; diff --git a/apps/meteor/app/livechat/server/api/lib/officeHour.js b/apps/meteor/app/livechat/server/api/lib/officeHour.js deleted file mode 100644 index 18512eec1df7..000000000000 --- a/apps/meteor/app/livechat/server/api/lib/officeHour.js +++ /dev/null @@ -1,13 +0,0 @@ -import { LivechatBusinessHours } from '@rocket.chat/models'; - -import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; - -export async function findLivechatOfficeHours({ userId }) { - if (!(await hasPermissionAsync(userId, 'view-livechat-business-hours'))) { - throw new Error('error-not-authorized'); - } - - return { - officeHours: (await LivechatBusinessHours.findOneDefaultBusinessHour()).workHours, - }; -} diff --git a/apps/meteor/app/livechat/server/index.js b/apps/meteor/app/livechat/server/index.js index 217db0c7a35b..e681d8010ae4 100644 --- a/apps/meteor/app/livechat/server/index.js +++ b/apps/meteor/app/livechat/server/index.js @@ -31,7 +31,6 @@ import './methods/getAgentData'; import './methods/getAgentOverviewData'; import './methods/getAnalyticsChartData'; import './methods/getAnalyticsOverviewData'; -import './methods/getInitialData'; import './methods/getNextAgent'; import './methods/getRoutingConfig'; import './methods/loadHistory'; @@ -61,7 +60,6 @@ import './methods/sendOfflineMessage'; import './methods/setCustomField'; import './methods/setDepartmentForVisitor'; import './methods/startVideoCall'; -import './methods/startFileUploadRoom'; import './methods/transfer'; import './methods/webhookTest'; import './methods/setUpConnection'; diff --git a/apps/meteor/app/livechat/server/methods/getInitialData.js b/apps/meteor/app/livechat/server/methods/getInitialData.js deleted file mode 100644 index b6eab00f57bd..000000000000 --- a/apps/meteor/app/livechat/server/methods/getInitialData.js +++ /dev/null @@ -1,112 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; -import { LivechatTrigger, LivechatVisitors } from '@rocket.chat/models'; - -import { LivechatRooms, Users, LivechatDepartment } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; -import { deprecationWarning } from '../../../api/server/helpers/deprecationWarning'; - -Meteor.methods({ - async 'livechat:getInitialData'(visitorToken, departmentId) { - const info = { - enabled: null, - title: null, - color: null, - registrationForm: null, - room: null, - visitor: null, - triggers: [], - departments: [], - allowSwitchingDepartments: null, - online: true, - offlineColor: null, - offlineMessage: null, - offlineSuccessMessage: null, - offlineUnavailableMessage: null, - displayOfflineForm: null, - videoCall: null, - fileUpload: null, - conversationFinishedMessage: null, - conversationFinishedText: null, - nameFieldRegistrationForm: null, - emailFieldRegistrationForm: null, - registrationFormMessage: null, - showConnecting: false, - }; - - const options = { - fields: { - name: 1, - t: 1, - cl: 1, - u: 1, - usernames: 1, - v: 1, - servedBy: 1, - departmentId: 1, - }, - }; - const room = departmentId - ? LivechatRooms.findOpenByVisitorTokenAndDepartmentId(visitorToken, departmentId, options).fetch() - : LivechatRooms.findOpenByVisitorToken(visitorToken, options).fetch(); - if (room && room.length > 0) { - info.room = room[0]; - } - - const visitor = await LivechatVisitors.getVisitorByToken(visitorToken, { - fields: { - name: 1, - username: 1, - visitorEmails: 1, - department: 1, - }, - }); - - if (room) { - info.visitor = visitor; - } - - const initSettings = Livechat.getInitSettings(); - - info.title = initSettings.Livechat_title; - info.color = initSettings.Livechat_title_color; - info.enabled = initSettings.Livechat_enabled; - info.registrationForm = initSettings.Livechat_registration_form; - info.offlineTitle = initSettings.Livechat_offline_title; - info.offlineColor = initSettings.Livechat_offline_title_color; - info.offlineMessage = initSettings.Livechat_offline_message; - info.offlineSuccessMessage = initSettings.Livechat_offline_success_message; - info.offlineUnavailableMessage = initSettings.Livechat_offline_form_unavailable; - info.displayOfflineForm = initSettings.Livechat_display_offline_form; - info.language = initSettings.Language; - info.videoCall = initSettings.Omnichannel_call_provider === 'Jitsi' && initSettings.Jitsi_Enabled === true; - info.fileUpload = initSettings.Livechat_fileupload_enabled && initSettings.FileUpload_Enabled; - info.transcript = initSettings.Livechat_enable_transcript; - info.transcriptMessage = initSettings.Livechat_transcript_message; - info.conversationFinishedMessage = initSettings.Livechat_conversation_finished_message; - info.conversationFinishedText = initSettings.Livechat_conversation_finished_text; - info.nameFieldRegistrationForm = initSettings.Livechat_name_field_registration_form; - info.emailFieldRegistrationForm = initSettings.Livechat_email_field_registration_form; - info.registrationFormMessage = initSettings.Livechat_registration_form_message; - info.showConnecting = initSettings.Livechat_Show_Connecting; - - info.agentData = room && room[0] && room[0].servedBy && Users.getAgentInfo(room[0].servedBy._id); - - await LivechatTrigger.findEnabled().forEach((trigger) => { - info.triggers.push(_.pick(trigger, '_id', 'actions', 'conditions', 'runOnce')); - }); - - LivechatDepartment.findEnabledWithAgents().forEach((department) => { - info.departments.push(department); - }); - info.allowSwitchingDepartments = initSettings.Livechat_allow_switching_departments; - - info.online = Users.findOnlineAgents().count() > 0; - - return deprecationWarning({ - endpoint: 'livechat:getInitialData', - versionWillBeRemoved: '5.0', - response: info, - }); - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/startFileUploadRoom.js b/apps/meteor/app/livechat/server/methods/startFileUploadRoom.js deleted file mode 100644 index 5f8f6a7c8889..000000000000 --- a/apps/meteor/app/livechat/server/methods/startFileUploadRoom.js +++ /dev/null @@ -1,30 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import { OmnichannelSourceType } from '@rocket.chat/core-typings'; -import { LivechatVisitors } from '@rocket.chat/models'; - -import { Livechat } from '../lib/Livechat'; -import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; - -// TODO: check if this is still in use -Meteor.methods({ - async 'livechat:startFileUploadRoom'(roomId, token) { - methodDeprecationLogger.warn('livechat:startFileUploadRoom will be deprecated in future versions of Rocket.Chat'); - const guest = await LivechatVisitors.getVisitorByToken(token); - - const message = { - _id: Random.id(), - rid: roomId || Random.id(), - msg: '', - ts: new Date(), - token: guest.token, - }; - - const roomInfo = { - source: OmnichannelSourceType.API, - alias: 'file-upload', - }; - - return Livechat.getRoom(guest, message, roomInfo); - }, -}); diff --git a/apps/meteor/client/components/Omnichannel/Tags.tsx b/apps/meteor/client/components/Omnichannel/Tags.tsx index 6887bfe07e4b..14c740690d7f 100644 --- a/apps/meteor/client/components/Omnichannel/Tags.tsx +++ b/apps/meteor/client/components/Omnichannel/Tags.tsx @@ -22,7 +22,7 @@ const Tags = ({ const t = useTranslation(); const forms = useFormsSubscription() as any; - const { value: tagsResult, phase: stateTags } = useEndpointData('/v1/livechat/tags.list'); + const { value: tagsResult, phase: stateTags } = useEndpointData('/v1/livechat/tags'); // TODO: Refactor the formsSubscription to use components instead of hooks (since the only thing the hook does is return a component) const { useCurrentChatTags } = forms; diff --git a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts index 8a5d99b9f83e..282897f298fb 100644 --- a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts +++ b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts @@ -22,7 +22,7 @@ export const useDepartmentsByUnitsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const getDepartments = useEndpoint('GET', `/v1/livechat/departments.available-by-unit/${options.unitId || 'none'}`); + const getDepartments = useEndpoint('GET', `/v1/livechat/units/${options.unitId || 'none'}/departments/available`); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/views/hooks/useMonitorsList.ts b/apps/meteor/client/views/hooks/useMonitorsList.ts index decfa3ee3c70..3bac71b62df2 100644 --- a/apps/meteor/client/views/hooks/useMonitorsList.ts +++ b/apps/meteor/client/views/hooks/useMonitorsList.ts @@ -21,7 +21,7 @@ export const useMonitorsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const getMonitors = useEndpoint('GET', '/v1/livechat/monitors.list'); + const getMonitors = useEndpoint('GET', '/v1/livechat/monitors'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/PriorityField.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/PriorityField.js index 66626c80715b..3e6506348a35 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/PriorityField.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/PriorityField.js @@ -1,6 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo } from 'react'; +import React from 'react'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; import { AsyncStatePhase } from '../../../../../lib/asyncState'; @@ -11,14 +11,7 @@ import { FormSkeleton } from '../../Skeleton'; const PriorityField = ({ id }) => { const t = useTranslation(); - const { - value: data, - phase: state, - error, - } = useEndpointData( - '/v1/livechat/priorities.getOne', - useMemo(() => ({ priorityId: id }), [id]), - ); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/priorities/${id}`); if (state === AsyncStatePhase.LOADING) { return ; } diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js index fdcdeeaabc6a..e819921ad55d 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js @@ -64,7 +64,7 @@ function RoomEdit({ room, visitor, reload, reloadInfo, close }) { const [customFieldsError, setCustomFieldsError] = useState([]); const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('/v1/livechat/custom-fields'); - const { value: prioritiesResult = {}, phase: statePriorities } = useEndpointData('/v1/livechat/priorities.list'); + const { value: prioritiesResult = {}, phase: statePriorities } = useEndpointData('/v1/livechat/priorities'); const jsonConverterToValidFormat = (customFields) => { const jsonObj = {}; diff --git a/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js b/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js index 622e0896bc07..758ca394b47a 100644 --- a/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js +++ b/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js @@ -1,7 +1,8 @@ import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { LivechatDepartmentAgents, CannedResponse, LivechatUnit } from '@rocket.chat/models'; +import { LivechatDepartmentAgents, CannedResponse } from '@rocket.chat/models'; import { hasPermissionAsync } from '../../../../../app/authorization/server/functions/hasPermission'; +import LivechatUnit from '../../../models/server/models/LivechatUnit'; export async function findAllCannedResponses({ userId }) { if (!(await hasPermissionAsync(userId, 'view-canned-responses'))) { diff --git a/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorEditCustomFieldsForm.js b/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorEditCustomFieldsForm.js index 65b844dea979..2f1048b619a1 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorEditCustomFieldsForm.js +++ b/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorEditCustomFieldsForm.js @@ -24,6 +24,6 @@ Template.visitorEditCustomFieldsForm.onCreated(async function () { if (priorityId) { this.roomPriority.set(priorityId); } - const { priorities } = await APIClient.get('/v1/livechat/priorities.list'); + const { priorities } = await APIClient.get('/v1/livechat/priorities'); this.priorities.set(priorities); }); diff --git a/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorInfoCustomForm.js b/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorInfoCustomForm.js index 20e02feaebbc..67f15789064f 100644 --- a/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorInfoCustomForm.js +++ b/apps/meteor/ee/app/livechat-enterprise/client/views/app/customTemplates/visitorInfoCustomForm.js @@ -20,7 +20,7 @@ Template.visitorInfoCustomForm.onCreated(function () { let priority; if (priorityId) { - priority = await APIClient.get('/v1/livechat/priorities.getOne', { priorityId }); + priority = await APIClient.get(`/v1/livechat/priorities/${priorityId}`); } this.priority.set(priority); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts index 8f024abe8041..507952e5162a 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts @@ -2,7 +2,7 @@ import { API } from '../../../../../app/api/server'; import { findBusinessHours } from '../business-hour/lib/business-hour'; API.v1.addRoute( - 'livechat/business-hours.list', + 'livechat/business-hours', { authRequired: true }, { async get() { diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/departments.js b/apps/meteor/ee/app/livechat-enterprise/server/api/departments.js index 25f596288c05..09228006e48c 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/departments.js +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/departments.js @@ -12,7 +12,6 @@ import { findPercentageOfAbandonedRooms, findAllAverageOfChatDurationTime, } from '../../../../../app/livechat/server/lib/analytics/departments'; -import { findAllDepartmentsAvailable, findAllDepartmentsByUnit } from '../lib/Department'; API.v1.addRoute( 'livechat/analytics/departments/amount-of-chats', @@ -351,52 +350,3 @@ API.v1.addRoute( }, }, ); - -API.v1.addRoute( - 'livechat/departments.available-by-unit/:unitId', - { authRequired: true }, - { - get() { - check(this.urlParams, { - unitId: Match.Maybe(String), - }); - const { offset, count } = this.getPaginationItems(); - const { unitId } = this.urlParams; - const { text, onlyMyDepartments } = this.queryParams; - - const { departments, total } = Promise.await( - findAllDepartmentsAvailable(this.userId, unitId, offset, count, text, onlyMyDepartments === 'true'), - ); - - return API.v1.success({ - departments, - count: departments.length, - offset, - total, - }); - }, - }, -); - -API.v1.addRoute( - 'livechat/departments.by-unit/:id', - { authRequired: true }, - { - async get() { - check(this.urlParams, { - id: String, - }); - const { offset, count } = this.getPaginationItems(); - const { id } = this.urlParams; - - const { departments, total } = await findAllDepartmentsByUnit(id, offset, count); - - return API.v1.success({ - departments, - count: departments.length, - offset, - total, - }); - }, - }, -); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/index.js b/apps/meteor/ee/app/livechat-enterprise/server/api/index.ts similarity index 100% rename from apps/meteor/ee/app/livechat-enterprise/server/api/index.js rename to apps/meteor/ee/app/livechat-enterprise/server/api/index.ts diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.js b/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.ts similarity index 74% rename from apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.js rename to apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.ts index e5d689a80e67..15adb00b8e2a 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.js +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.ts @@ -5,18 +5,16 @@ API.v1.addRoute( 'livechat/inquiry.prioritize', { authRequired: true }, { - put() { + async put() { const { roomId, priority } = this.bodyParams; if (!roomId) { return API.v1.failure("The 'roomId' param is required"); } - Promise.await( - setPriorityToInquiry({ - userId: this.userId, - roomId, - priority, - }), - ); + await setPriorityToInquiry({ + userId: this.userId, + roomId, + priority, + }); return API.v1.success(); }, }, diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.js b/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.js deleted file mode 100644 index 5d14e24c356e..000000000000 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.js +++ /dev/null @@ -1,38 +0,0 @@ -import { escapeRegExp } from '@rocket.chat/string-helpers'; -import LivechatPriority from '@rocket.chat/models'; - -import { hasPermissionAsync } from '../../../../../../app/authorization/server/functions/hasPermission'; - -export async function findPriorities({ userId, text, pagination: { offset, count, sort } }) { - if (!(await hasPermissionAsync(userId, 'manage-livechat-priorities')) && !(await hasPermissionAsync(userId, 'view-l-room'))) { - throw new Error('error-not-authorized'); - } - - const filterReg = new RegExp(escapeRegExp(text), 'i'); - - const query = { ...(text && { $or: [{ name: filterReg }, { description: filterReg }] }) }; - - const cursor = LivechatPriority.find(query, { - sort: sort || { name: 1 }, - skip: offset, - limit: count, - }); - - const total = await cursor.count(); - - const priorities = await cursor.toArray(); - - return { - priorities, - count: priorities.length, - offset, - total, - }; -} - -export async function findPriorityById({ userId, priorityId }) { - if (!(await hasPermissionAsync(userId, 'manage-livechat-priorities')) && !(await hasPermissionAsync(userId, 'view-l-room'))) { - throw new Error('error-not-authorized'); - } - return LivechatPriority.findOneById(priorityId); -} diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.ts new file mode 100644 index 000000000000..c376a3f0ff6a --- /dev/null +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.ts @@ -0,0 +1,67 @@ +import { escapeRegExp } from '@rocket.chat/string-helpers'; +import { LivechatPriority } from '@rocket.chat/models'; +import { ILivechatPriority } from '@rocket.chat/core-typings'; + +import { hasPermissionAsync } from '../../../../../../app/authorization/server/functions/hasPermission'; + +type FindPrioritiesParams = { + userId: string; + text?: string; + pagination: { + offset: number; + count: number; + sort: object; + }; +}; + +type FindPrioritiesResult = { + priorities: ILivechatPriority[]; + count: number; + offset: number; + total: number; +}; + +type FindPrioritiesByIdParams = { + userId: string; + priorityId: string; +}; + +type FindPrioritiesByIdResult = ILivechatPriority | null; + +export async function findPriorities({ + userId, + text, + pagination: { offset, count, sort }, +}: FindPrioritiesParams): Promise { + if (!(await hasPermissionAsync(userId, 'manage-livechat-priorities')) && !(await hasPermissionAsync(userId, 'view-l-room'))) { + throw new Error('error-not-authorized'); + } + + const query = { + ...(text && { $or: [{ name: new RegExp(escapeRegExp(text), 'i') }, { description: new RegExp(escapeRegExp(text), 'i') }] }), + }; + + const cursor = LivechatPriority.find(query, { + sort: sort || { name: 1 }, + skip: offset, + limit: count, + }); + + const total = await cursor.count(); + + const priorities = await cursor.toArray(); + + return { + priorities, + count: priorities.length, + offset, + total, + }; +} + +export async function findPriorityById({ userId, priorityId }: FindPrioritiesByIdParams): Promise { + if (!(await hasPermissionAsync(userId, 'manage-livechat-priorities')) && !(await hasPermissionAsync(userId, 'view-l-room'))) { + throw new Error('error-not-authorized'); + } + return LivechatPriority.findOneById(priorityId); +} diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts index 89f259eb3aa6..6d46f86b5287 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts @@ -6,7 +6,7 @@ import { hasPermissionAsync } from '../../../../../../app/authorization/server/f type FindTagsParams = { userId: string; - text: string; + text?: string; pagination: { offset: number; count: number; @@ -32,8 +32,9 @@ export async function findTags({ userId, text, pagination: { offset, count, sort if (!(await hasPermissionAsync(userId, 'manage-livechat-tags')) && !(await hasPermissionAsync(userId, 'view-l-room'))) { throw new Error('error-not-authorized'); } - const filterReg = new RegExp(escapeRegExp(text), 'i'); - const query = { ...(text && { $or: [{ name: filterReg }, { description: filterReg }] }) }; + const query = { + ...(text && { $or: [{ name: new RegExp(escapeRegExp(text), 'i') }, { description: new RegExp(escapeRegExp(text), 'i') }] }), + }; const cursor = LivechatTag.find(query, { sort: sort || { name: 1 }, diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.js b/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts similarity index 53% rename from apps/meteor/ee/app/livechat-enterprise/server/api/monitors.js rename to apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts index 340d6ba925a7..3c28d32a7cf8 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.js +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts @@ -2,45 +2,41 @@ import { API } from '../../../../../app/api/server'; import { findMonitors, findMonitorByUsername } from './lib/monitors'; API.v1.addRoute( - 'livechat/monitors.list', + 'livechat/monitors', { authRequired: true }, { - get() { + async get() { const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); const { text } = this.queryParams; return API.v1.success( - Promise.await( - findMonitors({ - userId: this.userId, - text, - pagination: { - offset, - count, - sort, - }, - }), - ), + await findMonitors({ + userId: this.userId, + text, + pagination: { + offset, + count, + sort, + }, + }), ); }, }, ); API.v1.addRoute( - 'livechat/monitors.getOne', + 'livechat/monitors/:username', { authRequired: true }, { - get() { - const { username } = this.queryParams; + async get() { + const { username } = this.urlParams; return API.v1.success( - Promise.await( - findMonitorByUsername({ - userId: this.userId, - username, - }), - ), + await findMonitorByUsername({ + userId: this.userId, + username, + }), ); }, }, diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.js b/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.js deleted file mode 100644 index 9c6792d15175..000000000000 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.js +++ /dev/null @@ -1,47 +0,0 @@ -import { API } from '../../../../../app/api/server'; -import { findPriorities, findPriorityById } from './lib/priorities'; - -API.v1.addRoute( - 'livechat/priorities.list', - { authRequired: true }, - { - get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { text } = this.queryParams; - - return API.v1.success( - Promise.await( - findPriorities({ - userId: this.userId, - text, - pagination: { - offset, - count, - sort, - }, - }), - ), - ); - }, - }, -); - -API.v1.addRoute( - 'livechat/priorities.getOne', - { authRequired: true }, - { - get() { - const { priorityId } = this.queryParams; - - return API.v1.success( - Promise.await( - findPriorityById({ - userId: this.userId, - priorityId, - }), - ), - ); - }, - }, -); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.ts new file mode 100644 index 000000000000..dce9f005856f --- /dev/null +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.ts @@ -0,0 +1,47 @@ +import { API } from '../../../../../app/api/server'; +import { findPriorities, findPriorityById } from './lib/priorities'; + +API.v1.addRoute( + 'livechat/priorities', + { authRequired: true }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { text } = this.queryParams; + + return API.v1.success( + await findPriorities({ + userId: this.userId, + text, + pagination: { + offset, + count, + sort, + }, + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/priorities/:priorityId', + { authRequired: true }, + { + async get() { + const { priorityId } = this.urlParams; + + const priority = await findPriorityById({ + userId: this.userId, + priorityId, + }); + + if (!priority) { + return API.v1.notFound(`Priority with id ${priorityId} not found`); + } + + return API.v1.success(priority); + }, + }, +); diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/tags.js b/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts similarity index 52% rename from apps/meteor/ee/app/livechat-enterprise/server/api/tags.js rename to apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts index b6ed298cd785..790366f22d83 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/tags.js +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts @@ -2,45 +2,41 @@ import { API } from '../../../../../app/api/server'; import { findTags, findTagById } from './lib/tags'; API.v1.addRoute( - 'livechat/tags.list', + 'livechat/tags', { authRequired: true }, { - get() { + async get() { const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); const { text } = this.queryParams; return API.v1.success( - Promise.await( - findTags({ - userId: this.userId, - text, - pagination: { - offset, - count, - sort: JSON.parse(sort || '{}'), - }, - }), - ), + await findTags({ + userId: this.userId, + text, + pagination: { + offset, + count, + sort: typeof sort === 'string' ? JSON.parse(sort || '{}') : sort, + }, + }), ); }, }, ); API.v1.addRoute( - 'livechat/tags.getOne', + 'livechat/tags/:tagId', { authRequired: true }, { - get() { - const { tagId } = this.queryParams; + async get() { + const { tagId } = this.urlParams; return API.v1.success( - Promise.await( - findTagById({ - userId: this.userId, - tagId, - }), - ), + await findTagById({ + userId: this.userId, + tagId, + }), ); }, }, diff --git a/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts b/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts index 0e7d0f8fc423..930b6f554ad1 100644 --- a/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts +++ b/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts @@ -1,59 +1,14 @@ import { API } from '../../../../../app/api/server'; -import { deprecationWarning } from '../../../../../app/api/server/helpers/deprecationWarning'; import { findUnits, findUnitById, findUnitMonitors } from './lib/units'; import { LivechatEnterprise } from '../lib/LivechatEnterprise'; +import { findAllDepartmentsAvailable, findAllDepartmentsByUnit } from '../lib/Department'; API.v1.addRoute( - 'livechat/units.list', + 'livechat/units/:unitId/monitors', { authRequired: true }, { async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { text } = this.queryParams; - - const response = await findUnits({ - userId: this.userId, - text, - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(deprecationWarning({ response, endpoint: 'livechat/units.list' })); - }, - }, -); - -API.v1.addRoute( - 'livechat/units.getOne', - { authRequired: true }, - { - async get() { - const { unitId } = this.queryParams; - - if (!unitId) { - return API.v1.failure('Missing "unitId" query parameter'); - } - - const unit = await findUnitById({ - userId: this.userId, - unitId, - }); - - return API.v1.success(deprecationWarning({ response: unit, endpoint: 'livechat/units.getOne' })); - }, - }, -); - -API.v1.addRoute( - 'livechat/unitMonitors.list', - { authRequired: true }, - { - async get() { - const { unitId } = this.queryParams; + const { unitId } = this.urlParams; if (!unitId) { return API.v1.failure('The "unitId" parameter is required'); @@ -122,3 +77,51 @@ API.v1.addRoute( }, }, ); + +API.v1.addRoute( + 'livechat/units/:unitId/departments', + { authRequired: true }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { unitId } = this.urlParams; + + const { departments, total } = await findAllDepartmentsByUnit(unitId, offset, count); + + return API.v1.success({ + departments, + count: departments.length, + offset, + total, + }); + }, + }, +); + +API.v1.addRoute( + 'livechat/units/:unitId/departments/available', + { authRequired: true }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { unitId } = this.urlParams; + const { text, onlyMyDepartments } = this.queryParams; + + const { departments, total } = await findAllDepartmentsAvailable( + this.userId, + unitId, + offset, + count, + text, + onlyMyDepartments === 'true', + ); + + return API.v1.success({ + departments, + count: departments.length, + offset, + total, + }); + }, + }, +); diff --git a/apps/meteor/ee/client/hooks/useTagsList.ts b/apps/meteor/ee/client/hooks/useTagsList.ts index 2e3452cb46da..5c887d28d713 100644 --- a/apps/meteor/ee/client/hooks/useTagsList.ts +++ b/apps/meteor/ee/client/hooks/useTagsList.ts @@ -21,7 +21,7 @@ export const useTagsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const getTags = useEndpoint('GET', '/v1/livechat/tags.list'); + const getTags = useEndpoint('GET', '/v1/livechat/tags'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js b/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js index 601ebdd0ecd2..b0603a932c85 100644 --- a/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js +++ b/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js @@ -15,7 +15,7 @@ const BusinessHoursTableContainer = () => { phase: state, reload, } = useEndpointData( - '/v1/livechat/business-hours.list', + '/v1/livechat/business-hours', useMemo( () => ({ count: params.itemsPerPage, diff --git a/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js b/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js index d0bf1593fc1c..1be85c984ec9 100644 --- a/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js +++ b/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js @@ -30,7 +30,7 @@ const MonitorsPage = () => { const [sort, setSort] = useState(['name', 'asc']); const [username, setUsername] = useState(''); - const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/monitors.list', useQuery(params, sort)); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/monitors', useQuery(params, sort)); const addMonitor = useMethod('livechat:addMonitor'); diff --git a/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.js b/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.js index 2d143cdfd3e6..7d1d4e4536ae 100644 --- a/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.js +++ b/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.js @@ -61,7 +61,7 @@ function PrioritiesRoute() { }), ); - const { value: data = {}, reload } = useEndpointData('/v1/livechat/priorities.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/priorities', query); const header = useMemo( () => diff --git a/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js b/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js index c1303c4d5caa..9362d516e5bb 100644 --- a/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js +++ b/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js @@ -1,6 +1,6 @@ import { Callout } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo } from 'react'; +import React from 'react'; import { FormSkeleton } from '../../../../client/components/Skeleton'; import { AsyncStatePhase } from '../../../../client/hooks/useAsyncState'; @@ -8,8 +8,7 @@ import { useEndpointData } from '../../../../client/hooks/useEndpointData'; import PriorityEdit from './PriorityEdit'; function PriorityEditWithData({ priorityId, reload }) { - const query = useMemo(() => ({ priorityId }), [priorityId]); - const { value: data, phase: state, error } = useEndpointData('/v1/livechat/priorities.getOne', query); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/priorities/${priorityId}`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js b/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js index 5b53f7f20ed8..9e575230aa7c 100644 --- a/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js +++ b/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js @@ -1,6 +1,6 @@ import { Callout } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo } from 'react'; +import React from 'react'; import { FormSkeleton } from '../../../../client/components/Skeleton'; import { AsyncStatePhase } from '../../../../client/hooks/useAsyncState'; @@ -9,8 +9,7 @@ import TagEdit from './TagEdit'; import TagEditWithDepartmentData from './TagEditWithDepartmentData'; function TagEditWithData({ tagId, reload, title }) { - const query = useMemo(() => ({ tagId }), [tagId]); - const { value: data, phase: state, error } = useEndpointData('/v1/livechat/tags.getOne', query); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/tags/${tagId}`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js b/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js index 80b8e8e06204..84edbcc511dc 100644 --- a/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js +++ b/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js @@ -59,7 +59,7 @@ function TagsRoute() { }), ); - const { value: data = {}, reload } = useEndpointData('/v1/livechat/tags.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/tags', query); const header = useMemo( () => diff --git a/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx b/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx index af33ccc139d1..c1e9b58ec8c8 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx +++ b/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx @@ -1,6 +1,6 @@ import { Callout } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo, FC } from 'react'; +import React, { FC } from 'react'; import { FormSkeleton } from '../../../../client/components/Skeleton'; import { AsyncStatePhase } from '../../../../client/hooks/useAsyncState'; @@ -12,21 +12,19 @@ const UnitEditWithData: FC<{ title: string; reload: () => void; }> = function UnitEditWithData({ unitId, reload, title }) { - const query = useMemo(() => ({ unitId }), [unitId]); - - const { value: data, phase: state, error } = useEndpointData('/v1/livechat/units.getOne', query); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/units/${unitId}`); const { value: unitMonitors, phase: unitMonitorsState, error: unitMonitorsError, - } = useEndpointData('/v1/livechat/unitMonitors.list', query); + } = useEndpointData(`/v1/livechat/units/${unitId}/monitors`); const { value: unitDepartments, phase: unitDepartmentsState, error: unitDepartmentsError, - } = useEndpointData(`/v1/livechat/departments.by-unit/${unitId}`); + } = useEndpointData(`/v1/livechat/units/${unitId}/departments`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/units/UnitNew.js b/apps/meteor/ee/client/omnichannel/units/UnitNew.js index 1f93c587bb68..3bc99fa38ad6 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitNew.js +++ b/apps/meteor/ee/client/omnichannel/units/UnitNew.js @@ -19,7 +19,7 @@ function UnitNew({ reload, allUnits }) { value: availableMonitors, phase: availableMonitorsState, error: availableMonitorsError, - } = useEndpointData('/v1/livechat/monitors.list'); + } = useEndpointData('/v1/livechat/monitors'); if ([availableDepartmentsState, availableMonitorsState].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js b/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js index 5362af00f8f0..7fcfb57b4ee4 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js +++ b/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js @@ -7,6 +7,7 @@ import GenericTable from '../../../../client/components/GenericTable'; import { useEndpointData } from '../../../../client/hooks/useEndpointData'; import NotAuthorizedPage from '../../../../client/views/notAuthorized/NotAuthorizedPage'; import RemoveUnitButton from './RemoveUnitButton'; +import UnitEdit from './UnitEdit'; import UnitEditWithData from './UnitEditWithData'; import UnitsPage from './UnitsPage'; @@ -59,7 +60,7 @@ function UnitsRoute() { }), ); - const { value: data = {}, reload } = useEndpointData('/v1/livechat/units.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/units', query); const header = useMemo( () => @@ -94,8 +95,12 @@ function UnitsRoute() { [reload, onRowClick], ); - if (context === 'edit' || context === 'new') { - return ; + if (context === 'edit') { + return ; + } + + if (context === 'new') { + return ; } if (!canViewUnits) { diff --git a/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts b/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts index 3eff58121555..4e3e09befe40 100644 --- a/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts +++ b/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts @@ -3,7 +3,7 @@ import type { ILivechatBusinessHour } from '@rocket.chat/core-typings'; declare module '@rocket.chat/rest-typings' { // eslint-disable-next-line @typescript-eslint/interface-name-prefix interface Endpoints { - '/v1/livechat/business-hours.list': { + '/v1/livechat/business-hours': { GET: (params: { name?: string; offset: number; count: number; sort: Record }) => { businessHours: ILivechatBusinessHour[]; count: number; diff --git a/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts b/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts index 5f01ca96b3e0..88f38bc3e39e 100644 --- a/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts +++ b/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts @@ -9,10 +9,7 @@ declare module '@rocket.chat/rest-typings' { units: IOmnichannelBusinessUnit[]; }; }; - '/v1/livechat/units.getOne': { - GET: (params: { unitId: string }) => IOmnichannelBusinessUnit; - }; - '/v1/livechat/unitMonitors.list': { + '/v1/livechat/units/:unitId/monitors': { GET: (params: { unitId: string }) => { monitors: ILivechatMonitor[] }; }; '/v1/livechat/units': { diff --git a/apps/meteor/ee/server/models/raw/LivechatPriority.ts b/apps/meteor/ee/server/models/raw/LivechatPriority.ts index 2a85d7fa3873..60bcc3aaee85 100644 --- a/apps/meteor/ee/server/models/raw/LivechatPriority.ts +++ b/apps/meteor/ee/server/models/raw/LivechatPriority.ts @@ -1,4 +1,4 @@ -import type { IRocketChatRecord } from '@rocket.chat/core-typings'; +import type { ILivechatPriority } from '@rocket.chat/core-typings'; import type { ILivechatPriorityModel } from '@rocket.chat/model-typings'; import type { Db } from 'mongodb'; import { getCollectionName } from '@rocket.chat/models'; @@ -6,7 +6,7 @@ import { getCollectionName } from '@rocket.chat/models'; import { BaseRaw } from '../../../../server/models/raw/BaseRaw'; // TODO need to define type for LivechatPriority object -export class LivechatPriorityRaw extends BaseRaw implements ILivechatPriorityModel { +export class LivechatPriorityRaw extends BaseRaw implements ILivechatPriorityModel { constructor(db: Db) { super(db, getCollectionName('livechat_priority')); } diff --git a/apps/meteor/tests/end-to-end/api/livechat/01-department.js b/apps/meteor/tests/end-to-end/api/livechat/01-department.js index 84822885ec63..224a5016b937 100644 --- a/apps/meteor/tests/end-to-end/api/livechat/01-department.js +++ b/apps/meteor/tests/end-to-end/api/livechat/01-department.js @@ -29,10 +29,10 @@ describe('LIVECHAT - departments', function () { .get(api('livechat/department')) .set(credentials) .expect('Content-Type', 'application/json') - .expect(400) + .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); - expect(res.body.error).to.be.equal('error-not-authorized'); + expect(res.body.error).to.be.equal('unauthorized'); }) .end(done); }); @@ -90,7 +90,7 @@ describe('LIVECHAT - departments', function () { .get(api(`livechat/department/${department._id}`)) .set(credentials) .expect('Content-Type', 'application/json') - .expect(400) + .expect(403) .expect((res) => { expect(res.body).to.have.property('success', false); expect(res.body.error).to.be.equal('error-not-authorized'); diff --git a/apps/meteor/tests/end-to-end/api/livechat/office-hour.js b/apps/meteor/tests/end-to-end/api/livechat/office-hour.js deleted file mode 100644 index 22448b88d525..000000000000 --- a/apps/meteor/tests/end-to-end/api/livechat/office-hour.js +++ /dev/null @@ -1,46 +0,0 @@ -import { expect } from 'chai'; - -import { getCredentials, api, request, credentials } from '../../../data/api-data.js'; -import { updatePermission, updateSetting } from '../../../data/permissions.helper'; - -describe('LIVECHAT - office hours', function () { - this.retries(0); - - before((done) => getCredentials(done)); - - before((done) => { - updateSetting('Livechat_enabled', true).then(done); - }); - - describe('livechat/office-hours', () => { - it('should return an "unauthorized error" when the user does not have the necessary permission', (done) => { - updatePermission('view-livechat-business-hours', []).then(() => { - request - .get(api('livechat/office-hours')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - expect(res.body.error).to.be.equal('error-not-authorized'); - }) - .end(done); - }); - }); - it('should return an array of office hours', (done) => { - updatePermission('view-livechat-business-hours', ['admin']).then(() => { - request - .get(api('livechat/office-hours')) - .set(credentials) - .expect('Content-Type', 'application/json') - .expect(200) - .expect((res) => { - expect(res.body).to.have.property('success', true); - expect(res.body).to.have.property('officeHours'); - expect(res.body.officeHours).to.be.an('array'); - }) - .end(done); - }); - }); - }); -}); diff --git a/packages/core-typings/src/ILivechatPriority.ts b/packages/core-typings/src/ILivechatPriority.ts new file mode 100644 index 000000000000..3ef6bde7dee3 --- /dev/null +++ b/packages/core-typings/src/ILivechatPriority.ts @@ -0,0 +1,7 @@ +import type { IRocketChatRecord } from './IRocketChatRecord'; + +export interface ILivechatPriority extends IRocketChatRecord { + name: string; + description: string; + dueTimeInMinutes: number; +} diff --git a/packages/core-typings/src/index.ts b/packages/core-typings/src/index.ts index 929032632856..ae31c6cb0f3f 100644 --- a/packages/core-typings/src/index.ts +++ b/packages/core-typings/src/index.ts @@ -107,5 +107,6 @@ export * from './IVoipServerConfig'; export * from './IVoipServerConnectivityStatus'; export * from './IOmnichannelVoipServiceResult'; export * from './IInquiry'; +export * from './ILivechatPriority'; export * from './IAutoTranslate'; diff --git a/packages/model-typings/src/models/ILivechatPriorityModel.ts b/packages/model-typings/src/models/ILivechatPriorityModel.ts index 1ece4ef9b247..2439a92a2bbd 100644 --- a/packages/model-typings/src/models/ILivechatPriorityModel.ts +++ b/packages/model-typings/src/models/ILivechatPriorityModel.ts @@ -1,7 +1,7 @@ -import type { IRocketChatRecord } from '@rocket.chat/core-typings'; +import type { ILivechatPriority } from '@rocket.chat/core-typings'; import type { IBaseModel } from './IBaseModel'; -export interface ILivechatPriorityModel extends IBaseModel { +export interface ILivechatPriorityModel extends IBaseModel { findOneByIdOrName(_idOrName: string, options?: any): any; } diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index ff1a26f8e9b7..4ffa9b3fe0cf 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -12,6 +12,7 @@ import type { IOmnichannelRoom, IRoom, ISetting, + ILivechatPriority, } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; @@ -382,7 +383,7 @@ const LivechatDepartmentSchema = { export const isLivechatDepartmentProps = ajv.compile(LivechatDepartmentSchema); -type LivechatDepartmentsAvailableByUnitIdProps = PaginatedRequest<{ text: string }>; +type LivechatDepartmentsAvailableByUnitIdProps = PaginatedRequest<{ text: string; onlyMyDepartments?: 'true' | 'false' }>; const LivechatDepartmentsAvailableByUnitIdSchema = { type: 'object', @@ -390,6 +391,11 @@ const LivechatDepartmentsAvailableByUnitIdSchema = { text: { type: 'string', }, + onlyMyDepartments: { + type: 'string', + enum: ['true', 'false'], + nullable: true, + }, count: { type: 'number', nullable: true, @@ -446,7 +452,7 @@ const LivechatDepartmentsByUnitSchema = { export const isLivechatDepartmentsByUnitProps = ajv.compile(LivechatDepartmentsByUnitSchema); -type LivechatDepartmentsByUnitIdProps = PaginatedRequest<{ text: string }>; +type LivechatDepartmentsByUnitIdProps = PaginatedRequest<{}>; const LivechatDepartmentsByUnitIdSchema = { type: 'object', @@ -777,6 +783,38 @@ const LivechatUsersAgentSchema = { export const isLivechatUsersAgentProps = ajv.compile(LivechatUsersAgentSchema); +type LivechatPrioritiesProps = PaginatedRequest<{ text?: string }>; + +const LivechatPrioritiesPropsSchema = { + type: 'object', + properties: { + text: { + type: 'string', + nullable: true, + }, + count: { + type: 'number', + nullable: true, + }, + offset: { + type: 'number', + nullable: true, + }, + sort: { + type: 'string', + nullable: true, + }, + query: { + type: 'string', + nullable: true, + }, + }, + required: [], + additionalProperties: false, +}; + +export const isLivechatPrioritiesProps = ajv.compile(LivechatPrioritiesPropsSchema); + export type OmnichannelEndpoints = { '/v1/livechat/appearance': { GET: () => { @@ -803,16 +841,22 @@ export type OmnichannelEndpoints = { '/v1/livechat/room.join': { GET: (params: LiveChatRoomJoin) => { success: boolean }; }; - '/v1/livechat/monitors.list': { + '/v1/livechat/monitors': { GET: (params: LivechatMonitorsListProps) => PaginatedResult<{ monitors: ILivechatMonitor[]; }>; }; - '/v1/livechat/tags.list': { + '/v1/livechat/monitors/:username': { + GET: () => ILivechatMonitor; + }; + '/v1/livechat/tags': { GET: (params: LivechatTagsListProps) => PaginatedResult<{ tags: ILivechatTag[]; }>; }; + '/v1/livechat/tags/:tagId': { + GET: () => ILivechatTag | null; + }; '/v1/livechat/department': { GET: (params: LivechatDepartmentProps) => PaginatedResult<{ departments: ILivechatDepartment[]; @@ -842,7 +886,7 @@ export type OmnichannelEndpoints = { GET: (params: LivechatDepartmentDepartmentIdAgentsGET) => PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>; POST: (params: LivechatDepartmentDepartmentIdAgentsPOST) => void; }; - '/v1/livechat/departments.available-by-unit/:id': { + '/v1/livechat/units/:unitId/departments/available': { GET: (params: LivechatDepartmentsAvailableByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; @@ -853,7 +897,7 @@ export type OmnichannelEndpoints = { }>; }; - '/v1/livechat/departments.by-unit/:id': { + '/v1/livechat/units/:unitId/departments': { GET: (params: LivechatDepartmentsByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; @@ -978,4 +1022,10 @@ export type OmnichannelEndpoints = { '/v1/livechat/webrtc.call/:callId': { PUT: (params: { rid: string; status: 'ended' }) => void; }; + '/v1/livechat/priorities': { + GET: (params: LivechatPrioritiesProps) => PaginatedResult<{ priorities: ILivechatPriority[] }>; + }; + '/v1/livechat/priorities/:priorityId': { + GET: () => ILivechatPriority; + }; };