From 2a292e4febdf2e9cddcfa86e37aea254918f4de1 Mon Sep 17 00:00:00 2001 From: Tiago Evangelista Pinto Date: Wed, 8 Jun 2022 15:05:01 -0300 Subject: [PATCH 1/8] [FIX] AccountBox checks for condition (#25708) ## Proposed changes (including videos or screenshots) ## Issue(s) Close: #25704 ## Steps to test or reproduce ## Further comments Fixes #25704 --- .../app/ui-utils/client/lib/AccountBox.ts | 36 +++++++++++++------ .../client/sidebar/header/UserDropdown.tsx | 6 ++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts index a0b2e8a6ac43..a3f42a8645bc 100644 --- a/apps/meteor/app/ui-utils/client/lib/AccountBox.ts +++ b/apps/meteor/app/ui-utils/client/lib/AccountBox.ts @@ -1,4 +1,4 @@ -import { IUActionButtonWhen, IUIActionButton } from '@rocket.chat/apps-engine/definition/ui/IUIActionButtonDescriptor'; +import { IUIActionButton, IUActionButtonWhen } from '@rocket.chat/apps-engine/definition/ui/IUIActionButtonDescriptor'; import { ReactiveVar } from 'meteor/reactive-var'; import { Tracker } from 'meteor/tracker'; import { Meteor } from 'meteor/meteor'; @@ -6,18 +6,28 @@ import { Meteor } from 'meteor/meteor'; import { SideNav } from './SideNav'; import { applyDropdownActionButtonFilters } from '../../../ui-message/client/actionButtons/lib/applyButtonFilters'; -export interface IAccountBoxItem extends Omit { +export interface IAppAccountBoxItem extends IUIActionButton { name: string; icon?: string; href?: string; sideNav?: string; isAppButtonItem?: boolean; - subItems?: [IAccountBoxItem]; + subItems?: [IAppAccountBoxItem]; when?: Omit; } +type AccountBoxItem = { + name: string; + icon: string; + href: string; + sideNav?: string; + condition: () => boolean; +}; + +export const isAppAccountBoxItem = (item: IAppAccountBoxItem | AccountBoxItem): item is IAppAccountBoxItem => 'isAppButtonItem' in item; + export class AccountBoxBase { - private items = new ReactiveVar([]); + private items = new ReactiveVar([]); private status = 0; @@ -48,25 +58,31 @@ export class AccountBoxBase { this.status = 0; } - public async addItem(newItem: IAccountBoxItem): Promise { + public async addItem(newItem: IAppAccountBoxItem): Promise { Tracker.nonreactive(() => { const actual = this.items.get(); - actual.push(newItem as never); + actual.push(newItem); this.items.set(actual); }); } - public async deleteItem(item: IAccountBoxItem): Promise { + public async deleteItem(item: IAppAccountBoxItem): Promise { Tracker.nonreactive(() => { const actual = this.items.get(); - const itemIndex = actual.findIndex((actualItem: IAccountBoxItem) => actualItem.appId === item.appId); + const itemIndex = actual.findIndex((actualItem: IAppAccountBoxItem) => actualItem.appId === item.appId); actual.splice(itemIndex, 1); this.items.set(actual); }); } - public getItems(): IAccountBoxItem[] { - return this.items.get().filter((item: IAccountBoxItem) => applyDropdownActionButtonFilters(item)); + public getItems(): (IAppAccountBoxItem | AccountBoxItem)[] { + return this.items.get().filter((item: IAppAccountBoxItem | AccountBoxItem) => { + if ('condition' in item) { + return item.condition(); + } + + return applyDropdownActionButtonFilters(item); + }); } } diff --git a/apps/meteor/client/sidebar/header/UserDropdown.tsx b/apps/meteor/client/sidebar/header/UserDropdown.tsx index a56c63d6abba..d74898a8e173 100644 --- a/apps/meteor/client/sidebar/header/UserDropdown.tsx +++ b/apps/meteor/client/sidebar/header/UserDropdown.tsx @@ -8,7 +8,7 @@ import React, { ReactElement } from 'react'; import { triggerActionButtonAction } from '../../../app/ui-message/client/ActionManager'; import { AccountBox, SideNav } from '../../../app/ui-utils/client'; -import { IAccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox'; +import { IAppAccountBoxItem, isAppAccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox'; import { userStatus } from '../../../app/user-status/client'; import { callbacks } from '../../../lib/callbacks'; import MarkdownText from '../../components/MarkdownText'; @@ -105,7 +105,7 @@ const UserDropdown = ({ user, onClose }: UserDropdownProps): ReactElement => { const accountBoxItems = useReactiveValue(getItems); - const appBoxItems = (): IAccountBoxItem[] => accountBoxItems.filter((item) => item.isAppButtonItem); + const appBoxItems = (): IAppAccountBoxItem[] => accountBoxItems.filter((item): item is IAppAccountBoxItem => isAppAccountBoxItem(item)); return ( @@ -176,7 +176,7 @@ const UserDropdown = ({ user, onClose }: UserDropdownProps): ReactElement => { {showAdmin && } {accountBoxItems - .filter((item) => !item.isAppButtonItem) + .filter((item) => !isAppAccountBoxItem(item)) .map((item, i) => { const action = (): void => { if (item.href) { From d5367a725b010342f81f286cdda3454272ebfba6 Mon Sep 17 00:00:00 2001 From: Duda Nogueira Date: Wed, 8 Jun 2022 15:22:49 -0300 Subject: [PATCH 2/8] [FIX] Wrong argument name preventing Omnichannel Chat Forward to User (#25723) --- .../client/components/Omnichannel/modals/ForwardChatModal.tsx | 2 +- packages/rest-typings/src/v1/users.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx index 853dd7c7d293..e28465d697e2 100644 --- a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx @@ -59,7 +59,7 @@ const ForwardChatModal = ({ let uid; if (username) { - const { user } = await getUserData({ userName: username }); + const { user } = await getUserData({ username }); uid = user?._id; } diff --git a/packages/rest-typings/src/v1/users.ts b/packages/rest-typings/src/v1/users.ts index 4b311d1af3d2..dc6e6b736558 100644 --- a/packages/rest-typings/src/v1/users.ts +++ b/packages/rest-typings/src/v1/users.ts @@ -5,7 +5,7 @@ const ajv = new Ajv({ coerceTypes: true, }); -type UsersInfo = { userId?: IUser['_id']; userName?: IUser['username'] }; +type UsersInfo = { userId?: IUser['_id']; username?: IUser['username'] }; const UsersInfoSchema = { type: 'object', @@ -14,7 +14,7 @@ const UsersInfoSchema = { type: 'string', nullable: true, }, - userName: { + username: { type: 'string', nullable: true, }, From 611c0b31fbb865b52f6e8a4eb5febddcb33e9b79 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 8 Jun 2022 16:06:24 -0300 Subject: [PATCH 3/8] Chore: RestApiClient as Package (#25469) ## Proposed changes (including videos or screenshots) ## Issue(s) ## Steps to test or reproduce ## Further comments Co-authored-by: Tasso Evangelista <2263066+tassoevan@users.noreply.github.com> --- .../app/api/server/lib/getUploadFormData.js | 1 - .../v1/{emoji-custom.js => emoji-custom.ts} | 79 +++--- apps/meteor/app/api/server/v1/settings.ts | 2 +- .../app/apps/client/RealAppsEngineUIHost.js | 2 +- .../apps/client/communication/websockets.js | 2 +- .../app/apps/client/gameCenter/gameCenter.js | 2 +- .../apps/client/gameCenter/gameContainer.js | 4 +- apps/meteor/app/apps/client/orchestrator.ts | 36 +-- .../app/authorization/client/startup.js | 4 +- .../authorization/server/methods/saveRole.ts | 10 +- .../emoji-custom/client/lib/emojiCustom.js | 2 +- .../client/lib/stream/queueManager.js | 4 +- .../client/views/app/dialog/closeRoom.js | 6 +- .../client/views/app/livechatReadOnly.js | 6 +- .../client/views/app/tabbar/agentEdit.js | 6 +- .../client/views/app/tabbar/agentInfo.js | 6 +- .../views/app/tabbar/contactChatHistory.js | 6 +- .../app/tabbar/contactChatHistoryMessages.js | 18 +- .../client/views/app/tabbar/visitorEdit.js | 8 +- .../views/app/tabbar/visitorForward.html | 57 ++--- .../client/views/app/tabbar/visitorForward.js | 2 +- .../client/views/app/tabbar/visitorInfo.js | 8 +- .../views/app/tabbar/visitorNavigation.js | 7 +- .../views/app/tabbar/visitorTranscript.js | 4 +- .../client/views/mentionsFlexTab.js | 5 +- .../client/views/pinnedMessages.js | 5 +- .../client/page/snippetPage.js | 2 +- .../client/tabBar/views/snippetedMessages.js | 5 +- .../client/views/starredMessages.js | 5 +- .../client/autocomplete-client.js | 2 +- .../app/models/server/raw/EmojiCustom.ts | 2 +- .../client/oauth/oauth2-client.js | 2 +- .../app/otr/client/rocketchat.otr.room.js | 2 +- .../ui-message/client/ActionButtonSyncer.ts | 2 +- .../app/ui-message/client/ActionManager.js | 5 +- apps/meteor/app/ui/client/lib/chatMessages.js | 2 +- apps/meteor/app/ui/client/lib/fileUpload.js | 164 ------------ apps/meteor/app/ui/client/lib/fileUpload.ts | 236 ++++++++++++++++++ .../app/utils/client/lib/RestApiClient.ts | 52 ++++ ...RestApiClient.d.ts => _RestApiClient.d.ts} | 8 +- .../{RestApiClient.js => _RestApiClient.js} | 0 .../app/utils/lib/fileUploadRestrictions.js | 2 +- apps/meteor/app/utils/lib/slashCommand.ts | 2 +- .../app/videobridge/client/actionLink.js | 2 +- apps/meteor/app/webdav/client/startup/sync.js | 2 +- apps/meteor/app/webrtc/client/actionLink.tsx | 2 +- apps/meteor/app/webrtc/client/tabBar.tsx | 2 +- .../CreateDiscussion/CreateDiscussion.tsx | 2 +- .../DefaultParentRoomField.tsx | 2 +- .../client/components/Omnichannel/Tags.tsx | 2 +- .../Omnichannel/hooks/useAgentsList.ts | 3 +- .../hooks/useAvailableAgentsList.ts | 3 +- .../Omnichannel/hooks/useDepartmentsList.ts | 2 +- .../Omnichannel/modals/CloseChatModalData.tsx | 2 +- .../Omnichannel/modals/ForwardChatModal.tsx | 2 +- .../RoomAutoComplete/RoomAutoComplete.tsx | 2 +- .../RoomAutoComplete/hooks/useRoomsList.ts | 3 +- .../lib/OmnichannelRoomIcon.ts | 3 +- .../TwoFactorModal/TwoFactorEmailModal.tsx | 2 +- .../UserAutoComplete/UserAutoComplete.tsx | 2 +- .../UserAutoCompleteMultiple.tsx | 2 +- .../components/message/Metrics/Thread.tsx | 4 +- apps/meteor/client/hooks/useEndpointUpload.ts | 7 +- apps/meteor/client/hooks/useUpdateAvatar.ts | 6 +- apps/meteor/client/lib/meteorCallWrapper.ts | 6 +- apps/meteor/client/lib/presence.ts | 11 +- apps/meteor/client/lib/userData.ts | 2 +- .../providers/CallProvider/CallProvider.tsx | 8 +- .../CallProvider/hooks/useVoipClient.ts | 4 +- .../client/providers/ServerProvider.tsx | 17 +- .../client/sidebar/footer/voip/index.tsx | 2 +- .../sidebar/header/CreateChannelWithData.tsx | 4 +- .../sidebar/header/CreateDirectMessage.tsx | 2 +- apps/meteor/client/startup/banners.ts | 10 +- apps/meteor/client/startup/routes.tsx | 4 +- apps/meteor/client/startup/slashCommands.ts | 8 +- .../stories/contexts/ServerContextMock.tsx | 4 +- .../views/account/AccountProfilePage.js | 2 +- .../views/account/tokens/AccountTokensPage.js | 2 +- .../client/views/admin/cloud/PasteStep.tsx | 2 +- .../admin/customEmoji/AddCustomEmoji.tsx | 2 +- .../views/admin/customEmoji/CustomEmoji.tsx | 2 +- .../admin/customEmoji/EditCustomEmoji.tsx | 4 +- .../customEmoji/EditCustomEmojiWithData.tsx | 2 +- .../admin/customSounds/AdminSoundsRoute.tsx | 2 +- .../admin/customSounds/EditCustomSound.tsx | 2 +- .../CustomUserStatusFormWithData.tsx | 2 +- .../CustomUserStatusTable.tsx | 2 +- .../emailInbox/EmailInboxEditWithData.tsx | 2 +- .../views/admin/emailInbox/EmailInboxForm.js | 8 +- .../admin/emailInbox/EmailInboxTable.tsx | 2 +- .../views/admin/emailInbox/SendTestButton.tsx | 2 +- .../views/admin/import/ImportHistoryPage.js | 8 +- .../views/admin/import/ImportProgressPage.js | 4 +- .../views/admin/import/NewImportPage.js | 4 +- .../views/admin/import/PrepareImportPage.js | 6 +- .../views/admin/info/InformationRoute.tsx | 2 +- .../client/views/admin/info/LicenseCard.tsx | 2 +- .../admin/integrations/IntegrationsTable.js | 2 +- .../edit/EditIncomingWebhookWithData.js | 2 +- .../edit/EditOutgoingWebhookWithData.js | 2 +- .../edit/OutgoingWebhookHistoryPage.js | 2 +- .../client/views/admin/invites/InviteRow.tsx | 2 +- .../views/admin/invites/InvitesPage.tsx | 2 +- .../admin/oauthApps/EditOauthAppWithData.tsx | 2 +- .../views/admin/oauthApps/OAuthAppsTable.tsx | 2 +- .../views/admin/permissions/EditRolePage.tsx | 6 +- .../UsersInRole/UsersInRolePage.tsx | 2 +- .../UsersInRoleTable/UsersInRoleTable.tsx | 2 +- .../UsersInRoleTableWithData.tsx | 2 +- .../client/views/admin/rooms/EditRoom.tsx | 6 +- .../views/admin/rooms/EditRoomWithData.tsx | 2 +- .../client/views/admin/rooms/RoomsTable.tsx | 2 +- .../admin/settings/groups/LDAPGroupPage.tsx | 6 +- .../settings/groups/voip/AssignAgentModal.tsx | 4 +- .../groups/voip/RemoveAgentButton.tsx | 2 +- .../groups/voip/VoipExtensionsPage.tsx | 2 +- .../client/views/admin/users/AddUser.js | 2 +- .../client/views/admin/users/EditUser.js | 8 +- .../views/admin/users/EditUserWithData.js | 4 +- .../client/views/admin/users/UserInfo.js | 2 +- .../views/admin/users/UserInfoActions.js | 8 +- .../client/views/admin/users/UsersPage.js | 2 +- .../views/admin/viewLogs/ServerLogs.tsx | 2 +- .../client/views/directory/ChannelsTable.js | 2 +- .../client/views/directory/TeamsTable.js | 2 +- .../client/views/directory/UserTable.js | 2 +- .../views/hooks/useDepartmentsByUnitsList.ts | 3 +- .../client/views/hooks/useMembersList.ts | 6 +- .../client/views/hooks/useMonitorsList.ts | 4 +- .../client/views/hooks/useUpgradeTabParams.ts | 4 +- .../meteor/client/views/invite/InvitePage.tsx | 16 +- apps/meteor/client/views/meet/MeetPage.tsx | 15 +- .../omnichannel/DepartmentAutoComplete.js | 2 +- .../views/omnichannel/agents/AddAgent.tsx | 2 +- .../omnichannel/agents/AgentEditWithData.tsx | 6 +- .../views/omnichannel/agents/AgentInfo.tsx | 2 +- .../omnichannel/agents/AgentInfoActions.tsx | 2 +- .../views/omnichannel/agents/AgentsPage.tsx | 2 +- .../omnichannel/agents/RemoveAgentButton.tsx | 2 +- .../appearance/AppearancePageContainer.tsx | 2 +- .../businessHours/EditBusinessHoursPage.js | 2 +- .../omnichannel/components/CustomField.js | 2 +- .../currentChats/CurrentChatsRoute.tsx | 2 +- .../omnichannel/currentChats/FilterByText.tsx | 2 +- .../customFields/CustomFieldsRoute.js | 2 +- .../EditCustomFieldsPageContainer.js | 2 +- .../views/omnichannel/departments/AddAgent.js | 2 +- .../departments/DepartmentsRoute.js | 2 +- .../omnichannel/departments/EditDepartment.js | 2 +- .../EditDepartmentWithAllowedForwardData.js | 2 +- .../departments/EditDepartmentWithData.js | 2 +- .../departments/RemoveDepartmentButton.js | 2 +- .../directory/CallsContextualBarDirectory.tsx | 2 +- .../directory/ChatsContextualBar.tsx | 2 +- .../omnichannel/directory/calls/CallTable.tsx | 2 +- .../omnichannel/directory/chats/ChatTable.tsx | 2 +- .../chats/contextualBar/AgentField.js | 7 +- .../directory/chats/contextualBar/ChatInfo.js | 2 +- .../chats/contextualBar/ChatInfoDirectory.js | 2 +- .../chats/contextualBar/ContactField.js | 11 +- .../chats/contextualBar/DepartmentField.js | 2 +- .../chats/contextualBar/PriorityField.js | 11 +- .../directory/chats/contextualBar/RoomEdit.js | 4 +- .../chats/contextualBar/RoomEditWithData.js | 11 +- .../chats/contextualBar/VisitorClientInfo.js | 11 +- .../chats/contextualBar/VisitorData.js | 11 +- .../directory/contacts/ContactTable.js | 2 +- .../contextualBar/ContactEditWithData.js | 11 +- .../contacts/contextualBar/ContactInfo.js | 13 +- .../contacts/contextualBar/ContactNewEdit.js | 16 +- .../views/omnichannel/managers/AddManager.tsx | 2 +- .../omnichannel/managers/ManagersRoute.tsx | 2 +- .../managers/RemoveManagerButton.tsx | 2 +- .../views/omnichannel/queueList/index.tsx | 2 +- .../charts/AgentStatusChart.js | 2 +- .../charts/ChatDurationChart.js | 2 +- .../realTimeMonitoring/charts/ChatsChart.js | 2 +- .../charts/ChatsPerAgentChart.js | 2 +- .../charts/ChatsPerDepartmentChart.js | 2 +- .../charts/ResponseTimesChart.js | 2 +- .../overviews/AgentsOverview.js | 2 +- .../overviews/ChatsOverview.js | 2 +- .../overviews/ConversationOverview.js | 2 +- .../overviews/ProductivityOverview.js | 2 +- .../triggers/EditTriggerPageContainer.js | 2 +- .../triggers/TriggersTableContainer.js | 2 +- .../webhooks/WebhooksPageContainer.js | 2 +- .../QuickActions/hooks/useQuickActions.tsx | 4 +- .../Header/ParentRoomWithEndpointData.tsx | 2 +- .../client/views/room/Header/ParentTeam.tsx | 4 +- .../providers/MessageListProvider.tsx | 2 +- .../client/views/room/UserCard/index.js | 2 +- .../AutoTranslate/AutoTranslateWithData.tsx | 4 +- .../Discussions/useDiscussionsList.ts | 2 +- .../ExportMessages/FileExport.tsx | 2 +- .../ExportMessages/MailExportForm.tsx | 2 +- .../Info/EditRoomInfo/EditChannel.js | 4 +- .../PruneMessages/PruneMessagesWithData.tsx | 2 +- .../RoomFiles/hooks/useFilesList.ts | 12 +- .../InviteUsers/WrappedInviteUsers.js | 2 +- .../contextualBar/Threads/useThreadsList.ts | 2 +- .../UserInfo/UserInfoWithData.js | 2 +- .../views/room/hooks/useUserInfoActions.js | 4 +- .../views/room/threads/ThreadComponent.tsx | 2 +- .../providers/SetupWizardProvider.tsx | 2 +- .../steps/CloudAccountConfirmation.tsx | 2 +- .../ConvertToChannelModal.tsx | 2 +- .../teams/CreateTeamModal/CreateTeamModal.tsx | 2 +- .../teams/CreateTeamModal/UsersInput.tsx | 2 +- .../TeamAutocomplete/TeamAutocomplete.js | 2 +- .../AddExistingModal/AddExistingModal.tsx | 2 +- .../channels/AddExistingModal/RoomsInput.tsx | 2 +- .../channels/hooks/useTeamsChannelList.ts | 2 +- .../info/Delete/DeleteTeamModalWithRooms.tsx | 2 +- .../teams/contextualBar/info/Leave/index.js | 2 +- .../views/teams/contextualBar/info/index.js | 2 +- .../RemoveUsersModal/RemoveUsersModal.js | 4 +- .../externals/meteor/accounts-base.d.ts | 4 + .../definition/externals/meteor/session.d.ts | 7 + .../client/startup/responses.js | 2 +- .../visitorEditCustomFieldsForm.js | 2 +- .../customTemplates/visitorInfoCustomForm.js | 2 +- apps/meteor/ee/client/audit/AuditPageBase.js | 2 +- .../RoomAutoComplete/RoomAutoComplete.js | 2 +- .../ee/client/audit/VisitorAutoComplete.js | 2 +- apps/meteor/ee/client/ecdh.ts | 12 +- apps/meteor/ee/client/hooks/useAgentsList.ts | 2 +- apps/meteor/ee/client/hooks/useTagsList.ts | 2 +- apps/meteor/ee/client/lib/getFromRestApi.ts | 4 +- .../BusinessHoursTableContainer.js | 14 +- .../client/omnichannel/ContactManagerInfo.js | 7 +- .../DepartmentBusinessHours.js | 2 +- .../cannedResponses/CannedResponseEdit.tsx | 2 +- .../CannedResponseEditWithData.tsx | 2 +- .../CannedResponseEditWithDepartmentData.tsx | 2 +- .../cannedResponses/CannedResponsesRoute.tsx | 4 +- .../modals/CreateCannedResponse/index.tsx | 2 +- .../hooks/useCannedResponseFilterOptions.ts | 2 +- .../hooks/useCannedResponseList.ts | 4 +- .../omnichannel/monitors/MonitorsPage.js | 2 +- .../omnichannel/priorities/PrioritiesRoute.js | 2 +- .../priorities/PriorityEditWithData.js | 2 +- .../omnichannel/tags/TagEditWithData.js | 2 +- .../tags/TagEditWithDepartmentData.tsx | 2 +- .../ee/client/omnichannel/tags/TagNew.js | 2 +- .../ee/client/omnichannel/tags/TagsRoute.js | 2 +- .../omnichannel/units/UnitEditWithData.tsx | 10 +- .../ee/client/omnichannel/units/UnitNew.js | 4 +- .../ee/client/omnichannel/units/UnitsRoute.js | 2 +- .../EngagementDashboardRoute.tsx | 2 +- .../client/views/admin/users/useSeatsCap.ts | 2 +- .../rest/v1/omnichannel/businessHours.ts | 2 +- .../rest/v1/omnichannel/businessUnits.ts | 10 +- .../rest/v1/omnichannel/cannedResponses.ts | 4 +- apps/meteor/package.json | 3 + packages/api-client/.eslintrc | 4 + packages/api-client/package.json | 32 +++ .../api-client/src/RestClientInterface.ts | 61 +++++ packages/api-client/src/index.ts | 215 ++++++++++++++++ packages/api-client/tsconfig.json | 8 + .../src/ICustomEmojiDescriptor.ts | 2 +- packages/core-typings/src/IEmojiCustom.ts | 2 +- packages/rest-typings/src/apps/index.ts | 11 + packages/rest-typings/src/index.ts | 8 +- packages/rest-typings/src/v1/autoTranslate.ts | 6 +- packages/rest-typings/src/v1/banners.ts | 8 +- .../rest-typings/src/v1/channels/channels.ts | 58 ++--- packages/rest-typings/src/v1/chat.ts | 34 +-- packages/rest-typings/src/v1/cloud.ts | 8 +- packages/rest-typings/src/v1/commands.ts | 8 +- packages/rest-typings/src/v1/customSounds.ts | 2 +- .../rest-typings/src/v1/customUserStatus.ts | 8 +- packages/rest-typings/src/v1/directory.ts | 2 +- packages/rest-typings/src/v1/dm/dm.ts | 26 +- packages/rest-typings/src/v1/dm/im.ts | 30 +-- packages/rest-typings/src/v1/dns.ts | 4 +- packages/rest-typings/src/v1/e2e.ts | 10 +- packages/rest-typings/src/v1/email-inbox.ts | 10 +- packages/rest-typings/src/v1/emojiCustom.ts | 32 ++- packages/rest-typings/src/v1/groups.ts | 28 +-- packages/rest-typings/src/v1/instances.ts | 2 +- packages/rest-typings/src/v1/invites.ts | 10 +- packages/rest-typings/src/v1/ldap.ts | 6 +- packages/rest-typings/src/v1/licenses.ts | 8 +- packages/rest-typings/src/v1/me.ts | 35 +++ packages/rest-typings/src/v1/misc.ts | 2 +- packages/rest-typings/src/v1/oauthapps.ts | 4 +- packages/rest-typings/src/v1/omnichannel.ts | 71 +++--- packages/rest-typings/src/v1/permissions.ts | 4 +- packages/rest-typings/src/v1/push.ts | 4 +- packages/rest-typings/src/v1/roles.ts | 16 +- packages/rest-typings/src/v1/rooms.ts | 42 ++-- packages/rest-typings/src/v1/settings.ts | 12 +- packages/rest-typings/src/v1/statistics.ts | 6 +- packages/rest-typings/src/v1/teams/index.ts | 36 +-- packages/rest-typings/src/v1/users.ts | 21 +- .../rest-typings/src/v1/videoConference.ts | 2 +- packages/rest-typings/src/v1/voip.ts | 28 +-- packages/rest-typings/src/v1/webdav.ts | 2 +- .../src/ServerContext/ServerContext.ts | 5 +- packages/ui-contexts/src/hooks/useUpload.ts | 7 +- yarn.lock | 55 ++++ 303 files changed, 1598 insertions(+), 938 deletions(-) rename apps/meteor/app/api/server/v1/{emoji-custom.js => emoji-custom.ts} (69%) delete mode 100644 apps/meteor/app/ui/client/lib/fileUpload.js create mode 100644 apps/meteor/app/ui/client/lib/fileUpload.ts create mode 100644 apps/meteor/app/utils/client/lib/RestApiClient.ts rename apps/meteor/app/utils/client/lib/{RestApiClient.d.ts => _RestApiClient.d.ts} (74%) rename apps/meteor/app/utils/client/lib/{RestApiClient.js => _RestApiClient.js} (100%) create mode 100644 apps/meteor/definition/externals/meteor/session.d.ts create mode 100644 packages/api-client/.eslintrc create mode 100644 packages/api-client/package.json create mode 100644 packages/api-client/src/RestClientInterface.ts create mode 100644 packages/api-client/src/index.ts create mode 100644 packages/api-client/tsconfig.json create mode 100644 packages/rest-typings/src/v1/me.ts diff --git a/apps/meteor/app/api/server/lib/getUploadFormData.js b/apps/meteor/app/api/server/lib/getUploadFormData.js index 39b0e7436c13..553ebe0a27ba 100644 --- a/apps/meteor/app/api/server/lib/getUploadFormData.js +++ b/apps/meteor/app/api/server/lib/getUploadFormData.js @@ -9,7 +9,6 @@ export const getUploadFormData = async ({ request }) => bb.on('file', (fieldname, file, { filename, encoding, mimeType: mimetype }) => { const fileData = []; - console.log(file); file.on('data', (data) => fileData.push(data)); file.on('end', () => { diff --git a/apps/meteor/app/api/server/v1/emoji-custom.js b/apps/meteor/app/api/server/v1/emoji-custom.ts similarity index 69% rename from apps/meteor/app/api/server/v1/emoji-custom.js rename to apps/meteor/app/api/server/v1/emoji-custom.ts index 6a5fb2260e1b..fe16e3ed2392 100644 --- a/apps/meteor/app/api/server/v1/emoji-custom.js +++ b/apps/meteor/app/api/server/v1/emoji-custom.ts @@ -10,27 +10,29 @@ API.v1.addRoute( 'emoji-custom.list', { authRequired: true }, { - get() { + async get() { const { query } = this.parseJsonQuery(); const { updatedSince } = this.queryParams; - let updatedSinceDate; if (updatedSince) { + const updatedSinceDate = new Date(updatedSince); if (isNaN(Date.parse(updatedSince))) { throw new Meteor.Error('error-roomId-param-invalid', 'The "updatedSince" query parameter must be a valid date.'); - } else { - updatedSinceDate = new Date(updatedSince); } + const [update, remove] = await Promise.all([ + EmojiCustom.find({ ...query, _updatedAt: { $gt: updatedSinceDate } }).toArray(), + EmojiCustom.trashFindDeletedAfter(updatedSinceDate).toArray(), + ]); return API.v1.success({ emojis: { - update: Promise.await(EmojiCustom.find({ ...query, _updatedAt: { $gt: updatedSinceDate } }).toArray()), - remove: Promise.await(EmojiCustom.trashFindDeletedAfter(updatedSinceDate).toArray()), + update, + remove, }, }); } return API.v1.success({ emojis: { - update: Promise.await(EmojiCustom.find(query).toArray()), + update: await EmojiCustom.find(query).toArray(), remove: [], }, }); @@ -42,21 +44,19 @@ API.v1.addRoute( 'emoji-custom.all', { authRequired: true }, { - get() { + async get() { const { offset, count } = this.getPaginationItems(); const { sort, query } = this.parseJsonQuery(); return API.v1.success( - Promise.await( - findEmojisCustom({ - query, - pagination: { - offset, - count, - sort, - }, - }), - ), + await findEmojisCustom({ + query, + pagination: { + offset, + count, + sort, + }, + }), ); }, }, @@ -66,18 +66,16 @@ API.v1.addRoute( 'emoji-custom.create', { authRequired: true }, { - post() { - const { emoji, ...fields } = Promise.await( - getUploadFormData({ - request: this.request, - }), - ); + async post() { + const { emoji, ...fields } = await getUploadFormData({ + request: this.request, + }); if (!emoji) { throw new Meteor.Error('invalid-field'); } - const isUploadable = Promise.await(Media.isImage(emoji.fileBuffer)); + const isUploadable = await Media.isImage(emoji.fileBuffer); if (!isUploadable) { throw new Meteor.Error('emoji-is-not-image', "Emoji file provided cannot be uploaded since it's not an image"); } @@ -88,10 +86,10 @@ API.v1.addRoute( fields.newFile = true; fields.aliases = fields.aliases || ''; - Meteor.runAsUser(this.userId, () => { - Meteor.call('insertOrUpdateEmoji', fields); - Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, fields); - }); + Meteor.call('insertOrUpdateEmoji', fields); + Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, fields); + + return API.v1.success(); }, }, ); @@ -100,12 +98,10 @@ API.v1.addRoute( 'emoji-custom.update', { authRequired: true }, { - post() { - const { emoji, ...fields } = Promise.await( - getUploadFormData({ - request: this.request, - }), - ); + async post() { + const { emoji, ...fields } = await getUploadFormData({ + request: this.request, + }); if (!fields._id) { throw new Meteor.Error('The required "_id" query param is missing.'); @@ -133,12 +129,11 @@ API.v1.addRoute( fields.extension = emojiToUpdate.extension; } - Meteor.runAsUser(this.userId, () => { - Meteor.call('insertOrUpdateEmoji', fields); - if (fields.newFile) { - Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, fields); - } - }); + Meteor.call('insertOrUpdateEmoji', fields); + if (fields.newFile) { + Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, fields); + } + return API.v1.success(); }, }, ); @@ -153,7 +148,7 @@ API.v1.addRoute( return API.v1.failure('The "emojiId" params is required!'); } - Meteor.runAsUser(this.userId, () => Meteor.call('deleteEmojiCustom', emojiId)); + Meteor.call('deleteEmojiCustom', emojiId); return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/settings.ts b/apps/meteor/app/api/server/v1/settings.ts index f8bdb46c352f..f91c09d2166a 100644 --- a/apps/meteor/app/api/server/v1/settings.ts +++ b/apps/meteor/app/api/server/v1/settings.ts @@ -154,7 +154,7 @@ API.v1.addRoute( }, post: { twoFactorRequired: true, - async action(): Promise> { + async action(): Promise> { if (!hasPermission(this.userId, 'edit-privileged-setting')) { return API.v1.unauthorized(); } diff --git a/apps/meteor/app/apps/client/RealAppsEngineUIHost.js b/apps/meteor/app/apps/client/RealAppsEngineUIHost.js index c7d15fd467ef..6a73e7f38a7e 100644 --- a/apps/meteor/app/apps/client/RealAppsEngineUIHost.js +++ b/apps/meteor/app/apps/client/RealAppsEngineUIHost.js @@ -29,7 +29,7 @@ export class RealAppsEngineUIHost extends AppsEngineUIHost { let cachedMembers = []; try { - const { members } = await APIClient.get('v1/groups.members', { roomId: id }); + const { members } = await APIClient.get('/v1/groups.members', { roomId: id }); cachedMembers = members.map(({ _id, username }) => ({ id: _id, diff --git a/apps/meteor/app/apps/client/communication/websockets.js b/apps/meteor/app/apps/client/communication/websockets.js index 090fb059edaf..6c2707af230d 100644 --- a/apps/meteor/app/apps/client/communication/websockets.js +++ b/apps/meteor/app/apps/client/communication/websockets.js @@ -50,7 +50,7 @@ export class AppWebsocketReceiver extends Emitter { } onCommandAddedOrUpdated = (command) => { - APIClient.v1.get('commands.get', { command }).then((result) => { + APIClient.get('/v1/commands.get', { command }).then((result) => { slashCommands.commands[command] = result.command; }); }; diff --git a/apps/meteor/app/apps/client/gameCenter/gameCenter.js b/apps/meteor/app/apps/client/gameCenter/gameCenter.js index bd3e19669302..6486573f4974 100644 --- a/apps/meteor/app/apps/client/gameCenter/gameCenter.js +++ b/apps/meteor/app/apps/client/gameCenter/gameCenter.js @@ -8,7 +8,7 @@ import { handleError } from '../../../../client/lib/utils/handleError'; const getExternalComponents = async (instance) => { try { - const { externalComponents } = await APIClient.get('apps/externalComponents'); + const { externalComponents } = await APIClient.get('/apps/externalComponents'); instance.games.set(externalComponents); } catch (e) { handleError(e); diff --git a/apps/meteor/app/apps/client/gameCenter/gameContainer.js b/apps/meteor/app/apps/client/gameCenter/gameContainer.js index 7ee2285ee901..d954c06d1c25 100644 --- a/apps/meteor/app/apps/client/gameCenter/gameContainer.js +++ b/apps/meteor/app/apps/client/gameCenter/gameContainer.js @@ -62,7 +62,7 @@ Template.GameContainer.events({ Template.GameContainer.onCreated(async () => { const externalComponent = await getExternalComponent(); - APIClient.post('apps/externalComponentEvent', { + APIClient.post('/apps/externalComponentEvent', { event: 'IPostExternalComponentOpened', externalComponent, }); @@ -71,7 +71,7 @@ Template.GameContainer.onCreated(async () => { Template.GameContainer.onDestroyed(async () => { const externalComponent = await getExternalComponent(); - APIClient.post('apps/externalComponentEvent', { + APIClient.post('/apps/externalComponentEvent', { event: 'IPostExternalComponentClosed', externalComponent, }); diff --git a/apps/meteor/app/apps/client/orchestrator.ts b/apps/meteor/app/apps/client/orchestrator.ts index ecbe4c9ed818..0062d6206990 100644 --- a/apps/meteor/app/apps/client/orchestrator.ts +++ b/apps/meteor/app/apps/client/orchestrator.ts @@ -124,7 +124,7 @@ class AppClientOrchestrator { } public screenshots(appId: string): IAppScreenshots { - return APIClient.get(`apps/${appId}/screenshots`); + return APIClient.get(`/v1/apps/${appId}/screenshots`); } public isEnabled(): Promise | undefined { @@ -132,12 +132,12 @@ class AppClientOrchestrator { } public async getApps(): Promise { - const { apps } = await APIClient.get('apps'); + const { apps } = await APIClient.get('/v1/apps'); return apps; } public async getAppsFromMarketplace(): Promise { - const appsOverviews: IAppFromMarketplace[] = await APIClient.get('apps', { marketplace: 'true' }); + const appsOverviews: IAppFromMarketplace[] = await APIClient.get('/v1/apps', { marketplace: 'true' }); return appsOverviews.map((app: IAppFromMarketplace) => { const { latest, price, pricingPlans, purchaseType, isEnterpriseOnly, modifiedAt } = app; return { @@ -152,22 +152,22 @@ class AppClientOrchestrator { } public async getAppsOnBundle(bundleId: string): Promise { - const { apps } = await APIClient.get(`apps/bundles/${bundleId}/apps`); + const { apps } = await APIClient.get(`/v1/apps/bundles/${bundleId}/apps`); return apps; } public async getAppsLanguages(): Promise { - const { apps } = await APIClient.get('apps/languages'); + const { apps } = await APIClient.get('/v1/apps/languages'); return apps; } public async getApp(appId: string): Promise { - const { app } = await APIClient.get(`apps/${appId}`); + const { app } = await APIClient.get(`/v1/apps/${appId}`); return app; } public async getAppFromMarketplace(appId: string, version: string): Promise { - const { app } = await APIClient.get(`apps/${appId}`, { + const { app } = await APIClient.get(`/v1/apps/${appId}`, { marketplace: 'true', version, }); @@ -175,7 +175,7 @@ class AppClientOrchestrator { } public async getLatestAppFromMarketplace(appId: string, version: string): Promise { - const { app } = await APIClient.get(`apps/${appId}`, { + const { app } = await APIClient.get(`/v1/apps/${appId}`, { marketplace: 'true', update: 'true', appVersion: version, @@ -184,27 +184,27 @@ class AppClientOrchestrator { } public async getAppSettings(appId: string): Promise { - const { settings } = await APIClient.get(`apps/${appId}/settings`); + const { settings } = await APIClient.get(`/v1/apps/${appId}/settings`); return settings; } public async setAppSettings(appId: string, settings: ISettingsPayload): Promise { - const { updated } = await APIClient.post(`apps/${appId}/settings`, undefined, { settings }); + const { updated } = await APIClient.post(`/v1/apps/${appId}/settings`, undefined, { settings }); return updated; } public async getAppApis(appId: string): Promise { - const { apis } = await APIClient.get(`apps/${appId}/apis`); + const { apis } = await APIClient.get(`/v1/apps/${appId}/apis`); return apis; } public async getAppLanguages(appId: string): Promise { - const { languages } = await APIClient.get(`apps/${appId}/languages`); + const { languages } = await APIClient.get(`/v1/apps/${appId}/languages`); return languages; } public async installApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const { app } = await APIClient.post('apps/', { + const { app } = await APIClient.post('/v1/apps/', { appId, marketplace: true, version, @@ -214,7 +214,7 @@ class AppClientOrchestrator { } public async updateApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const { app } = await APIClient.post(`apps/${appId}`, { + const { app } = await APIClient.post(`/v1/apps/${appId}`, { appId, marketplace: true, version, @@ -228,11 +228,11 @@ class AppClientOrchestrator { } public syncApp(appId: string): IAppSynced { - return APIClient.post(`apps/${appId}/sync`); + return APIClient.post(`/v1/apps/${appId}/sync`); } public async setAppStatus(appId: string, status: AppStatus): Promise { - const { status: effectiveStatus } = await APIClient.post(`apps/${appId}/status`, { status }); + const { status: effectiveStatus } = await APIClient.post(`/v1/apps/${appId}/status`, { status }); return effectiveStatus; } @@ -245,7 +245,7 @@ class AppClientOrchestrator { } public buildExternalUrl(appId: string, purchaseType = 'buy', details = false): IAppExternalURL { - return APIClient.get('apps', { + return APIClient.get('/v1/apps', { buildExternalUrl: 'true', appId, purchaseType, @@ -254,7 +254,7 @@ class AppClientOrchestrator { } public async getCategories(): Promise { - const categories = await APIClient.get('apps', { categories: 'true' }); + const categories = await APIClient.get('/v1/apps', { categories: 'true' }); return categories; } diff --git a/apps/meteor/app/authorization/client/startup.js b/apps/meteor/app/authorization/client/startup.js index 7b1643224acd..6a7d79cb79cc 100644 --- a/apps/meteor/app/authorization/client/startup.js +++ b/apps/meteor/app/authorization/client/startup.js @@ -2,13 +2,13 @@ import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; import { CachedCollectionManager } from '../../ui-cached-collection'; -import { APIClient } from '../../utils/client'; +import { APIClient } from '../../utils/client/lib/RestApiClient'; import { Roles } from '../../models/client'; import { rolesStreamer } from './lib/streamer'; Meteor.startup(() => { CachedCollectionManager.onLogin(async () => { - const { roles } = await APIClient.v1.get('roles.list'); + const { roles } = await APIClient.get('/v1/roles.list'); // if a role is checked before this collection is populated, it will return undefined Roles._collection._docs._map = new Map(roles.map((record) => [Roles._collection._docs._idStringify(record._id), record])); Object.values(Roles._collection.queries).forEach((query) => Roles._collection._recomputeResults(query)); diff --git a/apps/meteor/app/authorization/server/methods/saveRole.ts b/apps/meteor/app/authorization/server/methods/saveRole.ts index 3b0517852865..5a4b485a5e15 100644 --- a/apps/meteor/app/authorization/server/methods/saveRole.ts +++ b/apps/meteor/app/authorization/server/methods/saveRole.ts @@ -13,16 +13,16 @@ Meteor.methods({ methodDeprecationLogger.warn('authorization:saveRole will be deprecated in future versions of Rocket.Chat'); const userId = Meteor.userId(); - if (!userId || !hasPermission(userId, 'access-permissions')) { - throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', { + if (!isRoleCreateProps(roleData)) { + throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.', { method: 'authorization:saveRole', - action: 'Accessing_permissions', }); } - if (!isRoleCreateProps(roleData)) { - throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.', { + if (!userId || !hasPermission(userId, 'access-permissions')) { + throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', { method: 'authorization:saveRole', + action: 'Accessing_permissions', }); } diff --git a/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js b/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js index 46cb53fcbf56..a3df7135cc5f 100644 --- a/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js +++ b/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js @@ -184,7 +184,7 @@ Meteor.startup(() => try { const { emojis: { update: emojis }, - } = await APIClient.v1.get('emoji-custom.list'); + } = await APIClient.get('/v1/emoji-custom.list'); emoji.packages.emojiCustom.emojisByCategory = { rocket: [] }; for (const currentEmoji of emojis) { diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.js b/apps/meteor/app/livechat/client/lib/stream/queueManager.js index f76e5679d279..1a17c2169b30 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.js +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.js @@ -45,7 +45,7 @@ const updateCollection = (inquiry) => { }; const getInquiriesFromAPI = async () => { - const { inquiries } = await APIClient.v1.get('livechat/inquiries.queuedForUser?sort={"ts": 1}'); + const { inquiries } = await APIClient.get('/v1/livechat/inquiries.queuedForUser?sort={"ts": 1}'); return inquiries; }; @@ -68,7 +68,7 @@ const updateInquiries = async (inquiries = []) => inquiries.forEach((inquiry) => LivechatInquiry.upsert({ _id: inquiry._id }, { ...inquiry, _updatedAt: new Date(inquiry._updatedAt) })); const getAgentsDepartments = async (userId) => { - const { departments } = await APIClient.v1.get(`livechat/agents/${userId}/departments?enabledDepartmentsOnly=true`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${userId}/departments?enabledDepartmentsOnly=true`); return departments; }; diff --git a/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js b/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js index 3db0d930cfc9..779b7e9f5938 100644 --- a/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js +++ b/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js @@ -167,16 +167,16 @@ Template.closeRoom.onCreated(async function () { this.onEnterTag = () => this.invalidTags.set(!validateRoomTags(this.tagsRequired.get(), this.tags.get())); const { rid } = Template.currentData(); - const { room } = await APIClient.v1.get(`rooms.info?roomId=${rid}`); + const { room } = await APIClient.get(`/v1/rooms.info?roomId=${rid}`); this.tags.set(room?.tags || []); if (room?.departmentId) { - const { department } = await APIClient.v1.get(`livechat/department/${room.departmentId}?includeAgents=false`); + const { department } = await APIClient.get(`/v1/livechat/department/${room.departmentId}?includeAgents=false`); this.tagsRequired.set(department?.requestTagBeforeClosingChat); } const uid = Meteor.userId(); - const { departments } = await APIClient.v1.get(`livechat/agents/${uid}/departments`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${uid}/departments`); const agentDepartments = departments.map((dept) => dept.departmentId); this.agentDepartments.set(agentDepartments); diff --git a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js index fa38742ca152..a42d81f029bb 100644 --- a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js +++ b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js @@ -61,7 +61,7 @@ Template.livechatReadOnly.events({ event.stopPropagation(); try { - const { success } = (await APIClient.v1.get(`livechat/room.join?roomId=${this.rid}`)) || {}; + const { success } = (await APIClient.get(`/v1/livechat/room.join?roomId=${this.rid}`)) || {}; if (!success) { throw new Meteor.Error('error-join-room', 'Error joining room'); } @@ -99,13 +99,13 @@ Template.livechatReadOnly.onCreated(async function () { this.loadRoomAndInquiry = async (roomId) => { this.preparing.set(true); - const { inquiry } = await APIClient.v1.get(`livechat/inquiries.getOne?roomId=${roomId}`); + const { inquiry } = await APIClient.get(`/v1/livechat/inquiries.getOne?roomId=${roomId}`); this.inquiry.set(inquiry); if (inquiry && inquiry._id) { inquiryDataStream.on(inquiry._id, this.updateInquiry); } - const { room } = await APIClient.v1.get(`rooms.info?roomId=${roomId}`); + const { room } = await APIClient.get(`/v1/rooms.info?roomId=${roomId}`); this.room.set(room); if (room && room._id) { RoomManager.roomStream.on(roomId, (room) => this.room.set(room)); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/agentEdit.js b/apps/meteor/app/livechat/client/views/app/tabbar/agentEdit.js index ff14df8f7832..c1fef6d7fd76 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/agentEdit.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/agentEdit.js @@ -133,7 +133,7 @@ Template.agentEdit.onCreated(async function () { this.availableDepartments = new ReactiveVar([]); this.back = Template.currentData().back; - const { departments } = await APIClient.v1.get('livechat/department?sort={"name": 1}'); + const { departments } = await APIClient.get('/v1/livechat/department?sort={"name": 1}'); this.departments.set(departments); this.availableDepartments.set(departments.filter(({ enabled }) => enabled)); @@ -146,8 +146,8 @@ Template.agentEdit.onCreated(async function () { return; } - const { user } = await APIClient.v1.get(`livechat/users/agent/${agentId}`); - const { departments } = await APIClient.v1.get(`livechat/agents/${agentId}/departments`); + const { user } = await APIClient.get(`/v1/livechat/users/agent/${agentId}`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${agentId}/departments`); this.agent.set(user); this.agentDepartments.set((departments || []).map((department) => department.departmentId)); this.ready.set(true); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/agentInfo.js b/apps/meteor/app/livechat/client/views/app/tabbar/agentInfo.js index af15c9ba3f7e..725a2ec0dfea 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/agentInfo.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/agentInfo.js @@ -153,14 +153,14 @@ Template.agentInfo.onCreated(async function () { this.tabBar = Template.currentData().tabBar; this.onRemoveAgent = Template.currentData().onRemoveAgent; - const { departments } = await APIClient.v1.get('livechat/department?sort={"name": 1}'); + const { departments } = await APIClient.get('/v1/livechat/department?sort={"name": 1}'); this.departments.set(departments); this.availableDepartments.set(departments.filter(({ enabled }) => enabled)); const loadAgentData = async (agentId) => { this.ready.set(false); - const { user } = await APIClient.v1.get(`livechat/users/agent/${agentId}`); - const { departments } = await APIClient.v1.get(`livechat/agents/${agentId}/departments`); + const { user } = await APIClient.get(`/v1/livechat/users/agent/${agentId}`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${agentId}/departments`); this.agent.set(user); this.agentDepartments.set((departments || []).map((department) => department.departmentId)); this.ready.set(true); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js index 9dcd6d690ba1..10e05932b3fb 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js @@ -70,7 +70,7 @@ Template.contactChatHistory.onCreated(async function () { const offset = this.offset.get(); const searchTerm = this.searchTerm.get(); - let baseUrl = `livechat/visitors.searchChats/room/${ + let baseUrl = `/v1/livechat/visitors.searchChats/room/${ currentData.rid }/visitor/${this.visitorId.get()}?count=${limit}&offset=${offset}&closedChatsOnly=true&servedChatsOnly=true`; if (searchTerm) { @@ -78,14 +78,14 @@ Template.contactChatHistory.onCreated(async function () { } this.isLoading.set(true); - const { history, total } = await APIClient.v1.get(baseUrl); + const { history, total } = await APIClient.get(baseUrl); this.history.set(offset === 0 ? history : this.history.get().concat(history)); this.hasMore.set(total > this.history.get().length); this.isLoading.set(false); }); this.autorun(async () => { - const { room } = await APIClient.v1.get(`rooms.info?roomId=${currentData.rid}`); + const { room } = await APIClient.get(`/v1/rooms.info?roomId=${currentData.rid}`); if (room?.v) { this.visitorId.set(room.v._id); } diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js index 2b668732fc5c..f00adaf28354 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js @@ -81,12 +81,12 @@ Template.contactChatHistoryMessages.onCreated(function () { this.hasError = new ReactiveVar(false); this.error = new ReactiveVar(null); - this.loadMessages = async (url) => { + this.loadMessages = async (url, params) => { this.isLoading.set(true); const offset = this.offset.get(); try { - const { messages, total } = await APIClient.v1.get(url); + const { messages, total } = await APIClient.get(url, params); this.messages.set(offset === 0 ? messages : this.messages.get().concat(messages)); this.hasMore.set(total > this.messages.get().length); } catch (e) { @@ -103,10 +103,20 @@ Template.contactChatHistoryMessages.onCreated(function () { const searchTerm = this.searchTerm.get(); if (searchTerm !== '') { - return this.loadMessages(`chat.search/?roomId=${this.rid}&searchText=${searchTerm}&count=${limit}&offset=${offset}&sort={"ts": 1}`); + return this.loadMessages('/v1/chat.search', { + roomId: this.rid, + searchText: searchTerm, + count: limit, + offset, + sort: '{"ts": 1}', + }); } - this.loadMessages(`livechat/${this.rid}/messages?count=${limit}&offset=${offset}&sort={"ts": 1}`); + this.loadMessages(`/v1/livechat/${this.rid}/messages`, { + count: limit, + offset, + sort: '{"ts": 1}', + }); }); this.autorun(() => { diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorEdit.js b/apps/meteor/app/livechat/client/views/app/tabbar/visitorEdit.js index ce70d5e979b8..46f4f0cc2af4 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorEdit.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorEdit.js @@ -114,7 +114,7 @@ Template.visitorEdit.onCreated(async function () { this.autorun(async () => { const { visitorId } = Template.currentData(); if (visitorId) { - const { visitor } = await APIClient.v1.get(`livechat/visitors.info?visitorId=${visitorId}`); + const { visitor } = await APIClient.get('/v1/livechat/visitors.info', { visitorId }); this.visitor.set(visitor); } }); @@ -122,15 +122,15 @@ Template.visitorEdit.onCreated(async function () { const rid = Template.currentData().roomId; this.autorun(async () => { - const { room } = await APIClient.v1.get(`rooms.info?roomId=${rid}`); - const { customFields } = await APIClient.v1.get(`livechat/custom-fields?count=${CUSTOM_FIELDS_COUNT}`); + const { room } = await APIClient.get('/v1/rooms.info', { roomId: rid }); + const { customFields } = await APIClient.get('/v1/livechat/custom-fields', { count: CUSTOM_FIELDS_COUNT }); this.room.set(room); this.tags.set((room && room.tags) || []); this.customFields.set(customFields || []); }); const uid = Meteor.userId(); - const { departments } = await APIClient.v1.get(`livechat/agents/${uid}/departments`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${uid}/departments`); const agentDepartments = departments.map((dept) => dept.departmentId); this.agentDepartments.set(agentDepartments); Meteor.call('livechat:getTagsList', (err, tagsList) => { diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.html b/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.html index 45c909a10ded..82ce65ae4706 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.html +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.html @@ -3,34 +3,20 @@

{{_ "Forward_chat"}}

{{#with visitor}} -
- - {{username}} -
+
+ + {{username}} +
{{/with}}
- {{> livechatAutocompleteUser - onClickTag=onClickTagDepartment - list=selectedDepartments - onSelect=onSelectDepartments - collection='CachedDepartmentList' - endpoint='livechat/department.autocomplete' - field='name' - sort='name' - icon="queue" - label="Enter_a_department_name" - placeholder="Enter_a_department_name" - name="department" - noMatchTemplate="userSearchEmpty" - templateItem="popupList_item_channel" - template="roomSearch" - noMatchTemplate="roomSearchEmpty" - modifier=departmentModifier - conditions=departmentConditions - }} + {{> livechatAutocompleteUser onClickTag=onClickTagDepartment list=selectedDepartments onSelect=onSelectDepartments + collection='CachedDepartmentList' endpoint='livechat/department.autocomplete' field='name' sort='name' icon="queue" + label="Enter_a_department_name" placeholder="Enter_a_department_name" name="department" noMatchTemplate="userSearchEmpty" + templateItem="popupList_item_channel" template="roomSearch" noMatchTemplate="roomSearchEmpty" modifier=departmentModifier + conditions=departmentConditions }}
@@ -40,23 +26,10 @@

{{_ "Forward_chat"}}

- {{> livechatAutocompleteUser - onClickTag=onClickTagAgent - list=selectedAgents - onSelect=onSelectAgents - collection='UserAndRoom' - endpoint='users.autocomplete' - field='username' - sort='username' - label="Select_a_user" - placeholder="Select_a_user" - name="agent" - icon="at" - noMatchTemplate="userSearchEmpty" - templateItem="popupList_item_default" - modifier=agentModifier - conditions=agentConditions - }} + {{> livechatAutocompleteUser onClickTag=onClickTagAgent list=selectedAgents onSelect=onSelectAgents collection='UserAndRoom' + endpoint='/v1/users.autocomplete' field='username' sort='username' label="Select_a_user" placeholder="Select_a_user" + name="agent" icon="at" noMatchTemplate="userSearchEmpty" templateItem="popupList_item_default" modifier=agentModifier + conditions=agentConditions }}
@@ -66,8 +39,8 @@

{{_ "Forward_chat"}}

diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.js b/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.js index b591ed84e52d..8e6c407bc03a 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorForward.js @@ -99,7 +99,7 @@ Template.visitorForward.onCreated(async function () { } }); - const { departments } = await APIClient.v1.get('livechat/department?enabled=true'); + const { departments } = await APIClient.get('/v1/livechat/department', { enabled: true }); this.departments.set(departments); }); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorInfo.js b/apps/meteor/app/livechat/client/views/app/tabbar/visitorInfo.js index 4a5d71e94c14..475987d158b2 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorInfo.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorInfo.js @@ -355,7 +355,7 @@ Template.visitorInfo.events({ confirmButtonText: t('Yes'), }, async () => { - const { success } = await APIClient.v1.post('livechat/room.onHold', { roomId: this.rid }); + const { success } = await APIClient.post('/v1/livechat/room.onHold', { roomId: this.rid }); if (success) { modal.open({ title: t('Chat_On_Hold'), @@ -382,7 +382,7 @@ Template.visitorInfo.onCreated(function () { this.room = new ReactiveVar({}); this.updateVisitor = async (visitorId) => { - const { visitor } = await APIClient.v1.get(`livechat/visitors.info?visitorId=${visitorId}`); + const { visitor } = await APIClient.get('/v1/livechat/visitors.info', { visitorId }); this.user.set(visitor); }; @@ -409,7 +409,7 @@ Template.visitorInfo.onCreated(function () { }); const loadRoomData = async (rid) => { - const { room } = await APIClient.v1.get(`rooms.info?roomId=${rid}`); + const { room } = await APIClient.get('/v1/rooms.info', { roomId: rid }); this.updateRoom(room); }; @@ -420,7 +420,7 @@ Template.visitorInfo.onCreated(function () { this.autorun(async () => { if (this.departmentId.get()) { - const { department } = await APIClient.v1.get(`livechat/department/${this.departmentId.get()}?includeAgents=false`); + const { department } = await APIClient.get(`/v1/livechat/department/${this.departmentId.get()}`, { includeAgents: false }); this.department.set(department); } }); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorNavigation.js b/apps/meteor/app/livechat/client/views/app/tabbar/visitorNavigation.js index 3142aa92a423..3f5a9a77d55e 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorNavigation.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorNavigation.js @@ -65,9 +65,10 @@ Template.visitorNavigation.onCreated(async function () { this.isLoading.set(true); const offset = this.offset.get(); if (currentData && currentData.rid) { - const { pages, total } = await APIClient.v1.get( - `livechat/visitors.pagesVisited/${currentData.rid}?count=${ITEMS_COUNT}&offset=${offset}`, - ); + const { pages, total } = await APIClient.get(`/v1/livechat/visitors.pagesVisited/${currentData.rid}`, { + count: ITEMS_COUNT, + offset, + }); this.isLoading.set(false); this.total.set(total); this.pages.set(this.pages.get().concat(pages)); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/visitorTranscript.js b/apps/meteor/app/livechat/client/views/app/tabbar/visitorTranscript.js index de70f61347f2..94f107319e9c 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/visitorTranscript.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/visitorTranscript.js @@ -169,12 +169,12 @@ Template.visitorTranscript.onCreated(async function () { this.infoMessage = new ReactiveVar(''); this.autorun(async () => { - const { visitor } = await APIClient.v1.get(`livechat/visitors.info?visitorId=${Template.currentData().visitorId}`); + const { visitor } = await APIClient.get('/v1/livechat/visitors.info', { visitorId: Template.currentData().visitorId }); this.visitor.set(visitor); }); this.autorun(async () => { - const { room } = await APIClient.v1.get(`rooms.info?roomId=${Template.currentData().roomId}`); + const { room } = await APIClient.get('/v1/rooms.info', { roomId: Template.currentData().roomId }); this.room.set(room); if (room?.transcriptRequest) { diff --git a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js b/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js index 97fd7e1c5659..92b10b8a57d0 100644 --- a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js +++ b/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js @@ -61,7 +61,10 @@ Template.mentionsFlexTab.onCreated(function () { this.autorun(async () => { const limit = this.limit.get(); - const { messages, total } = await APIClient.v1.get(`chat.getMentionedMessages?roomId=${this.data.rid}&count=${limit}`); + const { messages, total } = await APIClient.get('/v1/chat.getMentionedMessages', { + roomId: this.data.rid, + count: limit, + }); upsertMessageBulk({ msgs: messages }, this.messages); diff --git a/apps/meteor/app/message-pin/client/views/pinnedMessages.js b/apps/meteor/app/message-pin/client/views/pinnedMessages.js index 104777b58eee..75fc482f913c 100644 --- a/apps/meteor/app/message-pin/client/views/pinnedMessages.js +++ b/apps/meteor/app/message-pin/client/views/pinnedMessages.js @@ -62,7 +62,10 @@ Template.pinnedMessages.onCreated(function () { this.autorun(async () => { const limit = this.limit.get(); - const { messages, total } = await APIClient.v1.get(`chat.getPinnedMessages?roomId=${this.rid}&count=${limit}`); + const { messages, total } = await APIClient.get('/v1/chat.getPinnedMessages', { + roomId: this.rid, + count: limit, + }); upsertMessageBulk({ msgs: messages }, this.messages); diff --git a/apps/meteor/app/message-snippet/client/page/snippetPage.js b/apps/meteor/app/message-snippet/client/page/snippetPage.js index 48e2706302aa..0cd662305e7d 100644 --- a/apps/meteor/app/message-snippet/client/page/snippetPage.js +++ b/apps/meteor/app/message-snippet/client/page/snippetPage.js @@ -39,6 +39,6 @@ Template.snippetPage.onCreated(async function () { const snippetId = FlowRouter.getParam('snippetId'); this.message = new ReactiveVar({}); - const { message } = await APIClient.v1.get(`chat.getSnippetedMessageById?messageId=${snippetId}`); + const { message } = await APIClient.get('/v1/chat.getSnippetedMessageById', { messageId: snippetId }); this.message.set(message); }); diff --git a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js b/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js index 0dbefc6c01bb..4ee7fee88472 100644 --- a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js +++ b/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js @@ -56,7 +56,10 @@ Template.snippetedMessages.onCreated(function () { this.autorun(async () => { const limit = this.limit.get(); - const { messages, total } = await APIClient.v1.get(`chat.getSnippetedMessages?roomId=${this.rid}&count=${limit}`); + const { messages, total } = await APIClient.get('/v1/chat.getSnippetedMessages', { + roomId: this.rid, + count: limit, + }); upsertMessageBulk({ msgs: messages }, this.messages); diff --git a/apps/meteor/app/message-star/client/views/starredMessages.js b/apps/meteor/app/message-star/client/views/starredMessages.js index a0906d92b604..8b44b85e3f7f 100644 --- a/apps/meteor/app/message-star/client/views/starredMessages.js +++ b/apps/meteor/app/message-star/client/views/starredMessages.js @@ -61,7 +61,10 @@ Template.starredMessages.onCreated(function () { this.autorun(async () => { const limit = this.limit.get(); - const { messages, total } = await APIClient.v1.get(`chat.getStarredMessages?roomId=${this.rid}&count=${limit}`); + const { messages, total } = await APIClient.get('/v1/chat.getStarredMessages', { + roomId: this.rid, + count: limit, + }); upsertMessageBulk({ msgs: messages }, this.messages); diff --git a/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js b/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js index ee50a510cbca..55db42563b26 100755 --- a/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js +++ b/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js @@ -131,7 +131,7 @@ export default class AutoComplete { // console.debug 'Subscribing to <%s> in <%s>.<%s>', filter, rule.collection, rule.field this.setLoaded(false); const endpointName = rule.endpoint || 'users.autocomplete'; - const { items } = await APIClient.v1.get(`${endpointName}?selector=${JSON.stringify(selector)}`); + const { items } = await APIClient.get(`/v1/${endpointName}`, { selector: JSON.stringify(selector) }); AutoCompleteRecords.remove({}); items.forEach((item) => AutoCompleteRecords.insert(item)); this.setLoaded(true); diff --git a/apps/meteor/app/models/server/raw/EmojiCustom.ts b/apps/meteor/app/models/server/raw/EmojiCustom.ts index 30186cbdd3e4..0a8005cb379f 100644 --- a/apps/meteor/app/models/server/raw/EmojiCustom.ts +++ b/apps/meteor/app/models/server/raw/EmojiCustom.ts @@ -43,7 +43,7 @@ export class EmojiCustomRaw extends BaseRaw { return this.updateOne({ _id }, update); } - setAliases(_id: string, aliases: string): Promise { + setAliases(_id: string, aliases: string[]): Promise { const update = { $set: { aliases, diff --git a/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js b/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js index 47e5f0e958d9..55d7162d7f3a 100644 --- a/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js +++ b/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js @@ -7,7 +7,7 @@ import { APIClient } from '../../../utils/client'; Template.authorize.onCreated(async function () { this.oauthApp = new ReactiveVar({}); - const { oauthApp } = await APIClient.v1.get(`oauth-apps.get?clientId=${this.data.client_id()}`); + const { oauthApp } = await APIClient.get(`/v1/oauth-apps.get?clientId=${this.data.client_id()}`); this.oauthApp.set(oauthApp); }); diff --git a/apps/meteor/app/otr/client/rocketchat.otr.room.js b/apps/meteor/app/otr/client/rocketchat.otr.room.js index 95b57ad70b78..cf9dcd37308d 100644 --- a/apps/meteor/app/otr/client/rocketchat.otr.room.js +++ b/apps/meteor/app/otr/client/rocketchat.otr.room.js @@ -62,7 +62,7 @@ OTR.Room = class { } acknowledge() { - APIClient.v1.post('statistics.telemetry', { params: [{ eventName: 'otrStats', timestamp: Date.now(), rid: this.roomId }] }); + APIClient.post('/v1/statistics.telemetry', { params: [{ eventName: 'otrStats', timestamp: Date.now(), rid: this.roomId }] }); Notifications.notifyUser(this.peerId, 'otr', 'acknowledge', { roomId: this.roomId, diff --git a/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts b/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts index 7410fa2deeca..0ec6f94d7fb0 100644 --- a/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts +++ b/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts @@ -46,7 +46,7 @@ export const removeButton = (button: IUIActionButton): void => { }; export const loadButtons = (): Promise => - APIClient.get('apps/actionButtons').then((value: Array) => { + APIClient.get('/apps/actionButtons').then((value) => { registeredButtons.forEach((button) => removeButton(button)); registeredButtons = []; value.map(addButton); diff --git a/apps/meteor/app/ui-message/client/ActionManager.js b/apps/meteor/app/ui-message/client/ActionManager.js index 1d422855dd73..f172a412dacd 100644 --- a/apps/meteor/app/ui-message/client/ActionManager.js +++ b/apps/meteor/app/ui-message/client/ActionManager.js @@ -8,10 +8,9 @@ import { UIKitInteractionTypes } from '@rocket.chat/core-typings'; import Notifications from '../../notifications/client/lib/Notifications'; import { CachedCollectionManager } from '../../ui-cached-collection'; import { modal } from '../../ui-utils/client/lib/modal'; -import { APIClient } from '../../utils'; +import { APIClient, t } from '../../utils/client'; import * as banners from '../../../client/lib/banners'; import { dispatchToastMessage } from '../../../client/lib/toast'; -import { t } from '../../utils/client'; const events = new Emitter(); @@ -169,7 +168,7 @@ export const triggerAction = async ({ type, actionId, appId, rid, mid, viewId, c setTimeout(reject, TRIGGER_TIMEOUT, [TRIGGER_TIMEOUT_ERROR, { triggerId, appId }]); - const { type: interactionType, ...data } = await APIClient.post(`apps/ui.interaction/${appId}`, { + const { type: interactionType, ...data } = await APIClient.post(`/apps/ui.interaction/${appId}`, { type, actionId, payload, diff --git a/apps/meteor/app/ui/client/lib/chatMessages.js b/apps/meteor/app/ui/client/lib/chatMessages.js index 145ef57d03dc..4dc81166f21e 100644 --- a/apps/meteor/app/ui/client/lib/chatMessages.js +++ b/apps/meteor/app/ui/client/lib/chatMessages.js @@ -428,7 +428,7 @@ export class ChatMessages { if (commandOptions.clientOnly) { commandOptions.callback(command, param, msgObject); } else { - APIClient.v1.post('statistics.telemetry', { params: [{ eventName: 'slashCommandsStats', timestamp: Date.now(), command }] }); + APIClient.post('/v1/statistics.telemetry', { params: [{ eventName: 'slashCommandsStats', timestamp: Date.now(), command }] }); const triggerId = generateTriggerId(slashCommands.commands[command].appId); Meteor.call('slashCommand', { cmd: command, params: param, msg: msgObject, triggerId }, (err, result) => { typeof commandOptions.result === 'function' && diff --git a/apps/meteor/app/ui/client/lib/fileUpload.js b/apps/meteor/app/ui/client/lib/fileUpload.js deleted file mode 100644 index 179bf5e5fd44..000000000000 --- a/apps/meteor/app/ui/client/lib/fileUpload.js +++ /dev/null @@ -1,164 +0,0 @@ -import { Tracker } from 'meteor/tracker'; -import { Session } from 'meteor/session'; -import { Random } from 'meteor/random'; -import { Meteor } from 'meteor/meteor'; - -import { settings } from '../../../settings/client'; -import { UserAction, USER_ACTIVITIES } from '../index'; -import { fileUploadIsValidContentType, APIClient } from '../../../utils'; -import { imperativeModal } from '../../../../client/lib/imperativeModal'; -import FileUploadModal from '../../../../client/views/room/modals/FileUploadModal'; -import { prependReplies } from '../../../../client/lib/utils/prependReplies'; -import { chatMessages } from '../views/app/room'; - -export const uploadFileWithMessage = async (rid, tmid, { description, fileName, msg, file }) => { - const data = new FormData(); - description && data.append('description', description); - msg && data.append('msg', msg); - tmid && data.append('tmid', tmid); - data.append('file', file.file, fileName); - - const uploads = Session.get('uploading') || []; - - const upload = { - id: Random.id(), - name: fileName, - percentage: 0, - }; - - uploads.push(upload); - Session.set('uploading', uploads); - - const { xhr, promise } = APIClient.upload(`v1/rooms.upload/${rid}`, {}, data, { - progress(progress) { - const uploads = Session.get('uploading') || []; - - if (progress === 100) { - return; - } - uploads - .filter((u) => u.id === upload.id) - .forEach((u) => { - u.percentage = Math.round(progress) || 0; - }); - Session.set('uploading', uploads); - }, - error(error) { - const uploads = Session.get('uploading') || []; - uploads - .filter((u) => u.id === upload.id) - .forEach((u) => { - u.error = error.message; - u.percentage = 0; - }); - Session.set('uploading', uploads); - }, - }); - if (Session.get('uploading').length) { - UserAction.performContinuously(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); - } - - Tracker.autorun((computation) => { - const isCanceling = Session.get(`uploading-cancel-${upload.id}`); - if (!isCanceling) { - return; - } - computation.stop(); - Session.delete(`uploading-cancel-${upload.id}`); - - xhr.abort(); - - const uploads = Session.get('uploading') || {}; - Session.set( - 'uploading', - uploads.filter((u) => u.id !== upload.id), - ); - }); - - try { - await promise; - const uploads = Session.get('uploading') || []; - const remainingUploads = Session.set( - 'uploading', - uploads.filter((u) => u.id !== upload.id), - ); - - if (!Session.get('uploading').length) { - UserAction.stop(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); - } - return remainingUploads; - } catch (error) { - const uploads = Session.get('uploading') || []; - uploads - .filter((u) => u.id === upload.id) - .forEach((u) => { - u.error = (error.xhr && error.xhr.responseJSON && error.xhr.responseJSON.error) || error.message; - u.percentage = 0; - }); - if (!uploads.length) { - UserAction.stop(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); - } - Session.set('uploading', uploads); - } -}; - -export const fileUpload = async (files, input, { rid, tmid }) => { - const threadsEnabled = settings.get('Threads_enabled'); - - files = [].concat(files); - - const replies = $(input).data('reply') || []; - const mention = $(input).data('mention-user') || false; - - let msg = ''; - - if (!mention || !threadsEnabled) { - msg = await prependReplies('', replies, mention); - } - - if (mention && threadsEnabled && replies.length) { - tmid = replies[0]._id; - } - - const key = ['messagebox', rid, tmid].filter(Boolean).join('_'); - const messageBoxText = Meteor._localStorage.getItem(key) || ''; - - const uploadNextFile = () => { - const file = files.pop(); - if (!file) { - return; - } - - imperativeModal.open({ - component: FileUploadModal, - props: { - file: file.file, - fileName: file.name, - fileDescription: messageBoxText, - onClose: () => { - imperativeModal.close(); - uploadNextFile(); - }, - onSubmit: (fileName, description) => { - uploadFileWithMessage(rid, tmid, { - description, - fileName, - msg: msg || undefined, - file, - }); - const localStorageKey = ['messagebox', rid, tmid].filter(Boolean).join('_'); - const chatMessageKey = [rid, tmid].filter(Boolean).join('-'); - const { input } = chatMessages[chatMessageKey]; - input.value = null; - $(input).trigger('input'); - Meteor._localStorage.removeItem(localStorageKey); - imperativeModal.close(); - uploadNextFile(); - }, - invalidContentType: file.file.type && !fileUploadIsValidContentType(file.file.type), - }, - }); - }; - - uploadNextFile(); -}; diff --git a/apps/meteor/app/ui/client/lib/fileUpload.ts b/apps/meteor/app/ui/client/lib/fileUpload.ts new file mode 100644 index 000000000000..dc4d70cf3070 --- /dev/null +++ b/apps/meteor/app/ui/client/lib/fileUpload.ts @@ -0,0 +1,236 @@ +import { Tracker } from 'meteor/tracker'; +import { Session } from 'meteor/session'; +import { Random } from 'meteor/random'; +import { Meteor } from 'meteor/meteor'; + +import { settings } from '../../../settings/client'; +import { UserAction, USER_ACTIVITIES } from '../index'; +import { fileUploadIsValidContentType, APIClient } from '../../../utils/client'; +import { imperativeModal } from '../../../../client/lib/imperativeModal'; +import FileUploadModal from '../../../../client/views/room/modals/FileUploadModal'; +import { prependReplies } from '../../../../client/lib/utils/prependReplies'; +import { chatMessages } from '../views/app/room'; + +type Uploading = { + id: string; + name: string; + percentage: number; + error?: Error; +}; + +declare module 'meteor/session' { + // eslint-disable-next-line @typescript-eslint/interface-name-prefix + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Session { + function get(key: 'uploading'): Uploading[]; + function set(key: 'uploading', param: Uploading[]): void; + } +} + +Session.setDefault('uploading', []); + +export const uploadFileWithMessage = async ( + rid: string, + { + description, + msg, + file, + }: { + file: File; + description?: string; + msg?: string; + }, + tmid?: string, +): Promise => { + const uploads = Session.get('uploading'); + + const upload = { + id: Random.id(), + name: file.name, + percentage: 0, + }; + + uploads.push(upload); + Session.set('uploading', uploads); + + try { + await new Promise((resolve, reject) => { + const xhr = APIClient.upload( + `/v1/rooms.upload/${rid}`, + { + msg, + tmid, + file, + description, + }, + { + load: (event) => { + return resolve(event); + }, + progress: (event) => { + if (!event.lengthComputable) { + return; + } + const progress = (event.loaded / event.total) * 100; + if (progress === 100) { + return; + } + + const uploads = Session.get('uploading'); + + uploads + .filter((u) => u.id === upload.id) + .forEach((u) => { + u.percentage = Math.round(progress) || 0; + }); + Session.set('uploading', uploads); + }, + error: (error) => { + const uploads = Session.get('uploading'); + uploads + .filter((u) => u.id === upload.id) + .forEach((u) => { + u.error = new Error(xhr.responseText); + u.percentage = 0; + }); + Session.set('uploading', uploads); + reject(error); + }, + }, + ); + + if (Session.get('uploading').length) { + UserAction.performContinuously(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); + } + + Tracker.autorun((computation) => { + const isCanceling = Session.get(`uploading-cancel-${upload.id}`); + if (!isCanceling) { + return; + } + computation.stop(); + Session.delete(`uploading-cancel-${upload.id}`); + + xhr.abort(); + + const uploads = Session.get('uploading'); + Session.set( + 'uploading', + uploads.filter((u) => u.id !== upload.id), + ); + }); + }); + + const uploads = Session.get('uploading'); + Session.set( + 'uploading', + uploads.filter((u) => u.id !== upload.id), + ); + + if (!Session.get('uploading').length) { + UserAction.stop(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); + } + } catch (error) { + const uploads = Session.get('uploading'); + uploads + .filter((u) => u.id === upload.id) + .forEach((u) => { + u.error = (error.xhr && error.xhr.responseJSON && error.xhr.responseJSON.error) || error.message; + u.percentage = 0; + }); + if (!uploads.length) { + UserAction.stop(rid, USER_ACTIVITIES.USER_UPLOADING, { tmid }); + } + Session.set('uploading', uploads); + } +}; + +type SingleOrArray = T | T[]; + +type FileUploadProp = SingleOrArray<{ + file: File; + name: string; +}>; + +/* @deprecated */ +export const fileUpload = async ( + f: FileUploadProp, + input: HTMLInputElement, + { + rid, + tmid, + }: { + rid: string; + tmid?: string; + }, +): Promise => { + if (!f) { + throw new Error('No files to upload'); + } + + const threadsEnabled = settings.get('Threads_enabled'); + + const files = Array.isArray(f) ? f : [f]; + + const replies = $(input).data('reply') || []; + const mention = $(input).data('mention-user') || false; + + let msg = ''; + + if (!mention || !threadsEnabled) { + msg = await prependReplies('', replies, mention); + } + + if (mention && threadsEnabled && replies.length) { + tmid = replies[0]._id; + } + + const key = ['messagebox', rid, tmid].filter(Boolean).join('_'); + const messageBoxText = Meteor._localStorage.getItem(key) || ''; + + const uploadNextFile = (): void => { + const file = files.pop(); + if (!file) { + return; + } + + imperativeModal.open({ + component: FileUploadModal, + props: { + file: file.file, + fileName: file.name, + fileDescription: messageBoxText, + onClose: (): void => { + imperativeModal.close(); + uploadNextFile(); + }, + onSubmit: (fileName: string, description?: string): void => { + Object.defineProperty(file.file, 'name', { + writable: true, + value: fileName, + }); + uploadFileWithMessage( + rid, + { + description, + msg, + file: file.file, + }, + tmid, + ); + const localStorageKey = ['messagebox', rid, tmid].filter(Boolean).join('_'); + const chatMessageKey = [rid, tmid].filter(Boolean).join('-'); + const { input } = chatMessages[chatMessageKey]; + input.value = null; + $(input).trigger('input'); + Meteor._localStorage.removeItem(localStorageKey); + imperativeModal.close(); + uploadNextFile(); + }, + invalidContentType: Boolean(file.file.type && !fileUploadIsValidContentType(file.file.type)), + }, + }); + }; + + uploadNextFile(); +}; diff --git a/apps/meteor/app/utils/client/lib/RestApiClient.ts b/apps/meteor/app/utils/client/lib/RestApiClient.ts new file mode 100644 index 000000000000..0621fe9850da --- /dev/null +++ b/apps/meteor/app/utils/client/lib/RestApiClient.ts @@ -0,0 +1,52 @@ +import { RestClient } from '@rocket.chat/api-client'; +import { Meteor } from 'meteor/meteor'; +import { Accounts } from 'meteor/accounts-base'; + +import { baseURI } from '../../../../client/lib/baseURI'; +import { process2faReturn } from '../../../../client/lib/2fa/process2faReturn'; + +export class RestApiClient extends RestClient { + getCredentials(): + | { + 'X-User-Id': string; + 'X-Auth-Token': string; + } + | undefined { + const [uid, token] = [Meteor._localStorage.getItem(Accounts.USER_ID_KEY), Meteor._localStorage.getItem(Accounts.LOGIN_TOKEN_KEY)]; + + if (!uid || !token) { + return; + } + return { + 'X-User-Id': uid, + 'X-Auth-Token': token, + }; + } +} + +export const APIClient = new RestApiClient({ + baseUrl: baseURI.replace(/\/$/, ''), +}); + +APIClient.use(function (request, next) { + try { + return next(...request); + } catch (e) { + return new Promise((resolve, reject) => { + process2faReturn({ + error: e, + result: null, + emailOrUsername: undefined, + originalCallback: () => reject(e), + onCode(code, method) { + return resolve( + next(request[0], request[1], { + ...request[2], + headers: { ...request[2].headers, 'x-2fa-code': code, 'x-2fa-method': method }, + }), + ); + }, + }); + }); + } +}); diff --git a/apps/meteor/app/utils/client/lib/RestApiClient.d.ts b/apps/meteor/app/utils/client/lib/_RestApiClient.d.ts similarity index 74% rename from apps/meteor/app/utils/client/lib/RestApiClient.d.ts rename to apps/meteor/app/utils/client/lib/_RestApiClient.d.ts index c5789be139ce..ede0c5034e5f 100644 --- a/apps/meteor/app/utils/client/lib/RestApiClient.d.ts +++ b/apps/meteor/app/utils/client/lib/_RestApiClient.d.ts @@ -1,4 +1,5 @@ import { Serialized } from '@rocket.chat/core-typings'; +import { RestClientInterface } from '@rocket.chat/api-client'; export declare const APIClient: { delete(endpoint: string, params?: Serialized

): Promise>; @@ -18,11 +19,8 @@ export declare const APIClient: { 'X-Auth-Token': string; }; _jqueryCall(method?: string, endpoint?: string, params?: any, body?: any, headers?: Record, dataType?: string): any; + /* @deprecated */ v1: { - delete(endpoint: string, params?: Serialized

): Promise>; - get(endpoint: string, params?: Serialized

): Promise>; - post(endpoint: string, params?: Serialized

, body?: B): Promise>; - put(endpoint: string, params?: Serialized

, body?: B): Promise>; upload( endpoint: string, params?: Serialized

, @@ -32,5 +30,5 @@ export declare const APIClient: { error: (ev: ProgressEvent) => void; }, ): { promise: Promise> }; - }; + } & RestClientInterface; }; diff --git a/apps/meteor/app/utils/client/lib/RestApiClient.js b/apps/meteor/app/utils/client/lib/_RestApiClient.js similarity index 100% rename from apps/meteor/app/utils/client/lib/RestApiClient.js rename to apps/meteor/app/utils/client/lib/_RestApiClient.js diff --git a/apps/meteor/app/utils/lib/fileUploadRestrictions.js b/apps/meteor/app/utils/lib/fileUploadRestrictions.js index 8fad52cbb372..403f5503cf7a 100644 --- a/apps/meteor/app/utils/lib/fileUploadRestrictions.js +++ b/apps/meteor/app/utils/lib/fileUploadRestrictions.js @@ -8,7 +8,7 @@ if (Meteor.isClient) { settings = require('../../settings/server').settings; } -const fileUploadMediaWhiteList = function (customWhiteList) { +export const fileUploadMediaWhiteList = function (customWhiteList) { const mediaTypeWhiteList = customWhiteList || settings.get('FileUpload_MediaTypeWhiteList'); if (!mediaTypeWhiteList || mediaTypeWhiteList === '*') { diff --git a/apps/meteor/app/utils/lib/slashCommand.ts b/apps/meteor/app/utils/lib/slashCommand.ts index 9c1ed3b2741d..813272a460ef 100644 --- a/apps/meteor/app/utils/lib/slashCommand.ts +++ b/apps/meteor/app/utils/lib/slashCommand.ts @@ -27,7 +27,7 @@ export const slashCommands = { permission: options.permission, clientOnly: options.clientOnly || false, result, - providesPreview, + providesPreview: Boolean(providesPreview), previewer, previewCallback, } as SlashCommand; diff --git a/apps/meteor/app/videobridge/client/actionLink.js b/apps/meteor/app/videobridge/client/actionLink.js index e99981c072eb..e09db09aeb61 100644 --- a/apps/meteor/app/videobridge/client/actionLink.js +++ b/apps/meteor/app/videobridge/client/actionLink.js @@ -29,7 +29,7 @@ actionLinks.register('joinJitsiCall', function (message, params, instance) { const clickTime = new Date(); const jitsiTimeout = new Date(room.jitsiTimeout); - APIClient.v1.post('statistics.telemetry', { + APIClient.post('/v1/statistics.telemetry', { params: [{ eventName: 'updateCounter', timestamp: Date.now(), settingsId: 'Jitsi_Click_To_Join_Count' }], }); diff --git a/apps/meteor/app/webdav/client/startup/sync.js b/apps/meteor/app/webdav/client/startup/sync.js index c3547ee4bfe4..8f96b8234838 100644 --- a/apps/meteor/app/webdav/client/startup/sync.js +++ b/apps/meteor/app/webdav/client/startup/sync.js @@ -14,7 +14,7 @@ Tracker.autorun(async () => { if (!Meteor.userId()) { return; } - const { accounts } = await APIClient.v1.get('webdav.getMyAccounts'); + const { accounts } = await APIClient.get('/v1/webdav.getMyAccounts'); accounts.forEach((account) => WebdavAccounts.insert(account)); Notifications.onUser('webdav', ({ type, account }) => events[type](account)); }); diff --git a/apps/meteor/app/webrtc/client/actionLink.tsx b/apps/meteor/app/webrtc/client/actionLink.tsx index 1265d52b14b5..b787d9601b52 100644 --- a/apps/meteor/app/webrtc/client/actionLink.tsx +++ b/apps/meteor/app/webrtc/client/actionLink.tsx @@ -22,6 +22,6 @@ actionLinks.register('endLivechatWebRTCCall', async (message: IMessage) => { dispatchToastMessage({ type: 'info', message: TAPi18n.__('Call_Already_Ended') }); return; } - await APIClient.v1.put(`livechat/webrtc.call/${message._id}`, {}, { rid: _id, status: 'ended' }); + await APIClient.put(`/v1/livechat/webrtc.call/${message._id}`, { rid: _id, status: 'ended' }); Notifications.notifyRoom(_id, 'webrtc', 'callStatus', { callStatus: 'ended' }); }); diff --git a/apps/meteor/app/webrtc/client/tabBar.tsx b/apps/meteor/app/webrtc/client/tabBar.tsx index 13f5ff1e0329..a69df1935809 100644 --- a/apps/meteor/app/webrtc/client/tabBar.tsx +++ b/apps/meteor/app/webrtc/client/tabBar.tsx @@ -9,7 +9,7 @@ addAction('webRTCVideo', ({ room }) => { const handleClick = useCallback(async (): Promise => { if (!room.callStatus || room.callStatus === 'declined' || room.callStatus === 'ended') { - await APIClient.v1.get('livechat/webrtc.call', { rid: room._id }); + await APIClient.get('/v1/livechat/webrtc.call', { rid: room._id }); } window.open(`/meet/${room._id}`, room._id); }, [room._id, room.callStatus]); diff --git a/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx b/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx index 685b9f29fbf4..585c86cc8cb0 100644 --- a/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx +++ b/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx @@ -43,7 +43,7 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug const canCreate = (parentRoom || defaultParentRoom) && name; - const createDiscussion = useEndpointActionExperimental('POST', 'rooms.createDiscussion'); + const createDiscussion = useEndpointActionExperimental('POST', '/v1/rooms.createDiscussion'); const create = useMutableCallback(async (): Promise => { try { diff --git a/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx b/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx index bdbb32108457..3fda044a7914 100644 --- a/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx +++ b/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx @@ -9,7 +9,7 @@ import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; const DefaultParentRoomField = ({ defaultParentRoom }: { defaultParentRoom: string }): ReactElement => { const t = useTranslation(); const { value, phase } = useEndpointData( - 'rooms.info', + '/v1/rooms.info', useMemo( () => ({ roomId: defaultParentRoom, diff --git a/apps/meteor/client/components/Omnichannel/Tags.tsx b/apps/meteor/client/components/Omnichannel/Tags.tsx index f0d13fec4df0..ad2d515f4373 100644 --- a/apps/meteor/client/components/Omnichannel/Tags.tsx +++ b/apps/meteor/client/components/Omnichannel/Tags.tsx @@ -23,7 +23,7 @@ const Tags = ({ const t = useTranslation(); const forms = useSubscription(formsSubscription); - const { value: tagsResult, phase: stateTags } = useEndpointData('livechat/tags.list'); + const { value: tagsResult, phase: stateTags } = useEndpointData('/v1/livechat/tags.list'); // 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/components/Omnichannel/hooks/useAgentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts index c5436312abc8..732cfa615740 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts @@ -22,9 +22,8 @@ export const useAgentsList = ( const t = useTranslation(); const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = 'livechat/users/agent'; - const getAgents = useEndpoint('GET', endpoint); + const getAgents = useEndpoint('GET', '/v1/livechat/users/agent'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts index d0c2db186100..f0ee99e153cc 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts @@ -21,9 +21,8 @@ export const useAvailableAgentsList = ( } => { const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = 'omnichannel/agents/available'; - const getAgents = useEndpoint('GET', endpoint); + const getAgents = useEndpoint('GET', '/v1/omnichannel/agents/available'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts index 1d87a9f6e6da..0c9752891ab8 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts @@ -28,7 +28,7 @@ export const useDepartmentsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const getDepartments = useEndpoint('GET', 'livechat/department'); + const getDepartments = useEndpoint('GET', '/v1/livechat/department'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx b/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx index 978931731889..ae1314a006fe 100644 --- a/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx @@ -15,7 +15,7 @@ const CloseChatModalData = ({ onCancel: () => void; onConfirm: (comment?: string, tags?: string[]) => Promise; }): ReactElement => { - const { value: data, phase: state } = useEndpointData(`livechat/department/${departmentId}`); + const { value: data, phase: state } = useEndpointData(`/v1/livechat/department/${departmentId}`); if ([state].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx index e28465d697e2..6fdd7ad9b5ed 100644 --- a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx @@ -22,7 +22,7 @@ const ForwardChatModal = ({ room: IOmnichannelRoom; }): ReactElement => { const t = useTranslation(); - const getUserData = useEndpoint('GET', 'users.info'); + const getUserData = useEndpoint('GET', '/v1/users.info'); const { getValues, handleSubmit, register, setFocus, setValue, watch } = useForm(); diff --git a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx index 4cf8077e9853..9b5b43af8ced 100644 --- a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx +++ b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx @@ -20,7 +20,7 @@ type RoomAutoCompleteProps = Omit, 'value const RoomAutoComplete = (props: RoomAutoCompleteProps): ReactElement => { const [filter, setFilter] = useState(''); const { value: data } = useEndpointData( - 'rooms.autocomplete.channelAndPrivate', + '/v1/rooms.autocomplete.channelAndPrivate', useMemo(() => query(filter), [filter]), ); const options = useMemo( diff --git a/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts b/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts index 8b5cc7fbd320..6be189937373 100644 --- a/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts +++ b/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts @@ -20,9 +20,8 @@ export const useRoomsList = ( } => { const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = 'rooms.autocomplete.channelAndPrivate.withPagination'; - const getRooms = useEndpoint('GET', endpoint); + const getRooms = useEndpoint('GET', '/v1/rooms.autocomplete.channelAndPrivate.withPagination'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts b/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts index 0567502ff315..b6c572c31a48 100644 --- a/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts +++ b/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts @@ -14,10 +14,11 @@ const OmnichannelRoomIcon = new (class extends Emitter { if (!appId || !icon) { return; } + if (this.icons.has(`${appId}-${icon}`)) { return `${appId}-${icon}`; } - APIClient.get(`apps/public/${appId}/get-sidebar-icon`, { icon }).then((response) => { + APIClient.get(`/apps/public/${appId}/get-sidebar-icon`, { icon }).then((response: any) => { this.icons.set( `${appId}-${icon}`, DOMPurify.sanitize(response, { diff --git a/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx b/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx index fa61a2a3dd12..0e4569694fe1 100644 --- a/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx +++ b/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx @@ -18,7 +18,7 @@ const TwoFactorEmailModal = ({ onConfirm, onClose, emailOrUsername }: TwoFactorE const [code, setCode] = useState(''); const ref = useAutoFocus(); - const sendEmailCode = useEndpoint('POST', 'users.2fa.sendEmailCode'); + const sendEmailCode = useEndpoint('POST', '/v1/users.2fa.sendEmailCode'); const onClickResendCode = async (): Promise => { try { diff --git a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx b/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx index 376b055a7830..b8e23f6e44d3 100644 --- a/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx +++ b/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx @@ -25,7 +25,7 @@ const UserAutoComplete = ({ value, ...props }: UserAutoCompleteProps): ReactElem const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, 1000); const { value: data } = useEndpointData( - 'users.autocomplete', + '/v1/users.autocomplete', // eslint-disable-next-line react-hooks/exhaustive-deps useMemo(() => query(debouncedFilter, conditions), [filter]), ); diff --git a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx index 5e3d7e03bbb7..b27c6d6034f9 100644 --- a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx +++ b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx @@ -22,7 +22,7 @@ const UserAutoCompleteMultiple = ({ onChange, ...props }: UserAutoCompleteMultip const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, 1000); const { value: data } = useEndpointData( - 'users.autocomplete', + '/v1/users.autocomplete', useMemo(() => query(debouncedFilter), [debouncedFilter]), ); diff --git a/apps/meteor/client/components/message/Metrics/Thread.tsx b/apps/meteor/client/components/message/Metrics/Thread.tsx index 1f33834f1f2a..702c508a59f0 100644 --- a/apps/meteor/client/components/message/Metrics/Thread.tsx +++ b/apps/meteor/client/components/message/Metrics/Thread.tsx @@ -22,8 +22,8 @@ type ThreadReplyOptions = { const ThreadMetric: FC = ({ unread, mention, all, rid, mid, counter, participants, following, lm, openThread }) => { const t = useTranslation(); - const followMessage = useEndpoint('POST', 'chat.followMessage'); - const unfollowMessage = useEndpoint('POST', 'chat.unfollowMessage'); + const followMessage = useEndpoint('POST', '/v1/chat.followMessage'); + const unfollowMessage = useEndpoint('POST', '/v1/chat.unfollowMessage'); const format = useTimeAgo(); const handleFollow = useCallback( diff --git a/apps/meteor/client/hooks/useEndpointUpload.ts b/apps/meteor/client/hooks/useEndpointUpload.ts index 8a699171aa92..c25e95000fcc 100644 --- a/apps/meteor/client/hooks/useEndpointUpload.ts +++ b/apps/meteor/client/hooks/useEndpointUpload.ts @@ -2,8 +2,7 @@ import { useToastMessageDispatch, UploadResult, useUpload } from '@rocket.chat/u import { useCallback } from 'react'; export const useEndpointUpload = ( - endpoint: string, - params = {}, + endpoint: Parameters[0], successMessage: string, ): ((formData: FormData) => Promise<{ success: boolean }>) => { const sendData = useUpload(endpoint); @@ -12,7 +11,7 @@ export const useEndpointUpload = ( return useCallback( async (formData: FormData) => { try { - const data = sendData(params, formData); + const data = sendData(formData); const promise = data instanceof Promise ? data : data.promise; @@ -30,6 +29,6 @@ export const useEndpointUpload = ( return { success: false }; } }, - [dispatchToastMessage, params, sendData, successMessage], + [dispatchToastMessage, sendData, successMessage], ); }; diff --git a/apps/meteor/client/hooks/useUpdateAvatar.ts b/apps/meteor/client/hooks/useUpdateAvatar.ts index ae9eb2336d3e..fdcac425c928 100644 --- a/apps/meteor/client/hooks/useUpdateAvatar.ts +++ b/apps/meteor/client/hooks/useUpdateAvatar.ts @@ -48,9 +48,9 @@ export const useUpdateAvatar = (avatarObj: AvatarObject, userId: IUser['_id']): [userId], ); - const saveAvatarAction = useEndpointUpload('users.setAvatar', saveAvatarQuery, successText); - const saveAvatarUrlAction = useEndpointAction('POST', 'users.setAvatar', saveAvatarQuery, successText); - const resetAvatarAction = useEndpointAction('POST', 'users.resetAvatar', resetAvatarQuery, successText); + const saveAvatarAction = useEndpointUpload('/v1/users.setAvatar', successText); + const saveAvatarUrlAction = useEndpointAction('POST', '/v1/users.setAvatar', saveAvatarQuery, successText); + const resetAvatarAction = useEndpointAction('POST', '/v1/users.resetAvatar', resetAvatarQuery, successText); const updateAvatar = useCallback(async () => { if (isAvatarReset(avatarObj)) { diff --git a/apps/meteor/client/lib/meteorCallWrapper.ts b/apps/meteor/client/lib/meteorCallWrapper.ts index 72e83529184e..2615b6c4385d 100644 --- a/apps/meteor/client/lib/meteorCallWrapper.ts +++ b/apps/meteor/client/lib/meteorCallWrapper.ts @@ -50,8 +50,10 @@ function wrapMeteorDDPCalls(): void { Meteor.connection.onMessage(_message); }; - APIClient.v1 - .post(`${endpoint}/${encodeURIComponent(message.method.replace(/\//g, ':'))}`, restParams) + APIClient.post( + `/v1/${endpoint}/${encodeURIComponent(message.method.replace(/\//g, ':'))}` as Parameters[0], + restParams as any, + ) .then(({ message: _message }) => { processResult(_message); if (message.method === 'login') { diff --git a/apps/meteor/client/lib/presence.ts b/apps/meteor/client/lib/presence.ts index c5d927a101e0..5c81820e7e4e 100644 --- a/apps/meteor/client/lib/presence.ts +++ b/apps/meteor/client/lib/presence.ts @@ -51,6 +51,15 @@ const notify = (presence: UserPresence): void => { } }; +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/interface-name-prefix + export interface Endpoints { + '/v1/users.presence': { + GET: (params: { ids: string[] }) => UsersPresencePayload; + }; + } +} + const getPresence = ((): ((uid: UserPresence['_id']) => void) => { let timer: ReturnType; @@ -81,7 +90,7 @@ const getPresence = ((): ((uid: UserPresence['_id']) => void) => { ids: [...currentUids], }; - const { users } = (await APIClient.v1.get('users.presence', params)) as UsersPresencePayload; + const { users } = await APIClient.get('/v1/users.presence', params); users.forEach((user) => { if (!store.has(user._id)) { diff --git a/apps/meteor/client/lib/userData.ts b/apps/meteor/client/lib/userData.ts index a1a5bad7b5ad..112028faa0cc 100644 --- a/apps/meteor/client/lib/userData.ts +++ b/apps/meteor/client/lib/userData.ts @@ -81,7 +81,7 @@ export const synchronizeUserData = async (uid: Meteor.User['_id']): Promise { const voipEnabled = useSetting('VoIP_Enabled'); const subscribeToNotifyUser = useStream('notify-user'); - const dispatchEvent = useEndpoint('POST', 'voip/events'); + const dispatchEvent = useEndpoint('POST', '/v1/voip/events'); const result = useVoipClient(); const user = useUser(); @@ -234,9 +234,9 @@ export const CallProvider: FC = ({ children }) => { }; }, [onNetworkConnected, onNetworkDisconnected, result.voipClient]); - const visitorEndpoint = useEndpoint('POST', 'livechat/visitor'); - const voipEndpoint = useEndpoint('GET', 'voip/room'); - const voipCloseRoomEndpoint = useEndpoint('POST', 'voip/room.close'); + const visitorEndpoint = useEndpoint('POST', '/v1/livechat/visitor'); + const voipEndpoint = useEndpoint('GET', '/v1/voip/room'); + const voipCloseRoomEndpoint = useEndpoint('POST', '/v1/voip/room.close'); const [roomInfo, setRoomInfo] = useState<{ v: { token?: string }; rid: string }>(); diff --git a/apps/meteor/client/providers/CallProvider/hooks/useVoipClient.ts b/apps/meteor/client/providers/CallProvider/hooks/useVoipClient.ts index bc154ac17cac..bcf7e2558f4b 100644 --- a/apps/meteor/client/providers/CallProvider/hooks/useVoipClient.ts +++ b/apps/meteor/client/providers/CallProvider/hooks/useVoipClient.ts @@ -22,8 +22,8 @@ export const useVoipClient = (): UseVoipClientResult => { const [voipEnabled, setVoipEnabled] = useSafely(useState(useSetting('VoIP_Enabled'))); const voipRetryCount = useSetting('VoIP_Retry_Count'); const enableKeepAlive = useSetting('VoIP_Enable_Keep_Alive_For_Unstable_Networks'); - const registrationInfo = useEndpoint('GET', 'connector.extension.getRegistrationInfoByUserId'); - const membership = useEndpoint('GET', 'voip/queues.getMembershipSubscription'); + const registrationInfo = useEndpoint('GET', '/v1/connector.extension.getRegistrationInfoByUserId'); + const membership = useEndpoint('GET', '/v1/voip/queues.getMembershipSubscription'); const user = useUser(); const subscribeToNotifyLoggedIn = useStream('notify-logged'); const iceServers = useWebRtcServers(); diff --git a/apps/meteor/client/providers/ServerProvider.tsx b/apps/meteor/client/providers/ServerProvider.tsx index 1c5ec443195d..18e6ac307680 100644 --- a/apps/meteor/client/providers/ServerProvider.tsx +++ b/apps/meteor/client/providers/ServerProvider.tsx @@ -28,31 +28,22 @@ const callEndpoint = >( path: TPath, params: Serialized>>, ): Promise>>> => { - const api = path[0] === '/' ? APIClient : APIClient.v1; - const endpointPath = path[0] === '/' ? path.slice(1) : path; - switch (method) { case 'GET': - return api.get(endpointPath, params); + return APIClient.get(path as Parameters[0], params) as any; case 'POST': - return api.post(endpointPath, {}, params); + return APIClient.post(path as Parameters[0], params) as ReturnType; case 'DELETE': - return api.delete(endpointPath, params); + return APIClient.delete(path as Parameters[0], params) as ReturnType; default: throw new Error('Invalid HTTP method'); } }; -const uploadToEndpoint = (endpoint: string, params: any, formData: any): Promise => { - if (endpoint[0] === '/') { - return APIClient.upload(endpoint.slice(1), params, formData).promise; - } - - return APIClient.v1.upload(endpoint, params, formData).promise; -}; +const uploadToEndpoint = (endpoint: PathFor<'POST'>, formData: any): Promise => APIClient.post(endpoint, formData); const getStream = (streamName: string, options: {} = {}): ((eventName: string, callback: (data: T) => void) => () => void) => { const streamer = Meteor.StreamerCentral.instances[streamName] diff --git a/apps/meteor/client/sidebar/footer/voip/index.tsx b/apps/meteor/client/sidebar/footer/voip/index.tsx index ec6f83ff6d0e..bf137fa946a1 100644 --- a/apps/meteor/client/sidebar/footer/voip/index.tsx +++ b/apps/meteor/client/sidebar/footer/voip/index.tsx @@ -16,7 +16,7 @@ export const VoipFooter = (): ReactElement | null => { const t = useTranslation(); const callerInfo = useCallerInfo(); const callActions = useCallActions(); - const dispatchEvent = useEndpoint('POST', 'voip/events'); + const dispatchEvent = useEndpoint('POST', '/v1/voip/events'); const createRoom = useCallCreateRoom(); const openRoom = useCallOpenRoom(); diff --git a/apps/meteor/client/sidebar/header/CreateChannelWithData.tsx b/apps/meteor/client/sidebar/header/CreateChannelWithData.tsx index 8af0453b5ed6..467f6c23be36 100644 --- a/apps/meteor/client/sidebar/header/CreateChannelWithData.tsx +++ b/apps/meteor/client/sidebar/header/CreateChannelWithData.tsx @@ -25,8 +25,8 @@ type UseFormValues = { }; const CreateChannelWithData = ({ onClose, teamId = '', reload }: CreateChannelWithDataProps): ReactElement => { - const createChannel = useEndpointActionExperimental('POST', 'channels.create'); - const createPrivateChannel = useEndpointActionExperimental('POST', 'groups.create'); + const createChannel = useEndpointActionExperimental('POST', '/v1/channels.create'); + const createPrivateChannel = useEndpointActionExperimental('POST', '/v1/groups.create'); const canCreateChannel = usePermission('create-c'); const canCreatePrivateChannel = usePermission('create-p'); const e2eEnabledForPrivateByDefault = useSetting('E2E_Enabled_Default_PrivateRooms'); diff --git a/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx b/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx index 01375f00eda3..719f38eb54db 100644 --- a/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx +++ b/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx @@ -18,7 +18,7 @@ const CreateDirectMessage: FC = ({ onClose }) => { const t = useTranslation(); const [users, setUsers] = useState>([]); - const createDirect = useEndpointActionExperimental('POST', 'dm.create'); + const createDirect = useEndpointActionExperimental('POST', '/v1/dm.create'); const onChangeUsers = useMutableCallback((value: Username | any, action: 'remove' | undefined) => { if (!action) { diff --git a/apps/meteor/client/startup/banners.ts b/apps/meteor/client/startup/banners.ts index 93fbedc7fe49..19ffaf103951 100644 --- a/apps/meteor/client/startup/banners.ts +++ b/apps/meteor/client/startup/banners.ts @@ -1,4 +1,4 @@ -import { IBanner, BannerPlatform, Serialized } from '@rocket.chat/core-typings'; +import { BannerPlatform } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; @@ -7,9 +7,7 @@ import { APIClient } from '../../app/utils/client'; import * as banners from '../lib/banners'; const fetchInitialBanners = async (): Promise => { - const response: Serialized<{ - banners: IBanner[]; - }> = await APIClient.get('v1/banners', { + const response = await APIClient.get('/v1/banners', { platform: BannerPlatform.Web, }); @@ -22,9 +20,7 @@ const fetchInitialBanners = async (): Promise => { }; const handleBanner = async (event: { bannerId: string }): Promise => { - const response: Serialized<{ - banners: IBanner[]; - }> = await APIClient.get(`v1/banners/${event.bannerId}`, { + const response = await APIClient.get(`/v1/banners/${event.bannerId}`, { platform: BannerPlatform.Web, }); diff --git a/apps/meteor/client/startup/routes.tsx b/apps/meteor/client/startup/routes.tsx index b86b36053d3c..8aa9a42172fe 100644 --- a/apps/meteor/client/startup/routes.tsx +++ b/apps/meteor/client/startup/routes.tsx @@ -74,8 +74,8 @@ FlowRouter.route('/meet/:rid', { async action(_params, queryParams) { if (queryParams?.token !== undefined) { // visitor login - const visitor = await APIClient.v1.get(`livechat/visitor/${queryParams?.token}`); - if (visitor?.visitor) { + const result = await APIClient.get(`/v1/livechat/visitor/${queryParams.token}`); + if ('visitor' in result) { appLayout.render(); return; } diff --git a/apps/meteor/client/startup/slashCommands.ts b/apps/meteor/client/startup/slashCommands.ts index 40c291174568..97dc8c46aa79 100644 --- a/apps/meteor/client/startup/slashCommands.ts +++ b/apps/meteor/client/startup/slashCommands.ts @@ -6,12 +6,12 @@ import { slashCommands, APIClient } from '../../app/utils/client'; let oldUserId: IUser['_id'] | null = null; -Tracker.autorun(() => { +Tracker.autorun(async () => { const newUserId = Meteor.userId(); if (oldUserId === null && newUserId) { - APIClient.v1.get('commands.list').then((result) => { - result.commands.forEach((command: typeof slashCommands.commands[string]) => { - slashCommands.commands[command.command] = command; + APIClient.get('/v1/commands.list').then((result) => { + result.commands.forEach((command) => { + slashCommands.add(command.command); }); }); } diff --git a/apps/meteor/client/stories/contexts/ServerContextMock.tsx b/apps/meteor/client/stories/contexts/ServerContextMock.tsx index 0a01e883ace2..bba776e442df 100644 --- a/apps/meteor/client/stories/contexts/ServerContextMock.tsx +++ b/apps/meteor/client/stories/contexts/ServerContextMock.tsx @@ -9,8 +9,8 @@ const logAction = action('ServerContext'); const randomDelay = (): Promise => new Promise((resolve) => setTimeout(resolve, Math.random() * 1000)); -const uploadToEndpoint = (endpoint: string, params: any, formData: any): Promise => - Promise.resolve(logAction('uploadToEndpoint', endpoint, params, formData)).then(randomDelay); +const uploadToEndpoint = (endpoint: PathFor<'POST'>, formData: any): Promise => + Promise.resolve(logAction('uploadToEndpoint', endpoint, formData)).then(randomDelay); const getStream = (streamName: string, options: {} = {}): ((eventName: string, callback: (data: T) => void) => () => void) => { logAction('getStream', streamName, options); diff --git a/apps/meteor/client/views/account/AccountProfilePage.js b/apps/meteor/client/views/account/AccountProfilePage.js index 7238d21f5861..7694764d011b 100644 --- a/apps/meteor/client/views/account/AccountProfilePage.js +++ b/apps/meteor/client/views/account/AccountProfilePage.js @@ -47,7 +47,7 @@ const AccountProfilePage = () => { const logout = useLogout(); const [loggingOut, setLoggingOut] = useState(false); - const logoutOtherClients = useEndpoint('POST', 'users.logoutOtherClients'); + const logoutOtherClients = useEndpoint('POST', '/v1/users.logoutOtherClients'); const deleteOwnAccount = useMethod('deleteUserOwnAccount'); const saveFn = useMethod('saveUserProfile'); diff --git a/apps/meteor/client/views/account/tokens/AccountTokensPage.js b/apps/meteor/client/views/account/tokens/AccountTokensPage.js index ba7a939753d4..da4f878977ec 100644 --- a/apps/meteor/client/views/account/tokens/AccountTokensPage.js +++ b/apps/meteor/client/views/account/tokens/AccountTokensPage.js @@ -8,7 +8,7 @@ import AddToken from './AddToken'; const AccountTokensPage = () => { const t = useTranslation(); - const { value: data, reload } = useEndpointData('users.getPersonalAccessTokens'); + const { value: data, reload } = useEndpointData('/v1/users.getPersonalAccessTokens'); return ( diff --git a/apps/meteor/client/views/admin/cloud/PasteStep.tsx b/apps/meteor/client/views/admin/cloud/PasteStep.tsx index 254882680d32..c66923c8bbe8 100644 --- a/apps/meteor/client/views/admin/cloud/PasteStep.tsx +++ b/apps/meteor/client/views/admin/cloud/PasteStep.tsx @@ -18,7 +18,7 @@ const PasteStep: FC = ({ onBackButtonClick, onFinish }) => { setCloudKey(e.currentTarget.value); }; - const registerManually = useEndpoint('POST', 'cloud.manualRegister'); + const registerManually = useEndpoint('POST', '/v1/cloud.manualRegister'); const handleFinishButtonClick = async (): Promise => { setLoading(true); diff --git a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx index 6566c69c2243..2e8b629a8332 100644 --- a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx @@ -28,7 +28,7 @@ const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps): Rea [setEmojiFile], ); - const saveAction = useEndpointUpload('emoji-custom.create', {}, t('Custom_Emoji_Added_Successfully')); + const saveAction = useEndpointUpload('/v1/emoji-custom.create', t('Custom_Emoji_Added_Successfully')); const handleSave = useCallback(async () => { if (!name) { diff --git a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx index 2bccdf19ba1c..cb80bbf7d148 100644 --- a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx @@ -45,7 +45,7 @@ const CustomEmoji: FC = function CustomEmoji({ onClick, reload 500, ); - const { value: data, phase, reload: reloadEndPoint } = useEndpointData('emoji-custom.all', query); + const { value: data, phase, reload: reloadEndPoint } = useEndpointData('/v1/emoji-custom.all', query); useEffect(() => { reload.current = reloadEndPoint; diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx index 61472d809323..d67444b666d6 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx @@ -53,7 +53,7 @@ const EditCustomEmoji: FC = ({ close, onChange, data, ...p [previousName, name, aliases, previousAliases, emojiFile], ); - const saveAction = useEndpointUpload('emoji-custom.update', {}, t('Custom_Emoji_Updated_Successfully')); + const saveAction = useEndpointUpload('/v1/emoji-custom.update', t('Custom_Emoji_Updated_Successfully')); const handleSave = useCallback(async () => { if (!name) { @@ -82,7 +82,7 @@ const EditCustomEmoji: FC = ({ close, onChange, data, ...p const deleteAction = useEndpointAction( 'POST', - 'emoji-custom.delete', + '/v1/emoji-custom.delete', useMemo(() => ({ emojiId: _id }), [_id]), ); diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx index 8bff47185cb7..681ea859fc18 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx @@ -25,7 +25,7 @@ const EditCustomEmojiWithData: FC = ({ _id, onChan phase: state, error, reload, - } = useEndpointData('emoji-custom.list', query); + } = useEndpointData('/v1/emoji-custom.list', query); if (state === AsyncStatePhase.LOADING) { return ( diff --git a/apps/meteor/client/views/admin/customSounds/AdminSoundsRoute.tsx b/apps/meteor/client/views/admin/customSounds/AdminSoundsRoute.tsx index e489eb7b3eeb..66b2ea019358 100644 --- a/apps/meteor/client/views/admin/customSounds/AdminSoundsRoute.tsx +++ b/apps/meteor/client/views/admin/customSounds/AdminSoundsRoute.tsx @@ -48,7 +48,7 @@ function CustomSoundsRoute(): ReactElement { 500, ); - const { reload, ...result } = useEndpointData('custom-sounds.list', query); + const { reload, ...result } = useEndpointData('/v1/custom-sounds.list', query); const handleItemClick = useCallback( (_id) => (): void => { diff --git a/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx b/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx index 3fdb38b9b400..4fae6bcdcb7b 100644 --- a/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx @@ -14,7 +14,7 @@ type EditCustomSoundProps = { function EditCustomSound({ _id, onChange, ...props }: EditCustomSoundProps): ReactElement { const query = useMemo(() => ({ query: JSON.stringify({ _id }) }), [_id]); - const { value: data, phase: state, error, reload } = useEndpointData('custom-sounds.list', query); + const { value: data, phase: state, error, reload } = useEndpointData('/v1/custom-sounds.list', query); if (state === AsyncStatePhase.LOADING) { return ( diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx index ace27c478ec8..e3e6be9d3551 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx @@ -17,7 +17,7 @@ const CustomUserStatusFormWithData = ({ _id, onReload, onClose }: CustomUserStat const t = useTranslation(); const query = useMemo(() => ({ query: JSON.stringify({ _id }) }), [_id]); - const { value: data, phase: state, error, reload } = useEndpointData('custom-user-status.list', query); + const { value: data, phase: state, error, reload } = useEndpointData('/v1/custom-user-status.list', query); const handleReload = (): void => { onReload?.(); diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx index 4407b664695a..ef0169704b8f 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx @@ -41,7 +41,7 @@ const CustomUserStatus = ({ reload, onClick }: CustomUserStatusProps): ReactElem 500, ); - const { value, reload: reloadEndpoint, phase } = useEndpointData('custom-user-status.list', query); + const { value, reload: reloadEndpoint, phase } = useEndpointData('/v1/custom-user-status.list', query); useEffect(() => { reload.current = reloadEndpoint; diff --git a/apps/meteor/client/views/admin/emailInbox/EmailInboxEditWithData.tsx b/apps/meteor/client/views/admin/emailInbox/EmailInboxEditWithData.tsx index 3dd4484224ec..47f20f6a25ee 100644 --- a/apps/meteor/client/views/admin/emailInbox/EmailInboxEditWithData.tsx +++ b/apps/meteor/client/views/admin/emailInbox/EmailInboxEditWithData.tsx @@ -13,7 +13,7 @@ type EmailInboxEditWithDataProps = { const EmailInboxEditWithData = ({ id }: EmailInboxEditWithDataProps): ReactElement => { const t = useTranslation(); - const { value: data, error, phase: state } = useEndpointData(`email-inbox/${id}`); + const { value: data, error, phase: state } = useEndpointData(`/v1/email-inbox/${id}`); if ([state].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.js b/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.js index 2597997e3859..f06b60f977f2 100644 --- a/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.js +++ b/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.js @@ -123,9 +123,9 @@ function EmailInboxForm({ id, data }) { const close = useCallback(() => router.push({}), [router]); - const saveEmailInbox = useEndpoint('POST', 'email-inbox'); - const deleteAction = useEndpoint('DELETE', `email-inbox/${id}`); - const emailAlreadyExistsAction = useEndpoint('GET', `email-inbox.search?email=${email}`); + const saveEmailInbox = useEndpoint('POST', '/v1/email-inbox'); + const deleteAction = useEndpoint('DELETE', `/v1/email-inbox/${id}`); + const emailAlreadyExistsAction = useEndpoint('GET', '/v1/email-inbox.search'); useComponentDidUpdate(() => { setEmailError(!validateEmail(email) ? t('Validate_email_address') : null); @@ -202,7 +202,7 @@ function EmailInboxForm({ id, data }) { if (!email && !validateEmail(email)) { return; } - const { emailInbox } = await emailAlreadyExistsAction(); + const { emailInbox } = await emailAlreadyExistsAction({ email }); if (!emailInbox || (id && emailInbox._id === id)) { return; diff --git a/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx b/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx index 499249a054c8..52718ccdd521 100644 --- a/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx +++ b/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx @@ -59,7 +59,7 @@ const EmailInboxTable = (): ReactElement => { [router], ); - const { phase, value: { emailInboxes = [], count = 0 } = {} } = useEndpointData('email-inbox.list', query); + const { phase, value: { emailInboxes = [], count = 0 } = {} } = useEndpointData('/v1/email-inbox.list', query); return ( <> diff --git a/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx b/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx index d1d2937459c0..fd1d6b627548 100644 --- a/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx +++ b/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx @@ -10,7 +10,7 @@ const SendTestButton = ({ id }: SendTestButtonProps): ReactElement => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const sendTest = useEndpoint('POST', `email-inbox.send-test/${id}`); + const sendTest = useEndpoint('POST', `/v1/email-inbox.send-test/${id}`); const handleOnClick = (e: React.MouseEvent): void => { e.preventDefault(); diff --git a/apps/meteor/client/views/admin/import/ImportHistoryPage.js b/apps/meteor/client/views/admin/import/ImportHistoryPage.js index e68f2e01a3d6..d24ea6793e6e 100644 --- a/apps/meteor/client/views/admin/import/ImportHistoryPage.js +++ b/apps/meteor/client/views/admin/import/ImportHistoryPage.js @@ -15,10 +15,10 @@ function ImportHistoryPage() { const [currentOperation, setCurrentOperation] = useSafely(useState()); const [latestOperations, setLatestOperations] = useSafely(useState([])); - const getCurrentImportOperation = useEndpoint('GET', 'getCurrentImportOperation'); - const getLatestImportOperations = useEndpoint('GET', 'getLatestImportOperations'); - const downloadPendingFiles = useEndpoint('POST', 'downloadPendingFiles'); - const downloadPendingAvatars = useEndpoint('POST', 'downloadPendingAvatars'); + const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); + const getLatestImportOperations = useEndpoint('GET', '/v1/getLatestImportOperations'); + const downloadPendingFiles = useEndpoint('POST', '/v1/downloadPendingFiles'); + const downloadPendingAvatars = useEndpoint('POST', '/v1/downloadPendingAvatars'); const newImportRoute = useRoute('admin-import-new'); const importProgressRoute = useRoute('admin-import-progress'); diff --git a/apps/meteor/client/views/admin/import/ImportProgressPage.js b/apps/meteor/client/views/admin/import/ImportProgressPage.js index 555def448057..911f27bbb8cf 100644 --- a/apps/meteor/client/views/admin/import/ImportProgressPage.js +++ b/apps/meteor/client/views/admin/import/ImportProgressPage.js @@ -19,8 +19,8 @@ function ImportProgressPage() { const [completed, setCompleted] = useSafely(useState(0)); const [total, setTotal] = useSafely(useState(0)); - const getCurrentImportOperation = useEndpoint('GET', 'getCurrentImportOperation'); - const getImportProgress = useEndpoint('GET', 'getImportProgress'); + const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); + const getImportProgress = useEndpoint('GET', '/v1/getImportProgress'); const importHistoryRoute = useRoute('admin-import'); const prepareImportRoute = useRoute('admin-import-prepare'); diff --git a/apps/meteor/client/views/admin/import/NewImportPage.js b/apps/meteor/client/views/admin/import/NewImportPage.js index 8e41803da6ce..6655d1468f81 100644 --- a/apps/meteor/client/views/admin/import/NewImportPage.js +++ b/apps/meteor/client/views/admin/import/NewImportPage.js @@ -38,8 +38,8 @@ function NewImportPage() { const newImportRoute = useRoute('admin-import-new'); const prepareImportRoute = useRoute('admin-import-prepare'); - const uploadImportFile = useEndpoint('POST', 'uploadImportFile'); - const downloadPublicImportFile = useEndpoint('POST', 'downloadPublicImportFile'); + const uploadImportFile = useEndpoint('POST', '/v1/uploadImportFile'); + const downloadPublicImportFile = useEndpoint('POST', '/v1/downloadPublicImportFile'); useEffect(() => { if (importerKey && !importer) { diff --git a/apps/meteor/client/views/admin/import/PrepareImportPage.js b/apps/meteor/client/views/admin/import/PrepareImportPage.js index b41004936da1..2765b3aa0aa1 100644 --- a/apps/meteor/client/views/admin/import/PrepareImportPage.js +++ b/apps/meteor/client/views/admin/import/PrepareImportPage.js @@ -53,9 +53,9 @@ function PrepareImportPage() { const newImportRoute = useRoute('admin-import-new'); const importProgressRoute = useRoute('admin-import-progress'); - const getImportFileData = useEndpoint('GET', 'getImportFileData'); - const getCurrentImportOperation = useEndpoint('GET', 'getCurrentImportOperation'); - const startImport = useEndpoint('POST', 'startImport'); + const getImportFileData = useEndpoint('GET', '/v1/getImportFileData'); + const getCurrentImportOperation = useEndpoint('GET', '/v1/getCurrentImportOperation'); + const startImport = useEndpoint('POST', '/v1/startImport'); useEffect(() => { const streamer = new Meteor.Streamer('importers'); diff --git a/apps/meteor/client/views/admin/info/InformationRoute.tsx b/apps/meteor/client/views/admin/info/InformationRoute.tsx index 207ce117d568..0f3e68e5a35a 100644 --- a/apps/meteor/client/views/admin/info/InformationRoute.tsx +++ b/apps/meteor/client/views/admin/info/InformationRoute.tsx @@ -20,7 +20,7 @@ const InformationRoute = (): ReactElement => { const [statistics, setStatistics] = useState(); const [instances, setInstances] = useState([]); const [fetchStatistics, setFetchStatistics] = useState(() => (): void => undefined); - const getStatistics = useEndpoint('GET', 'statistics'); + const getStatistics = useEndpoint('GET', '/v1/statistics'); const getInstances = useMethod('instances/get'); useEffect(() => { diff --git a/apps/meteor/client/views/admin/info/LicenseCard.tsx b/apps/meteor/client/views/admin/info/LicenseCard.tsx index 7490331b478c..7f0a3b4105f3 100644 --- a/apps/meteor/client/views/admin/info/LicenseCard.tsx +++ b/apps/meteor/client/views/admin/info/LicenseCard.tsx @@ -19,7 +19,7 @@ const LicenseCard = (): ReactElement => { const isAirGapped = true; - const { value, phase, error } = useEndpointData('licenses.get'); + const { value, phase, error } = useEndpointData('/v1/licenses.get'); const endpointLoading = phase === AsyncStatePhase.LOADING; const { modules = [] } = endpointLoading || error || !value?.licenses.length ? {} : value.licenses[0]; diff --git a/apps/meteor/client/views/admin/integrations/IntegrationsTable.js b/apps/meteor/client/views/admin/integrations/IntegrationsTable.js index 68d26b57cfb1..6f27e7aba61c 100644 --- a/apps/meteor/client/views/admin/integrations/IntegrationsTable.js +++ b/apps/meteor/client/views/admin/integrations/IntegrationsTable.js @@ -36,7 +36,7 @@ function IntegrationsTable({ type }) { const debouncedSort = useDebouncedValue(sort, 500); const query = useQuery({ ...params, text: debouncedText, type }, debouncedSort); - const { value: data } = useEndpointData('integrations.list', query); + const { value: data } = useEndpointData('/v1/integrations.list', query); const router = useRoute('admin-integrations'); diff --git a/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js b/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js index 4dcfca1bb1e7..1babc968c285 100644 --- a/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js +++ b/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js @@ -10,7 +10,7 @@ function EditIncomingWebhookWithData({ integrationId, ...props }) { const t = useTranslation(); const params = useMemo(() => ({ integrationId }), [integrationId]); - const { value: data, phase: state, error, reload } = useEndpointData('integrations.get', params); + const { value: data, phase: state, error, reload } = useEndpointData('/v1/integrations.get', params); const onChange = () => { reload(); diff --git a/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js b/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js index 30d61342ea56..18de6d51f192 100644 --- a/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js +++ b/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js @@ -10,7 +10,7 @@ function EditOutgoingWebhookWithData({ integrationId, ...props }) { const t = useTranslation(); const params = useMemo(() => ({ integrationId }), [integrationId]); - const { value: data, phase: state, error, reload } = useEndpointData('integrations.get', params); + const { value: data, phase: state, error, reload } = useEndpointData('/v1/integrations.get', params); const onChange = () => { reload(); diff --git a/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.js b/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.js index b917cc85149f..9eda4f9ee606 100644 --- a/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.js +++ b/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.js @@ -35,7 +35,7 @@ function OutgoingWebhookHistoryPage(props) { [id, itemsPerPage, current], ); - const { value: data, phase: state, reload } = useEndpointData('integrations.history', query); + const { value: data, phase: state, reload } = useEndpointData('/v1/integrations.history', query); const handleClearHistory = async () => { try { diff --git a/apps/meteor/client/views/admin/invites/InviteRow.tsx b/apps/meteor/client/views/admin/invites/InviteRow.tsx index 571f09f56293..2591df3a10e5 100644 --- a/apps/meteor/client/views/admin/invites/InviteRow.tsx +++ b/apps/meteor/client/views/admin/invites/InviteRow.tsx @@ -26,7 +26,7 @@ type InviteRowProps = Omit & { const InviteRow = ({ _id, createdAt, expires, uses, maxUses, onRemove }: InviteRowProps): ReactElement => { const t = useTranslation(); const formatDateAndTime = useFormatDateAndTime(); - const removeInvite = useEndpoint('DELETE', `removeInvite/${_id}`); + const removeInvite = useEndpoint('DELETE', `/v1/removeInvite/${_id}`); const getTimeFromNow = useTimeFromNow(false); diff --git a/apps/meteor/client/views/admin/invites/InvitesPage.tsx b/apps/meteor/client/views/admin/invites/InvitesPage.tsx index 293c326faace..3599e685b567 100644 --- a/apps/meteor/client/views/admin/invites/InvitesPage.tsx +++ b/apps/meteor/client/views/admin/invites/InvitesPage.tsx @@ -20,7 +20,7 @@ const InvitesPage = (): ReactElement => { const dispatchToastMessage = useToastMessageDispatch(); const setModal = useSetModal(); - const { phase, value, reload } = useEndpointData('listInvites'); + const { phase, value, reload } = useEndpointData('/v1/listInvites'); const onRemove = (removeInvite: () => void): void => { const confirmRemove = async (): Promise => { diff --git a/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx b/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx index e246de859be2..a72e02e2f011 100644 --- a/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx +++ b/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx @@ -11,7 +11,7 @@ const EditOauthAppWithData = ({ _id, ...props }: { _id: string }): ReactElement const params = useMemo(() => ({ appId: _id }), [_id]); - const { value: data, phase: state, error, reload } = useEndpointData('oauth-apps.get', params); + const { value: data, phase: state, error, reload } = useEndpointData('/v1/oauth-apps.get', params); const onChange = useCallback(() => { reload(); diff --git a/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx b/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx index 7cc9f6799ba4..e450483cbd07 100644 --- a/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx +++ b/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx @@ -10,7 +10,7 @@ const OAuthAppsTable = (): ReactElement => { const t = useTranslation(); const formatDateAndTime = useFormatDateAndTime(); - const { value: data } = useEndpointData('oauth-apps.list'); + const { value: data } = useEndpointData('/v1/oauth-apps.list'); const router = useRoute('admin-oauth-apps'); diff --git a/apps/meteor/client/views/admin/permissions/EditRolePage.tsx b/apps/meteor/client/views/admin/permissions/EditRolePage.tsx index 7ae9cc135eed..2d890c30e722 100644 --- a/apps/meteor/client/views/admin/permissions/EditRolePage.tsx +++ b/apps/meteor/client/views/admin/permissions/EditRolePage.tsx @@ -16,9 +16,9 @@ const EditRolePage = ({ role }: { role?: IRole }): ReactElement => { const usersInRoleRouter = useRoute('admin-permissions'); const router = useRoute('admin-permissions'); - const createRole = useEndpoint('POST', 'roles.create'); - const updateRole = useEndpoint('POST', 'roles.update'); - const deleteRole = useEndpoint('POST', 'roles.delete'); + const createRole = useEndpoint('POST', '/v1/roles.create'); + const updateRole = useEndpoint('POST', '/v1/roles.update'); + const deleteRole = useEndpoint('POST', '/v1/roles.delete'); const methods = useForm({ defaultValues: { diff --git a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx index 33352a1147c7..837b412521ec 100644 --- a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx +++ b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx @@ -19,7 +19,7 @@ const UsersInRolePage = ({ role }: { role: IRole }): ReactElement => { const { _id, name, description } = role; const router = useRoute('admin-permissions'); - const addUser = useEndpoint('POST', 'roles.addUserToRole'); + const addUser = useEndpoint('POST', '/v1/roles.addUserToRole'); const handleReturn = useMutableCallback(() => { router.push({ diff --git a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx index 3d8f78c6ff8d..3577fde2c89f 100644 --- a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx +++ b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx @@ -24,7 +24,7 @@ const UsersInRoleTable = ({ users, reload, roleName, roleId, description, total, const t = useTranslation(); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); - const removeUser = useEndpoint('POST', 'roles.removeUserFromRole'); + const removeUser = useEndpoint('POST', '/v1/roles.removeUserFromRole'); const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = paginationData; const closeModal = (): void => setModal(); diff --git a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx index 91dedabe1722..b6c94d1f6532 100644 --- a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx +++ b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx @@ -33,7 +33,7 @@ const UsersInRoleTableWithData = ({ [itemsPerPage, current, rid, roleId], ); - const { reload, ...result } = useEndpointData('roles.getUsersInRole', query); + const { reload, ...result } = useEndpointData('/v1/roles.getUsersInRole', query); useEffect(() => { reloadRef.current = reload; diff --git a/apps/meteor/client/views/admin/rooms/EditRoom.tsx b/apps/meteor/client/views/admin/rooms/EditRoom.tsx index 029c1fbb251b..b4551958e6b4 100644 --- a/apps/meteor/client/views/admin/rooms/EditRoom.tsx +++ b/apps/meteor/client/views/admin/rooms/EditRoom.tsx @@ -116,8 +116,8 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement => const archiveSelector = room.archived ? 'unarchive' : 'archive'; const archiveMessage = room.archived ? 'Room_has_been_unarchived' : 'Room_has_been_archived'; - const saveAction = useEndpointActionExperimental('POST', 'rooms.saveRoomSettings', t('Room_updated_successfully')); - const archiveAction = useEndpointActionExperimental('POST', 'rooms.changeArchivationState', t(archiveMessage)); + const saveAction = useEndpointActionExperimental('POST', '/v1/rooms.saveRoomSettings', t('Room_updated_successfully')); + const archiveAction = useEndpointActionExperimental('POST', '/v1/rooms.changeArchivationState', t(archiveMessage)); const handleSave = useMutableCallback(async () => { const save = (): Promise<{ success: boolean; rid: string }> => @@ -149,7 +149,7 @@ const EditRoom = ({ room, onChange, onDelete }: EditRoomProps): ReactElement => }); const eraseRoom = useMethod('eraseRoom'); - const deleteTeam = useEndpoint('POST', 'teams.delete'); + const deleteTeam = useEndpoint('POST', '/v1/teams.delete'); const handleDelete = useMutableCallback(() => { if (room.teamMain) { diff --git a/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx b/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx index 95f822faca9b..49fbc18fefcf 100644 --- a/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx +++ b/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx @@ -12,7 +12,7 @@ const EditRoomWithData: FC<{ rid?: string; onReload: () => void }> = ({ rid, onR error, reload, } = useEndpointData( - 'rooms.adminRooms.getRoom', + '/v1/rooms.adminRooms.getRoom', useMemo(() => ({ rid }), [rid]), ); diff --git a/apps/meteor/client/views/admin/rooms/RoomsTable.tsx b/apps/meteor/client/views/admin/rooms/RoomsTable.tsx index eebd3b2e1790..00fff51bae51 100644 --- a/apps/meteor/client/views/admin/rooms/RoomsTable.tsx +++ b/apps/meteor/client/views/admin/rooms/RoomsTable.tsx @@ -112,7 +112,7 @@ const RoomsTable = ({ reload }: { reload: MutableRefObject<() => void> }): React const query = useQuery(debouncedParams, debouncedSort); - const endpointData = useEndpointData('rooms.adminRooms', query); + const endpointData = useEndpointData('/v1/rooms.adminRooms', query); const { value: data, reload: reloadEndPoint } = endpointData; diff --git a/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx b/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx index ff5a041e3d81..7cc0c3e895c7 100644 --- a/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx @@ -11,9 +11,9 @@ import TabbedGroupPage from './TabbedGroupPage'; function LDAPGroupPage({ _id, ...group }: ISetting): JSX.Element { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const testConnection = useEndpoint('POST', 'ldap.testConnection'); - const syncNow = useEndpoint('POST', 'ldap.syncNow'); - const testSearch = useEndpoint('POST', 'ldap.testSearch'); + const testConnection = useEndpoint('POST', '/v1/ldap.testConnection'); + const syncNow = useEndpoint('POST', '/v1/ldap.syncNow'); + const testSearch = useEndpoint('POST', '/v1/ldap.testSearch'); const ldapEnabled = useSetting('LDAP_Enable'); const setModal = useSetModal(); const closeModal = useMutableCallback(() => setModal()); diff --git a/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx b/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx index 838518a65068..7c0180df4ec7 100644 --- a/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx +++ b/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx @@ -20,7 +20,7 @@ const AssignAgentModal: FC = ({ existingExtension, close const [extension, setExtension] = useState(existingExtension || ''); const query = useMemo(() => ({ type: 'available' as const, userId: agent }), [agent]); - const assignAgent = useEndpoint('POST', 'omnichannel/agent/extension'); + const assignAgent = useEndpoint('POST', '/v1/omnichannel/agent/extension'); const handleAssignment = useMutableCallback(async () => { try { @@ -33,7 +33,7 @@ const AssignAgentModal: FC = ({ existingExtension, close }); const handleAgentChange = useMutableCallback((e) => setAgent(e)); - const { value: availableExtensions, phase: state } = useEndpointData('omnichannel/extension', query); + const { value: availableExtensions, phase: state } = useEndpointData('/v1/omnichannel/extension', query); return ( diff --git a/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx b/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx index df3ec0fb57b6..a08c6da2f02d 100644 --- a/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx +++ b/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import GenericModal from '../../../../../components/GenericModal'; const RemoveAgentButton: FC<{ username: string; reload: () => void }> = ({ username, reload }) => { - const removeAgent = useEndpoint('DELETE', 'omnichannel/agent/extension'); + const removeAgent = useEndpoint('DELETE', '/v1/omnichannel/agent/extension'); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); diff --git a/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx b/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx index a4030165ca18..e8a7a6ad482d 100644 --- a/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx +++ b/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx @@ -29,7 +29,7 @@ const VoipExtensionsPage: FC = () => { [itemsPerPage, current], ); - const { value: data, reload } = useEndpointData('omnichannel/extensions', query); + const { value: data, reload } = useEndpointData('/v1/omnichannel/extensions', query); const header = useMemo( () => diff --git a/apps/meteor/client/views/admin/users/AddUser.js b/apps/meteor/client/views/admin/users/AddUser.js index 010d20659b81..5aa3eb2cf9c9 100644 --- a/apps/meteor/client/views/admin/users/AddUser.js +++ b/apps/meteor/client/views/admin/users/AddUser.js @@ -13,7 +13,7 @@ export function AddUser({ roles, onReload, ...props }) { const router = useRoute('admin-users'); - const { value: roleData } = useEndpointData('roles.list', ''); + const { value: roleData } = useEndpointData('/v1/roles.list', ''); const [errors, setErrors] = useState({}); const validationKeys = { diff --git a/apps/meteor/client/views/admin/users/EditUser.js b/apps/meteor/client/views/admin/users/EditUser.js index a2e6ae02513e..a8130ca64484 100644 --- a/apps/meteor/client/views/admin/users/EditUser.js +++ b/apps/meteor/client/views/admin/users/EditUser.js @@ -89,10 +89,10 @@ function EditUser({ data, roles, onReload, ...props }) { [data._id], ); - const saveAction = useEndpointAction('POST', 'users.update', saveQuery, t('User_updated_successfully')); - const saveAvatarAction = useEndpointUpload('users.setAvatar', saveAvatarQuery, t('Avatar_changed_successfully')); - const saveAvatarUrlAction = useEndpointAction('POST', 'users.setAvatar', saveAvatarQuery, t('Avatar_changed_successfully')); - const resetAvatarAction = useEndpointAction('POST', 'users.resetAvatar', resetAvatarQuery, t('Avatar_changed_successfully')); + const saveAction = useEndpointAction('POST', '/v1/users.update', saveQuery, t('User_updated_successfully')); + const saveAvatarAction = useEndpointUpload('users.setAvatar', t('Avatar_changed_successfully')); + const saveAvatarUrlAction = useEndpointAction('POST', '/v1/users.setAvatar', saveAvatarQuery, t('Avatar_changed_successfully')); + const resetAvatarAction = useEndpointAction('POST', '/v1/users.resetAvatar', resetAvatarQuery, t('Avatar_changed_successfully')); const updateAvatar = useCallback(async () => { if (avatarObj === 'reset') { diff --git a/apps/meteor/client/views/admin/users/EditUserWithData.js b/apps/meteor/client/views/admin/users/EditUserWithData.js index aec9e89807c1..0e4ba0328ac4 100644 --- a/apps/meteor/client/views/admin/users/EditUserWithData.js +++ b/apps/meteor/client/views/admin/users/EditUserWithData.js @@ -9,13 +9,13 @@ import EditUser from './EditUser'; function EditUserWithData({ uid, ...props }) { const t = useTranslation(); - const { value: roleData, phase: roleState, error: roleError } = useEndpointData('roles.list', ''); + const { value: roleData, phase: roleState, error: roleError } = useEndpointData('/v1/roles.list', ''); const { value: data, phase: state, error, } = useEndpointData( - 'users.info', + '/v1/users.info', useMemo(() => ({ userId: uid }), [uid]), ); diff --git a/apps/meteor/client/views/admin/users/UserInfo.js b/apps/meteor/client/views/admin/users/UserInfo.js index 4a0be4ef9681..0be62c953161 100644 --- a/apps/meteor/client/views/admin/users/UserInfo.js +++ b/apps/meteor/client/views/admin/users/UserInfo.js @@ -25,7 +25,7 @@ export function UserInfoWithData({ uid, username, onReload, ...props }) { error, reload: reloadUserInfo, } = useEndpointData( - 'users.info', + '/v1/users.info', useMemo(() => ({ ...(uid && { userId: uid }), ...(username && { username }) }), [uid, username]), ); diff --git a/apps/meteor/client/views/admin/users/UserInfoActions.js b/apps/meteor/client/views/admin/users/UserInfoActions.js index c16388f7d0a0..da1d0b6847ac 100644 --- a/apps/meteor/client/views/admin/users/UserInfoActions.js +++ b/apps/meteor/client/views/admin/users/UserInfoActions.js @@ -75,7 +75,7 @@ export const UserInfoActions = ({ username, _id, isActive, isAdmin, onChange, on }; const deleteUserQuery = useMemo(() => ({ userId: _id }), [_id]); - const deleteUserEndpoint = useEndpoint('POST', 'users.delete'); + const deleteUserEndpoint = useEndpoint('POST', '/v1/users.delete'); const erasureType = useSetting('Message_ErasureType'); @@ -119,8 +119,8 @@ export const UserInfoActions = ({ username, _id, isActive, isAdmin, onChange, on } }, [_id, dispatchToastMessage, isAdmin, onChange, setAdminStatus, t]); - const resetE2EEKeyRequest = useEndpoint('POST', 'users.resetE2EKey'); - const resetTOTPRequest = useEndpoint('POST', 'users.resetTOTP'); + const resetE2EEKeyRequest = useEndpoint('POST', '/v1/users.resetE2EKey'); + const resetTOTPRequest = useEndpoint('POST', '/v1/users.resetTOTP'); const resetE2EEKey = useCallback(async () => { setModal(); const result = await resetE2EEKeyRequest({ userId: _id }); @@ -171,7 +171,7 @@ export const UserInfoActions = ({ username, _id, isActive, isAdmin, onChange, on [_id, isActive], ); const changeActiveStatusMessage = isActive ? 'User_has_been_deactivated' : 'User_has_been_activated'; - const changeActiveStatusRequest = useEndpoint('POST', 'users.setActiveStatus'); + const changeActiveStatusRequest = useEndpoint('POST', '/v1/users.setActiveStatus'); const changeActiveStatus = confirmOwnerChanges( async (confirm = false) => { diff --git a/apps/meteor/client/views/admin/users/UsersPage.js b/apps/meteor/client/views/admin/users/UsersPage.js index de5a6960468c..5dab712b1b53 100644 --- a/apps/meteor/client/views/admin/users/UsersPage.js +++ b/apps/meteor/client/views/admin/users/UsersPage.js @@ -77,7 +77,7 @@ function UsersPage() { const debouncedParams = useDebouncedValue(params, 500); const debouncedSort = useDebouncedValue(sort, 500); const query = useQuery(debouncedParams, debouncedSort); - const { value: data = {}, reload: reloadList } = useEndpointData('users.list', query); + const { value: data = {}, reload: reloadList } = useEndpointData('/v1/users.list', query); const reload = () => { seatsCap?.reload(); diff --git a/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx b/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx index 28f8bcb43b71..73f6f07c15b7 100644 --- a/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx +++ b/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx @@ -23,7 +23,7 @@ const ServerLogs = (): ReactElement => { const dispatchToastMessage = useToastMessageDispatch(); - const getStdoutQueue = useEndpoint('GET', 'stdout.queue'); + const getStdoutQueue = useEndpoint('GET', '/v1/stdout.queue'); const subscribeToStdout = useStream('stdout'); useEffect(() => { diff --git a/apps/meteor/client/views/directory/ChannelsTable.js b/apps/meteor/client/views/directory/ChannelsTable.js index d71bc76fde65..297f9e9869c0 100644 --- a/apps/meteor/client/views/directory/ChannelsTable.js +++ b/apps/meteor/client/views/directory/ChannelsTable.js @@ -93,7 +93,7 @@ function ChannelsTable() { const channelRoute = useRoute('channel'); const groupsRoute = useRoute('group'); - const { value: data = {} } = useEndpointData('directory', query); + const { value: data = {} } = useEndpointData('/v1/directory', query); const onClick = useMemo( () => (name, type) => (e) => { diff --git a/apps/meteor/client/views/directory/TeamsTable.js b/apps/meteor/client/views/directory/TeamsTable.js index da1d8e3a9071..614608ff7b47 100644 --- a/apps/meteor/client/views/directory/TeamsTable.js +++ b/apps/meteor/client/views/directory/TeamsTable.js @@ -69,7 +69,7 @@ function TeamsTable() { const query = useQuery(params, sort, 'teams'); - const { value: data = {} } = useEndpointData('directory', query); + const { value: data = {} } = useEndpointData('/v1/directory', query); const onClick = useMemo( () => (name, type) => (e) => { diff --git a/apps/meteor/client/views/directory/UserTable.js b/apps/meteor/client/views/directory/UserTable.js index 2ac612213c05..da868f2db689 100644 --- a/apps/meteor/client/views/directory/UserTable.js +++ b/apps/meteor/client/views/directory/UserTable.js @@ -84,7 +84,7 @@ function UserTable({ workspace = 'local' }) { const directRoute = useRoute('direct'); - const { value: data = {} } = useEndpointData('directory', query); + const { value: data = {} } = useEndpointData('/v1/directory', query); const onClick = useCallback( (username) => (e) => { diff --git a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts index cec014d1cc18..8a5d99b9f83e 100644 --- a/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts +++ b/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts @@ -21,9 +21,8 @@ export const useDepartmentsByUnitsList = ( } => { const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = `livechat/departments.available-by-unit/${options.unitId || 'none'}` as const; - const getDepartments = useEndpoint('GET', endpoint); + const getDepartments = useEndpoint('GET', `/v1/livechat/departments.available-by-unit/${options.unitId || 'none'}`); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/views/hooks/useMembersList.ts b/apps/meteor/client/views/hooks/useMembersList.ts index be18bd8db628..08d7616afce6 100644 --- a/apps/meteor/client/views/hooks/useMembersList.ts +++ b/apps/meteor/client/views/hooks/useMembersList.ts @@ -16,9 +16,9 @@ type MembersListOptions = { }; const endpointsByRoomType = { - d: 'im.members', - p: 'groups.members', - c: 'channels.members', + d: '/v1/im.members', + p: '/v1/groups.members', + c: '/v1/channels.members', } as const; export const useMembersList = ( diff --git a/apps/meteor/client/views/hooks/useMonitorsList.ts b/apps/meteor/client/views/hooks/useMonitorsList.ts index f1b884b915c3..decfa3ee3c70 100644 --- a/apps/meteor/client/views/hooks/useMonitorsList.ts +++ b/apps/meteor/client/views/hooks/useMonitorsList.ts @@ -21,9 +21,7 @@ export const useMonitorsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const endpoint = 'livechat/monitors.list'; - - const getMonitors = useEndpoint('GET', endpoint); + const getMonitors = useEndpoint('GET', '/v1/livechat/monitors.list'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/client/views/hooks/useUpgradeTabParams.ts b/apps/meteor/client/views/hooks/useUpgradeTabParams.ts index 6a91fd917776..234c54be5998 100644 --- a/apps/meteor/client/views/hooks/useUpgradeTabParams.ts +++ b/apps/meteor/client/views/hooks/useUpgradeTabParams.ts @@ -5,8 +5,8 @@ import { useQuery } from 'react-query'; import { UpgradeTabVariant, getUpgradeTabType } from '../../../lib/getUpgradeTabType'; export const useUpgradeTabParams = (): { tabType: UpgradeTabVariant | false; trialEndDate: string | undefined; isLoading: boolean } => { - const getRegistrationStatus = useEndpoint('GET', 'cloud.registrationStatus'); - const getLicenses = useEndpoint('GET', 'licenses.get'); + const getRegistrationStatus = useEndpoint('GET', '/v1/cloud.registrationStatus'); + const getLicenses = useEndpoint('GET', '/v1/licenses.get'); const cloudWorkspaceHadTrial = useSetting('Cloud_Workspace_Had_Trial') as boolean; const { data: registrationStatusData } = useQuery(['registrationStatus'], () => getRegistrationStatus()); diff --git a/apps/meteor/client/views/invite/InvitePage.tsx b/apps/meteor/client/views/invite/InvitePage.tsx index 319f997ba089..4e9f1e8cc57e 100644 --- a/apps/meteor/client/views/invite/InvitePage.tsx +++ b/apps/meteor/client/views/invite/InvitePage.tsx @@ -1,4 +1,3 @@ -import { OperationParams, OperationResult } from '@rocket.chat/rest-typings'; import { useToastMessageDispatch, useSessionDispatch, @@ -35,11 +34,7 @@ const InvitePage = (): ReactElement => { } try { - const { valid } = await APIClient.v1.post< - OperationParams<'POST', 'validateInviteToken'>, - never, - OperationResult<'POST', 'validateInviteToken'> - >('validateInviteToken', { token }); + const { valid } = await APIClient.post('/v1/validateInviteToken', { token }); return valid; } catch (error) { @@ -64,12 +59,9 @@ const InvitePage = (): ReactElement => { } try { - const result = await APIClient.v1.post< - OperationParams<'POST', 'useInviteToken'>, - never, - OperationResult<'POST', 'useInviteToken'> - >('useInviteToken', { token }); - if (!result?.room.name) { + const result = await APIClient.post('/v1/useInviteToken', { token }); + + if (!result.room.name) { dispatchToastMessage({ type: 'error', message: t('Failed_to_activate_invite_token') }); homeRoute.push(); return; diff --git a/apps/meteor/client/views/meet/MeetPage.tsx b/apps/meteor/client/views/meet/MeetPage.tsx index e0f673f6d9c2..8d9ea1235187 100644 --- a/apps/meteor/client/views/meet/MeetPage.tsx +++ b/apps/meteor/client/views/meet/MeetPage.tsx @@ -25,7 +25,14 @@ const MeetPage: FC = () => { const closeCallTab = (): void => window.close(); const setupCallForVisitor = useCallback(async () => { - const room = await APIClient.v1.get(`livechat/room?token=${visitorToken}&rid=${roomId}`); + if (!visitorToken || !roomId) { + throw new Error('Missing parameters'); + } + + const room = (await APIClient.get('/v1/livechat/room', { + token: visitorToken, + rid: roomId, + })) as any; if (room?.room?.v?.token === visitorToken) { setVisitorId(room.room.v._id); setVisitorName(room.room.fname); @@ -37,7 +44,11 @@ const MeetPage: FC = () => { }, [visitorToken, roomId]); const setupCallForAgent = useCallback(async () => { - const room = await APIClient.v1.get(`rooms.info?roomId=${roomId}`); + if (!roomId) { + throw new Error('Missing parameters'); + } + + const room = (await APIClient.get('/v1/rooms.info', { roomId })) as any; if (room?.room?.servedBy?._id === Meteor.userId()) { setVisitorName(room.room.fname); room?.room?.responseBy?.username ? setAgentName(room.room.responseBy.username) : setAgentName(room.room.servedBy.username); diff --git a/apps/meteor/client/views/omnichannel/DepartmentAutoComplete.js b/apps/meteor/client/views/omnichannel/DepartmentAutoComplete.js index d27c8d5adfbb..cfc62f03cfa3 100644 --- a/apps/meteor/client/views/omnichannel/DepartmentAutoComplete.js +++ b/apps/meteor/client/views/omnichannel/DepartmentAutoComplete.js @@ -16,7 +16,7 @@ const DepartmentAutoComplete = (props) => { const { enabled, onlyMyDepartments = false } = props; const [filter, setFilter] = useState(''); const { value: data } = useEndpointData( - 'livechat/department.autocomplete', + '/v1/livechat/department.autocomplete', useMemo(() => query(filter, enabled, onlyMyDepartments), [onlyMyDepartments, enabled, filter]), ); diff --git a/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx b/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx index dc1e7a9166d9..707d10876bc1 100644 --- a/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx @@ -14,7 +14,7 @@ const AddAgent = ({ reload }: AddAgentProps): ReactElement => { const t = useTranslation(); const [username, setUsername] = useState(''); - const saveAction = useEndpointAction('POST', 'livechat/users/agent', { username }); + const saveAction = useEndpointAction('POST', '/v1/livechat/users/agent', { username }); const handleSave = useMutableCallback(async () => { if (!username) { diff --git a/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx b/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx index 3ff846618622..b2aed4a9af46 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx @@ -14,17 +14,17 @@ type AgentEditWithDataProps = { const AgentEditWithData = ({ uid, reload }: AgentEditWithDataProps): ReactElement => { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData(`livechat/users/agent/${uid}`); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/users/agent/${uid}`); const { value: userDepartments, phase: userDepartmentsState, error: userDepartmentsError, - } = useEndpointData(`livechat/agents/${uid}/departments`); + } = useEndpointData(`/v1/livechat/agents/${uid}/departments`); const { value: availableDepartments, phase: availableDepartmentsState, error: availableDepartmentsError, - } = useEndpointData('livechat/department'); + } = useEndpointData('/v1/livechat/department'); if ( [state, availableDepartmentsState, userDepartmentsState].includes(AsyncStatePhase.LOADING) || diff --git a/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx b/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx index 3287aca13583..f53192c345cf 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx @@ -17,7 +17,7 @@ type AgentInfoProps = { export const AgentInfo = memo(function AgentInfo({ uid, children, ...props }) { const t = useTranslation(); - const result = useEndpointData(`livechat/users/agent/${uid}`); + const result = useEndpointData(`/v1/livechat/users/agent/${uid}`); const { useMaxChatsPerAgentDisplay } = useFormsSubscription(); diff --git a/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx b/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx index 089bb43078ff..21fb735c4630 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx @@ -10,7 +10,7 @@ const AgentInfoActions = ({ reload }: { reload: () => void }): ReactElement => { const t = useTranslation(); const _id = useRouteParameter('id'); const agentsRoute = useRoute('omnichannel-agents'); - const deleteAction = useEndpointAction('DELETE', `livechat/users/agent/${_id}`); + const deleteAction = useEndpointAction('DELETE', `/v1/livechat/users/agent/${_id}`); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); diff --git a/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx b/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx index 94045e8e982f..72b53541f8f6 100644 --- a/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx +++ b/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx @@ -36,7 +36,7 @@ const AgentsPage = (): ReactElement => { const { current, itemsPerPage, setItemsPerPage, setCurrent, ...paginationProps } = usePagination(); const query = useQuery({ text: debouncedFilter, current, itemsPerPage }, debouncedSort); - const { reload, ...result } = useEndpointData('livechat/users/agent', query); + const { reload, ...result } = useEndpointData('/v1/livechat/users/agent', query); const onHeaderClick = useMutableCallback((id) => { if (sortBy === id) { diff --git a/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx b/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx index a5f48da05a38..a94deecdc889 100644 --- a/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx +++ b/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx @@ -13,7 +13,7 @@ type RemoveAgentButtonProps = { }; const RemoveAgentButton = ({ _id, reload }: RemoveAgentButtonProps): ReactElement => { - const deleteAction = useEndpointAction('DELETE', `livechat/users/agent/${_id}`); + const deleteAction = useEndpointAction('DELETE', `/v1/livechat/users/agent/${_id}`); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); diff --git a/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx b/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx index f77d997b6f74..cb5d5432fd14 100644 --- a/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx +++ b/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx @@ -12,7 +12,7 @@ import AppearancePage from './AppearancePage'; const AppearancePageContainer: FC = () => { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData('livechat/appearance'); + const { value: data, phase: state, error } = useEndpointData('/v1/livechat/appearance'); const canViewAppearance = usePermission('view-livechat-appearance'); diff --git a/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js b/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js index 7bbc3c55a757..7482595dfcf4 100644 --- a/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js +++ b/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js @@ -17,7 +17,7 @@ const EditBusinessHoursPage = ({ id, type }) => { const isSingleBH = useIsSingleBusinessHours(); const { value: data, phase: state } = useEndpointData( - 'livechat/business-hour', + '/v1/livechat/business-hour', useMemo(() => ({ _id: id, type }), [id, type]), ); diff --git a/apps/meteor/client/views/omnichannel/components/CustomField.js b/apps/meteor/client/views/omnichannel/components/CustomField.js index 903bb010edb7..5960d5225467 100644 --- a/apps/meteor/client/views/omnichannel/components/CustomField.js +++ b/apps/meteor/client/views/omnichannel/components/CustomField.js @@ -11,7 +11,7 @@ import Label from './Label'; const CustomField = ({ id, value }) => { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData(`livechat/custom-fields/${id}`); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/custom-fields/${id}`); if (state === AsyncStatePhase.LOADING) { return ; } diff --git a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx index f2e7ad337ec7..7abf9affeb96 100644 --- a/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx +++ b/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx @@ -130,7 +130,7 @@ const CurrentChatsRoute = (): ReactElement => { directoryRoute.push({ id: _id }); }); - const { value: data, reload } = useEndpointData('livechat/rooms', query); + const { value: data, reload } = useEndpointData('/v1/livechat/rooms', query); const header = useMemo( () => diff --git a/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx b/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx index 8608a5f6754e..d7b92cb3463d 100644 --- a/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx +++ b/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx @@ -23,7 +23,7 @@ const FilterByText: FilterByTextType = ({ setFilter, reload, ...props }) => { const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); - const { value: allCustomFields } = useEndpointData('livechat/custom-fields'); + const { value: allCustomFields } = useEndpointData('/v1/livechat/custom-fields'); const statusOptions: [string, string][] = [ ['all', t('All')], ['closed', t('Closed')], diff --git a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js index 96c50c623bca..208035d08979 100644 --- a/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js +++ b/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js @@ -57,7 +57,7 @@ const CustomFieldsRoute = () => { }), ); - const { value: data, reload } = useEndpointData('livechat/custom-fields', query); + const { value: data, reload } = useEndpointData('/v1/livechat/custom-fields', query); const header = useMemo( () => diff --git a/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js b/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js index 0f9a45bb2d55..8c8e6455755d 100644 --- a/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js +++ b/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js @@ -12,7 +12,7 @@ const EditCustomFieldsPageContainer = ({ reload }) => { const t = useTranslation(); const id = useRouteParameter('id'); - const { value: data, phase: state, error } = useEndpointData(`livechat/custom-fields/${id}`); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/custom-fields/${id}`); if (state === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/client/views/omnichannel/departments/AddAgent.js b/apps/meteor/client/views/omnichannel/departments/AddAgent.js index ffc5175a13d7..a720bbee36e9 100644 --- a/apps/meteor/client/views/omnichannel/departments/AddAgent.js +++ b/apps/meteor/client/views/omnichannel/departments/AddAgent.js @@ -9,7 +9,7 @@ import { useEndpointAction } from '../../../hooks/useEndpointAction'; function AddAgent({ agentList, setAgentsAdded, setAgentList, ...props }) { const t = useTranslation(); const [userId, setUserId] = useState(); - const getAgent = useEndpointAction('GET', `livechat/users/agent/${userId}`); + const getAgent = useEndpointAction('GET', `/v1/livechat/users/agent/${userId}`); const dispatchToastMessage = useToastMessageDispatch(); const handleAgent = useMutableCallback((e) => setUserId(e)); diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.js b/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.js index 1ec5bcec1682..b752413441ec 100644 --- a/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.js +++ b/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.js @@ -66,7 +66,7 @@ function DepartmentsRoute() { }), ); - const { value: data = {}, reload } = useEndpointData('livechat/department', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/department', query); const header = useMemo( () => diff --git a/apps/meteor/client/views/omnichannel/departments/EditDepartment.js b/apps/meteor/client/views/omnichannel/departments/EditDepartment.js index f14f849ce062..ccde330932d0 100644 --- a/apps/meteor/client/views/omnichannel/departments/EditDepartment.js +++ b/apps/meteor/client/views/omnichannel/departments/EditDepartment.js @@ -138,7 +138,7 @@ function EditDepartment({ data, id, title, reload, allowedToForwardData }) { }; const saveDepartmentInfo = useMethod('livechat:saveDepartment'); - const saveDepartmentAgentsInfoOnEdit = useEndpoint('POST', `livechat/department/${id}/agents`); + const saveDepartmentAgentsInfoOnEdit = useEndpoint('POST', `/v1/livechat/department/${id}/agents`); const dispatchToastMessage = useToastMessageDispatch(); diff --git a/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js b/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js index d9bcade9284c..5df029fdab0a 100644 --- a/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js +++ b/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js @@ -15,7 +15,7 @@ function EditDepartmentWithAllowedForwardData({ data, ...props }) { phase: allowedToForwardState, error: allowedToForwardError, } = useEndpointData( - 'livechat/department.listByIds', + '/v1/livechat/department.listByIds', useMemo( () => ({ ids: data && data.department && data.department.departmentsAllowedToForward ? data.department.departmentsAllowedToForward : [], diff --git a/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js b/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js index 6c53ea6bfb8a..7fe2a08edc4a 100644 --- a/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js +++ b/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js @@ -11,7 +11,7 @@ import EditDepartmentWithAllowedForwardData from './EditDepartmentWithAllowedFor const param = { onlyMyDepartments: true }; function EditDepartmentWithData({ id, reload, title }) { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData(`livechat/department/${id}`, param); + const { value: data, phase: state, error } = useEndpointData(`/v1/livechat/department/${id}`, param); if ([state].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/views/omnichannel/departments/RemoveDepartmentButton.js b/apps/meteor/client/views/omnichannel/departments/RemoveDepartmentButton.js index 16889b62e906..99599a49daca 100644 --- a/apps/meteor/client/views/omnichannel/departments/RemoveDepartmentButton.js +++ b/apps/meteor/client/views/omnichannel/departments/RemoveDepartmentButton.js @@ -7,7 +7,7 @@ import GenericModal from '../../../components/GenericModal'; import { useEndpointAction } from '../../../hooks/useEndpointAction'; function RemoveDepartmentButton({ _id, reload }) { - const deleteAction = useEndpointAction('DELETE', `livechat/department/${_id}`); + const deleteAction = useEndpointAction('DELETE', `/v1/livechat/department/${_id}`); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); diff --git a/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx b/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx index a2df5446c180..e74e5ecfad3c 100644 --- a/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx +++ b/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx @@ -31,7 +31,7 @@ const CallsContextualBarDirectory: FC = () => { [id, token], ); - const { value: data, phase: state, error } = useEndpointData(`voip/room`, query); + const { value: data, phase: state, error } = useEndpointData(`/v1/voip/room`, query); if (bar === 'view' && id) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx b/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx index 01a39a2a981d..f13d2b17b293 100644 --- a/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx +++ b/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx @@ -37,7 +37,7 @@ const ChatsContextualBar: FC<{ chatReload?: () => void }> = ({ chatReload }) => [id], ); - const { value: data, phase: state, error, reload: reloadInfo } = useEndpointData(`rooms.info`, query); + const { value: data, phase: state, error, reload: reloadInfo } = useEndpointData(`/v1/rooms.info`, query); if (bar === 'view' && id) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx index 7d964af4c16a..db21eb25fe89 100644 --- a/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx @@ -75,7 +75,7 @@ const CallTable: FC = () => { ); }); - const { value: data } = useEndpointData('voip/rooms', query); + const { value: data } = useEndpointData('/v1/voip/rooms', query); const header = useMemo( () => diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx index 9258748ec959..3ad3b547b808 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx @@ -73,7 +73,7 @@ const ChatTable: FC<{ setChatReload: Dispatch> }> = ({ setCh }), ); - const { value: data, reload } = useEndpointData('livechat/rooms', query as any); // TODO: Check the typing for the livechat/rooms endpoint as it seems wrong + const { value: data, reload } = useEndpointData('/v1/livechat/rooms', query as any); // TODO: Check the typing for the livechat/rooms endpoint as it seems wrong useEffect(() => { setChatReload?.(() => reload); diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/AgentField.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/AgentField.js index 40c45afdd35c..56c34594eb6e 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/AgentField.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/AgentField.js @@ -1,6 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import UserCard from '../../../../../components/UserCard'; import { UserStatus } from '../../../../../components/UserStatus'; @@ -15,7 +15,10 @@ import { FormSkeleton } from '../../Skeleton'; const AgentField = ({ agent, isSmall = false }) => { const t = useTranslation(); const { username } = agent; - const { value, phase: state } = useEndpointData(`users.info?username=${username}`); + const { value, phase: state } = useEndpointData( + `/v1/users.info`, + useMemo(() => ({ username }), [username]), + ); if (state === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js index ee49c4f464d3..4c38f7979878 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js @@ -27,7 +27,7 @@ function ChatInfo({ id, route }) { const t = useTranslation(); const formatDateAndTime = useFormatDateAndTime(); - const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('livechat/custom-fields'); + const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('/v1/livechat/custom-fields'); const [customFields, setCustomFields] = useState([]); const formatDuration = useFormatDuration(); diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js index 1ac3accc8393..da0919789e44 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js @@ -24,7 +24,7 @@ function ChatInfoDirectory({ id, route = undefined, room }) { const t = useTranslation(); const formatDateAndTime = useFormatDateAndTime(); - const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('livechat/custom-fields'); + const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('/v1/livechat/custom-fields'); const [customFields, setCustomFields] = useState([]); const formatDuration = useFormatDuration(); diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ContactField.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ContactField.js index 9a0820019e1d..15ae3d4cf75e 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ContactField.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ContactField.js @@ -1,6 +1,6 @@ import { Avatar, Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import UserCard from '../../../../../components/UserCard'; import { UserStatus } from '../../../../../components/UserStatus'; @@ -18,7 +18,14 @@ const ContactField = ({ contact, room }) => { const { fname, t: type } = room; const avatarUrl = roomCoordinator.getRoomDirectives(type)?.getAvatarPath(room); - const { value: data, phase: state, error } = useEndpointData(`livechat/visitors.info?visitorId=${contact._id}`); + const { + value: data, + phase: state, + error, + } = useEndpointData( + '/v1/livechat/visitors.info', + useMemo(() => ({ visitorId: contact._id }), [contact._id]), + ); if (state === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.js index 8425894bfd44..5e68b7abb586 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.js @@ -10,7 +10,7 @@ import { FormSkeleton } from '../../Skeleton'; const DepartmentField = ({ departmentId }) => { const t = useTranslation(); - const { value: data, phase: state } = useEndpointData(`livechat/department/${departmentId}`); + const { value: data, phase: state } = useEndpointData(`/v1/livechat/department/${departmentId}`); if (state === AsyncStatePhase.LOADING) { return ; } 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 04a389787cc3..66626c80715b 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 from 'react'; +import React, { useMemo } from 'react'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; import { AsyncStatePhase } from '../../../../../lib/asyncState'; @@ -11,7 +11,14 @@ import { FormSkeleton } from '../../Skeleton'; const PriorityField = ({ id }) => { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData(`livechat/priorities.getOne?priorityId=${id}`); + const { + value: data, + phase: state, + error, + } = useEndpointData( + '/v1/livechat/priorities.getOne', + useMemo(() => ({ priorityId: id }), [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 81530fda9a53..0f4a5578c4b3 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit.js @@ -64,8 +64,8 @@ function RoomEdit({ room, visitor, reload, reloadInfo, close }) { const [customFieldsError, setCustomFieldsError] = useState([]); - const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('livechat/custom-fields'); - const { value: prioritiesResult = {}, phase: statePriorities } = useEndpointData('livechat/priorities.list'); + const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('/v1/livechat/custom-fields'); + const { value: prioritiesResult = {}, phase: statePriorities } = useEndpointData('/v1/livechat/priorities.list'); const jsonConverterToValidFormat = (customFields) => { const jsonObj = {}; diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEditWithData.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEditWithData.js index 9142e9f1ea2e..b4c566db5181 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEditWithData.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEditWithData.js @@ -1,6 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import { AsyncStatePhase } from '../../../../../hooks/useAsyncState'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; @@ -10,7 +10,14 @@ import VisitorData from './VisitorData'; function RoomEditWithData({ id, reload, reloadInfo, close }) { const t = useTranslation(); - const { value: roomData, phase: state, error } = useEndpointData(`rooms.info?roomId=${id}`); + const { + value: roomData, + phase: state, + error, + } = useEndpointData( + '/v1/rooms.info', + useMemo(() => ({ roomId: id }), [id]), + ); if ([state].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js index c68d9dce8216..3dce914bb3b7 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js @@ -1,5 +1,5 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import UAParser from 'ua-parser-js'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; @@ -11,7 +11,14 @@ import { FormSkeleton } from '../../Skeleton'; const VisitorClientInfo = ({ uid }) => { const t = useTranslation(); - const { value: userData, phase: state, error } = useEndpointData(`livechat/visitors.info?visitorId=${uid}`); + const { + value: userData, + phase: state, + error, + } = useEndpointData( + '/v1/livechat/visitors.info', + useMemo(() => ({ visitorId: uid }), [uid]), + ); if (state === AsyncStatePhase.LOADING) { return ; } diff --git a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorData.js b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorData.js index af665d5b227f..7d2b78a4bb26 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorData.js +++ b/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorData.js @@ -1,6 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import { AsyncStatePhase } from '../../../../../hooks/useAsyncState'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; @@ -16,7 +16,14 @@ function VisitorData({ room, reload, reloadInfo, close }) { }, } = room; - const { value: visitor, phase: stateVisitor, error: errorVisitor } = useEndpointData(`livechat/visitors.info?visitorId=${_id}`); + const { + value: visitor, + phase: stateVisitor, + error: errorVisitor, + } = useEndpointData( + '/v1/livechat/visitors.info', + useMemo(() => ({ visitorId: _id }), [_id]), + ); if ([stateVisitor].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.js b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.js index 1a400255e61f..b824f3a67185 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.js +++ b/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.js @@ -55,7 +55,7 @@ function ContactTable({ setContactReload }) { }), ); - const { value: data, reload } = useEndpointData('livechat/visitors.search', query); + const { value: data, reload } = useEndpointData('/v1/livechat/visitors.search', query); useEffect(() => { setContactReload(() => reload); diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js index 7f6fa1dd52bd..24c95fa64b35 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js +++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js @@ -1,6 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import React, { useMemo } from 'react'; import { AsyncStatePhase } from '../../../../../hooks/useAsyncState'; import { useEndpointData } from '../../../../../hooks/useEndpointData'; @@ -9,7 +9,14 @@ import ContactNewEdit from './ContactNewEdit'; function ContactEditWithData({ id, close }) { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData(`omnichannel/contact?contactId=${id}`); // TODO OMNICHANNEL + const { + value: data, + phase: state, + error, + } = useEndpointData( + '/v1/omnichannel/contact', + useMemo(() => ({ contactId: id }), [id]), + ); if ([state].includes(AsyncStatePhase.LOADING)) { return ; diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.js b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.js index 21f6bf43bac8..6e815bdf63d9 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.js +++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.js @@ -1,7 +1,7 @@ import { Box, Margins, ButtonGroup, Button, Icon } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useCurrentRoute, useRoute, useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { hasPermission } from '../../../../../../app/authorization/client'; import ContactManagerInfo from '../../../../../../ee/client/omnichannel/ContactManagerInfo'; @@ -22,7 +22,7 @@ const ContactInfo = ({ id, rid, route }) => { const t = useTranslation(); const routePath = useRoute(route || 'omnichannel-directory'); - const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('livechat/custom-fields'); + const { value: allCustomFields, phase: stateCustomFields } = useEndpointData('/v1/livechat/custom-fields'); const [customFields, setCustomFields] = useState([]); @@ -59,7 +59,14 @@ const ContactInfo = ({ id, rid, route }) => { } }, [allCustomFields, stateCustomFields]); - const { value: data, phase: state, error } = useEndpointData(`omnichannel/contact?contactId=${id}`); + const { + value: data, + phase: state, + error, + } = useEndpointData( + '/v1/omnichannel/contact', + useMemo(() => ({ contactId: id }), [id]), + ); const [currentRouteName] = useCurrentRoute(); const liveRoute = useRoute('live'); diff --git a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.js b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.js index be8159d46ce6..6380f16ab565 100644 --- a/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.js +++ b/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.js @@ -75,7 +75,7 @@ function ContactNewEdit({ id, data, close }) { const [phoneError, setPhoneError] = useState(); const [customFieldsError, setCustomFieldsError] = useState([]); - const { value: allCustomFields, phase: state } = useEndpointData('livechat/custom-fields'); + const { value: allCustomFields, phase: state } = useEndpointData('/v1/livechat/custom-fields'); const jsonConverterToValidFormat = (customFields) => { const jsonObj = {}; @@ -97,9 +97,17 @@ function ContactNewEdit({ id, data, close }) { [allCustomFields], ); - const saveContact = useEndpoint('POST', 'omnichannel/contact'); - const emailAlreadyExistsAction = useEndpoint('GET', `omnichannel/contact.search?email=${email}`); - const phoneAlreadyExistsAction = useEndpoint('GET', `omnichannel/contact.search?phone=${phone}`); + const saveContact = useEndpoint('POST', '/v1/omnichannel/contact'); + const emailAlreadyExistsAction = useEndpoint( + 'GET', + '/v1/omnichannel/contact.search', + useMemo(() => ({ email }), [email]), + ); + const phoneAlreadyExistsAction = useEndpoint( + 'GET', + '/v1/omnichannel/contact.search', + useMemo(() => ({ phone }), [phone]), + ); const checkEmailExists = useMutableCallback(async () => { if (!validateEmail(email)) { diff --git a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx index 58e6d956afce..c904b02d5291 100644 --- a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx +++ b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx @@ -10,7 +10,7 @@ const AddManager = ({ reload }: { reload: () => void }): ReactElement => { const t = useTranslation(); const [username, setUsername] = useState(''); - const saveAction = useEndpointAction('POST', 'livechat/users/manager', { username }); + const saveAction = useEndpointAction('POST', '/v1/livechat/users/manager', { username }); const handleSave = useMutableCallback(async () => { if (!username) { diff --git a/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx b/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx index 864e40debf77..c409f06c089e 100644 --- a/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx +++ b/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx @@ -42,7 +42,7 @@ const ManagersRoute = (): ReactElement => { 500, ); - const { reload, ...result } = useEndpointData('livechat/users/manager', query); + const { reload, ...result } = useEndpointData('/v1/livechat/users/manager', query); const canViewManagers = usePermission('manage-livechat-managers'); if (!canViewManagers) { diff --git a/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx b/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx index e1d428cb5e33..dd3083f2a467 100644 --- a/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx +++ b/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx @@ -8,7 +8,7 @@ import { useEndpointAction } from '../../../hooks/useEndpointAction'; const RemoveManagerButton = ({ _id, reload }: { _id: string; reload: () => void }): ReactElement => { const t = useTranslation(); - const deleteAction = useEndpointAction('DELETE', `livechat/users/manager/${_id}`); + const deleteAction = useEndpointAction('DELETE', `/v1/livechat/users/manager/${_id}`); const setModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); diff --git a/apps/meteor/client/views/omnichannel/queueList/index.tsx b/apps/meteor/client/views/omnichannel/queueList/index.tsx index e199e54cbbbb..9603d855cb6b 100644 --- a/apps/meteor/client/views/omnichannel/queueList/index.tsx +++ b/apps/meteor/client/views/omnichannel/queueList/index.tsx @@ -97,7 +97,7 @@ const QueueList = (): ReactElement => { const debouncedParams = useDebouncedValue(params, 500); const debouncedSort = useDebouncedValue(sort, 500); const query = useQuery(debouncedParams, debouncedSort); - const { value: data } = useEndpointData('livechat/queue', query); + const { value: data } = useEndpointData('/v1/livechat/queue', query); return ( diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js index 6012edcfc95a..71c2edee9c54 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js @@ -38,7 +38,7 @@ const AgentStatusChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/agents-status', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/agents-status', params); reloadRef.current.agentStatusChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js index c7a727b6d319..f1dc8f1072d9 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js @@ -45,7 +45,7 @@ const ChatDurationChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/timings', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/timings', params); reloadRef.current.chatDurationChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js index 239b1bb2815a..5cb49cafb013 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js @@ -38,7 +38,7 @@ const ChatsChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/chats', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/chats', params); reloadRef.current.chatsChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js index ea8156f2ed2c..4a2bbccab60e 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js @@ -31,7 +31,7 @@ const ChatsPerAgentChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/chats-per-agent', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/chats-per-agent', params); reloadRef.current.chatsPerAgentChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js index 09658ebe870f..55ba495d412a 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js @@ -31,7 +31,7 @@ const ChatsPerDepartmentChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/chats-per-department', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/chats-per-department', params); reloadRef.current.chatsPerDepartmentChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js index 903a37969cc1..04a2cf1af0b7 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js @@ -46,7 +46,7 @@ const ResponseTimesChart = ({ params, reloadRef, ...props }) => { init, }); - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/charts/timings', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/charts/timings', params); reloadRef.current.responseTimesChart = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js index dd52d328b687..f0c4fdc353bb 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js @@ -11,7 +11,7 @@ const overviewInitalValue = { const initialData = [overviewInitalValue, overviewInitalValue, overviewInitalValue]; const AgentsOverview = ({ params, reloadRef, ...props }) => { - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/agents-productivity-totalizers', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/agents-productivity-totalizers', params); reloadRef.current.agentsOverview = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js index 123c1924fc91..21912c1666cc 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js @@ -10,7 +10,7 @@ const initialData = [ ]; const ChatsOverview = ({ params, reloadRef, ...props }) => { - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/chats-totalizers', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/chats-totalizers', params); reloadRef.current.chatsOverview = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js index 4007fde085ec..141f50968d77 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js @@ -11,7 +11,7 @@ const overviewInitalValue = { const initialData = [overviewInitalValue, overviewInitalValue, overviewInitalValue, overviewInitalValue]; const ConversationOverview = ({ params, reloadRef, ...props }) => { - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/conversation-totalizers', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/conversation-totalizers', params); reloadRef.current.conversationOverview = reload; diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js index d244cb1c233b..9e76b9d3e337 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js @@ -8,7 +8,7 @@ const defaultValue = { title: '', value: '00:00:00' }; const initialData = [defaultValue, defaultValue, defaultValue, defaultValue]; const ProductivityOverview = ({ params, reloadRef, ...props }) => { - const { value: data, phase: state, reload } = useEndpointData('livechat/analytics/dashboards/productivity-totalizers', params); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/analytics/dashboards/productivity-totalizers', params); reloadRef.current.productivityOverview = reload; diff --git a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js b/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js index 74d2b54f4f20..96f76541d2db 100644 --- a/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js +++ b/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js @@ -9,7 +9,7 @@ import EditTriggerPage from './EditTriggerPage'; const EditTriggerPageContainer = ({ id, onSave }) => { const t = useTranslation(); - const { value: data, phase: state } = useEndpointData(`livechat/triggers/${id}`); + const { value: data, phase: state } = useEndpointData(`/v1/livechat/triggers/${id}`); if (state === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js b/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js index c4f68a47213c..270f702bd8ef 100644 --- a/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js +++ b/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js @@ -17,7 +17,7 @@ const TriggersTableContainer = ({ reloadRef }) => { phase: state, reload, } = useEndpointData( - 'livechat/triggers', + '/v1/livechat/triggers', useMemo(() => ({ offset: current, count: itemsPerPage }), [current, itemsPerPage]), ); diff --git a/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js b/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js index 970a636a726e..d1e7379e1c3c 100644 --- a/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js +++ b/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js @@ -18,7 +18,7 @@ const reduceSettings = (settings) => const WebhooksPageContainer = () => { const t = useTranslation(); - const { value: data, phase: state, error } = useEndpointData('livechat/integrations.settings'); + const { value: data, phase: state, error } = useEndpointData('/v1/livechat/integrations.settings'); const canViewLivechatWebhooks = usePermission('view-livechat-webhooks'); diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx index 5d354e35da0a..12a5dc517e19 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx @@ -48,7 +48,7 @@ export const useQuickActions = ( const uid = useUserId(); const roomLastMessage = room.lastMessage; - const getVisitorInfo = useEndpoint('GET', 'livechat/visitors.info'); + const getVisitorInfo = useEndpoint('GET', '/v1/livechat/visitors.info'); const getVisitorEmail = useMutableCallback(async () => { if (!visitorRoomId) { @@ -194,7 +194,7 @@ export const useQuickActions = ( [closeChat, closeModal, dispatchToastMessage, rid, t], ); - const onHoldChat = useEndpoint('POST', 'livechat/room.onHold'); + const onHoldChat = useEndpoint('POST', '/v1/livechat/room.onHold'); const handleOnHoldChat = useCallback(async () => { try { diff --git a/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx b/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx index 242dc6018940..fdcb48a4c2dc 100644 --- a/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx +++ b/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx @@ -12,7 +12,7 @@ type ParentRoomWithEndpointDataProps = { const ParentRoomWithEndpointData = ({ rid }: ParentRoomWithEndpointDataProps): ReactElement | null => { const { phase, value } = useEndpointData( - 'rooms.info', + '/v1/rooms.info', useMemo(() => ({ roomId: rid }), [rid]), ); diff --git a/apps/meteor/client/views/room/Header/ParentTeam.tsx b/apps/meteor/client/views/room/Header/ParentTeam.tsx index 4286c99695c3..1eb63ae2c214 100644 --- a/apps/meteor/client/views/room/Header/ParentTeam.tsx +++ b/apps/meteor/client/views/room/Header/ParentTeam.tsx @@ -25,12 +25,12 @@ const ParentTeam = ({ room }: ParentTeamProps): ReactElement | null => { } const { value, phase } = useEndpointData( - 'teams.info', + '/v1/teams.info', useMemo(() => ({ teamId }), [teamId]), ); const { value: userTeams, phase: userTeamsPhase } = useEndpointData( - 'users.listTeams', + '/v1/users.listTeams', useMemo(() => ({ userId }), [userId]), ); diff --git a/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx b/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx index b711e492b969..999e295ab1cc 100644 --- a/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx +++ b/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx @@ -13,7 +13,7 @@ const fields = {}; export const MessageListProvider: FC<{ rid: IRoom['_id']; }> = memo(function MessageListProvider({ rid, ...props }) { - const reactToMessage = useEndpoint('POST', 'chat.react'); + const reactToMessage = useEndpoint('POST', '/v1/chat.react'); const user = useUser(); const uid = user?._id; const username = user?.username; diff --git a/apps/meteor/client/views/room/UserCard/index.js b/apps/meteor/client/views/room/UserCard/index.js index 34701b45af9b..839326f8fefd 100644 --- a/apps/meteor/client/views/room/UserCard/index.js +++ b/apps/meteor/client/views/room/UserCard/index.js @@ -23,7 +23,7 @@ const UserCardWithData = ({ username, onClose, target, open, rid }) => { const query = useMemo(() => ({ username }), [username]); - const { value: data, phase: state } = useEndpointData('users.info', query); + const { value: data, phase: state } = useEndpointData('/v1/users.info', query); ref.current = target; diff --git a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx index f34171b39422..d159bc219e91 100644 --- a/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx +++ b/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx @@ -13,10 +13,10 @@ const AutoTranslateWithData = ({ rid }: { rid: IRoom['_id'] }): ReactElement => const userLanguage = useLanguage(); const subscription = useUserSubscription(rid); const [currentLanguage, setCurrentLanguage] = useState(subscription?.autoTranslateLanguage ?? ''); - const saveSettings = useEndpointActionExperimental('POST', 'autotranslate.saveSettings'); + const saveSettings = useEndpointActionExperimental('POST', '/v1/autotranslate.saveSettings'); const { value: translateData } = useEndpointData( - 'autotranslate.getSupportedLanguages', + '/v1/autotranslate.getSupportedLanguages', useMemo(() => ({ targetLanguage: userLanguage }), [userLanguage]), ); diff --git a/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts b/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts index fadc1684ecf5..5e5837da0960 100644 --- a/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts +++ b/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts @@ -17,7 +17,7 @@ export const useDiscussionsList = ( } => { const discussionsList = useMemo(() => new DiscussionsList(options), [options]); - const getDiscussions = useEndpoint('GET', 'chat.getDiscussions'); + const getDiscussions = useEndpoint('GET', '/v1/chat.getDiscussions'); const fetchMessages = useCallback( async (start, end) => { diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx index a15f7a8bec29..ba29b585698b 100644 --- a/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx +++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx @@ -34,7 +34,7 @@ const FileExport: FC = ({ onCancel, rid }) => { [t], ); - const roomsExport = useEndpoint('POST', 'rooms.export'); + const roomsExport = useEndpoint('POST', '/v1/rooms.export'); const dispatchToastMessage = useToastMessageDispatch(); diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx index d76b10d04cbc..ae7e164d5998 100644 --- a/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx +++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx @@ -94,7 +94,7 @@ const MailExportForm: FC = ({ onCancel, rid }) => { handleToUsers(toUsers.filter((current) => current !== value)); }); - const roomsExport = useEndpoint('POST', 'rooms.export'); + const roomsExport = useEndpoint('POST', '/v1/rooms.export'); const handleSubmit = async (): Promise => { if (toUsers.length === 0 && additionalEmails === '') { diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js index 7486de4e0839..354fb74d9978 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js @@ -224,8 +224,8 @@ function EditChannel({ room, onClickClose, onClickBack }) { const changeArchivation = archived !== !!room.archived; const archiveSelector = room.archived ? 'unarchive' : 'archive'; const archiveMessage = room.archived ? 'Room_has_been_unarchived' : 'Room_has_been_archived'; - const saveAction = useEndpointActionExperimental('POST', 'rooms.saveRoomSettings', t('Room_updated_successfully')); - const archiveAction = useEndpointActionExperimental('POST', 'rooms.changeArchivationState', t(archiveMessage)); + const saveAction = useEndpointActionExperimental('POST', '/v1/rooms.saveRoomSettings', t('Room_updated_successfully')); + const archiveAction = useEndpointActionExperimental('POST', '/v1/rooms.changeArchivationState', t(archiveMessage)); const handleSave = useMutableCallback(async () => { const { joinCodeRequired, hideSysMes, ...data } = saveData.current; diff --git a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx index dbf3f00b4cd3..cacbb05d349d 100644 --- a/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx +++ b/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx @@ -37,7 +37,7 @@ const PruneMessagesWithData = ({ rid, tabBar }: { rid: IRoom['_id']; tabBar: Too const onClickClose = useMutableCallback(() => tabBar?.close()); const closeModal = useCallback(() => setModal(null), [setModal]); const dispatchToastMessage = useToastMessageDispatch(); - const pruneMessagesAction = useEndpoint('POST', 'rooms.cleanHistory'); + const pruneMessagesAction = useEndpoint('POST', '/v1/rooms.cleanHistory'); const [fromDate, setFromDate] = useState(new Date('0001-01-01T00:00:00Z')); const [toDate, setToDate] = useState(new Date('9999-12-31T23:59:59Z')); diff --git a/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts b/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts index 23102f11c601..fe43a86d5e19 100644 --- a/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts +++ b/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts @@ -32,14 +32,14 @@ export const useFilesList = ( }, [filesList, options]); const roomTypes = { - c: 'channels.files', - l: 'channels.files', - v: 'channels.files', - d: 'im.files', - p: 'groups.files', + c: '/v1/channels.files', + l: '/v1/channels.files', + v: '/v1/channels.files', + d: '/v1/im.files', + p: '/v1/groups.files', } as const; - const apiEndPoint = room ? roomTypes[room.t] : 'channels.files'; + const apiEndPoint = room ? roomTypes[room.t] : '/v1/channels.files'; const getFiles = useEndpoint('GET', apiEndPoint); diff --git a/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/WrappedInviteUsers.js b/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/WrappedInviteUsers.js index 66b5ddf2c3cc..9f821423e64d 100644 --- a/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/WrappedInviteUsers.js +++ b/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/WrappedInviteUsers.js @@ -17,7 +17,7 @@ const WrappedInviteUsers = ({ rid, tabBar, onClickBack }) => { const handleEdit = useMutableCallback(() => setEditing(true)); const onClickBackEditing = useMutableCallback(() => setEditing(false)); - const findOrCreateInvite = useEndpoint('POST', 'findOrCreateInvite'); + const findOrCreateInvite = useEndpoint('POST', '/v1/findOrCreateInvite'); const [{ days = 1, maxUses = 0 }, setDayAndMaxUses] = useState({}); diff --git a/apps/meteor/client/views/room/contextualBar/Threads/useThreadsList.ts b/apps/meteor/client/views/room/contextualBar/Threads/useThreadsList.ts index 71454275a0f2..5477e009187f 100644 --- a/apps/meteor/client/views/room/contextualBar/Threads/useThreadsList.ts +++ b/apps/meteor/client/views/room/contextualBar/Threads/useThreadsList.ts @@ -17,7 +17,7 @@ export const useThreadsList = ( } => { const threadsList = useMemo(() => new ThreadsList(options), [options]); - const getThreadsList = useEndpoint('GET', 'chat.getThreadsList'); + const getThreadsList = useEndpoint('GET', '/v1/chat.getThreadsList'); const fetchMessages = useCallback( async (start, end) => { diff --git a/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.js b/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.js index a327dab0ea4c..b902bf13213c 100644 --- a/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.js +++ b/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.js @@ -27,7 +27,7 @@ function UserInfoWithData({ uid, username, tabBar, rid, onClickClose, onClose = phase: state, error, } = useEndpointData( - 'users.info', + '/v1/users.info', useMemo(() => ({ ...(uid && { userId: uid }), ...(username && { username }) }), [uid, username]), ); diff --git a/apps/meteor/client/views/room/hooks/useUserInfoActions.js b/apps/meteor/client/views/room/hooks/useUserInfoActions.js index 9f5f61b91b63..fc6fdabd4a1f 100644 --- a/apps/meteor/client/views/room/hooks/useUserInfoActions.js +++ b/apps/meteor/client/views/room/hooks/useUserInfoActions.js @@ -73,7 +73,7 @@ const WarningModal = ({ text, confirmText, close, confirm, ...props }) => { ); }; - +// TODO: Remove endpoint concatenation export const useUserInfoActions = (user = {}, rid, reload) => { const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); @@ -99,7 +99,7 @@ export const useUserInfoActions = (user = {}, rid, reload) => { const isIgnored = currentSubscription && currentSubscription.ignored && currentSubscription.ignored.indexOf(uid) > -1; const isMuted = getUserIsMuted(room, user, otherUserCanPostReadonly); - const endpointPrefix = room.t === 'p' ? 'groups' : 'channels'; + const endpointPrefix = room.t === 'p' ? '/v1/groups' : '/v1/channels'; const roomDirectives = room && room.t && roomCoordinator.getRoomDirectives(room.t); diff --git a/apps/meteor/client/views/room/threads/ThreadComponent.tsx b/apps/meteor/client/views/room/threads/ThreadComponent.tsx index e8f7a28c5862..ed123346152a 100644 --- a/apps/meteor/client/views/room/threads/ThreadComponent.tsx +++ b/apps/meteor/client/views/room/threads/ThreadComponent.tsx @@ -18,7 +18,7 @@ const subscriptionFields = {}; const useThreadMessage = (tmid: string): IMessage => { const [message, setMessage] = useState(() => Tracker.nonreactive(() => ChatMessage.findOne({ _id: tmid }))); - const getMessage = useEndpoint('GET', 'chat.getMessage'); + const getMessage = useEndpoint('GET', '/v1/chat.getMessage'); const getMessageParsed = useCallback<(params: { msgId: IMessage['_id'] }) => Promise>( async (params) => { const { message } = await getMessage(params); diff --git a/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx b/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx index ac5b00e47771..692854ba5192 100644 --- a/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx +++ b/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx @@ -54,7 +54,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle const defineUsername = useMethod('setUsername'); const loginWithPassword = useLoginWithPassword(); const setForceLogin = useSessionDispatch('forceLogin'); - const createRegistrationIntent = useEndpoint('POST', 'cloud.createRegistrationIntent'); + const createRegistrationIntent = useEndpoint('POST', '/v1/cloud.createRegistrationIntent'); const goToPreviousStep = useCallback(() => setCurrentStep((currentStep) => currentStep - 1), [setCurrentStep]); const goToNextStep = useCallback(() => setCurrentStep((currentStep) => currentStep + 1), [setCurrentStep]); diff --git a/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx b/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx index f54b441dafa8..4d5b73c00888 100644 --- a/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx +++ b/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx @@ -14,7 +14,7 @@ const CloudAccountConfirmation = (): ReactElement => { saveWorkspaceData, } = useSetupWizardContext(); const setShowSetupWizard = useSettingSetValue('Show_Setup_Wizard'); - const cloudConfirmationPoll = useEndpoint('GET', 'cloud.confirmationPoll'); + const cloudConfirmationPoll = useEndpoint('GET', '/v1/cloud.confirmationPoll'); const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); diff --git a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx index 219fab067cb5..422060b888a6 100644 --- a/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx +++ b/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx @@ -21,7 +21,7 @@ const ConvertToChannelModal: FC = ({ onClose, onCanc const t = useTranslation(); const { value, phase } = useEndpointData( - 'teams.listRoomsOfUser', + '/v1/teams.listRoomsOfUser', useMemo(() => ({ teamId, userId, canUserDelete: 'true' }), [teamId, userId]), ); diff --git a/apps/meteor/client/views/teams/CreateTeamModal/CreateTeamModal.tsx b/apps/meteor/client/views/teams/CreateTeamModal/CreateTeamModal.tsx index 00a579640286..c035fa4a7134 100644 --- a/apps/meteor/client/views/teams/CreateTeamModal/CreateTeamModal.tsx +++ b/apps/meteor/client/views/teams/CreateTeamModal/CreateTeamModal.tsx @@ -149,7 +149,7 @@ const useCreateTeamModalState = (onClose: () => void): CreateTeamModalState => { const canCreateTeam = usePermission('create-team'); const isCreateButtonEnabled = canSave && canCreateTeam; - const createTeam = useEndpointActionExperimental('POST', 'teams.create'); + const createTeam = useEndpointActionExperimental('POST', '/v1/teams.create'); const onCreate = useCallback(async () => { const params = { diff --git a/apps/meteor/client/views/teams/CreateTeamModal/UsersInput.tsx b/apps/meteor/client/views/teams/CreateTeamModal/UsersInput.tsx index 339b6565d6ed..13126e2c6838 100644 --- a/apps/meteor/client/views/teams/CreateTeamModal/UsersInput.tsx +++ b/apps/meteor/client/views/teams/CreateTeamModal/UsersInput.tsx @@ -19,7 +19,7 @@ const useUsersAutoComplete = (term: string): AutocompleteData => { }), [term], ); - const { value: data } = useEndpointData('users.autocomplete', params); + const { value: data } = useEndpointData('/v1/users.autocomplete', params); return useMemo(() => { if (!data) { diff --git a/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js b/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js index 5fa51fb5658a..0f06cb132b2c 100644 --- a/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js +++ b/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js @@ -8,7 +8,7 @@ const TeamAutocomplete = (props) => { const [filter, setFilter] = useState(''); const { value: data } = useEndpointData( - 'teams.autocomplete', + '/v1/teams.autocomplete', useMemo(() => ({ name: filter }), [filter]), ); diff --git a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx index 7a0de057239c..156a85e0b93d 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx @@ -22,7 +22,7 @@ type AddExistingModalProps = { const useAddExistingModalState = (onClose: () => void, teamId: string, reload: () => void): AddExistingModalState => { const t = useTranslation(); - const addRoomEndpoint = useEndpoint('POST', 'teams.addRooms'); + const addRoomEndpoint = useEndpoint('POST', '/v1/teams.addRooms'); const dispatchToastMessage = useToastMessageDispatch(); const { values, handlers, hasUnsavedChanges } = useForm({ diff --git a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx index 097a9adac959..3d2f63399760 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx @@ -26,7 +26,7 @@ const useRoomsAutoComplete = ( }), [name], ); - const { value: data } = useEndpointData('rooms.autocomplete.availableForTeams', params); + const { value: data } = useEndpointData('/v1/rooms.autocomplete.availableForTeams', params); const options = useMemo(() => { if (!data) { diff --git a/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts b/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts index 328d2007d628..a141f905b6d2 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts +++ b/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts @@ -22,7 +22,7 @@ export const useTeamsChannelList = ( reload: () => void; loadMoreItems: (start: number, end: number) => void; } => { - const apiEndPoint = useEndpoint('GET', 'teams.listRooms'); + const apiEndPoint = useEndpoint('GET', '/v1/teams.listRooms'); const [teamsChannelList, setTeamsChannelList] = useState(() => new RecordList()); const reload = useCallback(() => setTeamsChannelList(new RecordList()), []); diff --git a/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx b/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx index 3625da876daa..48e9b34a1415 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx +++ b/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx @@ -16,7 +16,7 @@ type DeleteTeamModalWithRoomsProps = { const DeleteTeamModalWithRooms = ({ teamId, onConfirm, onCancel }: DeleteTeamModalWithRoomsProps): ReactElement => { const { value, phase } = useEndpointData( - 'teams.listRooms', + '/v1/teams.listRooms', useMemo(() => ({ teamId }), [teamId]), ); diff --git a/apps/meteor/client/views/teams/contextualBar/info/Leave/index.js b/apps/meteor/client/views/teams/contextualBar/info/Leave/index.js index 90df97b6aa91..c559b2560310 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/Leave/index.js +++ b/apps/meteor/client/views/teams/contextualBar/info/Leave/index.js @@ -14,7 +14,7 @@ const LeaveTeamModalWithRooms = ({ teamId, onCancel, onConfirm }) => { const userId = useUserId(); - const listRooms = useEndpoint('GET', 'teams.listRoomsOfUser'); + const listRooms = useEndpoint('GET', '/v1/teams.listRoomsOfUser'); const { resolve, reject, reset, phase, value } = useAsyncState([]); const fetchData = useCallback(() => { diff --git a/apps/meteor/client/views/teams/contextualBar/info/index.js b/apps/meteor/client/views/teams/contextualBar/info/index.js index 124ecadaf36c..f903923050e8 100644 --- a/apps/meteor/client/views/teams/contextualBar/info/index.js +++ b/apps/meteor/client/views/teams/contextualBar/info/index.js @@ -15,7 +15,7 @@ export default function TeamsInfoWithRooms({ rid }) { const t = useTranslation(); const params = useMemo(() => ({ roomId: rid }), [rid]); - const { phase, value, error } = useEndpointData('rooms.info', params); + const { phase, value, error } = useEndpointData('/v1/rooms.info', params); if (phase === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js index 51e1085a1ce8..25bc54b72baa 100644 --- a/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js +++ b/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js @@ -12,11 +12,11 @@ const initialData = { user: { username: '' } }; const RemoveUsersModal = ({ teamId, userId, onClose, onCancel, onConfirm }) => { const t = useTranslation(); const { value, phase } = useEndpointData( - 'teams.listRoomsOfUser', + '/v1/teams.listRoomsOfUser', useMemo(() => ({ teamId, userId }), [teamId, userId]), ); const userDataFetch = useEndpointData( - 'users.info', + '/v1/users.info', useMemo(() => ({ userId }), [userId]), initialData, ); diff --git a/apps/meteor/definition/externals/meteor/accounts-base.d.ts b/apps/meteor/definition/externals/meteor/accounts-base.d.ts index 8f625c007331..a3f6e3151bba 100644 --- a/apps/meteor/definition/externals/meteor/accounts-base.d.ts +++ b/apps/meteor/definition/externals/meteor/accounts-base.d.ts @@ -17,5 +17,9 @@ declare module 'meteor/accounts-base' { export class LoginCancelledError extends Error { public static readonly numericError: number; } + + export const USER_ID_KEY: string; + + export const LOGIN_TOKEN_KEY: string; } } diff --git a/apps/meteor/definition/externals/meteor/session.d.ts b/apps/meteor/definition/externals/meteor/session.d.ts new file mode 100644 index 000000000000..9b65df618f04 --- /dev/null +++ b/apps/meteor/definition/externals/meteor/session.d.ts @@ -0,0 +1,7 @@ +declare module 'meteor/session' { + // eslint-disable-next-line @typescript-eslint/interface-name-prefix + namespace Session { + function _delete(key: string): void; + export { _delete as delete }; + } +} diff --git a/apps/meteor/ee/app/canned-responses/client/startup/responses.js b/apps/meteor/ee/app/canned-responses/client/startup/responses.js index a703390f3be4..3862de281836 100644 --- a/apps/meteor/ee/app/canned-responses/client/startup/responses.js +++ b/apps/meteor/ee/app/canned-responses/client/startup/responses.js @@ -34,7 +34,7 @@ Meteor.startup(() => { } events[response.type](response); }); - const { responses } = await APIClient.v1.get('canned-responses.get'); + const { responses } = await APIClient.get('/v1/canned-responses.get'); responses.forEach((response) => CannedResponse.insert(response)); c.stop(); } catch (error) { 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 68a3deebf2e3..65b844dea979 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.v1.get('livechat/priorities.list'); + const { priorities } = await APIClient.get('/v1/livechat/priorities.list'); 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 0248764d9127..20e02feaebbc 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.v1.get(`livechat/priorities.getOne?priorityId=${priorityId}`); + priority = await APIClient.get('/v1/livechat/priorities.getOne', { priorityId }); } this.priority.set(priority); diff --git a/apps/meteor/ee/client/audit/AuditPageBase.js b/apps/meteor/ee/client/audit/AuditPageBase.js index 4edb2d6ef96a..ca2540b98488 100644 --- a/apps/meteor/ee/client/audit/AuditPageBase.js +++ b/apps/meteor/ee/client/audit/AuditPageBase.js @@ -43,7 +43,7 @@ export const AuditPageBase = ({ handleType(type); }); - const eventStats = useEndpointAction('POST', 'statistics.telemetry', { + const eventStats = useEndpointAction('POST', '/v1/statistics.telemetry', { params: [{ eventName: 'updateCounter', settingsId: 'Message_Auditing_Apply_Count', timestamp: Date.now() }], }); diff --git a/apps/meteor/ee/client/audit/RoomAutoComplete/RoomAutoComplete.js b/apps/meteor/ee/client/audit/RoomAutoComplete/RoomAutoComplete.js index 47f361a64a30..f690814fed74 100644 --- a/apps/meteor/ee/client/audit/RoomAutoComplete/RoomAutoComplete.js +++ b/apps/meteor/ee/client/audit/RoomAutoComplete/RoomAutoComplete.js @@ -9,7 +9,7 @@ const query = (name = '') => ({ selector: JSON.stringify({ name }) }); const RoomAutoComplete = (props) => { const [filter, setFilter] = useState(''); const { value: data } = useEndpointData( - 'rooms.autocomplete.adminRooms', + '/v1/rooms.autocomplete.adminRooms', useMemo(() => query(filter), [filter]), ); const options = useMemo( diff --git a/apps/meteor/ee/client/audit/VisitorAutoComplete.js b/apps/meteor/ee/client/audit/VisitorAutoComplete.js index 71e0d5f23a2f..1bc9b22de288 100644 --- a/apps/meteor/ee/client/audit/VisitorAutoComplete.js +++ b/apps/meteor/ee/client/audit/VisitorAutoComplete.js @@ -8,7 +8,7 @@ const query = (term = '') => ({ selector: JSON.stringify({ term }) }); const VisitorAutoComplete = (props) => { const [filter, setFilter] = useState(''); const { value: data } = useEndpointData( - 'livechat/visitors.autocomplete', + '/v1/livechat/visitors.autocomplete', useMemo(() => query(filter), [filter]), ); const options = useMemo(() => (data && data.items.map((user) => ({ value: user._id, label: user.name }))) || [], [data]); diff --git a/apps/meteor/ee/client/ecdh.ts b/apps/meteor/ee/client/ecdh.ts index 32861f794e34..1aef97117ec1 100644 --- a/apps/meteor/ee/client/ecdh.ts +++ b/apps/meteor/ee/client/ecdh.ts @@ -65,18 +65,14 @@ async function initEncryptedSession(): Promise { } initEncryptedSession(); - -const _jqueryCall = APIClient._jqueryCall.bind(APIClient); - -APIClient._jqueryCall = async (method, endpoint, params, body, headers = {}): Promise => { +APIClient.use(async (request, next) => { const session = await sessionPromise; if (!session) { - return _jqueryCall(method, endpoint, params, body, headers); + return next(...request); } - - const result = await _jqueryCall(method, endpoint, params, body, headers, 'text'); + const result = await (await next(...request)).text(); const decrypted = await session.decrypt(result); const parsed = JSON.parse(decrypted); return parsed; -}; +}); diff --git a/apps/meteor/ee/client/hooks/useAgentsList.ts b/apps/meteor/ee/client/hooks/useAgentsList.ts index 63e6bdf4fb0a..e7acb5cca3c4 100644 --- a/apps/meteor/ee/client/hooks/useAgentsList.ts +++ b/apps/meteor/ee/client/hooks/useAgentsList.ts @@ -21,7 +21,7 @@ export const useAgentsList = ( const [itemsList, setItemsList] = useState(() => new RecordList()); const reload = useCallback(() => setItemsList(new RecordList()), []); - const getAgents = useEndpoint('GET', 'livechat/users/agent'); + const getAgents = useEndpoint('GET', '/v1/livechat/users/agent'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/ee/client/hooks/useTagsList.ts b/apps/meteor/ee/client/hooks/useTagsList.ts index d2f606b4dc22..2e3452cb46da 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', 'livechat/tags.list'); + const getTags = useEndpoint('GET', '/v1/livechat/tags.list'); useComponentDidUpdate(() => { options && reload(); diff --git a/apps/meteor/ee/client/lib/getFromRestApi.ts b/apps/meteor/ee/client/lib/getFromRestApi.ts index 6fa6800f217f..328264b530e0 100644 --- a/apps/meteor/ee/client/lib/getFromRestApi.ts +++ b/apps/meteor/ee/client/lib/getFromRestApi.ts @@ -1,4 +1,4 @@ -import { Serialized } from '@rocket.chat/core-typings'; +import type { Serialized } from '@rocket.chat/core-typings'; import type { MatchPathPattern, OperationParams, OperationResult, PathFor } from '@rocket.chat/rest-typings'; import { APIClient } from '../../../app/utils/client/lib/RestApiClient'; @@ -10,7 +10,7 @@ export const getFromRestApi = ? void : Serialized>>, ): Promise>>> => { - const response = await APIClient.get(endpoint.replace(/^\/+/, ''), params); + const response = await APIClient.get(endpoint.replace(/^\/+/, '') as TPath, params as any); if (typeof response === 'string') { throw new Error('invalid response data type'); diff --git a/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js b/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js index de454c697a6f..601ebdd0ecd2 100644 --- a/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js +++ b/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js @@ -1,6 +1,6 @@ import { Callout } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { AsyncStatePhase } from '../../../client/hooks/useAsyncState'; import { useEndpointData } from '../../../client/hooks/useEndpointData'; @@ -14,7 +14,17 @@ const BusinessHoursTableContainer = () => { value: data, phase: state, reload, - } = useEndpointData(`livechat/business-hours.list?count=${params.itemsPerPage}&offset=${params.current}&name=${params.text}`); + } = useEndpointData( + '/v1/livechat/business-hours.list', + useMemo( + () => ({ + count: params.itemsPerPage, + offset: params.current, + name: params.text, + }), + [params], + ), + ); if (state === AsyncStatePhase.REJECTED) { return {t('Error')}: error; diff --git a/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js b/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js index 4324016577e9..ecb563bd021a 100644 --- a/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js +++ b/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js @@ -1,6 +1,6 @@ import { css } from '@rocket.chat/css-in-js'; import { Box } from '@rocket.chat/fuselage'; -import React from 'react'; +import React, { useMemo } from 'react'; import UserCard from '../../../client/components/UserCard'; import { UserStatus } from '../../../client/components/UserStatus'; @@ -13,7 +13,10 @@ const wordBreak = css` `; function ContactManagerInfo({ username }) { - const { value: data, phase: state } = useEndpointData(`users.info?username=${username}`); + const { value: data, phase: state } = useEndpointData( + `/v1/users.info`, + useMemo(() => ({ username }), [username]), + ); if (!data && state === AsyncStatePhase.LOADING) { return null; } diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js b/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js index a259cae39916..12fb93f551df 100644 --- a/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js +++ b/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js @@ -7,7 +7,7 @@ import { useEndpointData } from '../../../../client/hooks/useEndpointData'; export const DepartmentBusinessHours = ({ bhId }) => { const t = useTranslation(); const { value: data } = useEndpointData( - 'livechat/business-hour', + '/v1/livechat/business-hour', useMemo(() => ({ _id: bhId, type: 'custom' }), [bhId]), ); diff --git a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx index a8cf541624f2..ef1716dd4213 100644 --- a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx +++ b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx @@ -30,7 +30,7 @@ const CannedResponseEdit: FC<{ }), ); - const saveCannedResponse = useEndpoint('POST', 'canned-responses'); + const saveCannedResponse = useEndpoint('POST', '/v1/canned-responses'); const hasManagerPermission = usePermission('view-all-canned-responses'); const hasMonitorPermission = usePermission('save-department-canned-responses'); diff --git a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx index f2cbbca85145..4625845fea3e 100644 --- a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx +++ b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx @@ -14,7 +14,7 @@ const CannedResponseEditWithData: FC<{ reload: () => void; totalDataReload: () => void; }> = ({ cannedResponseId, reload, totalDataReload }) => { - const { value: data, phase: state, error } = useEndpointData(`canned-responses/${cannedResponseId}`); + const { value: data, phase: state, error } = useEndpointData(`/v1/canned-responses/${cannedResponseId}`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx index 8d70c9db7a52..6ae941d18c5d 100644 --- a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx +++ b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx @@ -19,7 +19,7 @@ const CannedResponseEditWithData: FC<{ totalDataReload: () => void; }> = ({ data, reload, totalDataReload }) => { const departmentId = useMemo(() => data?.cannedResponse?.departmentId, [data]) as string; - const { value: departmentData, phase: state, error } = useEndpointData(`livechat/department/${departmentId}`); + const { value: departmentData, phase: state, error } = useEndpointData(`/v1/livechat/department/${departmentId}`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx index a3e0a8351bed..b0176783716f 100644 --- a/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx +++ b/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx @@ -103,8 +103,8 @@ const CannedResponsesRoute: FC = () => { [t], ); - const { value: data, reload } = useEndpointData('canned-responses', query); - const { value: totalData, phase: totalDataPhase, reload: totalDataReload } = useEndpointData('canned-responses'); + const { value: data, reload } = useEndpointData('/v1/canned-responses', query); + const { value: totalData, phase: totalDataPhase, reload: totalDataReload } = useEndpointData('/v1/canned-responses'); const getTime = useFormatDateAndTime(); diff --git a/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx b/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx index 926ce92f8954..10a494dd2aa4 100644 --- a/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx +++ b/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx @@ -9,7 +9,7 @@ const WrapCreateCannedResponseModal: FC<{ data?: any; reloadCannedList?: any }> const closeModal = useSetModal(); const dispatchToastMessage = useToastMessageDispatch(); - const saveCannedResponse = useEndpoint('POST', 'canned-responses'); + const saveCannedResponse = useEndpoint('POST', '/v1/canned-responses'); const hasManagerPermission = usePermission('view-all-canned-responses'); const hasMonitorPermission = usePermission('save-department-canned-responses'); diff --git a/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts b/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts index f8f99abb8c98..f3ca3b4159cf 100644 --- a/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts +++ b/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react'; export const useCannedResponseFilterOptions = (): string[][] => { const t = useTranslation(); - const getDepartments = useEndpoint('GET', 'livechat/department'); + const getDepartments = useEndpoint('GET', '/v1/livechat/department'); const defaultOptions = useMemo( () => [ diff --git a/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts b/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts index 8d74261be905..4f4e60e0f30a 100644 --- a/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts +++ b/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts @@ -26,8 +26,8 @@ export const useCannedResponseList = ( } }, [cannedList, options]); - const getCannedResponses = useEndpoint('GET', 'canned-responses'); - const getDepartments = useEndpoint('GET', 'livechat/department'); + const getCannedResponses = useEndpoint('GET', '/v1/canned-responses'); + const getDepartments = useEndpoint('GET', '/v1/livechat/department'); const fetchData = useCallback( async (start, end) => { diff --git a/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js b/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js index 093f72d54fd1..d0bf1593fc1c 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('livechat/monitors.list', useQuery(params, sort)); + const { value: data, phase: state, reload } = useEndpointData('/v1/livechat/monitors.list', 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 c92edc2bef1b..2d143cdfd3e6 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('livechat/priorities.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/priorities.list', 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 3159c164064d..c1303c4d5caa 100644 --- a/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js +++ b/apps/meteor/ee/client/omnichannel/priorities/PriorityEditWithData.js @@ -9,7 +9,7 @@ import PriorityEdit from './PriorityEdit'; function PriorityEditWithData({ priorityId, reload }) { const query = useMemo(() => ({ priorityId }), [priorityId]); - const { value: data, phase: state, error } = useEndpointData('livechat/priorities.getOne', query); + const { value: data, phase: state, error } = useEndpointData('/v1/livechat/priorities.getOne', query); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js b/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js index 2b76ca3fc93d..5b53f7f20ed8 100644 --- a/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js +++ b/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js @@ -10,7 +10,7 @@ import TagEditWithDepartmentData from './TagEditWithDepartmentData'; function TagEditWithData({ tagId, reload, title }) { const query = useMemo(() => ({ tagId }), [tagId]); - const { value: data, phase: state, error } = useEndpointData('livechat/tags.getOne', query); + const { value: data, phase: state, error } = useEndpointData('/v1/livechat/tags.getOne', query); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx b/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx index f8d231f95245..526c64cf0ce9 100644 --- a/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx +++ b/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx @@ -23,7 +23,7 @@ function TagEditWithDepartmentData({ data, title, ...props }: TagEditWithDepartm phase: currentDepartmentsState, error: currentDepartmentsError, } = useEndpointData( - 'livechat/department.listByIds', + '/v1/livechat/department.listByIds', useMemo(() => ({ ids: data?.departments ? data.departments : [] }), [data]), ); diff --git a/apps/meteor/ee/client/omnichannel/tags/TagNew.js b/apps/meteor/ee/client/omnichannel/tags/TagNew.js index 3ba4e7a9fb8b..d19f355bfad1 100644 --- a/apps/meteor/ee/client/omnichannel/tags/TagNew.js +++ b/apps/meteor/ee/client/omnichannel/tags/TagNew.js @@ -14,7 +14,7 @@ function TagNew({ reload }) { value: availableDepartments, phase: availableDepartmentsState, error: availableDepartmentsError, - } = useEndpointData('livechat/department'); + } = useEndpointData('/v1/livechat/department'); if (availableDepartmentsState === AsyncStatePhase.LOADING) { return ; diff --git a/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js b/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js index 1626fddc471a..80b8e8e06204 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('livechat/tags.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/tags.list', 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 9a374ddb811d..af33ccc139d1 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx +++ b/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx @@ -14,15 +14,19 @@ const UnitEditWithData: FC<{ }> = function UnitEditWithData({ unitId, reload, title }) { const query = useMemo(() => ({ unitId }), [unitId]); - const { value: data, phase: state, error } = useEndpointData('livechat/units.getOne', query); + const { value: data, phase: state, error } = useEndpointData('/v1/livechat/units.getOne', query); - const { value: unitMonitors, phase: unitMonitorsState, error: unitMonitorsError } = useEndpointData('livechat/unitMonitors.list', query); + const { + value: unitMonitors, + phase: unitMonitorsState, + error: unitMonitorsError, + } = useEndpointData('/v1/livechat/unitMonitors.list', query); const { value: unitDepartments, phase: unitDepartmentsState, error: unitDepartmentsError, - } = useEndpointData(`livechat/departments.by-unit/${unitId}`); + } = useEndpointData(`/v1/livechat/departments.by-unit/${unitId}`); const t = useTranslation(); diff --git a/apps/meteor/ee/client/omnichannel/units/UnitNew.js b/apps/meteor/ee/client/omnichannel/units/UnitNew.js index bb58fa036af2..1f93c587bb68 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitNew.js +++ b/apps/meteor/ee/client/omnichannel/units/UnitNew.js @@ -14,12 +14,12 @@ function UnitNew({ reload, allUnits }) { value: availableDepartments, phase: availableDepartmentsState, error: availableDepartmentsError, - } = useEndpointData('livechat/department'); + } = useEndpointData('/v1/livechat/department'); const { value: availableMonitors, phase: availableMonitorsState, error: availableMonitorsError, - } = useEndpointData('livechat/monitors.list'); + } = useEndpointData('/v1/livechat/monitors.list'); 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 816e0cd50327..5362af00f8f0 100644 --- a/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js +++ b/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js @@ -59,7 +59,7 @@ function UnitsRoute() { }), ); - const { value: data = {}, reload } = useEndpointData('livechat/units.list', query); + const { value: data = {}, reload } = useEndpointData('/v1/livechat/units.list', query); const header = useMemo( () => diff --git a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx index e6bca507779a..ee53c8c364d2 100644 --- a/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx +++ b/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx @@ -24,7 +24,7 @@ const EngagementDashboardRoute = (): ReactElement | null => { } }, [routeName, engagementDashboardRoute, tab]); - const eventStats = useEndpointAction('POST', 'statistics.telemetry', { + const eventStats = useEndpointAction('POST', '/v1/statistics.telemetry', { params: [{ eventName: 'updateCounter', settingsId: 'Engagement_Dashboard_Load_Count' }], }); diff --git a/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts b/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts index 338208ce95b8..99290f70d034 100644 --- a/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts +++ b/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts @@ -7,7 +7,7 @@ export const useSeatsCap = (): reload: () => void; } | undefined => { - const { value, reload } = useEndpointData('licenses.maxActiveUsers'); + const { value, reload } = useEndpointData('/v1/licenses.maxActiveUsers'); if (!value) { return undefined; diff --git a/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts b/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts index baac71fb1c14..3eff58121555 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 { - 'livechat/business-hours.list': { + '/v1/livechat/business-hours.list': { 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 616d404b18b4..5f01ca96b3e0 100644 --- a/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts +++ b/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts @@ -4,22 +4,22 @@ import type { PaginatedResult } from '@rocket.chat/rest-typings'; declare module '@rocket.chat/rest-typings' { // eslint-disable-next-line @typescript-eslint/interface-name-prefix interface Endpoints { - 'livechat/units.list': { + '/v1/livechat/units.list': { GET: (params: { text: string }) => PaginatedResult & { units: IOmnichannelBusinessUnit[]; }; }; - 'livechat/units.getOne': { + '/v1/livechat/units.getOne': { GET: (params: { unitId: string }) => IOmnichannelBusinessUnit; }; - 'livechat/unitMonitors.list': { + '/v1/livechat/unitMonitors.list': { GET: (params: { unitId: string }) => { monitors: ILivechatMonitor[] }; }; - 'livechat/units': { + '/v1/livechat/units': { GET: (params: { text: string }) => PaginatedResult & { units: IOmnichannelBusinessUnit[] }; POST: (params: { unitData: string; unitMonitors: string; unitDepartments: string }) => IOmnichannelBusinessUnit; }; - 'livechat/units/:id': { + '/v1/livechat/units/:id': { GET: () => IOmnichannelBusinessUnit; POST: (params: { unitData: string; unitMonitors: string; unitDepartments: string }) => IOmnichannelBusinessUnit; DELETE: () => number; diff --git a/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts b/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts index 13a6ec1d2224..e909aac72c95 100644 --- a/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts +++ b/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts @@ -4,7 +4,7 @@ import type { PaginatedResult, PaginatedRequest } from '@rocket.chat/rest-typing declare module '@rocket.chat/rest-typings' { // eslint-disable-next-line @typescript-eslint/interface-name-prefix interface Endpoints { - 'canned-responses': { + '/v1/canned-responses': { GET: ( params: PaginatedRequest<{ shortcut?: string; @@ -27,7 +27,7 @@ declare module '@rocket.chat/rest-typings' { }) => void; DELETE: (params: { _id: IOmnichannelCannedResponse['_id'] }) => void; }; - 'canned-responses/:_id': { + '/v1/canned-responses/:_id': { GET: () => { cannedResponse: IOmnichannelCannedResponse; }; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index 993111666eba..e6df68426608 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -123,6 +123,7 @@ "@types/semver": "^7.3.9", "@types/sharp": "^0.30.2", "@types/sinon": "^10.0.11", + "@types/strict-uri-encode": "^2", "@types/string-strip-html": "^5.0.0", "@types/supertest": "^2.0.11", "@types/ua-parser-js": "^0.7.36", @@ -185,6 +186,7 @@ "@nivo/heatmap": "0.73.0", "@nivo/line": "0.62.0", "@nivo/pie": "0.73.0", + "@rocket.chat/api-client": "workspace:^", "@rocket.chat/apps-engine": "1.32.0", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.12", @@ -333,6 +335,7 @@ "sodium-plus": "^0.9.0", "speakeasy": "^2.0.0", "stream-buffers": "^3.0.2", + "strict-uri-encode": "^2.0.0", "string-strip-html": "^7.0.3", "tar-stream": "^1.6.2", "tinykeys": "^1.4.0", diff --git a/packages/api-client/.eslintrc b/packages/api-client/.eslintrc new file mode 100644 index 000000000000..a83aeda48e66 --- /dev/null +++ b/packages/api-client/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": ["@rocket.chat/eslint-config"], + "ignorePatterns": ["**/dist"] +} diff --git a/packages/api-client/package.json b/packages/api-client/package.json new file mode 100644 index 000000000000..2100aaa8b0e1 --- /dev/null +++ b/packages/api-client/package.json @@ -0,0 +1,32 @@ +{ + "name": "@rocket.chat/api-client", + "version": "0.0.1", + "private": true, + "devDependencies": { + "@types/jest": "^27.4.1", + "@types/strict-uri-encode": "^2", + "eslint": "^8.12.0", + "jest": "^27.5.1", + "ts-jest": "^27.1.4", + "typescript": "~4.3.5" + }, + "scripts": { + "lint": "eslint --ext .js,.jsx,.ts,.tsx .", + "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix", + "jest": "jest", + "build": "tsc -p tsconfig.json" + }, + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "files": [ + "/dist" + ], + "dependencies": { + "@rocket.chat/core-typings": "workspace:^", + "@rocket.chat/rest-typings": "workspace:^", + "filter-obj": "^3.0.0", + "query-string": "^7.1.1", + "split-on-first": "^3.0.0", + "strict-uri-encode": "^2.0.0" + } +} diff --git a/packages/api-client/src/RestClientInterface.ts b/packages/api-client/src/RestClientInterface.ts new file mode 100644 index 000000000000..d9e3dd9ca373 --- /dev/null +++ b/packages/api-client/src/RestClientInterface.ts @@ -0,0 +1,61 @@ +import type { Serialized } from '@rocket.chat/core-typings/dist'; +import type { MatchPathPattern, OperationParams, OperationResult, PathFor } from '@rocket.chat/rest-typings'; + +type Next any> = (...args: Parameters) => ReturnType; + +export type Middleware any> = (context: Parameters, next: Next) => ReturnType; + +// eslint-disable-next-line @typescript-eslint/interface-name-prefix +export interface RestClientInterface { + get>( + endpoint: TPath, + params: void extends OperationParams<'GET', MatchPathPattern> ? never : OperationParams<'GET', MatchPathPattern>, + options?: Omit, + ): Promise>>>; + + get>( + endpoint: TPath, + params?: void extends OperationParams<'GET', MatchPathPattern> ? undefined : never, + options?: Omit, + ): Promise>>>; + + post>( + endpoint: TPath, + params: void extends OperationParams<'POST', MatchPathPattern> ? void : OperationParams<'POST', MatchPathPattern>, + options?: Omit, + ): Promise>>>; + + upload>( + endpoint: TPath, + params: void extends OperationParams<'POST', MatchPathPattern> ? void : OperationParams<'POST', MatchPathPattern>, + events?: { + load?: (event: ProgressEvent) => void; + progress?: (event: ProgressEvent) => void; + abort?: (event: ProgressEvent) => void; + error?: (event: ProgressEvent) => void; + }, + ): XMLHttpRequest; + + put>( + endpoint: TPath, + params: void extends OperationParams<'PUT', MatchPathPattern> ? void : OperationParams<'PUT', MatchPathPattern>, + options?: Omit, + ): Promise>>>; + + delete>( + endpoint: TPath, + params: void extends OperationParams<'DELETE', MatchPathPattern> ? void : OperationParams<'DELETE', MatchPathPattern>, + options?: Omit, + ): Promise>>>; + getCredentials(): + | { + 'X-User-Id': string; + 'X-Auth-Token': string; + } + | undefined; + setCredentials(credentials: undefined | { 'X-User-Id': string; 'X-Auth-Token': string }): void; + + use(middleware: Middleware): void; + + send(endpoint: string, method: string, options: Omit): Promise; +} diff --git a/packages/api-client/src/index.ts b/packages/api-client/src/index.ts new file mode 100644 index 000000000000..90905a7812b5 --- /dev/null +++ b/packages/api-client/src/index.ts @@ -0,0 +1,215 @@ +import { stringify } from 'query-string'; + +import type { Serialized } from '../../core-typings/dist'; +import type { MatchPathPattern, OperationParams, OperationResult, PathFor } from '../../rest-typings/dist'; +import type { Middleware, RestClientInterface } from './RestClientInterface'; + +export { RestClientInterface }; + +const pipe = + any>(fn: T) => + (...args: Parameters): ReturnType => + fn(...args); + +function buildFormData(data?: Record | void, formData = new FormData(), parentKey?: string): FormData { + if (data instanceof FormData) { + return data; + } + if (!data) { + return formData; + } + + if (typeof data === 'object' && !(data instanceof File)) { + Object.keys(data).forEach((key) => { + buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key); + }); + } else { + data && parentKey && formData.append(parentKey, data); + } + return formData; +} + +const checkIfIsFormData = (data: any = {}): boolean => { + if (data instanceof FormData) { + return true; + } + return Object.values(data).some((value) => { + if (typeof value === 'object' && !(value instanceof File)) { + return checkIfIsFormData(value); + } + return value instanceof File; + }); +}; + +export class RestClient implements RestClientInterface { + private readonly baseUrl: string; + + private headers: Record = {}; + + private credentials: + | { + 'X-User-Id': string; + 'X-Auth-Token': string; + } + | undefined; + + constructor({ + baseUrl, + credentials, + headers = {}, + }: { + baseUrl: string; + credentials?: { + 'X-User-Id': string; + 'X-Auth-Token': string; + }; + headers?: Record; + }) { + this.baseUrl = `${baseUrl}/api`; + this.setCredentials(credentials); + this.headers = headers; + } + + getCredentials(): ReturnType { + return this.credentials; + } + + setCredentials: RestClientInterface['setCredentials'] = (credentials) => { + this.credentials = credentials; + }; + + get>( + endpoint: TPath, + params: void extends OperationParams<'GET', MatchPathPattern> ? never : OperationParams<'GET', MatchPathPattern>, + options?: Omit, + ): Promise>>>; + + get>( + endpoint: TPath, + params?: void extends OperationParams<'GET', MatchPathPattern> ? undefined : never, + options?: Omit, + ): Promise>>>; + + get>( + endpoint: TPath, + params?: OperationParams<'GET', MatchPathPattern>, + options?: Omit, + ): Promise>>> { + if (/\?/.test(endpoint)) { + // throw new Error('Endpoint cannot contain query string'); + console.warn('Endpoint cannot contain query string', endpoint); + } + const queryParams = this.getParams(params); + return this.send(`${endpoint}${queryParams ? `?${queryParams}` : ''}`, 'GET', options).then(function (response) { + return response.json(); + }); + } + + post: RestClientInterface['post'] = (endpoint, params, { headers, ...options } = {}) => { + const isFormData = checkIfIsFormData(params); + + return this.send(endpoint, 'POST', { + body: isFormData ? buildFormData(params) : JSON.stringify(params), + + headers: { + Accept: 'application/json', + ...(!isFormData && { 'Content-Type': 'application/json' }), + ...headers, + }, + + ...options, + }).then(function (response) { + return response.json(); + }); + }; + + put: RestClientInterface['put'] = (endpoint, params, { headers, ...options } = {}) => { + const isFormData = checkIfIsFormData(params); + return this.send(endpoint, 'PUT', { + body: isFormData ? buildFormData(params) : JSON.stringify(params), + + headers: { + Accept: 'application/json', + ...(!isFormData && { 'Content-Type': 'application/json' }), + ...headers, + }, + + ...options, + }).then(function (response) { + return response.json(); + }); + }; + + delete: RestClientInterface['delete'] = (endpoint, params, options) => { + return this.send(endpoint, 'DELETE', options).then(function (response) { + return response.json(); + }); + }; + + protected getCredentialsAsHeaders(): Record { + const credentials = this.getCredentials(); + return credentials + ? { + 'X-User-Id': credentials['X-User-Id'], + 'X-Auth-Token': credentials['X-Auth-Token'], + } + : {}; + } + + send(endpoint: string, method: string, { headers, ...options }: Omit = {}): Promise { + return fetch(`${this.baseUrl}${`/${endpoint}`.replace(/\/+/, '/')}`, { + ...options, + headers: { ...this.getCredentialsAsHeaders(), ...this.headers, ...headers }, + method, + }); + } + + protected getParams(data: Record | void): string { + return data ? stringify(data, { arrayFormat: 'bracket' }) : ''; + } + + upload: RestClientInterface['upload'] = (endpoint, params, events) => { + if (!params) { + throw new Error('Missing params'); + } + const xhr = new XMLHttpRequest(); + const data = new FormData(); + + Object.entries(params as any).forEach(([key, value]) => { + if (value instanceof File) { + data.append(key, value, value.name); + return; + } + value && data.append(key, value as any); + }); + + xhr.open('POST', `${this.baseUrl}${`/${endpoint}`.replace(/\/+/, '/')}`, true); + Object.entries(this.getCredentialsAsHeaders()).forEach(([key, value]) => { + xhr.setRequestHeader(key, value); + }); + + if (events?.load) { + xhr.upload.addEventListener('load', events.load); + } + if (events?.progress) { + xhr.upload.addEventListener('progress', events.progress); + } + if (events?.error) { + xhr.addEventListener('error', events.error); + } + if (events?.abort) { + xhr.addEventListener('abort', events.abort); + } + + xhr.send(data); + + return xhr; + }; + + use(middleware: Middleware): void { + const fn = this.send.bind(this); + this.send = function (this: RestClient, ...context: Parameters): ReturnType { + return middleware(context, pipe(fn)); + } as RestClientInterface['send']; + } +} diff --git a/packages/api-client/tsconfig.json b/packages/api-client/tsconfig.json new file mode 100644 index 000000000000..455edb8149c4 --- /dev/null +++ b/packages/api-client/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*"] +} diff --git a/packages/core-typings/src/ICustomEmojiDescriptor.ts b/packages/core-typings/src/ICustomEmojiDescriptor.ts index 1fa3a97cee62..f04a19d42eab 100644 --- a/packages/core-typings/src/ICustomEmojiDescriptor.ts +++ b/packages/core-typings/src/ICustomEmojiDescriptor.ts @@ -2,6 +2,6 @@ import type { IRocketChatRecord } from './IRocketChatRecord'; export interface ICustomEmojiDescriptor extends IRocketChatRecord { name: string; - aliases: string[]; + aliases: string; extension: string; } diff --git a/packages/core-typings/src/IEmojiCustom.ts b/packages/core-typings/src/IEmojiCustom.ts index 64c2706fbb2e..98bbc9121d47 100644 --- a/packages/core-typings/src/IEmojiCustom.ts +++ b/packages/core-typings/src/IEmojiCustom.ts @@ -2,6 +2,6 @@ import type { IRocketChatRecord } from './IRocketChatRecord'; export interface IEmojiCustom extends IRocketChatRecord { name: string; - aliases: string; + aliases: string[]; extension: string; } diff --git a/packages/rest-typings/src/apps/index.ts b/packages/rest-typings/src/apps/index.ts index 26de92caaae4..50b9160d23e2 100644 --- a/packages/rest-typings/src/apps/index.ts +++ b/packages/rest-typings/src/apps/index.ts @@ -1,11 +1,21 @@ import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api'; import type { IExternalComponent } from '@rocket.chat/apps-engine/definition/externalComponent'; +import type { IUIActionButton } from '@rocket.chat/apps-engine/definition/ui'; import type { ISetting, AppScreenshot, App } from '@rocket.chat/core-typings'; export type AppsEndpoints = { '/apps/externalComponents': { GET: () => { externalComponents: IExternalComponent[] }; }; + + '/apps/actionButtons': { + GET: () => IUIActionButton[]; + }; + + '/apps/public/:appId/get-sidebar-icon': { + GET: (params: { icon: string }) => unknown; + }; + '/apps/:id/settings': { GET: () => { [key: string]: ISetting; @@ -23,6 +33,7 @@ export type AppsEndpoints = { apis: IApiEndpointMetadata[]; }; }; + '/apps/:id': { GET: (params: { marketplace?: 'true' | 'false'; update?: 'true' | 'false'; appVersion: string }) => { app: App; diff --git a/packages/rest-typings/src/index.ts b/packages/rest-typings/src/index.ts index 5c2b9fa56e4d..e50250dbb060 100644 --- a/packages/rest-typings/src/index.ts +++ b/packages/rest-typings/src/index.ts @@ -35,14 +35,17 @@ import type { VoipEndpoints } from './v1/voip'; import type { EmailInboxEndpoints } from './v1/email-inbox'; import type { WebdavEndpoints } from './v1/webdav'; import type { OAuthAppsEndpoint } from './v1/oauthapps'; -import type { SubscriptionsEndpoints } from './v1/subscriptionsEndpoints'; import type { CommandsEndpoints } from './v1/commands'; +import type { MeEndpoints } from './v1/me'; +import type { SubscriptionsEndpoints } from './v1/subscriptionsEndpoints'; // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/interface-name-prefix export interface Endpoints extends ChannelsEndpoints, + MeEndpoints, BannersEndpoints, ChatEndpoints, + CommandsEndpoints, CloudEndpoints, CommandsEndpoints, CustomUserStatusEndpoints, @@ -135,7 +138,7 @@ export type UrlParams = string extends T ? { [k in Param | keyof UrlParams]: string } : T extends `${infer _Start}:${infer Param}` ? { [k in Param]: string } - : {}; + : undefined | {}; export type MethodOf = TPathPattern extends any ? keyof Endpoints[TPathPattern] : never; @@ -172,3 +175,4 @@ export * from './v1/oauthapps'; export * from './helpers/PaginatedRequest'; export * from './helpers/PaginatedResult'; export * from './helpers/ReplacePlaceholders'; +export * from './v1/emojiCustom'; diff --git a/packages/rest-typings/src/v1/autoTranslate.ts b/packages/rest-typings/src/v1/autoTranslate.ts index 9f265c9aa6d4..b9710609501f 100644 --- a/packages/rest-typings/src/v1/autoTranslate.ts +++ b/packages/rest-typings/src/v1/autoTranslate.ts @@ -1,13 +1,13 @@ import type { ISupportedLanguage } from '@rocket.chat/core-typings'; export type AutoTranslateEndpoints = { - 'autotranslate.getSupportedLanguages': { + '/v1/autotranslate.getSupportedLanguages': { GET: (params: { targetLanguage: string }) => { languages: ISupportedLanguage[] }; }; - 'autotranslate.saveSettings': { + '/v1/autotranslate.saveSettings': { POST: (params: { roomId: string; field: string; value: boolean; defaultLanguage?: string }) => void; }; - 'autotranslate.translateMessage': { + '/v1/autotranslate.translateMessage': { POST: (params: { messageId: string; targetLanguage?: string }) => void; }; }; diff --git a/packages/rest-typings/src/v1/banners.ts b/packages/rest-typings/src/v1/banners.ts index 7045e2383a14..03ee39961a9a 100644 --- a/packages/rest-typings/src/v1/banners.ts +++ b/packages/rest-typings/src/v1/banners.ts @@ -80,25 +80,25 @@ export const isBannersDismissProps = ajv.compile(BannersDismissS export type BannersEndpoints = { /* @deprecated */ - 'banners.getNew': { + '/v1/banners.getNew': { GET: (params: BannersGetNew) => { banners: IBanner[]; }; }; - 'banners/:id': { + '/v1/banners/:id': { GET: (params: BannersId) => { banners: IBanner[]; }; }; - 'banners': { + '/v1/banners': { GET: (params: Banners) => { banners: IBanner[]; }; }; - 'banners.dismiss': { + '/v1/banners.dismiss': { POST: (params: BannersDismiss) => void; }; }; diff --git a/packages/rest-typings/src/v1/channels/channels.ts b/packages/rest-typings/src/v1/channels/channels.ts index 171f48703c10..dd3361172244 100644 --- a/packages/rest-typings/src/v1/channels/channels.ts +++ b/packages/rest-typings/src/v1/channels/channels.ts @@ -12,17 +12,17 @@ import type { ChannelsSetAnnouncementProps } from './ChannelsSetAnnouncementProp import type { ChannelsUnarchiveProps } from './ChannelsUnarchiveProps'; export type ChannelsEndpoints = { - 'channels.files': { + '/v1/channels.files': { GET: (params: PaginatedRequest<{ roomId: IRoom['_id'] }>) => PaginatedResult<{ files: IUpload[]; }>; }; - 'channels.members': { + '/v1/channels.members': { GET: (params: PaginatedRequest<{ roomId: IRoom['_id']; filter?: string; status?: string[] }>) => PaginatedResult<{ members: IUser[]; }>; }; - 'channels.history': { + '/v1/channels.history': { GET: ( params: PaginatedRequest<{ roomId: string; @@ -35,13 +35,13 @@ export type ChannelsEndpoints = { messages: IMessage[]; }>; }; - 'channels.archive': { + '/v1/channels.archive': { POST: (params: ChannelsArchiveProps) => void; }; - 'channels.unarchive': { + '/v1/channels.unarchive': { POST: (params: ChannelsUnarchiveProps) => void; }; - 'channels.create': { + '/v1/channels.create': { POST: (params: { name: string; members: string[]; @@ -55,15 +55,15 @@ export type ChannelsEndpoints = { group: Partial; }; }; - 'channels.convertToTeam': { + '/v1/channels.convertToTeam': { POST: (params: { channelId: string; channelName: string }) => { team: ITeam; }; }; - 'channels.info': { + '/v1/channels.info': { GET: (params: { roomId: string }) => { channel: IRoom }; }; - 'channels.counters': { + '/v1/channels.counters': { GET: (params: { roomId: string }) => { joined: boolean; members: number; @@ -74,76 +74,76 @@ export type ChannelsEndpoints = { userMentions: number; }; }; - 'channels.join': { + '/v1/channels.join': { POST: (params: { roomId: string; joinCode?: string }) => { channel: IRoom; }; }; - 'channels.close': { + '/v1/channels.close': { POST: (params: { roomId: string }) => {}; }; - 'channels.kick': { + '/v1/channels.kick': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.delete': { + '/v1/channels.delete': { POST: (params: ChannelsDeleteProps) => void; }; - 'channels.leave': { + '/v1/channels.leave': { POST: (params: { roomId: string }) => {}; }; - 'channels.addModerator': { + '/v1/channels.addModerator': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.removeModerator': { + '/v1/channels.removeModerator': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.addOwner': { + '/v1/channels.addOwner': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.removeOwner': { + '/v1/channels.removeOwner': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.addLeader': { + '/v1/channels.addLeader': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.removeLeader': { + '/v1/channels.removeLeader': { POST: (params: { roomId: string; userId: string }) => {}; }; - 'channels.roles': { + '/v1/channels.roles': { GET: (params: { roomId: string }) => { roles: IGetRoomRoles[] }; }; - 'channels.messages': { + '/v1/channels.messages': { GET: (params: ChannelsMessagesProps) => PaginatedResult<{ messages: IMessage[]; }>; }; - 'channels.open': { + '/v1/channels.open': { POST: (params: ChannelsOpenProps) => void; }; - 'channels.setReadOnly': { + '/v1/channels.setReadOnly': { POST: (params: { roomId: string; readOnly: boolean }) => { channel: IRoom; }; }; - 'channels.addAll': { + '/v1/channels.addAll': { POST: (params: ChannelsAddAllProps) => { channel: IRoom; }; }; - 'channels.anonymousread': { + '/v1/channels.anonymousread': { GET: (params: PaginatedRequest<{ roomId: string } | { roomName: string }>) => PaginatedResult<{ messages: IMessage[]; }>; }; - 'channels.setAnnouncement': { + '/v1/channels.setAnnouncement': { POST: (params: ChannelsSetAnnouncementProps) => {}; }; - 'channels.getAllUserMentionsByChannel': { + '/v1/channels.getAllUserMentionsByChannel': { GET: (params: ChannelsGetAllUserMentionsByChannelProps) => PaginatedResult<{ mentions: IUser[]; }>; }; - 'channels.moderators': { + '/v1/channels.moderators': { GET: (params: { roomId: string }) => { moderators: Pick[] }; }; }; diff --git a/packages/rest-typings/src/v1/chat.ts b/packages/rest-typings/src/v1/chat.ts index 1754c302f5a9..07024e9a4138 100644 --- a/packages/rest-typings/src/v1/chat.ts +++ b/packages/rest-typings/src/v1/chat.ts @@ -387,45 +387,45 @@ const ChatGetMessageReadReceiptsSchema = { export const isChatGetMessageReadReceiptsProps = ajv.compile(ChatGetMessageReadReceiptsSchema); export type ChatEndpoints = { - 'chat.getMessage': { + '/v1/chat.getMessage': { GET: (params: ChatGetMessage) => { message: IMessage; }; }; - 'chat.followMessage': { + '/v1/chat.followMessage': { POST: (params: ChatFollowMessage) => void; }; - 'chat.unfollowMessage': { + '/v1/chat.unfollowMessage': { POST: (params: ChatUnfollowMessage) => void; }; - 'chat.starMessage': { + '/v1/chat.starMessage': { POST: (params: ChatStarMessage) => void; }; - 'chat.unStarMessage': { + '/v1/chat.unStarMessage': { POST: (params: ChatUnstarMessage) => void; }; - 'chat.pinMessage': { + '/v1/chat.pinMessage': { POST: (params: ChatPinMessage) => void; }; - 'chat.unPinMessage': { + '/v1/chat.unPinMessage': { POST: (params: ChatUnpinMessage) => void; }; - 'chat.reportMessage': { + '/v1/chat.reportMessage': { POST: (params: ChatReportMessage) => void; }; - 'chat.getDiscussions': { + '/v1/chat.getDiscussions': { GET: (params: ChatGetDiscussions) => { messages: IMessage[]; total: number; }; }; - 'chat.getThreadsList': { + '/v1/chat.getThreadsList': { GET: (params: ChatGetThreadsList) => { threads: IMessage[]; total: number; }; }; - 'chat.syncThreadsList': { + '/v1/chat.syncThreadsList': { GET: (params: ChatSyncThreadsList) => { threads: { update: IMessage[]; @@ -433,30 +433,30 @@ export type ChatEndpoints = { }; }; }; - 'chat.delete': { + '/v1/chat.delete': { POST: (params: ChatDelete) => { _id: string; ts: string; message: Pick; }; }; - 'chat.react': { + '/v1/chat.react': { POST: (params: ChatReact) => void; }; - 'chat.ignoreUser': { + '/v1/chat.ignoreUser': { GET: (params: ChatIgnoreUser) => {}; }; - 'chat.search': { + '/v1/chat.search': { GET: (params: ChatSearch) => { messages: IMessage[]; }; }; - 'chat.update': { + '/v1/chat.update': { POST: (params: ChatUpdate) => { messages: IMessage; }; }; - 'chat.getMessageReadReceipts': { + '/v1/chat.getMessageReadReceipts': { GET: (params: ChatGetMessageReadReceipts) => { receipts: ReadReceipt[] }; }; }; diff --git a/packages/rest-typings/src/v1/cloud.ts b/packages/rest-typings/src/v1/cloud.ts index e27289566711..1e265f0025d9 100644 --- a/packages/rest-typings/src/v1/cloud.ts +++ b/packages/rest-typings/src/v1/cloud.ts @@ -67,20 +67,20 @@ const CloudConfirmationPollSchema = { export const isCloudConfirmationPollProps = ajv.compile(CloudConfirmationPollSchema); export type CloudEndpoints = { - 'cloud.manualRegister': { + '/v1/cloud.manualRegister': { POST: (params: CloudManualRegister) => void; }; - 'cloud.createRegistrationIntent': { + '/v1/cloud.createRegistrationIntent': { POST: (params: CloudCreateRegistrationIntent) => { intentData: CloudRegistrationIntentData; }; }; - 'cloud.confirmationPoll': { + '/v1/cloud.confirmationPoll': { GET: (params: CloudConfirmationPoll) => { pollData: CloudConfirmationPollData; }; }; - 'cloud.registrationStatus': { + '/v1/cloud.registrationStatus': { GET: (params: void) => { registrationStatus: CloudRegistrationStatus }; }; }; diff --git a/packages/rest-typings/src/v1/commands.ts b/packages/rest-typings/src/v1/commands.ts index aec14e57c669..97d93f161baa 100644 --- a/packages/rest-typings/src/v1/commands.ts +++ b/packages/rest-typings/src/v1/commands.ts @@ -3,12 +3,12 @@ import type { PaginatedRequest } from '../helpers/PaginatedRequest'; import type { PaginatedResult } from '../helpers/PaginatedResult'; export type CommandsEndpoints = { - 'commands.get': { + '/v1/commands.get': { GET: (params: { command: string }) => { command: Pick; }; }; - 'commands.list': { + '/v1/commands.list': { GET: ( params: PaginatedRequest<{ fields?: string; @@ -17,12 +17,12 @@ export type CommandsEndpoints = { commands: Pick[]; }>; }; - 'commands.run': { + '/v1/commands.run': { POST: (params: { command: string; params?: string; roomId: string; tmid?: string; triggerId: string }) => { result: unknown; }; }; - 'commands.preview': { + '/v1/commands.preview': { GET: (params: { command: string; params?: string; roomId: string }) => { preview: SlashCommandPreviews; }; diff --git a/packages/rest-typings/src/v1/customSounds.ts b/packages/rest-typings/src/v1/customSounds.ts index 84efd66ecb60..0380d954348f 100644 --- a/packages/rest-typings/src/v1/customSounds.ts +++ b/packages/rest-typings/src/v1/customSounds.ts @@ -36,7 +36,7 @@ const CustomSoundsListSchema = { export const isCustomSoundsListProps = ajv.compile(CustomSoundsListSchema); export type CustomSoundEndpoint = { - 'custom-sounds.list': { + '/v1/custom-sounds.list': { GET: (params: CustomSoundsList) => PaginatedResult<{ sounds: ICustomSound[]; }>; diff --git a/packages/rest-typings/src/v1/customUserStatus.ts b/packages/rest-typings/src/v1/customUserStatus.ts index dfd30aa9a117..a6131abfca8d 100644 --- a/packages/rest-typings/src/v1/customUserStatus.ts +++ b/packages/rest-typings/src/v1/customUserStatus.ts @@ -36,20 +36,20 @@ const CustomUserStatusListSchema = { export const isCustomUserStatusListProps = ajv.compile(CustomUserStatusListSchema); export type CustomUserStatusEndpoints = { - 'custom-user-status.list': { + '/v1/custom-user-status.list': { GET: (params: CustomUserStatusListProps) => PaginatedResult<{ statuses: IUserStatus[]; }>; }; - 'custom-user-status.create': { + '/v1/custom-user-status.create': { POST: (params: { name: string; statusType?: string }) => { customUserStatus: ICustomUserStatus; }; }; - 'custom-user-status.delete': { + '/v1/custom-user-status.delete': { POST: (params: { customUserStatusId: string }) => void; }; - 'custom-user-status.update': { + '/v1/custom-user-status.update': { POST: (params: { id: string; name?: string; statusType?: string }) => { customUserStatus: ICustomUserStatus; }; diff --git a/packages/rest-typings/src/v1/directory.ts b/packages/rest-typings/src/v1/directory.ts index af0ad5be6d8d..4a44f6539bf9 100644 --- a/packages/rest-typings/src/v1/directory.ts +++ b/packages/rest-typings/src/v1/directory.ts @@ -36,7 +36,7 @@ const DirectorySchema = { export const isDirectoryProps = ajv.compile(DirectorySchema); export type DirectoryEndpoint = { - directory: { + '/v1/directory': { GET: (params: DirectoryProps) => PaginatedResult<{ result: IRoom[] }>; }; }; diff --git a/packages/rest-typings/src/v1/dm/dm.ts b/packages/rest-typings/src/v1/dm/dm.ts index c23bae0b51b7..80955beeef04 100644 --- a/packages/rest-typings/src/v1/dm/dm.ts +++ b/packages/rest-typings/src/v1/dm/dm.ts @@ -1,17 +1,17 @@ import type { ImEndpoints } from './im'; export type DmEndpoints = { - 'dm.create': ImEndpoints['im.create']; - 'dm.delete': ImEndpoints['im.delete']; - 'dm.close': ImEndpoints['im.close']; - 'dm.counters': ImEndpoints['im.counters']; - 'dm.files': ImEndpoints['im.files']; - 'dm.history': ImEndpoints['im.history']; - 'dm.members': ImEndpoints['im.members']; - 'dm.messages': ImEndpoints['im.messages']; - 'dm.messages.others': ImEndpoints['im.messages.others']; - 'dm.list': ImEndpoints['im.list']; - 'dm.list.everyone': ImEndpoints['im.list.everyone']; - 'dm.open': ImEndpoints['im.open']; - 'dm.setTopic': ImEndpoints['im.setTopic']; + '/v1/dm.create': ImEndpoints['/v1/im.create']; + '/v1/dm.delete': ImEndpoints['/v1/im.delete']; + '/v1/dm.close': ImEndpoints['/v1/im.close']; + '/v1/dm.counters': ImEndpoints['/v1/im.counters']; + '/v1/dm.files': ImEndpoints['/v1/im.files']; + '/v1/dm.history': ImEndpoints['/v1/im.history']; + '/v1/dm.members': ImEndpoints['/v1/im.members']; + '/v1/dm.messages': ImEndpoints['/v1/im.messages']; + '/v1/dm.messages.others': ImEndpoints['/v1/im.messages.others']; + '/v1/dm.list': ImEndpoints['/v1/im.list']; + '/v1/dm.list.everyone': ImEndpoints['/v1/im.list.everyone']; + '/v1/dm.open': ImEndpoints['/v1/im.open']; + '/v1/dm.setTopic': ImEndpoints['/v1/im.setTopic']; }; diff --git a/packages/rest-typings/src/v1/dm/im.ts b/packages/rest-typings/src/v1/dm/im.ts index 87c4adfe4fa7..bd48bd6fd3b1 100644 --- a/packages/rest-typings/src/v1/dm/im.ts +++ b/packages/rest-typings/src/v1/dm/im.ts @@ -12,24 +12,24 @@ import type { DmMemberProps } from './DmMembersProps'; import type { DmMessagesProps } from './DmMessagesProps'; export type ImEndpoints = { - 'im.create': { + '/v1/im.create': { POST: (params: DmCreateProps) => { room: IRoom & { rid: IRoom['_id'] }; }; }; - 'im.delete': { + '/v1/im.delete': { POST: (params: DmDeleteProps) => void; }; - 'im.close': { + '/v1/im.close': { POST: (params: DmCloseProps) => void; }; - 'im.kick': { + '/v1/im.kick': { POST: (params: DmCloseProps) => void; }; - 'im.leave': { + '/v1/im.leave': { POST: (params: DmLeaveProps) => void; }; - 'im.counters': { + '/v1/im.counters': { GET: (params: { roomId: string; userId?: string }) => { joined: boolean; unreads: number | null; @@ -40,40 +40,40 @@ export type ImEndpoints = { userMentions: number | null; }; }; - 'im.files': { + '/v1/im.files': { GET: (params: DmFileProps) => PaginatedResult<{ files: IUpload[]; }>; }; - 'im.history': { + '/v1/im.history': { GET: (params: DmHistoryProps) => { messages: Pick[]; }; }; - 'im.members': { + '/v1/im.members': { GET: (params: DmMemberProps) => PaginatedResult<{ members: Pick[]; }>; }; - 'im.messages': { + '/v1/im.messages': { GET: (params: DmMessagesProps) => PaginatedResult<{ messages: IMessage[]; }>; }; - 'im.messages.others': { + '/v1/im.messages.others': { GET: (params: PaginatedRequest<{ roomId: IRoom['_id']; query?: string; fields?: string }>) => PaginatedResult<{ messages: IMessage[] }>; }; - 'im.list': { + '/v1/im.list': { GET: (params: PaginatedRequest<{ fields?: string }>) => PaginatedResult<{ ims: IRoom[] }>; }; - 'im.list.everyone': { + '/v1/im.list.everyone': { GET: (params: PaginatedRequest<{ query: string; fields?: string }>) => PaginatedResult<{ ims: IRoom[] }>; }; - 'im.open': { + '/v1/im.open': { POST: (params: { roomId: string }) => void; }; - 'im.setTopic': { + '/v1/im.setTopic': { POST: (params: { roomId: string; topic?: string }) => { topic?: string; }; diff --git a/packages/rest-typings/src/v1/dns.ts b/packages/rest-typings/src/v1/dns.ts index 28a630ea3352..b3cdb4e1ff68 100644 --- a/packages/rest-typings/src/v1/dns.ts +++ b/packages/rest-typings/src/v1/dns.ts @@ -39,12 +39,12 @@ const DnsResolveSrvSchema = { export const isDnsResolveSrvProps = ajv.compile(DnsResolveSrvSchema); export type DnsEndpoints = { - 'dns.resolve.srv': { + '/v1/dns.resolve.srv': { GET: (params: DnsResolveSrvProps) => { resolved: Record; }; }; - 'dns.resolve.txt': { + '/v1/dns.resolve.txt': { POST: (params: DnsResolveTxtProps) => { resolved: string; // resolved: Record; diff --git a/packages/rest-typings/src/v1/e2e.ts b/packages/rest-typings/src/v1/e2e.ts index 62ce4110ddbb..10827062e8b9 100644 --- a/packages/rest-typings/src/v1/e2e.ts +++ b/packages/rest-typings/src/v1/e2e.ts @@ -89,21 +89,21 @@ const E2eSetRoomKeyIdSchema = { export const isE2eSetRoomKeyIdProps = ajv.compile(E2eSetRoomKeyIdSchema); export type E2eEndpoints = { - 'e2e.setUserPublicAndPrivateKeys': { + '/v1/e2e.setUserPublicAndPrivateKeys': { POST: (params: E2eSetUserPublicAndPrivateKeysProps) => void; }; - 'e2e.getUsersOfRoomWithoutKey': { + '/v1/e2e.getUsersOfRoomWithoutKey': { GET: (params: E2eGetUsersOfRoomWithoutKeyProps) => { users: Pick[]; }; }; - 'e2e.updateGroupKey': { + '/v1/e2e.updateGroupKey': { POST: (params: E2eUpdateGroupKeyProps) => {}; }; - 'e2e.setRoomKeyID': { + '/v1/e2e.setRoomKeyID': { POST: (params: E2eSetRoomKeyIdProps) => {}; }; - 'e2e.fetchMyKeys': { + '/v1/e2e.fetchMyKeys': { GET: () => { public_key: string; private_key: string }; }; }; diff --git a/packages/rest-typings/src/v1/email-inbox.ts b/packages/rest-typings/src/v1/email-inbox.ts index d0347fe7e829..d62b5845b454 100644 --- a/packages/rest-typings/src/v1/email-inbox.ts +++ b/packages/rest-typings/src/v1/email-inbox.ts @@ -157,20 +157,20 @@ const EmailInboxSearchPropsSchema = { export const isEmailInboxSearch = ajv.compile(EmailInboxSearchPropsSchema); export type EmailInboxEndpoints = { - 'email-inbox.list': { + '/v1/email-inbox.list': { GET: (params: EmailInboxListProps) => PaginatedResult<{ emailInboxes: IEmailInbox[] }>; }; - 'email-inbox': { + '/v1/email-inbox': { POST: (params: EmailInboxProps) => { _id: string }; }; - 'email-inbox/:_id': { + '/v1/email-inbox/:_id': { GET: (params: void) => IEmailInbox | null; DELETE: (params: void) => { _id: string }; }; - 'email-inbox.search': { + '/v1/email-inbox.search': { GET: (params: EmailInboxSearchProps) => { emailInbox: IEmailInbox | null }; }; - 'email-inbox.send-test/:_id': { + '/v1/email-inbox.send-test/:_id': { POST: (params: void) => { _id: string }; }; }; diff --git a/packages/rest-typings/src/v1/emojiCustom.ts b/packages/rest-typings/src/v1/emojiCustom.ts index 2532879dd9a9..e0cd87906c36 100644 --- a/packages/rest-typings/src/v1/emojiCustom.ts +++ b/packages/rest-typings/src/v1/emojiCustom.ts @@ -1,4 +1,4 @@ -import type { ICustomEmojiDescriptor } from '@rocket.chat/core-typings'; +import type { ICustomEmojiDescriptor, IEmojiCustom } from '@rocket.chat/core-typings'; import Ajv from 'ajv'; import type { PaginatedRequest } from '../helpers/PaginatedRequest'; @@ -27,6 +27,7 @@ export const isEmojiCustomDelete = ajv.compile(emojiCust type emojiCustomList = { query: string; + updatedSince?: string; }; const emojiCustomListSchema = { @@ -35,27 +36,38 @@ const emojiCustomListSchema = { query: { type: 'string', }, + updatedSince: { + type: 'string', + nullable: true, + }, }, required: ['query'], additionalProperties: false, }; -export const isemojiCustomList = ajv.compile(emojiCustomListSchema); +export const isEmojiCustomList = ajv.compile(emojiCustomListSchema); export type EmojiCustomEndpoints = { - 'emoji-custom.all': { - GET: (params: PaginatedRequest<{ query: string }, 'name'>) => { - emojis: ICustomEmojiDescriptor[]; - } & PaginatedResult; + '/v1/emoji-custom.all': { + GET: (params: PaginatedRequest<{ query: string }, 'name'>) => PaginatedResult<{ + emojis: IEmojiCustom[]; + }>; }; - 'emoji-custom.list': { + '/v1/emoji-custom.list': { GET: (params: emojiCustomList) => { - emojis?: { - update: ICustomEmojiDescriptor[]; + emojis: { + update: IEmojiCustom[]; + remove: IEmojiCustom[]; }; }; }; - 'emoji-custom.delete': { + '/v1/emoji-custom.delete': { POST: (params: emojiCustomDeleteProps) => void; }; + '/v1/emoji-custom.create': { + POST: (params: { emoji: ICustomEmojiDescriptor }) => void; + }; + '/v1/emoji-custom.update': { + POST: (params: { emoji: ICustomEmojiDescriptor }) => void; + }; }; diff --git a/packages/rest-typings/src/v1/groups.ts b/packages/rest-typings/src/v1/groups.ts index 10540a3ecd62..7fc73cbe7440 100644 --- a/packages/rest-typings/src/v1/groups.ts +++ b/packages/rest-typings/src/v1/groups.ts @@ -318,12 +318,12 @@ const GroupsMessagePropsSchema = { export const isGroupsMessageProps = ajv.compile(GroupsMessagePropsSchema); export type GroupsEndpoints = { - 'groups.files': { + '/v1/groups.files': { GET: (params: GroupsFilesProps) => PaginatedResult<{ files: IUpload[]; }>; }; - 'groups.members': { + '/v1/groups.members': { GET: (params: GroupsMembersProps) => { count: number; offset: number; @@ -331,26 +331,26 @@ export type GroupsEndpoints = { total: number; }; }; - 'groups.history': { + '/v1/groups.history': { GET: (params: PaginatedRequest<{ roomId: string; latest?: string }>) => PaginatedResult<{ messages: IMessage[]; }>; }; - 'groups.archive': { + '/v1/groups.archive': { POST: (params: GroupsArchiveProps) => void; }; - 'groups.unarchive': { + '/v1/groups.unarchive': { POST: (params: GroupsUnarchiveProps) => void; }; - 'groups.create': { + '/v1/groups.create': { POST: (params: GroupsCreateProps) => { group: Partial; }; }; - 'groups.convertToTeam': { + '/v1/groups.convertToTeam': { POST: (params: GroupsConvertToTeamProps) => { team: ITeam }; }; - 'groups.counters': { + '/v1/groups.counters': { GET: (params: GroupsCountersProps) => { joined: boolean; members: number; @@ -361,22 +361,22 @@ export type GroupsEndpoints = { userMentions: number; }; }; - 'groups.close': { + '/v1/groups.close': { POST: (params: GroupsCloseProps) => {}; }; - 'groups.kick': { + '/v1/groups.kick': { POST: (params: GroupsKickProps) => {}; }; - 'groups.delete': { + '/v1/groups.delete': { POST: (params: GroupsDeleteProps) => {}; }; - 'groups.leave': { + '/v1/groups.leave': { POST: (params: GroupsLeaveProps) => {}; }; - 'groups.roles': { + '/v1/groups.roles': { GET: (params: GroupsRolesProps) => { roles: IGetRoomRoles[] }; }; - 'groups.messages': { + '/v1/groups.messages': { GET: (params: GroupsMessageProps) => PaginatedResult<{ messages: IMessage[]; }>; diff --git a/packages/rest-typings/src/v1/instances.ts b/packages/rest-typings/src/v1/instances.ts index ab37f127ad23..faf085e5ae92 100644 --- a/packages/rest-typings/src/v1/instances.ts +++ b/packages/rest-typings/src/v1/instances.ts @@ -1,7 +1,7 @@ import type { IInstanceStatus } from '@rocket.chat/core-typings'; export type InstancesEndpoints = { - 'instances.get': { + '/v1/instances.get': { GET: () => { instances: ( | IInstanceStatus diff --git a/packages/rest-typings/src/v1/invites.ts b/packages/rest-typings/src/v1/invites.ts index d123c3d18df7..f6e6bd7f70b3 100644 --- a/packages/rest-typings/src/v1/invites.ts +++ b/packages/rest-typings/src/v1/invites.ts @@ -61,13 +61,13 @@ const FindOrCreateInviteParamsSchema = { export const isFindOrCreateInviteParams = ajv.compile(FindOrCreateInviteParamsSchema); export type InvitesEndpoints = { - 'listInvites': { + '/v1/listInvites': { GET: () => Array; }; - 'removeInvite/:_id': { + '/v1/removeInvite/:_id': { DELETE: () => boolean; }; - 'useInviteToken': { + '/v1/useInviteToken': { POST: (params: UseInviteTokenProps) => { room: { rid: IRoom['_id']; @@ -78,10 +78,10 @@ export type InvitesEndpoints = { }; }; }; - 'validateInviteToken': { + '/v1/validateInviteToken': { POST: (params: ValidateInviteTokenProps) => { valid: boolean }; }; - 'findOrCreateInvite': { + '/v1/findOrCreateInvite': { POST: (params: FindOrCreateInviteParams) => IInvite; }; }; diff --git a/packages/rest-typings/src/v1/ldap.ts b/packages/rest-typings/src/v1/ldap.ts index 3fd343cf4c03..1591ff033393 100644 --- a/packages/rest-typings/src/v1/ldap.ts +++ b/packages/rest-typings/src/v1/ldap.ts @@ -22,17 +22,17 @@ const ldapTestSearchPropsSchema = { export const isLdapTestSearch = ajv.compile(ldapTestSearchPropsSchema); export type LDAPEndpoints = { - 'ldap.testConnection': { + '/v1/ldap.testConnection': { POST: () => { message: string; }; }; - 'ldap.testSearch': { + '/v1/ldap.testSearch': { POST: (params: ldapTestSearchProps) => { message: string; }; }; - 'ldap.syncNow': { + '/v1/ldap.syncNow': { POST: () => { message: string; }; diff --git a/packages/rest-typings/src/v1/licenses.ts b/packages/rest-typings/src/v1/licenses.ts index de477d37a813..88b1d34dc23f 100644 --- a/packages/rest-typings/src/v1/licenses.ts +++ b/packages/rest-typings/src/v1/licenses.ts @@ -23,16 +23,16 @@ const licensesAddPropsSchema = { export const isLicensesAddProps = ajv.compile(licensesAddPropsSchema); export type LicensesEndpoints = { - 'licenses.get': { + '/v1/licenses.get': { GET: () => { licenses: Array }; }; - 'licenses.add': { + '/v1/licenses.add': { POST: (params: licensesAddProps) => void; }; - 'licenses.maxActiveUsers': { + '/v1/licenses.maxActiveUsers': { GET: () => { maxActiveUsers: number | null; activeUsers: number }; }; - 'licenses.requestSeatsLink': { + '/v1/licenses.requestSeatsLink': { GET: () => { url: string }; }; }; diff --git a/packages/rest-typings/src/v1/me.ts b/packages/rest-typings/src/v1/me.ts new file mode 100644 index 000000000000..af406ac1d4d4 --- /dev/null +++ b/packages/rest-typings/src/v1/me.ts @@ -0,0 +1,35 @@ +import type { IUser, Serialized } from '@rocket.chat/core-typings'; + +type RawUserData = Serialized< + Pick< + IUser, + | '_id' + | 'type' + | 'name' + | 'username' + | 'emails' + | 'status' + | 'statusDefault' + | 'statusText' + | 'statusConnection' + | 'avatarOrigin' + | 'utcOffset' + | 'language' + | 'settings' + | 'roles' + | 'active' + | 'defaultRoom' + | 'customFields' + | 'statusLivechat' + | 'oauth' + | 'createdAt' + | '_updatedAt' + | 'avatarETag' + > +>; + +export type MeEndpoints = { + '/v1/me': { + GET: () => RawUserData; + }; +}; diff --git a/packages/rest-typings/src/v1/misc.ts b/packages/rest-typings/src/v1/misc.ts index f41ffe905860..c2d36fcc83cd 100644 --- a/packages/rest-typings/src/v1/misc.ts +++ b/packages/rest-typings/src/v1/misc.ts @@ -171,7 +171,7 @@ const MethodCallAnonSchema = { export const isMethodCallAnonProps = ajv.compile(MethodCallAnonSchema); export type MiscEndpoints = { - 'stdout.queue': { + '/v1/stdout.queue': { GET: () => { queue: { id: string; diff --git a/packages/rest-typings/src/v1/oauthapps.ts b/packages/rest-typings/src/v1/oauthapps.ts index 4928257efd1e..9dd2dfe3b984 100644 --- a/packages/rest-typings/src/v1/oauthapps.ts +++ b/packages/rest-typings/src/v1/oauthapps.ts @@ -8,13 +8,13 @@ const ajv = new Ajv({ export type OauthAppsGetParams = { clientId: string } | { appId: string }; export type OAuthAppsEndpoint = { - 'oauth-apps.list': { + '/v1/oauth-apps.list': { GET: (params: { uid: IUser['_id'] }) => { oauthApps: IOAuthApps[]; }; }; - 'oauth-apps.get': { + '/v1/oauth-apps.get': { GET: (params: OauthAppsGetParams) => { oauthApp: IOAuthApps; }; diff --git a/packages/rest-typings/src/v1/omnichannel.ts b/packages/rest-typings/src/v1/omnichannel.ts index fc2ab9e23fd9..ff1a26f8e9b7 100644 --- a/packages/rest-typings/src/v1/omnichannel.ts +++ b/packages/rest-typings/src/v1/omnichannel.ts @@ -778,12 +778,12 @@ const LivechatUsersAgentSchema = { export const isLivechatUsersAgentProps = ajv.compile(LivechatUsersAgentSchema); export type OmnichannelEndpoints = { - 'livechat/appearance': { + '/v1/livechat/appearance': { GET: () => { appearance: ISetting[]; }; }; - 'livechat/visitors.info': { + '/v1/livechat/visitors.info': { GET: (params: LivechatVisitorsInfo) => { visitor: { visitorEmails: Array<{ @@ -792,23 +792,28 @@ export type OmnichannelEndpoints = { }; }; }; - 'livechat/room.onHold': { + '/v1/livechat/room': { + GET: (params: { token: string; rid: IRoom['_id'] }) => { + room: IOmnichannelRoom; + }; + }; + '/v1/livechat/room.onHold': { POST: (params: LivechatRoomOnHold) => void; }; - 'livechat/room.join': { + '/v1/livechat/room.join': { GET: (params: LiveChatRoomJoin) => { success: boolean }; }; - 'livechat/monitors.list': { + '/v1/livechat/monitors.list': { GET: (params: LivechatMonitorsListProps) => PaginatedResult<{ monitors: ILivechatMonitor[]; }>; }; - 'livechat/tags.list': { + '/v1/livechat/tags.list': { GET: (params: LivechatTagsListProps) => PaginatedResult<{ tags: ILivechatTag[]; }>; }; - 'livechat/department': { + '/v1/livechat/department': { GET: (params: LivechatDepartmentProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; @@ -817,7 +822,7 @@ export type OmnichannelEndpoints = { agents: any[]; }; }; - 'livechat/department/:_id': { + '/v1/livechat/department/:_id': { GET: (params: LivechatDepartmentId) => { department: ILivechatDepartmentRecord | null; agents?: ILivechatDepartmentAgents[]; @@ -828,39 +833,39 @@ export type OmnichannelEndpoints = { }; DELETE: () => void; }; - 'livechat/department.autocomplete': { + '/v1/livechat/department.autocomplete': { GET: (params: LivechatDepartmentAutocomplete) => { items: ILivechatDepartment[]; }; }; - 'livechat/department/:departmentId/agents': { + '/v1/livechat/department/:departmentId/agents': { GET: (params: LivechatDepartmentDepartmentIdAgentsGET) => PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>; POST: (params: LivechatDepartmentDepartmentIdAgentsPOST) => void; }; - 'livechat/departments.available-by-unit/:id': { + '/v1/livechat/departments.available-by-unit/:id': { GET: (params: LivechatDepartmentsAvailableByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; - 'livechat/departments.by-unit/': { + '/v1/livechat/departments.by-unit/': { GET: (params: LivechatDepartmentsByUnitProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; - 'livechat/departments.by-unit/:id': { + '/v1/livechat/departments.by-unit/:id': { GET: (params: LivechatDepartmentsByUnitIdProps) => PaginatedResult<{ departments: ILivechatDepartment[]; }>; }; - 'livechat/department.listByIds': { + '/v1/livechat/department.listByIds': { GET: (params: { ids: string[]; fields?: Record }) => { departments: ILivechatDepartment[]; }; }; - 'livechat/custom-fields': { + '/v1/livechat/custom-fields': { GET: (params: LivechatCustomFieldsProps) => PaginatedResult<{ customFields: [ { @@ -870,25 +875,25 @@ export type OmnichannelEndpoints = { ]; }>; }; - 'livechat/rooms': { + '/v1/livechat/rooms': { GET: (params: LivechatRoomsProps) => PaginatedResult<{ rooms: IOmnichannelRoom[]; }>; }; - 'livechat/:rid/messages': { + '/v1/livechat/:rid/messages': { GET: (params: LivechatRidMessagesProps) => PaginatedResult<{ messages: IMessage[]; }>; }; - 'livechat/users/manager': { + '/v1/livechat/users/manager': { GET: (params: LivechatUsersManagerGETProps) => PaginatedResult<{ users: ILivechatAgent[]; }>; POST: (params: { username: string }) => { success: boolean }; }; - 'livechat/users/manager/:_id': { + '/v1/livechat/users/manager/:_id': { GET: ( params: PaginatedRequest<{ text: string; @@ -897,14 +902,14 @@ export type OmnichannelEndpoints = { DELETE: () => void; }; - 'livechat/users/agent': { + '/v1/livechat/users/agent': { GET: (params: PaginatedRequest<{ text?: string }>) => PaginatedResult<{ users: ILivechatAgent[]; }>; POST: (params: LivechatUsersManagerPOSTProps) => { success: boolean }; }; - 'livechat/users/agent/:_id': { + '/v1/livechat/users/agent/:_id': { GET: ( params: PaginatedRequest<{ text: string; @@ -913,38 +918,38 @@ export type OmnichannelEndpoints = { DELETE: () => { success: boolean }; }; - 'livechat/visitor': { + '/v1/livechat/visitor': { POST: (params: { visitor: ILivechatVisitorDTO }) => { visitor: ILivechatVisitor; }; }; - 'livechat/visitor/:token': { + '/v1/livechat/visitor/:token': { GET: (params: LivechatVisitorTokenGet) => { visitor: ILivechatVisitor }; DELETE: (params: LivechatVisitorTokenDelete) => { visitor: { _id: string; ts: string }; }; }; - 'livechat/visitor/:token/room': { + '/v1/livechat/visitor/:token/room': { GET: (params: LivechatVisitorTokenRoom) => { rooms: IOmnichannelRoom[] }; }; - 'livechat/visitor.callStatus': { + '/v1/livechat/visitor.callStatus': { POST: (params: LivechatVisitorCallStatus) => { token: string; callStatus: string; }; }; - 'livechat/visitor.status': { + '/v1/livechat/visitor.status': { POST: (params: LivechatVisitorStatus) => { token: string; status: string; }; }; - 'livechat/queue': { + '/v1/livechat/queue': { GET: (params: LivechatQueueProps) => { queue: { chats: number; @@ -956,13 +961,21 @@ export type OmnichannelEndpoints = { total: number; }; }; - 'livechat/agents/:uid/departments': { + '/v1/livechat/agents/:uid/departments': { GET: (params: { enableDepartmentsOnly: 'true' | 'false' | '0' | '1' }) => { departments: ILivechatDepartmentAgents[] }; }; - 'canned-responses': { + '/v1/canned-responses': { GET: (params: CannedResponsesProps) => PaginatedResult<{ cannedResponses: IOmnichannelCannedResponse[]; }>; }; + + '/v1/livechat/webrtc.call': { + GET: (params: { rid: string }) => void; + }; + + '/v1/livechat/webrtc.call/:callId': { + PUT: (params: { rid: string; status: 'ended' }) => void; + }; }; diff --git a/packages/rest-typings/src/v1/permissions.ts b/packages/rest-typings/src/v1/permissions.ts index 3128db4ec259..1021c9e72e99 100644 --- a/packages/rest-typings/src/v1/permissions.ts +++ b/packages/rest-typings/src/v1/permissions.ts @@ -54,13 +54,13 @@ const permissionUpdatePropsSchema = { export const isBodyParamsValidPermissionUpdate = ajv.compile(permissionUpdatePropsSchema); export type PermissionsEndpoints = { - 'permissions.listAll': { + '/v1/permissions.listAll': { GET: (params: PermissionsListAllProps) => { update: IPermission[]; remove: IPermission[]; }; }; - 'permissions.update': { + '/v1/permissions.update': { POST: (params: PermissionsUpdateProps) => { permissions: IPermission[]; }; diff --git a/packages/rest-typings/src/v1/push.ts b/packages/rest-typings/src/v1/push.ts index 54568328bc42..c9f439357975 100644 --- a/packages/rest-typings/src/v1/push.ts +++ b/packages/rest-typings/src/v1/push.ts @@ -53,11 +53,11 @@ const PushGetPropsSchema = { export const isPushGetProps = ajv.compile(PushGetPropsSchema); export type PushEndpoints = { - 'push.token': { + '/v1/push.token': { POST: (payload: PushTokenProps) => { result: IPushToken }; DELETE: (payload: { token: string }) => void; }; - 'push.get': { + '/v1/push.get': { GET: (params: PushGetProps) => { data: { message: IMessage; diff --git a/packages/rest-typings/src/v1/roles.ts b/packages/rest-typings/src/v1/roles.ts index 8c4135fc4b5b..499bc7273ea6 100644 --- a/packages/rest-typings/src/v1/roles.ts +++ b/packages/rest-typings/src/v1/roles.ts @@ -198,12 +198,12 @@ type RoleSyncProps = { }; export type RolesEndpoints = { - 'roles.list': { + '/v1/roles.list': { GET: () => { roles: IRole[]; }; }; - 'roles.sync': { + '/v1/roles.sync': { GET: (params: RoleSyncProps) => { roles: { update: IRole[]; @@ -211,36 +211,36 @@ export type RolesEndpoints = { }; }; }; - 'roles.create': { + '/v1/roles.create': { POST: (params: RoleCreateProps) => { role: IRole; }; }; - 'roles.addUserToRole': { + '/v1/roles.addUserToRole': { POST: (params: RoleAddUserToRoleProps) => { role: IRole; }; }; - 'roles.getUsersInRole': { + '/v1/roles.getUsersInRole': { GET: (params: RolesGetUsersInRoleProps) => { users: IUserInRole[]; total: number; }; }; - 'roles.update': { + '/v1/roles.update': { POST: (role: RoleUpdateProps) => { role: IRole; }; }; - 'roles.delete': { + '/v1/roles.delete': { POST: (prop: RoleDeleteProps) => void; }; - 'roles.removeUserFromRole': { + '/v1/roles.removeUserFromRole': { POST: (props: RoleRemoveUserFromRoleProps) => { role: IRole; }; diff --git a/packages/rest-typings/src/v1/rooms.ts b/packages/rest-typings/src/v1/rooms.ts index a57757a8476d..8cf6f32f49d4 100644 --- a/packages/rest-typings/src/v1/rooms.ts +++ b/packages/rest-typings/src/v1/rooms.ts @@ -394,30 +394,27 @@ const RoomsSaveRoomSettingsSchema = { export const isRoomsSaveRoomSettingsProps = ajv.compile(RoomsSaveRoomSettingsSchema); export type RoomsEndpoints = { - 'rooms.autocomplete.channelAndPrivate': { + '/v1/rooms.autocomplete.channelAndPrivate': { GET: (params: RoomsAutoCompleteChannelAndPrivateProps) => { items: IRoom[]; }; }; - 'rooms.autocomplete.channelAndPrivate.withPagination': { - GET: (params: RoomsAutocompleteChannelAndPrivateWithPaginationProps) => { + '/v1/rooms.autocomplete.channelAndPrivate.withPagination': { + GET: (params: RoomsAutocompleteChannelAndPrivateWithPaginationProps) => PaginatedResult<{ items: IRoom[]; - count: number; - offset: number; - total: number; - }; + }>; }; - 'rooms.autocomplete.availableForTeams': { + '/v1/rooms.autocomplete.availableForTeams': { GET: (params: RoomsAutocompleteAvailableForTeamsProps) => { items: IRoom[]; }; }; - 'rooms.info': { + '/v1/rooms.info': { GET: (params: RoomsInfoProps) => { room: IRoom; }; }; - 'rooms.cleanHistory': { + '/v1/rooms.cleanHistory': { POST: (params: { roomId: IRoom['_id']; latest: string; @@ -431,32 +428,45 @@ export type RoomsEndpoints = { ignoreThreads?: boolean; }) => { _id: IRoom['_id']; count: number; success: boolean }; }; - 'rooms.createDiscussion': { + '/v1/rooms.createDiscussion': { POST: (params: RoomsCreateDiscussionProps) => { discussion: IRoom; }; }; - 'rooms.export': { + '/v1/rooms.export': { POST: (params: RoomsExportProps) => { missing?: []; success: boolean; }; }; - 'rooms.adminRooms': { + '/v1/rooms.adminRooms': { GET: (params: RoomsAdminRoomsProps) => PaginatedResult<{ rooms: Pick[] }>; }; - 'rooms.adminRooms.getRoom': { + '/v1/rooms.adminRooms.getRoom': { GET: (params: RoomsAdminRoomsGetRoomProps) => Pick; }; - 'rooms.saveRoomSettings': { + '/v1/rooms.saveRoomSettings': { POST: (params: RoomsSaveRoomSettingsProps) => { success: boolean; rid: string; }; }; - 'rooms.changeArchivationState': { + '/v1/rooms.changeArchivationState': { POST: (params: RoomsChangeArchivationStateProps) => { success: boolean; }; }; + + '/v1/rooms.upload/:rid': { + POST: (params: { + file: File; + description?: string; + avatar?: string; + emoji?: string; + alias?: string; + groupable?: boolean; + msg?: string; + tmid?: string; + }) => { message: IMessage }; + }; }; diff --git a/packages/rest-typings/src/v1/settings.ts b/packages/rest-typings/src/v1/settings.ts index 8e9b09a3bddf..694ea9f59318 100644 --- a/packages/rest-typings/src/v1/settings.ts +++ b/packages/rest-typings/src/v1/settings.ts @@ -65,34 +65,34 @@ type SettingsUpdatePropDefault = { export const isSettingsUpdatePropDefault = (props: Partial): props is SettingsUpdatePropDefault => 'value' in props; export type SettingsEndpoints = { - 'settings.public': { + '/v1/settings.public': { GET: () => PaginatedResult & { settings: Array; }; }; - 'settings.oauth': { + '/v1/settings.oauth': { GET: () => { services: Partial[]; }; }; - 'settings.addCustomOAuth': { + '/v1/settings.addCustomOAuth': { POST: (params: { name: string }) => void; }; - 'settings': { + '/v1/settings': { GET: () => { settings: ISetting[]; }; }; - 'settings/:_id': { + '/v1/settings/:_id': { GET: () => Pick; POST: (params: SettingsUpdateProps) => void; }; - 'service.configurations': { + '/v1/service.configurations': { GET: () => { configurations: Array<{ appId: string; diff --git a/packages/rest-typings/src/v1/statistics.ts b/packages/rest-typings/src/v1/statistics.ts index 837bbf1afa0e..e9424b28c1cc 100644 --- a/packages/rest-typings/src/v1/statistics.ts +++ b/packages/rest-typings/src/v1/statistics.ts @@ -74,10 +74,10 @@ const StatisticsListSchema = { export const isStatisticsListProps = ajv.compile(StatisticsListSchema); export type StatisticsEndpoints = { - 'statistics': { + '/v1/statistics': { GET: (params: StatisticsProps) => IStats; }; - 'statistics.list': { + '/v1/statistics.list': { GET: (params: StatisticsListProps) => { statistics: IStats[]; count: number; @@ -85,7 +85,7 @@ export type StatisticsEndpoints = { total: number; }; }; - 'statistics.telemetry': { + '/v1/statistics.telemetry': { POST: (params: TelemetryPayload) => any; }; }; diff --git a/packages/rest-typings/src/v1/teams/index.ts b/packages/rest-typings/src/v1/teams/index.ts index 5aaccb50533c..82f1b1d0abcf 100644 --- a/packages/rest-typings/src/v1/teams/index.ts +++ b/packages/rest-typings/src/v1/teams/index.ts @@ -51,13 +51,13 @@ export const isTeamPropsWithTeamName = (props: T): props is export const isTeamPropsWithTeamId = (props: T): props is T & { teamId: string } => 'teamId' in props; export type TeamsEndpoints = { - 'teams.list': { + '/v1/teams.list': { GET: () => PaginatedResult & { teams: ITeam[] }; }; - 'teams.listAll': { + '/v1/teams.listAll': { GET: () => { teams: ITeam[] } & PaginatedResult; }; - 'teams.create': { + '/v1/teams.create': { POST: (params: { name: ITeam['name']; type: ITeam['type']; @@ -95,19 +95,19 @@ export type TeamsEndpoints = { }; }; - 'teams.convertToChannel': { + '/v1/teams.convertToChannel': { POST: (params: TeamsConvertToChannelProps) => void; }; - 'teams.addRooms': { + '/v1/teams.addRooms': { POST: (params: { rooms: IRoom['_id'][]; teamId: string } | { rooms: IRoom['_id'][]; teamName: string }) => { rooms: IRoom[] }; }; - 'teams.removeRoom': { + '/v1/teams.removeRoom': { POST: (params: TeamsRemoveRoomProps) => { room: IRoom }; }; - 'teams.members': { + '/v1/teams.members': { GET: ( params: ({ teamId: string } | { teamName: string }) & { status?: string[]; @@ -117,41 +117,41 @@ export type TeamsEndpoints = { ) => PaginatedResult & { members: ITeamMemberInfo[] }; }; - 'teams.addMembers': { + '/v1/teams.addMembers': { POST: (params: TeamsAddMembersProps) => void; }; - 'teams.updateMember': { + '/v1/teams.updateMember': { POST: (params: TeamsUpdateMemberProps) => void; }; - 'teams.removeMember': { + '/v1/teams.removeMember': { POST: (params: TeamsRemoveMemberProps) => void; }; - 'teams.leave': { + '/v1/teams.leave': { POST: (params: TeamsLeaveProps) => void; }; - 'teams.info': { + '/v1/teams.info': { GET: (params: ({ teamId: string } | { teamName: string }) & {}) => { teamInfo: Partial; }; }; - 'teams.autocomplete': { + '/v1/teams.autocomplete': { GET: (params: { name: string }) => { teams: ITeamAutocompleteResult[] }; }; - 'teams.update': { + '/v1/teams.update': { POST: (params: TeamsUpdateProps) => void; }; - 'teams.delete': { + '/v1/teams.delete': { POST: (params: TeamsDeleteProps) => void; }; - 'teams.listRoomsOfUser': { + '/v1/teams.listRoomsOfUser': { GET: ( params: | { @@ -167,7 +167,7 @@ export type TeamsEndpoints = { ) => PaginatedResult & { rooms: IRoom[] }; }; - 'teams.listRooms': { + '/v1/teams.listRooms': { GET: ( params: PaginatedRequest & ({ teamId: string } | { teamName: string }) & { @@ -177,7 +177,7 @@ export type TeamsEndpoints = { ) => PaginatedResult & { rooms: IRoom[] }; }; - 'teams.updateRoom': { + '/v1/teams.updateRoom': { POST: (params: { roomId: IRoom['_id']; isDefault: boolean }) => { room: IRoom; }; diff --git a/packages/rest-typings/src/v1/users.ts b/packages/rest-typings/src/v1/users.ts index dc6e6b736558..df11fb399124 100644 --- a/packages/rest-typings/src/v1/users.ts +++ b/packages/rest-typings/src/v1/users.ts @@ -114,27 +114,36 @@ const UsersResetAvatarSchema = { export const isUsersResetAvatarProps = ajv.compile(UsersResetAvatarSchema); +type UsersPresencePayload = { + users: UserPresence[]; + full: boolean; +}; + +export type UserPresence = Readonly< + Partial> & Required> +>; + export type UsersEndpoints = { - 'users.info': { + '/v1/users.info': { GET: (params: UsersInfo) => { user: IUser; }; }; - 'users.2fa.sendEmailCode': { + '/v1/users.2fa.sendEmailCode': { POST: (params: Users2faSendEmailCode) => void; }; - 'users.autocomplete': { + '/v1/users.autocomplete': { GET: (params: UsersAutocomplete) => { items: Required>[]; }; }; - 'users.listTeams': { + '/v1/users.listTeams': { GET: (params: UsersListTeams) => { teams: Array }; }; - 'users.setAvatar': { + '/v1/users.setAvatar': { POST: (params: UsersSetAvatar) => void; }; - 'users.resetAvatar': { + '/v1/users.resetAvatar': { POST: (params: UsersResetAvatar) => void; }; }; diff --git a/packages/rest-typings/src/v1/videoConference.ts b/packages/rest-typings/src/v1/videoConference.ts index c314e43deb6c..d6a4717e5131 100644 --- a/packages/rest-typings/src/v1/videoConference.ts +++ b/packages/rest-typings/src/v1/videoConference.ts @@ -27,7 +27,7 @@ export const isVideoConferenceJitsiUpdateTimeoutProps = ajv.compile { jitsiTimeout: number; }; diff --git a/packages/rest-typings/src/v1/voip.ts b/packages/rest-typings/src/v1/voip.ts index fbdeafc23fef..516b1131e9ac 100644 --- a/packages/rest-typings/src/v1/voip.ts +++ b/packages/rest-typings/src/v1/voip.ts @@ -489,53 +489,53 @@ const VoipRoomCloseSchema: JSONSchemaType = { export const isVoipRoomCloseProps = ajv.compile(VoipRoomCloseSchema); export type VoipEndpoints = { - 'connector.extension.getRegistrationInfoByUserId': { + '/v1/connector.extension.getRegistrationInfoByUserId': { GET: (params: ConnectorExtensionGetRegistrationInfoByUserId) => IRegistrationInfo | { result: string }; }; - 'voip/queues.getSummary': { + '/v1/voip/queues.getSummary': { GET: () => { summary: IQueueSummary[] }; }; - 'voip/queues.getQueuedCallsForThisExtension': { + '/v1/voip/queues.getQueuedCallsForThisExtension': { GET: (params: VoipQueuesGetQueuedCallsForThisExtension) => IQueueMembershipDetails; }; - 'voip/queues.getMembershipSubscription': { + '/v1/voip/queues.getMembershipSubscription': { GET: (params: VoipQueuesGetMembershipSubscription) => IQueueMembershipSubscription; }; - 'omnichannel/extensions': { + '/v1/omnichannel/extensions': { GET: (params: OmnichannelExtensions) => PaginatedResult<{ extensions: IVoipExtensionWithAgentInfo[] }>; }; - 'omnichannel/extension': { + '/v1/omnichannel/extension': { GET: (params: OmnichannelExtension) => { extensions: string[]; }; }; - 'omnichannel/agent/extension': { + '/v1/omnichannel/agent/extension': { GET: (params: OmnichannelAgentExtensionGET) => { extension: Pick }; POST: (params: OmnichannelAgentExtensionPOST) => void; DELETE: (params: OmnichannelAgentExtensionDELETE) => void; }; - 'omnichannel/agents/available': { + '/v1/omnichannel/agents/available': { GET: (params: OmnichannelAgentsAvailable) => PaginatedResult<{ agents: ILivechatAgent[] }>; }; - 'voip/events': { + '/v1/voip/events': { POST: (params: VoipEvents) => void; }; - 'voip/room': { + '/v1/voip/room': { GET: (params: VoipRoom) => { room: IVoipRoom; newRoom: boolean; }; }; - 'voip/managementServer/checkConnection': { + '/v1/voip/managementServer/checkConnection': { GET: (params: VoipManagementServerCheckConnection) => IManagementServerConnectionStatus; }; - 'voip/callServer/checkConnection': { + '/v1/voip/callServer/checkConnection': { GET: (params: VoipCallServerCheckConnection) => IManagementServerConnectionStatus; }; - 'voip/rooms': { + '/v1/voip/rooms': { GET: (params: VoipRooms) => PaginatedResult<{ rooms: IVoipRoom[] }>; }; - 'voip/room.close': { + '/v1/voip/room.close': { POST: (params: VoipRoomClose) => { rid: string }; }; }; diff --git a/packages/rest-typings/src/v1/webdav.ts b/packages/rest-typings/src/v1/webdav.ts index 51a810b9ce15..a4ee811c546a 100644 --- a/packages/rest-typings/src/v1/webdav.ts +++ b/packages/rest-typings/src/v1/webdav.ts @@ -1,7 +1,7 @@ import type { IWebdavAccount } from '@rocket.chat/core-typings'; export type WebdavEndpoints = { - 'webdav.getMyAccounts': { + '/v1/webdav.getMyAccounts': { GET: () => { accounts: Pick[]; }; diff --git a/packages/ui-contexts/src/ServerContext/ServerContext.ts b/packages/ui-contexts/src/ServerContext/ServerContext.ts index 4920adb44e96..41fe3215f4e4 100644 --- a/packages/ui-contexts/src/ServerContext/ServerContext.ts +++ b/packages/ui-contexts/src/ServerContext/ServerContext.ts @@ -1,5 +1,5 @@ import type { IServerInfo, Serialized } from '@rocket.chat/core-typings'; -import type { Method, PathFor, OperationParams, MatchPathPattern, OperationResult } from '@rocket.chat/rest-typings'; +import type { Method, OperationParams, MatchPathPattern, OperationResult, PathFor } from '@rocket.chat/rest-typings'; import { createContext } from 'react'; import type { ServerMethodName, ServerMethodParameters, ServerMethodReturn } from './methods'; @@ -23,8 +23,7 @@ export type ServerContextValue = { params: Serialized>>, ) => Promise>>>; uploadToEndpoint: ( - endpoint: string, - params: any, + endpoint: PathFor<'POST'>, formData: any, ) => | Promise diff --git a/packages/ui-contexts/src/hooks/useUpload.ts b/packages/ui-contexts/src/hooks/useUpload.ts index 802022643d8b..97bd49703619 100644 --- a/packages/ui-contexts/src/hooks/useUpload.ts +++ b/packages/ui-contexts/src/hooks/useUpload.ts @@ -1,10 +1,9 @@ +import type { PathFor } from '@rocket.chat/rest-typings'; import { useCallback, useContext } from 'react'; import { ServerContext, UploadResult } from '../ServerContext'; -export const useUpload = ( - endpoint: string, -): ((params: any, formData: any) => Promise | { promise: Promise }) => { +export const useUpload = (endpoint: PathFor<'POST'>): ((formData: any) => Promise | { promise: Promise }) => { const { uploadToEndpoint } = useContext(ServerContext); - return useCallback((params, formData: any) => uploadToEndpoint(endpoint, params, formData), [endpoint, uploadToEndpoint]); + return useCallback((formData: any) => uploadToEndpoint(endpoint, formData), [endpoint, uploadToEndpoint]); }; diff --git a/yarn.lock b/yarn.lock index 79f53cff45e9..9d7d07407dd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4222,6 +4222,25 @@ __metadata: languageName: node linkType: hard +"@rocket.chat/api-client@workspace:^, @rocket.chat/api-client@workspace:packages/api-client": + version: 0.0.0-use.local + resolution: "@rocket.chat/api-client@workspace:packages/api-client" + dependencies: + "@rocket.chat/core-typings": "workspace:^" + "@rocket.chat/rest-typings": "workspace:^" + "@types/jest": ^27.4.1 + "@types/strict-uri-encode": ^2 + eslint: ^8.12.0 + filter-obj: ^3.0.0 + jest: ^27.5.1 + query-string: ^7.1.1 + split-on-first: ^3.0.0 + strict-uri-encode: ^2.0.0 + ts-jest: ^27.1.4 + typescript: ~4.3.5 + languageName: unknown + linkType: soft + "@rocket.chat/apps-engine@npm:1.32.0": version: 1.32.0 resolution: "@rocket.chat/apps-engine@npm:1.32.0" @@ -4772,6 +4791,7 @@ __metadata: "@nivo/line": 0.62.0 "@nivo/pie": 0.73.0 "@playwright/test": ^1.21.1 + "@rocket.chat/api-client": "workspace:^" "@rocket.chat/apps-engine": 1.32.0 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.12 @@ -4858,6 +4878,7 @@ __metadata: "@types/sharp": ^0.30.2 "@types/sinon": ^10.0.11 "@types/speakeasy": ^2.0.7 + "@types/strict-uri-encode": ^2 "@types/string-strip-html": ^5.0.0 "@types/supertest": ^2.0.11 "@types/ua-parser-js": ^0.7.36 @@ -5020,6 +5041,7 @@ __metadata: source-map: ^0.7.3 speakeasy: ^2.0.0 stream-buffers: ^3.0.2 + strict-uri-encode: ^2.0.0 string-strip-html: ^7.0.3 stylelint: ^13.13.1 stylelint-order: ^4.1.0 @@ -7889,6 +7911,13 @@ __metadata: languageName: node linkType: hard +"@types/strict-uri-encode@npm:^2": + version: 2.0.0 + resolution: "@types/strict-uri-encode@npm:2.0.0" + checksum: e37b6e39fc1440d30bb5f114b3c56a4ecc5db1b7bb1f705bcf607d0eb9e8798953ccaa3792b35c97e74fe61fcc0ff80982d963c22bba056a0745098d4a5c6699 + languageName: node + linkType: hard + "@types/string-strip-html@npm:^5.0.0": version: 5.0.1 resolution: "@types/string-strip-html@npm:5.0.1" @@ -16194,6 +16223,13 @@ __metadata: languageName: node linkType: hard +"filter-obj@npm:^3.0.0": + version: 3.0.0 + resolution: "filter-obj@npm:3.0.0" + checksum: 93bee3cecc2bbd87cb9d786c4ba2ea36fbad5d237aec991deed419dcc892020dd46d0a77c982224ef45d922b1573c77be1588274b9d524c7389ccf8d1a91c330 + languageName: node + linkType: hard + "finalhandler@npm:1.1.2, finalhandler@npm:~1.1.2": version: 1.1.2 resolution: "finalhandler@npm:1.1.2" @@ -27274,6 +27310,18 @@ __metadata: languageName: node linkType: hard +"query-string@npm:^7.1.1": + version: 7.1.1 + resolution: "query-string@npm:7.1.1" + dependencies: + decode-uri-component: ^0.2.0 + filter-obj: ^1.1.0 + split-on-first: ^1.0.0 + strict-uri-encode: ^2.0.0 + checksum: b227d1f588ae93f9f0ad078c6b811295fa151dc5a160a03bb2bac5fa0e6919cb1daa570aad1d288e77c8e89fde5362ba505b1014e6e793da9b1e885b59a690a6 + languageName: node + linkType: hard + "querystring-es3@npm:*, querystring-es3@npm:^0.2.0": version: 0.2.1 resolution: "querystring-es3@npm:0.2.1" @@ -30281,6 +30329,13 @@ __metadata: languageName: node linkType: hard +"split-on-first@npm:^3.0.0": + version: 3.0.0 + resolution: "split-on-first@npm:3.0.0" + checksum: 75dc27ecbac65cfbeab9a3b90cf046307220192d3d7a30e46aa0f19571cc9b4802aac813f3de2cc9b16f2e46aae72f275659b5d2614bb5369c77724d739e5f73 + languageName: node + linkType: hard + "split-string@npm:^3.0.1, split-string@npm:^3.0.2": version: 3.1.0 resolution: "split-string@npm:3.1.0" From 993745d3996450036e8c39150a0b6926cdbbd869 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Wed, 8 Jun 2022 23:23:18 -0600 Subject: [PATCH 4/8] [BREAK] Remove RDStation integration (#25774) ## Proposed changes (including videos or screenshots) ## Issue(s) ## Steps to test or reproduce ## Further comments Co-authored-by: Guilherme Gazzo <5263975+ggazzo@users.noreply.github.com> --- apps/meteor/app/livechat/server/config.ts | 9 --- .../app/livechat/server/hooks/RDStation.js | 62 ------------------- apps/meteor/app/livechat/server/index.js | 1 - .../rocketchat-i18n/i18n/en.i18n.json | 2 - .../meteor/server/startup/migrations/index.ts | 1 + apps/meteor/server/startup/migrations/v268.ts | 10 +++ 6 files changed, 11 insertions(+), 74 deletions(-) delete mode 100644 apps/meteor/app/livechat/server/hooks/RDStation.js create mode 100644 apps/meteor/server/startup/migrations/v268.ts diff --git a/apps/meteor/app/livechat/server/config.ts b/apps/meteor/app/livechat/server/config.ts index 0e4042ce70d4..89339e29e2a2 100644 --- a/apps/meteor/app/livechat/server/config.ts +++ b/apps/meteor/app/livechat/server/config.ts @@ -471,15 +471,6 @@ Meteor.startup(function () { enableQuery: omnichannelEnabledQuery, }); - this.add('Livechat_RDStation_Token', '', { - type: 'string', - group: 'Omnichannel', - public: false, - section: 'RD Station', - i18nLabel: 'RDStation_Token', - enableQuery: omnichannelEnabledQuery, - }); - this.add('Livechat_Routing_Method', 'Auto_Selection', { type: 'select', group: 'Omnichannel', diff --git a/apps/meteor/app/livechat/server/hooks/RDStation.js b/apps/meteor/app/livechat/server/hooks/RDStation.js deleted file mode 100644 index b4f5398018c1..000000000000 --- a/apps/meteor/app/livechat/server/hooks/RDStation.js +++ /dev/null @@ -1,62 +0,0 @@ -import { HTTP } from 'meteor/http'; - -import { settings } from '../../../settings'; -import { callbacks } from '../../../../lib/callbacks'; -import { Livechat } from '../lib/Livechat'; -import { SystemLogger } from '../../../../server/lib/logger/system'; - -function sendToRDStation(room) { - if (!settings.get('Livechat_RDStation_Token')) { - return room; - } - - const livechatData = Livechat.getLivechatRoomGuestInfo(room); - - if (!livechatData.visitor.email) { - return room; - } - - const email = Array.isArray(livechatData.visitor.email) ? livechatData.visitor.email[0].address : livechatData.visitor.email; - - const options = { - headers: { - 'Content-Type': 'application/json', - }, - data: { - token_rdstation: settings.get('Livechat_RDStation_Token'), - identificador: 'rocketchat-livechat', - client_id: livechatData.visitor._id, - email, - }, - }; - - options.data.nome = livechatData.visitor.name || livechatData.visitor.username; - - if (livechatData.visitor.phone) { - options.data.telefone = livechatData.visitor.phone; - } - - if (livechatData.tags) { - options.data.tags = livechatData.tags; - } - - Object.keys(livechatData.customFields || {}).forEach((field) => { - options.data[field] = livechatData.customFields[field]; - }); - - Object.keys(livechatData.visitor.customFields || {}).forEach((field) => { - options.data[field] = livechatData.visitor.customFields[field]; - }); - - try { - HTTP.call('POST', 'https://www.rdstation.com.br/api/1.3/conversions', options); - } catch (e) { - SystemLogger.error('Error sending lead to RD Station ->', e); - } - - return room; -} - -callbacks.add('livechat.closeRoom', sendToRDStation, callbacks.priority.MEDIUM, 'livechat-rd-station-close-room'); - -callbacks.add('livechat.saveInfo', sendToRDStation, callbacks.priority.MEDIUM, 'livechat-rd-station-save-info'); diff --git a/apps/meteor/app/livechat/server/index.js b/apps/meteor/app/livechat/server/index.js index a6f03ba9c4dd..217db0c7a35b 100644 --- a/apps/meteor/app/livechat/server/index.js +++ b/apps/meteor/app/livechat/server/index.js @@ -10,7 +10,6 @@ import './hooks/leadCapture'; import './hooks/markRoomResponded'; import './hooks/offlineMessage'; import './hooks/offlineMessageToChannel'; -import './hooks/RDStation'; import './hooks/saveAnalyticsData'; import './hooks/sendToCRM'; import './hooks/sendToFacebook'; diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 3a8be97ee912..3e3c83355f4d 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3596,8 +3596,6 @@ "Rate Limiter_Description": "Control the rate of requests sent or recieved by your server to prevent cyber attacks and scraping.", "Rate_Limiter_Limit_RegisterUser": "Default number calls to the rate limiter for registering a user", "Rate_Limiter_Limit_RegisterUser_Description": "Number of default calls for user registering endpoints(REST and real-time API's), allowed within the time range defined in the API Rate Limiter section.", - "RD Station": "RD Station", - "RDStation_Token": "RD Station Token", "Reached_seat_limit_banner_warning": "*No more seats available* \nThis workspace has reached its seat limit so no more members can join. *[Request More Seats](__url__)*", "React_when_read_only": "Allow Reacting", "React_when_read_only_changed_successfully": "Allow reacting when read only changed successfully", diff --git a/apps/meteor/server/startup/migrations/index.ts b/apps/meteor/server/startup/migrations/index.ts index 440d32220fdf..6c045d2f447b 100644 --- a/apps/meteor/server/startup/migrations/index.ts +++ b/apps/meteor/server/startup/migrations/index.ts @@ -91,4 +91,5 @@ import './v264'; import './v265'; import './v266'; import './v267'; +import './v268'; import './xrun'; diff --git a/apps/meteor/server/startup/migrations/v268.ts b/apps/meteor/server/startup/migrations/v268.ts new file mode 100644 index 000000000000..b3202af1a870 --- /dev/null +++ b/apps/meteor/server/startup/migrations/v268.ts @@ -0,0 +1,10 @@ +import { addMigration } from '../../lib/migrations'; +import { Settings } from '../../../app/models/server/raw'; + +// Removes deprecated RDStation functionality from Omnichannel +addMigration({ + version: 268, + async up() { + await Settings.removeById('Livechat_RDStation_Token'); + }, +}); From c27412b0bcce47745d5b13938353073a5fddcd8f Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 9 Jun 2022 09:44:00 -0300 Subject: [PATCH 5/8] Regression: fix apps path (#25809) --- apps/meteor/app/api/server/v1/misc.ts | 28 ++-- .../app/apps/client/@types/IOrchestrator.ts | 19 +-- apps/meteor/app/apps/client/orchestrator.ts | 157 +++++++++--------- apps/meteor/client/lib/meteorCallWrapper.ts | 8 +- apps/meteor/client/lib/userData.ts | 27 ++- .../client/providers/ServerProvider.tsx | 8 +- .../views/admin/apps/AppDetailsPage.tsx | 4 +- .../views/admin/apps/hooks/useCategories.ts | 3 +- packages/core-typings/src/IUser.ts | 1 + packages/rest-typings/src/apps/index.ts | 63 ++++++- packages/rest-typings/src/v1/me.ts | 71 ++++---- packages/rest-typings/src/v1/misc.ts | 28 +--- 12 files changed, 251 insertions(+), 166 deletions(-) diff --git a/apps/meteor/app/api/server/v1/misc.ts b/apps/meteor/app/api/server/v1/misc.ts index 9a7b7135a56a..841cca8e885b 100644 --- a/apps/meteor/app/api/server/v1/misc.ts +++ b/apps/meteor/app/api/server/v1/misc.ts @@ -14,6 +14,7 @@ import { isMethodCallAnonProps, isMeteorCall, } from '@rocket.chat/rest-typings'; +import { IUser } from '@rocket.chat/core-typings'; import { hasPermission } from '../../../authorization/server'; import { Users } from '../../../models/server'; @@ -166,17 +167,24 @@ API.v1.addRoute( 'me', { authRequired: true }, { - get() { + async get() { const fields = getDefaultUserFields(); - const user = Users.findOneById(this.userId, { fields }); - - // The password hash shouldn't be leaked but the client may need to know if it exists. - if (user?.services?.password?.bcrypt) { - user.services.password.exists = true; - delete user.services.password.bcrypt; - } - - return API.v1.success(this.getUserInfo(user)); + const { services, ...user } = Users.findOneById(this.userId, { fields }) as IUser; + + return API.v1.success( + this.getUserInfo({ + ...user, + ...(services && { + services: { + ...services, + password: { + // The password hash shouldn't be leaked but the client may need to know if it exists. + exists: Boolean(services?.password?.bcrypt), + } as any, + }, + }), + }), + ); }, }, ); diff --git a/apps/meteor/app/apps/client/@types/IOrchestrator.ts b/apps/meteor/app/apps/client/@types/IOrchestrator.ts index f178cd03960d..55400407a946 100644 --- a/apps/meteor/app/apps/client/@types/IOrchestrator.ts +++ b/apps/meteor/app/apps/client/@types/IOrchestrator.ts @@ -1,4 +1,3 @@ -import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata/IAppInfo'; import { ISetting } from '@rocket.chat/apps-engine/definition/settings/ISetting'; export interface IDetailedDescription { @@ -148,7 +147,6 @@ export interface IAppLanguage { export interface IAppExternalURL { url: string; - success: boolean; } export interface ICategory { @@ -159,10 +157,10 @@ export interface ICategory { title: string; } -export interface IDeletedInstalledApp { - app: IAppInfo; - success: boolean; -} +// export interface IDeletedInstalledApp { +// app: IAppInfo; +// success: boolean; +// } export interface IAppSynced { app: IAppFromMarketplace; @@ -193,12 +191,3 @@ export interface ISettingsReturn { settings: ISettings; success: boolean; } - -export interface ISettingsPayload { - settings: ISetting[]; -} - -export interface ISettingsSetReturn { - updated: ISettings; - success: boolean; -} diff --git a/apps/meteor/app/apps/client/orchestrator.ts b/apps/meteor/app/apps/client/orchestrator.ts index 0062d6206990..dc37aef84e74 100644 --- a/apps/meteor/app/apps/client/orchestrator.ts +++ b/apps/meteor/app/apps/client/orchestrator.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ +import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import { AppClientManager } from '@rocket.chat/apps-engine/client/AppClientManager'; import { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api'; import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; @@ -6,6 +7,7 @@ import { IPermission } from '@rocket.chat/apps-engine/definition/permissions/IPe import { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage/IAppStorageItem'; import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; +import { AppScreenshot, Serialized } from '@rocket.chat/core-typings'; import { App } from '../../../client/views/admin/apps/types'; import { dispatchToastMessage } from '../../../client/lib/toast'; @@ -15,27 +17,23 @@ import { createDeferredValue } from '../lib/misc/DeferredValue'; import { IPricingPlan, EAppPurchaseType, - IAppFromMarketplace, + // IAppFromMarketplace, IAppLanguage, IAppExternalURL, ICategory, - IDeletedInstalledApp, - IAppSynced, - IAppScreenshots, + // IAppSynced, + // IAppScreenshots, + // IScreenshot, IAuthor, IDetailedChangelog, IDetailedDescription, ISubscriptionInfo, - ISettingsReturn, - ISettingsPayload, - ISettingsSetReturn, } from './@types/IOrchestrator'; import { AppWebsocketReceiver } from './communication'; import { handleI18nResources } from './i18n'; import { RealAppsEngineUIHost } from './RealAppsEngineUIHost'; - -const { APIClient } = require('../../utils'); -const { hasAtLeastOnePermission } = require('../../authorization'); +import { APIClient } from '../../utils/client'; +import { hasAtLeastOnePermission } from '../../authorization/client'; export interface IAppsFromMarketplace { price: number; @@ -123,8 +121,9 @@ class AppClientOrchestrator { } } - public screenshots(appId: string): IAppScreenshots { - return APIClient.get(`/v1/apps/${appId}/screenshots`); + public async screenshots(appId: string): Promise { + const { screenshots } = await APIClient.get(`/apps/${appId}/screenshots`); + return screenshots; } public isEnabled(): Promise | undefined { @@ -132,79 +131,87 @@ class AppClientOrchestrator { } public async getApps(): Promise { - const { apps } = await APIClient.get('/v1/apps'); - return apps; + const result = await APIClient.get('/apps'); + if ('apps' in result) { + return result.apps; + } + throw new Error('Apps not found'); } - public async getAppsFromMarketplace(): Promise { - const appsOverviews: IAppFromMarketplace[] = await APIClient.get('/v1/apps', { marketplace: 'true' }); - return appsOverviews.map((app: IAppFromMarketplace) => { - const { latest, price, pricingPlans, purchaseType, isEnterpriseOnly, modifiedAt } = app; - return { - ...latest, - price, - pricingPlans, - purchaseType, - isEnterpriseOnly, - modifiedAt, - }; - }); + public async getAppsFromMarketplace(): Promise { + const result = await APIClient.get('/apps', { marketplace: 'true' }); + + if ('apps' in result) { + const { apps: appsOverviews } = result; + return appsOverviews.map((app) => { + const { latest, price, pricingPlans, purchaseType, isEnterpriseOnly, modifiedAt } = app; + return { + ...latest, + price, + pricingPlans, + purchaseType, + isEnterpriseOnly, + modifiedAt, + }; + }); + } + throw new Error('Apps not found'); } public async getAppsOnBundle(bundleId: string): Promise { - const { apps } = await APIClient.get(`/v1/apps/bundles/${bundleId}/apps`); + const { apps } = await APIClient.get(`/apps/bundles/${bundleId}/apps`); return apps; } public async getAppsLanguages(): Promise { - const { apps } = await APIClient.get('/v1/apps/languages'); + const { apps } = await APIClient.get('/apps/languages'); return apps; } public async getApp(appId: string): Promise { - const { app } = await APIClient.get(`/v1/apps/${appId}`); + const { app } = await APIClient.get(`/apps/${appId}` as any); return app; } public async getAppFromMarketplace(appId: string, version: string): Promise { - const { app } = await APIClient.get(`/v1/apps/${appId}`, { - marketplace: 'true', - version, - }); - return app; + const result = await APIClient.get( + `/apps/${appId}` as any, + { + marketplace: 'true', + version, + } as any, + ); + return result; } public async getLatestAppFromMarketplace(appId: string, version: string): Promise { - const { app } = await APIClient.get(`/v1/apps/${appId}`, { - marketplace: 'true', - update: 'true', - appVersion: version, - }); + const { app } = await APIClient.get( + `/apps/${appId}` as any, + { + marketplace: 'true', + update: 'true', + appVersion: version, + } as any, + ); return app; } - public async getAppSettings(appId: string): Promise { - const { settings } = await APIClient.get(`/v1/apps/${appId}/settings`); - return settings; - } - - public async setAppSettings(appId: string, settings: ISettingsPayload): Promise { - const { updated } = await APIClient.post(`/v1/apps/${appId}/settings`, undefined, { settings }); - return updated; + public async setAppSettings(appId: string, settings: ISetting[]): Promise { + await APIClient.post(`/apps/${appId}/settings`, { settings }); } public async getAppApis(appId: string): Promise { - const { apis } = await APIClient.get(`/v1/apps/${appId}/apis`); + const { apis } = await APIClient.get(`/apps/${appId}/apis`); return apis; } public async getAppLanguages(appId: string): Promise { - const { languages } = await APIClient.get(`/v1/apps/${appId}/languages`); + const { languages } = await APIClient.get(`/apps/${appId}/languages`); return languages; } - public async installApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const { app } = await APIClient.post('/v1/apps/', { + public async installApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { + const { app } = await APIClient.post('/apps', { appId, marketplace: true, version, @@ -214,48 +221,48 @@ class AppClientOrchestrator { } public async updateApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const { app } = await APIClient.post(`/v1/apps/${appId}`, { + const result = (await (APIClient.post as any)(`/apps/${appId}` as any, { appId, marketplace: true, version, permissionsGranted, - }); - return app; - } + })) as any; - public uninstallApp(appId: string): IDeletedInstalledApp { - return APIClient.delete(`apps/${appId}`); - } - - public syncApp(appId: string): IAppSynced { - return APIClient.post(`/v1/apps/${appId}/sync`); + if ('app' in result) { + return result; + } + throw new Error('App not found'); } public async setAppStatus(appId: string, status: AppStatus): Promise { - const { status: effectiveStatus } = await APIClient.post(`/v1/apps/${appId}/status`, { status }); + const { status: effectiveStatus } = await APIClient.post(`/apps/${appId}/status`, { status }); return effectiveStatus; } - public enableApp(appId: string): Promise { - return this.setAppStatus(appId, AppStatus.MANUALLY_ENABLED); - } - public disableApp(appId: string): Promise { return this.setAppStatus(appId, AppStatus.MANUALLY_ENABLED); } - public buildExternalUrl(appId: string, purchaseType = 'buy', details = false): IAppExternalURL { - return APIClient.get('/v1/apps', { + public async buildExternalUrl(appId: string, purchaseType: 'buy' | 'subscription' = 'buy', details = false): Promise { + const result = await APIClient.get('/apps', { buildExternalUrl: 'true', appId, purchaseType, - details, + details: `${details}`, }); + + if ('url' in result) { + return result; + } + throw new Error('Failed to build external url'); } - public async getCategories(): Promise { - const categories = await APIClient.get('/v1/apps', { categories: 'true' }); - return categories; + public async getCategories(): Promise[]> { + const result = await APIClient.get('/apps', { categories: 'true' }); + if ('categories' in result) { + return result.categories; + } + throw new Error('Categories not found'); } public getUIHost(): RealAppsEngineUIHost { @@ -267,7 +274,7 @@ export const Apps = new AppClientOrchestrator(); Meteor.startup(() => { CachedCollectionManager.onLogin(() => { - Meteor.call('apps/is-enabled', (error: Error, isEnabled: boolean) => { + Meteor.call('/apps/is-enabled', (error: Error, isEnabled: boolean) => { if (error) { Apps.handleError(error); return; @@ -279,7 +286,7 @@ Meteor.startup(() => { }); Tracker.autorun(() => { - const isEnabled = settings.get('Apps_Framework_enabled'); + const isEnabled = settings.get('/Apps_Framework_enabled'); Apps.load(isEnabled); }); }); diff --git a/apps/meteor/client/lib/meteorCallWrapper.ts b/apps/meteor/client/lib/meteorCallWrapper.ts index 2615b6c4385d..7368cb328e38 100644 --- a/apps/meteor/client/lib/meteorCallWrapper.ts +++ b/apps/meteor/client/lib/meteorCallWrapper.ts @@ -49,15 +49,13 @@ function wrapMeteorDDPCalls(): void { }); Meteor.connection.onMessage(_message); }; + const method = encodeURIComponent(message.method.replace(/\//g, ':')); - APIClient.post( - `/v1/${endpoint}/${encodeURIComponent(message.method.replace(/\//g, ':'))}` as Parameters[0], - restParams as any, - ) + APIClient.post(`/v1/${endpoint}/${method}`, restParams) .then(({ message: _message }) => { processResult(_message); if (message.method === 'login') { - const parsedMessage = DDPCommon.parseDDP(_message) as { result?: { token?: string } }; + const parsedMessage = DDPCommon.parseDDP(_message as any) as { result?: { token?: string } }; if (parsedMessage.result?.token) { Meteor.loginWithToken(parsedMessage.result.token); } diff --git a/apps/meteor/client/lib/userData.ts b/apps/meteor/client/lib/userData.ts index 112028faa0cc..a75cc865f191 100644 --- a/apps/meteor/client/lib/userData.ts +++ b/apps/meteor/client/lib/userData.ts @@ -81,10 +81,35 @@ export const synchronizeUserData = async (uid: Meteor.User['_id']): Promise ({ + ...token, + when: new Date(token.when), + })), + }, + }), + }), + ...(lastLogin && { + lastLogin: new Date(lastLogin), + }), + ldap: Boolean(ldap), createdAt: new Date(userData.createdAt), _updatedAt: new Date(userData._updatedAt), }); diff --git a/apps/meteor/client/providers/ServerProvider.tsx b/apps/meteor/client/providers/ServerProvider.tsx index 18e6ac307680..50d288d73ec1 100644 --- a/apps/meteor/client/providers/ServerProvider.tsx +++ b/apps/meteor/client/providers/ServerProvider.tsx @@ -30,20 +30,20 @@ const callEndpoint = >( ): Promise>>> => { switch (method) { case 'GET': - return APIClient.get(path as Parameters[0], params) as any; + return APIClient.get(path as Parameters[0], params as any | undefined) as any; case 'POST': - return APIClient.post(path as Parameters[0], params) as ReturnType; + return APIClient.post(path as Parameters[0], params as never) as ReturnType; case 'DELETE': - return APIClient.delete(path as Parameters[0], params) as ReturnType; + return APIClient.delete(path as Parameters[0], params as never) as ReturnType; default: throw new Error('Invalid HTTP method'); } }; -const uploadToEndpoint = (endpoint: PathFor<'POST'>, formData: any): Promise => APIClient.post(endpoint, formData); +const uploadToEndpoint = (endpoint: PathFor<'POST'>, formData: any): Promise => APIClient.post(endpoint, formData as never); const getStream = (streamName: string, options: {} = {}): ((eventName: string, callback: (data: T) => void) => () => void) => { const streamer = Meteor.StreamerCentral.instances[streamName] diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx index 2d1748e392cf..c78ece156ece 100644 --- a/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx @@ -4,7 +4,7 @@ import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useTranslation, useCurrentRoute, useRoute, useRouteParameter } from '@rocket.chat/ui-contexts'; import React, { useState, useCallback, useRef, FC } from 'react'; -import { ISettings, ISettingsPayload } from '../../../../app/apps/client/@types/IOrchestrator'; +import { ISettings } from '../../../../app/apps/client/@types/IOrchestrator'; import { Apps } from '../../../../app/apps/client/orchestrator'; import Page from '../../../components/Page'; import APIsDisplay from './APIsDisplay'; @@ -49,7 +49,7 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) { (Object.values(settings || {}) as ISetting[]).map((value) => ({ ...value, value: current?.[value.id], - })) as unknown as ISettingsPayload, + })), ); } catch (e) { handleAPIError(e); diff --git a/apps/meteor/client/views/admin/apps/hooks/useCategories.ts b/apps/meteor/client/views/admin/apps/hooks/useCategories.ts index 075cc139f8ca..61dfae4e2999 100644 --- a/apps/meteor/client/views/admin/apps/hooks/useCategories.ts +++ b/apps/meteor/client/views/admin/apps/hooks/useCategories.ts @@ -1,7 +1,6 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { ICategory } from '../../../../../app/apps/client/@types/IOrchestrator'; import { Apps } from '../../../../../app/apps/client/orchestrator'; import { CategoryDropdownItem, CategoryDropDownListProps } from '../definitions/CategoryDropdownDefinitions'; import { handleAPIError } from '../helpers'; @@ -21,7 +20,7 @@ export const useCategories = (): [ try { const fetchedCategories = await Apps.getCategories(); - const mappedCategories = fetchedCategories.map((currentCategory: ICategory) => ({ + const mappedCategories = fetchedCategories.map((currentCategory) => ({ id: currentCategory.id, label: currentCategory.title, checked: false, diff --git a/packages/core-typings/src/IUser.ts b/packages/core-typings/src/IUser.ts index 9d0b4547d639..0dde24a2d7ba 100644 --- a/packages/core-typings/src/IUser.ts +++ b/packages/core-typings/src/IUser.ts @@ -116,6 +116,7 @@ export interface IUser extends IRocketChatRecord { status?: UserStatus; statusConnection?: string; lastLogin?: Date; + bio?: string; avatarOrigin?: string; avatarETag?: string; utcOffset?: number; diff --git a/packages/rest-typings/src/apps/index.ts b/packages/rest-typings/src/apps/index.ts index 50b9160d23e2..d7f6fd10c9b2 100644 --- a/packages/rest-typings/src/apps/index.ts +++ b/packages/rest-typings/src/apps/index.ts @@ -1,13 +1,26 @@ import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api'; +import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; import type { IExternalComponent } from '@rocket.chat/apps-engine/definition/externalComponent'; +import type { IPermission } from '@rocket.chat/apps-engine/definition/permissions/IPermission'; +import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import type { IUIActionButton } from '@rocket.chat/apps-engine/definition/ui'; -import type { ISetting, AppScreenshot, App } from '@rocket.chat/core-typings'; +import type { AppScreenshot, App } from '@rocket.chat/core-typings'; export type AppsEndpoints = { '/apps/externalComponents': { GET: () => { externalComponents: IExternalComponent[] }; }; + '/apps/:id': { + GET: (params: { marketplace?: 'true' | 'false'; version?: string; appVersion?: string; update?: 'true' | 'false' }) => { + app: App; + }; + DELETE: () => void; + POST: (params: { marketplace: boolean; version: string; permissionsGranted: IPermission[]; appId: string }) => { + app: App; + }; + }; + '/apps/actionButtons': { GET: () => IUIActionButton[]; }; @@ -18,8 +31,9 @@ export type AppsEndpoints = { '/apps/:id/settings': { GET: () => { - [key: string]: ISetting; + settings: { [key: string]: ISetting }; }; + POST: (params: { settings: ISetting[] }) => { updated: { [key: string]: ISetting } }; }; '/apps/:id/screenshots': { @@ -34,8 +48,49 @@ export type AppsEndpoints = { }; }; - '/apps/:id': { - GET: (params: { marketplace?: 'true' | 'false'; update?: 'true' | 'false'; appVersion: string }) => { + '/apps/bundles/:id/apps': { + GET: () => { + apps: App[]; + }; + }; + + '/apps/:id/sync': { + POST: () => { + app: App; + }; + }; + + '/apps/:id/status': { + POST: (params: { status: AppStatus }) => { + status: string; + }; + }; + + '/apps': { + GET: + | ((params: { buildExternalUrl: 'true'; purchaseType?: 'buy' | 'subscription'; appId?: string; details?: 'true' | 'false' }) => { + url: string; + }) + | ((params: { + purchaseType?: 'buy' | 'subscription'; + marketplace?: 'true' | 'false'; + version?: string; + appId?: string; + details?: 'true' | 'false'; + }) => { + apps: App[]; + }) + | ((params: { categories: 'true' | 'false' }) => { + categories: { + createdDate: string; + description: string; + id: string; + modifiedDate: Date; + title: string; + }[]; + }); + + POST: (params: { appId: string; marketplace: boolean; version: string; permissionsGranted: IPermission[] }) => { app: App; }; }; diff --git a/packages/rest-typings/src/v1/me.ts b/packages/rest-typings/src/v1/me.ts index af406ac1d4d4..048bd03f1f97 100644 --- a/packages/rest-typings/src/v1/me.ts +++ b/packages/rest-typings/src/v1/me.ts @@ -1,35 +1,48 @@ -import type { IUser, Serialized } from '@rocket.chat/core-typings'; +import type { IUser } from '@rocket.chat/core-typings'; -type RawUserData = Serialized< - Pick< - IUser, - | '_id' - | 'type' - | 'name' - | 'username' - | 'emails' - | 'status' - | 'statusDefault' - | 'statusText' - | 'statusConnection' - | 'avatarOrigin' - | 'utcOffset' - | 'language' - | 'settings' - | 'roles' - | 'active' - | 'defaultRoom' - | 'customFields' - | 'statusLivechat' - | 'oauth' - | 'createdAt' - | '_updatedAt' - | 'avatarETag' - > ->; +type Keys = + | 'name' + | 'username' + | 'nickname' + | 'emails' + | 'status' + | 'statusDefault' + | 'statusText' + | 'statusConnection' + | 'bio' + | 'avatarOrigin' + | 'utcOffset' + | 'language' + | 'settings' + | 'idleTimeLimit' + | 'roles' + | 'active' + | 'defaultRoom' + | 'customFields' + | 'requirePasswordChange' + | 'requirePasswordChangeReason' + | 'services.github' + | 'services.gitlab' + | 'services.tokenpass' + | 'services.password.bcrypt' + | 'services.totp.enabled' + | 'services.email2fa.enabled' + | 'statusLivechat' + | 'banners' + | 'oauth.authorizedClients' + | '_updatedAt' + | 'avatarETag' + | 'extension'; export type MeEndpoints = { '/v1/me': { - GET: () => RawUserData; + GET: (params: { fields: Record | Record; user: IUser }) => IUser & { + email?: string; + settings: { + profile: {}; + preferences: unknown; + }; + avatarUrl: string; + }; }; }; diff --git a/packages/rest-typings/src/v1/misc.ts b/packages/rest-typings/src/v1/misc.ts index c2d36fcc83cd..5271af72212b 100644 --- a/packages/rest-typings/src/v1/misc.ts +++ b/packages/rest-typings/src/v1/misc.ts @@ -180,45 +180,35 @@ export type MiscEndpoints = { }[]; }; }; - 'me': { - GET: (params: { fields: { [k: string]: number }; user: IUser }) => IUser & { - email?: string; - settings: { - profile: {}; - preferences: unknown; - }; - avatarUrl: string; - }; - }; - 'shield.svg': { + '/v1/shield.svg': { GET: (params: ShieldSvg) => { svg: string; }; }; - 'spotlight': { + '/v1/spotlight': { GET: (params: Spotlight) => { users: Pick[]; rooms: IRoom[]; }; }; - 'directory': { + '/v1/directory': { GET: (params: Directory) => PaginatedResult<{ result: (IUser | IRoom | ITeam)[]; }>; }; - 'method.call': { - POST: (params: MethodCall) => { - result: unknown; + '/v1/method.call/:method': { + POST: (params: { message: string }) => { + message: unknown; }; }; - 'method.callAnon': { - POST: (params: MethodCallAnon) => { - result: unknown; + '/v1/method.callAnon/:method': { + POST: (params: { message: string }) => { + message: unknown; }; }; }; From 11a9d235895b70aa8b4f3536c087c0c31858fc7a Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Thu, 9 Jun 2022 07:19:31 -0600 Subject: [PATCH 6/8] Chore: use params instead of URL building on livechat endpoints (#25810) ## Proposed changes (including videos or screenshots) ## Issue(s) ## Steps to test or reproduce ## Further comments --- .../livechat/client/lib/stream/queueManager.js | 2 +- .../client/views/app/dialog/closeRoom.js | 4 ++-- .../client/views/app/livechatReadOnly.js | 6 +++--- .../views/app/tabbar/contactChatHistory.js | 18 ++++++++++-------- .../client/oauth/oauth2-client.js | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.js b/apps/meteor/app/livechat/client/lib/stream/queueManager.js index 1a17c2169b30..10bdfe1d5820 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.js +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.js @@ -68,7 +68,7 @@ const updateInquiries = async (inquiries = []) => inquiries.forEach((inquiry) => LivechatInquiry.upsert({ _id: inquiry._id }, { ...inquiry, _updatedAt: new Date(inquiry._updatedAt) })); const getAgentsDepartments = async (userId) => { - const { departments } = await APIClient.get(`/v1/livechat/agents/${userId}/departments?enabledDepartmentsOnly=true`); + const { departments } = await APIClient.get(`/v1/livechat/agents/${userId}/departments`, { enabledDepartmentsOnly: true }); return departments; }; diff --git a/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js b/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js index 779b7e9f5938..767bd0168d75 100644 --- a/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js +++ b/apps/meteor/app/livechat/client/views/app/dialog/closeRoom.js @@ -167,11 +167,11 @@ Template.closeRoom.onCreated(async function () { this.onEnterTag = () => this.invalidTags.set(!validateRoomTags(this.tagsRequired.get(), this.tags.get())); const { rid } = Template.currentData(); - const { room } = await APIClient.get(`/v1/rooms.info?roomId=${rid}`); + const { room } = await APIClient.get(`/v1/rooms.info`, { roomId: rid }); this.tags.set(room?.tags || []); if (room?.departmentId) { - const { department } = await APIClient.get(`/v1/livechat/department/${room.departmentId}?includeAgents=false`); + const { department } = await APIClient.get(`/v1/livechat/department/${room.departmentId}`, { includeAgents: false }); this.tagsRequired.set(department?.requestTagBeforeClosingChat); } diff --git a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js index a42d81f029bb..e860e67869a6 100644 --- a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js +++ b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js @@ -61,7 +61,7 @@ Template.livechatReadOnly.events({ event.stopPropagation(); try { - const { success } = (await APIClient.get(`/v1/livechat/room.join?roomId=${this.rid}`)) || {}; + const { success } = (await APIClient.get(`/v1/livechat/room.join`, { roomId: this.rid })) || {}; if (!success) { throw new Meteor.Error('error-join-room', 'Error joining room'); } @@ -99,13 +99,13 @@ Template.livechatReadOnly.onCreated(async function () { this.loadRoomAndInquiry = async (roomId) => { this.preparing.set(true); - const { inquiry } = await APIClient.get(`/v1/livechat/inquiries.getOne?roomId=${roomId}`); + const { inquiry } = await APIClient.get(`/v1/livechat/inquiries.getOne`, { roomId }); this.inquiry.set(inquiry); if (inquiry && inquiry._id) { inquiryDataStream.on(inquiry._id, this.updateInquiry); } - const { room } = await APIClient.get(`/v1/rooms.info?roomId=${roomId}`); + const { room } = await APIClient.get(`/v1/rooms.info`, { roomId }); this.room.set(room); if (room && room._id) { RoomManager.roomStream.on(roomId, (room) => this.room.set(room)); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js index 10e05932b3fb..690402564a14 100644 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js +++ b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js @@ -70,22 +70,24 @@ Template.contactChatHistory.onCreated(async function () { const offset = this.offset.get(); const searchTerm = this.searchTerm.get(); - let baseUrl = `/v1/livechat/visitors.searchChats/room/${ - currentData.rid - }/visitor/${this.visitorId.get()}?count=${limit}&offset=${offset}&closedChatsOnly=true&servedChatsOnly=true`; - if (searchTerm) { - baseUrl += `&searchText=${searchTerm}`; - } + const baseUrl = `/v1/livechat/visitors.searchChats/room/${currentData.rid}/visitor/${this.visitorId.get()}`; + const params = { + count: limit, + offset, + closedChatsOnly: true, + servedChatsOnly: true, + ...(searchTerm && { searchText: searchTerm }), + }; this.isLoading.set(true); - const { history, total } = await APIClient.get(baseUrl); + const { history, total } = await APIClient.get(baseUrl, params); this.history.set(offset === 0 ? history : this.history.get().concat(history)); this.hasMore.set(total > this.history.get().length); this.isLoading.set(false); }); this.autorun(async () => { - const { room } = await APIClient.get(`/v1/rooms.info?roomId=${currentData.rid}`); + const { room } = await APIClient.get(`/v1/rooms.info`, { roomId: currentData.rid }); if (room?.v) { this.visitorId.set(room.v._id); } diff --git a/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js b/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js index 55d7162d7f3a..05edccb9972d 100644 --- a/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js +++ b/apps/meteor/app/oauth2-server-config/client/oauth/oauth2-client.js @@ -7,7 +7,7 @@ import { APIClient } from '../../../utils/client'; Template.authorize.onCreated(async function () { this.oauthApp = new ReactiveVar({}); - const { oauthApp } = await APIClient.get(`/v1/oauth-apps.get?clientId=${this.data.client_id()}`); + const { oauthApp } = await APIClient.get(`/v1/oauth-apps.get`, { clientId: this.data.client_id() }); this.oauthApp.set(oauthApp); }); From 6b3908bf6e9496e711b3da9542c62ba87ba6960f Mon Sep 17 00:00:00 2001 From: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com> Date: Thu, 9 Jun 2022 18:49:43 +0530 Subject: [PATCH 7/8] [FIX] allow only livechat-agents to be contact manager for any omnichannel contact (#25451) ## Proposed changes (including videos or screenshots) ## Issue(s) ![image](https://user-images.githubusercontent.com/34130764/169371479-30b0b88b-08e8-4975-8f36-6387d968a568.png) ## Steps to test or reproduce ## Further comments Tasks: - [x] Frontend change on auto-select component - [x] Backend API checks --- .../app/lib/server/functions/deleteUser.ts | 8 ++--- .../app/livechat/server/api/v1/contact.js | 4 ++- .../app/livechat/server/lib/Contacts.js | 13 ++++++++ .../app/livechat/server/lib/Livechat.js | 3 +- .../models/server/models/LivechatVisitors.js | 14 -------- .../app/models/server/raw/LivechatVisitors.ts | 17 +++++++++- .../additionalForms/ContactManager.js | 32 ++++++++++++++++--- packages/core-typings/src/ILivechatVisitor.ts | 3 ++ 8 files changed, 68 insertions(+), 26 deletions(-) diff --git a/apps/meteor/app/lib/server/functions/deleteUser.ts b/apps/meteor/app/lib/server/functions/deleteUser.ts index f9901701628a..63339692bb5d 100644 --- a/apps/meteor/app/lib/server/functions/deleteUser.ts +++ b/apps/meteor/app/lib/server/functions/deleteUser.ts @@ -3,8 +3,8 @@ import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { FileProp } from '@rocket.chat/core-typings'; import { FileUpload } from '../../../file-upload/server'; -import { Users, Subscriptions, Messages, Rooms, LivechatDepartmentAgents, LivechatVisitors } from '../../../models/server'; -import { FederationServers, Integrations } from '../../../models/server/raw'; +import { Users, Subscriptions, Messages, Rooms, LivechatDepartmentAgents } from '../../../models/server'; +import { FederationServers, Integrations, LivechatVisitors } from '../../../models/server/raw'; import { settings } from '../../../settings/server'; import { updateGroupDMsName } from './updateGroupDMsName'; import { relinquishRoomOwnerships } from './relinquishRoomOwnerships'; @@ -65,13 +65,13 @@ export async function deleteUser(userId: string, confirmRelinquish = false): Pro if (user.roles.includes('livechat-agent')) { // Remove user as livechat agent LivechatDepartmentAgents.removeByAgentId(userId); - LivechatVisitors.removeContactManagerByUsername(user.username); + await LivechatVisitors.removeContactManagerByUsername(user.username); } if (user.roles.includes('livechat-monitor')) { // Remove user as Unit Monitor LivechatUnitMonitors.removeByMonitorId(userId); - LivechatVisitors.removeContactManagerByUsername(user.username); + await LivechatVisitors.removeContactManagerByUsername(user.username); } // removes user's avatar diff --git a/apps/meteor/app/livechat/server/api/v1/contact.js b/apps/meteor/app/livechat/server/api/v1/contact.js index 21cc25519faa..41a2ee9ec6d3 100644 --- a/apps/meteor/app/livechat/server/api/v1/contact.js +++ b/apps/meteor/app/livechat/server/api/v1/contact.js @@ -18,7 +18,9 @@ API.v1.addRoute( email: Match.Maybe(String), phone: Match.Maybe(String), customFields: Match.Maybe(Object), - contactManager: Match.Maybe(Object), + contactManager: Match.Maybe({ + username: String, + }), }); const contact = Contacts.registerContact(this.bodyParams); diff --git a/apps/meteor/app/livechat/server/lib/Contacts.js b/apps/meteor/app/livechat/server/lib/Contacts.js index 980828f0a360..24909685e6a9 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.js +++ b/apps/meteor/app/livechat/server/lib/Contacts.js @@ -1,7 +1,9 @@ import { check } from 'meteor/check'; +import { Meteor } from 'meteor/meteor'; import s from 'underscore.string'; import { LivechatVisitors, LivechatCustomField, LivechatRooms, Rooms, LivechatInquiry, Subscriptions } from '../../../models'; +import { Users } from '../../../models/server/raw'; export const Contacts = { registerContact({ token, name, email, phone, username, customFields = {}, contactManager = {} } = {}) { @@ -9,6 +11,17 @@ export const Contacts = { const visitorEmail = s.trim(email).toLowerCase(); + if (contactManager?.username) { + // verify if the user exists with this username and has a livechat-agent role + const user = Promise.await(Users.findOneByUsername(contactManager.username, { projection: { roles: 1 } })); + if (!user) { + throw new Meteor.Error('error-contact-manager-not-found', `No user found with username ${contactManager.username}`); + } + if (!user.roles || !Array.isArray(user.roles) || !user.roles.includes('livechat-agent')) { + throw new Meteor.Error('error-invalid-contact-manager', 'The contact manager must have the role "livechat-agent"'); + } + } + let contactId; const updateUser = { $set: { diff --git a/apps/meteor/app/livechat/server/lib/Livechat.js b/apps/meteor/app/livechat/server/lib/Livechat.js index 3c387b73f532..d71d12a3e606 100644 --- a/apps/meteor/app/livechat/server/lib/Livechat.js +++ b/apps/meteor/app/livechat/server/lib/Livechat.js @@ -40,7 +40,7 @@ import { normalizeTransferredByData, parseAgentCustomFields, updateDepartmentAge import { Apps, AppEvents } from '../../../apps/server'; import { businessHourManager } from '../business-hour'; import notifications from '../../../notifications/server/lib/Notifications'; -import { Users as UsersRaw } from '../../../models/server/raw'; +import { Users as UsersRaw, LivechatVisitors as LivechatVisitorsRaw } from '../../../models/server/raw'; import { addUserRoles } from '../../../../server/lib/roles/addUserRoles'; import { removeUserFromRoles } from '../../../../server/lib/roles/removeUserFromRoles'; @@ -925,6 +925,7 @@ export const Livechat = { Users.removeLivechatData(_id); this.setUserStatusLivechat(_id, 'not-available'); LivechatDepartmentAgents.removeByAgentId(_id); + Promise.await(LivechatVisitorsRaw.removeContactManagerByUsername(username)); return true; } diff --git a/apps/meteor/app/models/server/models/LivechatVisitors.js b/apps/meteor/app/models/server/models/LivechatVisitors.js index 01642e36e84d..ffffe1095fcd 100644 --- a/apps/meteor/app/models/server/models/LivechatVisitors.js +++ b/apps/meteor/app/models/server/models/LivechatVisitors.js @@ -248,20 +248,6 @@ export class LivechatVisitors extends Base { const query = { _id }; return this.remove(query); } - - removeContactManagerByUsername(manager) { - const query = { - contactManager: { - username: manager, - }, - }; - const update = { - $unset: { - contactManager: 1, - }, - }; - return this.update(query, update); - } } export default new LivechatVisitors(); diff --git a/apps/meteor/app/models/server/raw/LivechatVisitors.ts b/apps/meteor/app/models/server/raw/LivechatVisitors.ts index 8cb7ebbfb75f..222b44918617 100644 --- a/apps/meteor/app/models/server/raw/LivechatVisitors.ts +++ b/apps/meteor/app/models/server/raw/LivechatVisitors.ts @@ -1,5 +1,5 @@ import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { AggregationCursor, Cursor, FilterQuery, FindOneOptions, WithoutProjection } from 'mongodb'; +import { AggregationCursor, Cursor, FilterQuery, FindOneOptions, UpdateWriteOpResult, WithoutProjection } from 'mongodb'; import type { ILivechatVisitor } from '@rocket.chat/core-typings'; import { BaseRaw } from './BaseRaw'; @@ -105,4 +105,19 @@ export class LivechatVisitorsRaw extends BaseRaw { return this.find(query, options); } + + removeContactManagerByUsername(manager: string): Promise { + return this.updateMany( + { + contactManager: { + username: manager, + }, + }, + { + $unset: { + contactManager: true, + }, + }, + ); + } } diff --git a/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js b/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js index db8b1d9fe03a..4eaefaf29beb 100644 --- a/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js +++ b/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js @@ -1,17 +1,39 @@ import { Field } from '@rocket.chat/fuselage'; -import { useTranslation } from '@rocket.chat/ui-contexts'; -import React from 'react'; +import { useEndpoint, useTranslation } from '@rocket.chat/ui-contexts'; +import React, { useEffect, useState, useCallback } from 'react'; -import UserAutoComplete from '../../../../client/components/UserAutoComplete'; +import AutoCompleteAgent from '../../../../client/components/AutoCompleteAgent'; -export const ContactManager = ({ value, handler }) => { +export const ContactManager = ({ value: username, handler }) => { const t = useTranslation(); + const [userId, setUserId] = useState(); + + const getUserData = useEndpoint('GET', 'users.info'); + + const fetchUserId = async () => { + const { user } = await getUserData({ username }); + user._id && setUserId(user._id); + }; + + const handleAgent = useCallback( + async (e) => { + setUserId(e); + const { user } = await getUserData({ userId: e }); + handler(user.username); + }, + [handler, setUserId, getUserData], + ); + + useEffect(() => { + fetchUserId(); + }); + return ( {t('Contact_Manager')} - + ); diff --git a/packages/core-typings/src/ILivechatVisitor.ts b/packages/core-typings/src/ILivechatVisitor.ts index 3145854c3868..d7e2772721e6 100644 --- a/packages/core-typings/src/ILivechatVisitor.ts +++ b/packages/core-typings/src/ILivechatVisitor.ts @@ -32,6 +32,9 @@ export interface ILivechatVisitor extends IRocketChatRecord { ip?: string; host?: string; visitorEmails?: IVisitorEmail[]; + contactManager?: { + username: string; + }; } export interface ILivechatVisitorDTO { From 5a74a5c164ce54e8e0d3a52ef7c48d395ae88383 Mon Sep 17 00:00:00 2001 From: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com> Date: Thu, 9 Jun 2022 20:07:39 +0530 Subject: [PATCH 8/8] [FIX] Voip endpoint permissions (#25783) ## Proposed changes (including videos or screenshots) ## Issue(s) Earlier we didn't check for any permissions while creating or closing VoIP room. This new PR will enforce those permission checks ## Steps to test or reproduce ## Further comments --- apps/meteor/app/api/server/v1/voip/rooms.ts | 8 ++++++-- apps/meteor/tests/end-to-end/api/02-channels.js | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/meteor/app/api/server/v1/voip/rooms.ts b/apps/meteor/app/api/server/v1/voip/rooms.ts index f04feaf0e084..79e77c607972 100644 --- a/apps/meteor/app/api/server/v1/voip/rooms.ts +++ b/apps/meteor/app/api/server/v1/voip/rooms.ts @@ -82,7 +82,11 @@ const parseAndValidate = (property: string, date?: string): DateParam => { API.v1.addRoute( 'voip/room', - { authRequired: false, rateLimiterOptions: { numRequestsAllowed: 5, intervalTimeInMS: 60000 } }, + { + authRequired: true, + rateLimiterOptions: { numRequestsAllowed: 5, intervalTimeInMS: 60000 }, + permissionsRequired: ['inbound-voip-calls'], + }, { async get() { const defaultCheckParams = { @@ -212,7 +216,7 @@ API.v1.addRoute( */ API.v1.addRoute( 'voip/room.close', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['inbound-voip-calls'] }, { async post() { check(this.bodyParams, { diff --git a/apps/meteor/tests/end-to-end/api/02-channels.js b/apps/meteor/tests/end-to-end/api/02-channels.js index 80e7435c8e8f..5469295f68bd 100644 --- a/apps/meteor/tests/end-to-end/api/02-channels.js +++ b/apps/meteor/tests/end-to-end/api/02-channels.js @@ -305,11 +305,13 @@ describe('[Channels]', function () { before(() => updateSetting('VoIP_Enabled', true)); const createVoipRoom = async () => { const testUser = await createUser({ roles: ['user', 'livechat-agent'] }); + const testUserCredentials = await login(testUser.username, password); const visitor = await createVisitor(); const roomResponse = await createRoom({ token: visitor.token, type: 'v', agentId: testUser._id, + credentials: testUserCredentials, }); return roomResponse.body.room; };