From 13eab981436c4769a9c65ea19e84398db8cf072e Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Thu, 15 Apr 2021 10:04:36 -0400 Subject: [PATCH] Refactor rest client class to use mixin and a bit of cleanup (#5318) --- app/actions/apps.ts | 2 +- app/actions/helpers/channels.test.js | 2 +- app/actions/helpers/channels.ts | 2 +- app/actions/views/channel.js | 2 +- app/actions/views/emoji.js | 2 +- app/actions/views/login.js | 2 +- app/actions/views/login.test.js | 2 +- app/actions/views/post.js | 2 +- app/actions/views/post.test.js | 2 +- app/actions/views/root.js | 2 +- app/actions/views/session.js | 2 +- app/actions/views/user.js | 2 +- app/actions/websocket/channels.test.js | 2 +- app/actions/websocket/channels.ts | 2 +- app/actions/websocket/general.test.js | 2 +- app/actions/websocket/index.ts | 2 +- app/actions/websocket/integrations.test.js | 2 +- app/actions/websocket/posts.test.js | 2 +- app/actions/websocket/reactions.test.js | 2 +- app/actions/websocket/teams.test.js | 2 +- app/actions/websocket/teams.ts | 2 +- app/actions/websocket/users.test.js | 2 +- app/actions/websocket/users.ts | 4 +- app/actions/websocket/websocket.test.js | 2 +- app/client/rest/apps.ts | 36 + app/client/rest/base.ts | 373 ++ app/client/rest/bots.ts | 39 + app/client/rest/channels.ts | 308 ++ app/client/rest/constants.ts | 14 + app/client/rest/emojis.ts | 101 + app/client/rest/error.ts | 26 + app/client/rest/files.ts | 47 + app/client/rest/general.ts | 98 + app/client/rest/groups.ts | 53 + .../rest/index.test.js} | 3 +- app/client/rest/index.ts | 56 + app/client/rest/integrations.ts | 68 + app/client/rest/posts.ts | 237 ++ app/client/rest/preferences.ts | 35 + app/client/rest/teams.ts | 177 + app/client/rest/tos.ts | 25 + app/client/rest/users.ts | 398 +++ .../{websocket.ts => websocket/index.ts} | 0 .../app_command_parser_test_dependencies.ts | 2 +- .../slash_suggestion/slash_suggestion.tsx | 2 +- app/components/emoji/index.js | 2 +- .../file_attachment_image.js | 2 +- .../file_attachment_image.test.js | 2 +- .../file_attachment_list.js | 2 +- .../uploads/upload_item/upload_item.js | 2 +- app/components/post_profile_picture/index.js | 2 +- .../profile_picture/profile_picture.js | 2 +- app/components/profile_picture_button.js | 2 +- app/components/profile_picture_button.test.js | 2 +- app/components/root/root.js | 2 +- app/components/team_icon/team_icon.js | 2 +- app/init/credentials.js | 2 +- app/init/fetch.js | 7 +- app/init/fetch.test.js | 10 +- app/init/global_event_handler.js | 2 +- app/mm-redux/action_types/channels.ts | 7 - app/mm-redux/action_types/index.ts | 4 - app/mm-redux/action_types/integrations.ts | 10 - app/mm-redux/action_types/jobs.ts | 25 - app/mm-redux/action_types/roles.ts | 12 - app/mm-redux/action_types/schemes.ts | 19 - app/mm-redux/action_types/teams.ts | 8 - app/mm-redux/action_types/users.ts | 1 - app/mm-redux/actions/apps.ts | 2 +- app/mm-redux/actions/bots.test.js | 80 +- app/mm-redux/actions/bots.ts | 55 +- app/mm-redux/actions/channels.test.js | 310 +- app/mm-redux/actions/channels.ts | 127 +- app/mm-redux/actions/emojis.test.js | 2 +- app/mm-redux/actions/emojis.ts | 2 +- app/mm-redux/actions/errors.test.js | 2 +- app/mm-redux/actions/errors.ts | 2 +- app/mm-redux/actions/files.test.js | 51 +- app/mm-redux/actions/files.ts | 2 +- app/mm-redux/actions/general.test.js | 2 +- app/mm-redux/actions/general.ts | 2 +- app/mm-redux/actions/helpers.test.js | 4 +- app/mm-redux/actions/helpers.ts | 2 +- app/mm-redux/actions/index.ts | 4 - app/mm-redux/actions/integrations.test.js | 593 +-- app/mm-redux/actions/integrations.ts | 312 +- app/mm-redux/actions/jobs.test.js | 145 - app/mm-redux/actions/jobs.ts | 72 - app/mm-redux/actions/posts.test.js | 27 +- app/mm-redux/actions/posts.ts | 29 +- app/mm-redux/actions/preferences.test.js | 2 +- app/mm-redux/actions/preferences.ts | 2 +- app/mm-redux/actions/roles.test.js | 49 +- app/mm-redux/actions/roles.ts | 42 +- app/mm-redux/actions/schemes.test.js | 104 - app/mm-redux/actions/schemes.ts | 95 - app/mm-redux/actions/search.test.js | 2 +- app/mm-redux/actions/search.ts | 2 +- app/mm-redux/actions/teams.test.js | 253 +- app/mm-redux/actions/teams.ts | 318 +- app/mm-redux/actions/users.test.js | 570 +-- app/mm-redux/actions/users.ts | 482 +-- app/mm-redux/client/client4.ts | 3178 ----------------- app/mm-redux/client/fetch_etag.ts | 38 - app/mm-redux/client/index.ts | 5 - app/mm-redux/constants/general.ts | 2 - .../reducers/entities/channels.test.js | 108 - app/mm-redux/reducers/entities/channels.ts | 61 +- app/mm-redux/reducers/entities/index.ts | 4 - .../reducers/entities/integrations.ts | 123 +- app/mm-redux/reducers/entities/jobs.ts | 49 - app/mm-redux/reducers/entities/schemes.ts | 44 - app/mm-redux/reducers/entities/teams.ts | 59 +- app/mm-redux/reducers/entities/users.ts | 30 - app/mm-redux/reducers/requests/index.ts | 2 - app/mm-redux/reducers/requests/jobs.ts | 56 - app/mm-redux/reducers/requests/roles.ts | 33 - .../selectors/entities/channels.test.js | 25 +- app/mm-redux/selectors/entities/channels.ts | 6 +- app/mm-redux/selectors/entities/jobs.ts | 22 - .../selectors/entities/schemes.test.js | 81 - app/mm-redux/selectors/entities/schemes.ts | 82 - app/mm-redux/selectors/entities/users.test.js | 15 - app/mm-redux/selectors/entities/users.ts | 8 - app/mm-redux/types/channels.ts | 1 - app/mm-redux/types/index.ts | 4 - app/mm-redux/types/jobs.ts | 23 - app/mm-redux/types/posts.ts | 4 + app/mm-redux/types/requests.ts | 10 - app/mm-redux/types/schemes.ts | 26 - app/mm-redux/types/store.ts | 7 +- app/mm-redux/types/users.ts | 1 - app/mm-redux/utils/emoji_utils.ts | 2 +- app/mm-redux/utils/file_utils.test.js | 2 +- app/mm-redux/utils/file_utils.ts | 2 +- app/mm-redux/utils/mix.ts | 17 + app/mm-redux/utils/sentry.test.js | 4 +- app/mm-redux/utils/sentry.ts | 2 +- app/screens/channel/index.js | 2 +- app/screens/edit_profile/edit_profile.js | 2 +- app/screens/gallery/footer/index.tsx | 2 +- .../footer/prepare_file/prepare_file.tsx | 2 +- app/screens/gallery/footer/summary/index.ts | 2 +- app/screens/gallery/gallery_video.tsx | 2 +- .../notification/notification_icon.tsx | 2 +- app/screens/select_server/select_server.js | 2 +- app/screens/sso/index.tsx | 2 +- app/screens/sso/sso_with_webview.tsx | 2 +- app/store/initial_state.js | 1 - app/utils/error_handling.js | 2 +- app/utils/image_cache_manager.js | 2 +- app/utils/mix.ts | 17 + app/utils/network.js | 2 +- app/utils/security.js | 2 +- app/utils/sentry/index.js | 4 +- app/utils/sentry/index.test.js | 2 +- babel.config.js | 1 + share_extension/actions/index.ts | 2 +- share_extension/screens/share.tsx | 2 +- test/test_helper.js | 2 +- tsconfig.json | 1 + 161 files changed, 2261 insertions(+), 7960 deletions(-) create mode 100644 app/client/rest/apps.ts create mode 100644 app/client/rest/base.ts create mode 100644 app/client/rest/bots.ts create mode 100644 app/client/rest/channels.ts create mode 100644 app/client/rest/constants.ts create mode 100644 app/client/rest/emojis.ts create mode 100644 app/client/rest/error.ts create mode 100644 app/client/rest/files.ts create mode 100644 app/client/rest/general.ts create mode 100644 app/client/rest/groups.ts rename app/{mm-redux/client/client4.test.js => client/rest/index.test.js} (96%) create mode 100644 app/client/rest/index.ts create mode 100644 app/client/rest/integrations.ts create mode 100644 app/client/rest/posts.ts create mode 100644 app/client/rest/preferences.ts create mode 100644 app/client/rest/teams.ts create mode 100644 app/client/rest/tos.ts create mode 100644 app/client/rest/users.ts rename app/client/{websocket.ts => websocket/index.ts} (100%) delete mode 100644 app/mm-redux/action_types/jobs.ts delete mode 100644 app/mm-redux/action_types/schemes.ts delete mode 100644 app/mm-redux/actions/jobs.test.js delete mode 100644 app/mm-redux/actions/jobs.ts delete mode 100644 app/mm-redux/actions/schemes.test.js delete mode 100644 app/mm-redux/actions/schemes.ts delete mode 100644 app/mm-redux/client/client4.ts delete mode 100644 app/mm-redux/client/fetch_etag.ts delete mode 100644 app/mm-redux/client/index.ts delete mode 100644 app/mm-redux/reducers/entities/jobs.ts delete mode 100644 app/mm-redux/reducers/entities/schemes.ts delete mode 100644 app/mm-redux/reducers/requests/jobs.ts delete mode 100644 app/mm-redux/selectors/entities/jobs.ts delete mode 100644 app/mm-redux/selectors/entities/schemes.test.js delete mode 100644 app/mm-redux/selectors/entities/schemes.ts delete mode 100644 app/mm-redux/types/jobs.ts delete mode 100644 app/mm-redux/types/schemes.ts create mode 100644 app/mm-redux/utils/mix.ts create mode 100644 app/utils/mix.ts diff --git a/app/actions/apps.ts b/app/actions/apps.ts index c654382ad..6f8281f7d 100644 --- a/app/actions/apps.ts +++ b/app/actions/apps.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {ActionFunc} from '@mm-redux/types/actions'; import {AppCallResponse, AppForm, AppCallRequest, AppCallType} from '@mm-redux/types/apps'; import {AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps'; diff --git a/app/actions/helpers/channels.test.js b/app/actions/helpers/channels.test.js index 51edf98e1..e1ba04b95 100644 --- a/app/actions/helpers/channels.test.js +++ b/app/actions/helpers/channels.test.js @@ -3,7 +3,7 @@ /* eslint-disable no-import-assign */ -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Preferences} from '@mm-redux/constants'; import {PreferenceTypes} from '@mm-redux/action_types'; diff --git a/app/actions/helpers/channels.ts b/app/actions/helpers/channels.ts index 384daf274..d23873b18 100644 --- a/app/actions/helpers/channels.ts +++ b/app/actions/helpers/channels.ts @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {ChannelTypes, PreferenceTypes, RoleTypes, UserTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Preferences} from '@mm-redux/constants'; import {getCurrentChannelId, getRedirectChannelNameForTeam, getChannelsNameMapInTeam} from '@mm-redux/selectors/entities/channels'; import {getConfig} from '@mm-redux/selectors/entities/general'; diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index 1b603a4c6..e56cc7760 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -15,7 +15,7 @@ import { import {savePreferences} from '@mm-redux/actions/preferences'; import {getLicense} from '@mm-redux/selectors/entities/general'; import {addUserToTeam, getTeamByName, removeUserFromTeam, selectTeam} from '@mm-redux/actions/teams'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Preferences} from '@mm-redux/constants'; import {getPostIdsInChannel} from '@mm-redux/selectors/entities/posts'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; diff --git a/app/actions/views/emoji.js b/app/actions/views/emoji.js index 5afc6aa27..3ea9f7853 100644 --- a/app/actions/views/emoji.js +++ b/app/actions/views/emoji.js @@ -5,7 +5,7 @@ import {batchActions} from 'redux-batched-actions'; import {EmojiTypes} from '@mm-redux/action_types'; import {addReaction as serviceAddReaction, getNeededCustomEmojis} from '@mm-redux/actions/posts'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getPostIdsInCurrentChannel, makeGetPostIdsForThread} from '@mm-redux/selectors/entities/posts'; import {ViewTypes} from 'app/constants'; diff --git a/app/actions/views/login.js b/app/actions/views/login.js index 17a9d19fa..deea77edb 100644 --- a/app/actions/views/login.js +++ b/app/actions/views/login.js @@ -7,7 +7,7 @@ import {getDataRetentionPolicy} from '@mm-redux/actions/general'; import {GeneralTypes} from '@mm-redux/action_types'; import {getSessions} from '@mm-redux/actions/users'; import {autoUpdateTimezone} from '@mm-redux/actions/timezone'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getConfig, getLicense} from '@mm-redux/selectors/entities/general'; import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone'; import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; diff --git a/app/actions/views/login.test.js b/app/actions/views/login.test.js index 4e7ba1aeb..307458db6 100644 --- a/app/actions/views/login.test.js +++ b/app/actions/views/login.test.js @@ -4,7 +4,7 @@ import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {handleSuccessfulLogin} from 'app/actions/views/login'; diff --git a/app/actions/views/post.js b/app/actions/views/post.js index 009de775e..640bfbb0d 100644 --- a/app/actions/views/post.js +++ b/app/actions/views/post.js @@ -15,7 +15,7 @@ import { receivedPostsSince, receivedPostsInThread, } from '@mm-redux/actions/posts'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Posts} from '@mm-redux/constants'; import {getPost as selectPost, getPostIdsInChannel} from '@mm-redux/selectors/entities/posts'; import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels'; diff --git a/app/actions/views/post.test.js b/app/actions/views/post.test.js index 9354907d5..c9961cfbe 100644 --- a/app/actions/views/post.test.js +++ b/app/actions/views/post.test.js @@ -6,7 +6,7 @@ import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {PostTypes, UserTypes} from '@mm-redux/action_types'; import * as PostSelectors from '@mm-redux/selectors/entities/posts'; diff --git a/app/actions/views/root.js b/app/actions/views/root.js index 3a697249f..5130338a2 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -10,7 +10,7 @@ import {fetchMyChannelsAndMembers, getChannelAndMyMember} from '@mm-redux/action import {getDataRetentionPolicy} from '@mm-redux/actions/general'; import {receivedNewPost} from '@mm-redux/actions/posts'; import {getMyTeams, getMyTeamMembers} from '@mm-redux/actions/teams'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import EventEmitter from '@mm-redux/utils/event_emitter'; import initialState from '@store/initial_state'; diff --git a/app/actions/views/session.js b/app/actions/views/session.js index 0af04c2f4..91c62c688 100644 --- a/app/actions/views/session.js +++ b/app/actions/views/session.js @@ -4,7 +4,7 @@ import moment from 'moment-timezone'; import {getSessions} from '@mm-redux/actions/users'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getConfig} from '@mm-redux/selectors/entities/general'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; diff --git a/app/actions/views/user.js b/app/actions/views/user.js index a3804a4ec..9ab0187f6 100644 --- a/app/actions/views/user.js +++ b/app/actions/views/user.js @@ -8,7 +8,7 @@ import {GeneralTypes, RoleTypes, UserTypes} from '@mm-redux/action_types'; import {getDataRetentionPolicy} from '@mm-redux/actions/general'; import * as HelperActions from '@mm-redux/actions/helpers'; import {autoUpdateTimezone} from '@mm-redux/actions/timezone'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {getConfig, getLicense} from '@mm-redux/selectors/entities/general'; diff --git a/app/actions/websocket/channels.test.js b/app/actions/websocket/channels.test.js index 4c2a12a58..79badc58a 100644 --- a/app/actions/websocket/channels.test.js +++ b/app/actions/websocket/channels.test.js @@ -12,7 +12,7 @@ import configureMockStore from 'redux-mock-store'; import {ChannelTypes, RoleTypes} from '@mm-redux/action_types'; import * as ChannelActions from '@mm-redux/actions/channels'; import * as TeamActions from '@mm-redux/actions/teams'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import * as Actions from '@actions/websocket'; diff --git a/app/actions/websocket/channels.ts b/app/actions/websocket/channels.ts index b77f2ebaa..399cce0d1 100644 --- a/app/actions/websocket/channels.ts +++ b/app/actions/websocket/channels.ts @@ -5,7 +5,7 @@ import {fetchChannelAndMyMember} from '@actions/helpers/channels'; import {loadChannelsForTeam} from '@actions/views/channel'; import {WebsocketEvents} from '@constants'; import {markChannelAsRead} from '@mm-redux/actions/channels'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {ChannelTypes, TeamTypes, RoleTypes} from '@mm-redux/action_types'; import {General} from '@mm-redux/constants'; import { diff --git a/app/actions/websocket/general.test.js b/app/actions/websocket/general.test.js index 2e4695b18..b99517706 100644 --- a/app/actions/websocket/general.test.js +++ b/app/actions/websocket/general.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import {Server, WebSocket as MockWebSocket} from 'mock-socket'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as Actions from '@actions/websocket'; import {WebsocketEvents} from '@constants'; diff --git a/app/actions/websocket/index.ts b/app/actions/websocket/index.ts index d22785178..c2ad99c4d 100644 --- a/app/actions/websocket/index.ts +++ b/app/actions/websocket/index.ts @@ -7,7 +7,7 @@ import {loadMe} from '@actions/views/user'; import {WebsocketEvents} from '@constants'; import {ChannelTypes, GeneralTypes, PreferenceTypes, TeamTypes, UserTypes, RoleTypes} from '@mm-redux/action_types'; import {getProfilesByIds, getStatusesByIds} from '@mm-redux/actions/users'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import {getCurrentChannelId, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels'; import {getConfig} from '@mm-redux/selectors/entities/general'; diff --git a/app/actions/websocket/integrations.test.js b/app/actions/websocket/integrations.test.js index c56f4685d..243a025d0 100644 --- a/app/actions/websocket/integrations.test.js +++ b/app/actions/websocket/integrations.test.js @@ -3,7 +3,7 @@ import assert from 'assert'; import {Server, WebSocket as MockWebSocket} from 'mock-socket'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as Actions from '@actions/websocket'; import {WebsocketEvents} from '@constants'; diff --git a/app/actions/websocket/posts.test.js b/app/actions/websocket/posts.test.js index 142691cec..5b9504811 100644 --- a/app/actions/websocket/posts.test.js +++ b/app/actions/websocket/posts.test.js @@ -9,7 +9,7 @@ import {Server, WebSocket as MockWebSocket} from 'mock-socket'; import * as ChannelActions from '@mm-redux/actions/channels'; import * as PostActions from '@mm-redux/actions/posts'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Posts} from '@mm-redux/constants'; import * as PostSelectors from '@mm-redux/selectors/entities/posts'; import EventEmitter from '@mm-redux/utils/event_emitter'; diff --git a/app/actions/websocket/reactions.test.js b/app/actions/websocket/reactions.test.js index 19e2273c2..7ea1eea6b 100644 --- a/app/actions/websocket/reactions.test.js +++ b/app/actions/websocket/reactions.test.js @@ -4,7 +4,7 @@ import assert from 'assert'; import {Server, WebSocket as MockWebSocket} from 'mock-socket'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as Actions from '@actions/websocket'; import {WebsocketEvents} from '@constants'; diff --git a/app/actions/websocket/teams.test.js b/app/actions/websocket/teams.test.js index c65a06aba..eb290c8d9 100644 --- a/app/actions/websocket/teams.test.js +++ b/app/actions/websocket/teams.test.js @@ -7,7 +7,7 @@ import {Server, WebSocket as MockWebSocket} from 'mock-socket'; import {batchActions} from 'redux-batched-actions'; import {TeamTypes, UserTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as Actions from '@actions/websocket'; import {WebsocketEvents} from '@constants'; diff --git a/app/actions/websocket/teams.ts b/app/actions/websocket/teams.ts index a08ee6196..ecef00607 100644 --- a/app/actions/websocket/teams.ts +++ b/app/actions/websocket/teams.ts @@ -3,7 +3,7 @@ import {RoleTypes, TeamTypes} from '@mm-redux/action_types'; import {notVisibleUsersActions} from '@mm-redux/actions/helpers'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getCurrentTeamId, getTeams as getTeamsSelector} from '@mm-redux/selectors/entities/teams'; import {getCurrentUser} from '@mm-redux/selectors/entities/users'; import {ActionResult, DispatchFunc, GenericAction, GetStateFunc, batchActions} from '@mm-redux/types/actions'; diff --git a/app/actions/websocket/users.test.js b/app/actions/websocket/users.test.js index 58c1f4c40..8b1b564d8 100644 --- a/app/actions/websocket/users.test.js +++ b/app/actions/websocket/users.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import {Server, WebSocket as MockWebSocket} from 'mock-socket'; import {batchActions} from 'redux-batched-actions'; import {TeamTypes, UserTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as Actions from '@actions/websocket'; import {WebsocketEvents} from '@constants'; diff --git a/app/actions/websocket/users.ts b/app/actions/websocket/users.ts index 4f905a616..3120d54f9 100644 --- a/app/actions/websocket/users.ts +++ b/app/actions/websocket/users.ts @@ -6,7 +6,7 @@ import {loadChannelsForTeam} from '@actions/views/channel'; import {getMe} from '@actions/views/user'; import {ChannelTypes, TeamTypes, UserTypes, RoleTypes} from '@mm-redux/action_types'; import {notVisibleUsersActions} from '@mm-redux/actions/helpers'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import {getAllChannels, getCurrentChannelId, getChannelMembersInChannels} from '@mm-redux/selectors/entities/channels'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; @@ -171,7 +171,7 @@ export function handleUserRoleUpdated(msg: WebSocketMessage) { dispatch({ type: RoleTypes.RECEIVED_ROLES, - data: data.roles, + data, }); } catch { // do nothing diff --git a/app/actions/websocket/websocket.test.js b/app/actions/websocket/websocket.test.js index 288d6d955..e7a70d678 100644 --- a/app/actions/websocket/websocket.test.js +++ b/app/actions/websocket/websocket.test.js @@ -11,7 +11,7 @@ import configureMockStore from 'redux-mock-store'; import {GeneralTypes, UserTypes} from '@mm-redux/action_types'; import {notVisibleUsersActions} from '@mm-redux/actions/helpers'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Posts, RequestStatus} from '@mm-redux/constants'; import * as Actions from '@actions/websocket'; diff --git a/app/client/rest/apps.ts b/app/client/rest/apps.ts new file mode 100644 index 000000000..f8372ff3f --- /dev/null +++ b/app/client/rest/apps.ts @@ -0,0 +1,36 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import type {AppBinding, AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps'; + +export interface ClientAppsMix { + executeAppCall: (call: AppCallRequest, type: AppCallType) => Promise; + getAppsBindings: (userID: string, channelID: string) => Promise; +} + +const ClientApps = (superclass: any) => class extends superclass { + executeAppCall = async (call: AppCallRequest, type: AppCallType) => { + const callCopy = { + ...call, + path: `${call.path}/${type}`, + context: { + ...call.context, + user_agent: 'mobile', + }, + }; + + return this.doFetch( + `${this.getAppsProxyRoute()}/api/v1/call`, + {method: 'post', body: JSON.stringify(callCopy)}, + ); + } + + getAppsBindings = async (userID: string, channelID: string) => { + return this.doFetch( + this.getAppsProxyRoute() + `/api/v1/bindings?user_id=${userID}&channel_id=${channelID}&user_agent_type=mobile`, + {method: 'get'}, + ); + } +}; + +export default ClientApps; diff --git a/app/client/rest/base.ts b/app/client/rest/base.ts new file mode 100644 index 000000000..acf0d9666 --- /dev/null +++ b/app/client/rest/base.ts @@ -0,0 +1,373 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {RNFetchBlobFetchRepsonse} from 'rn-fetch-blob'; +import urlParse from 'url-parse'; + +import {Options} from '@mm-redux/types/client4'; + +import * as ClientConstants from './constants'; +import ClientError from './error'; + +export default class ClientBase { + clusterId = ''; + csrf = ''; + defaultHeaders: {[x: string]: string} = {}; + diagnosticId = ''; + enableLogging = false; + includeCookies = true; + logToConsole = false; + managedConfig: any = null; + serverVersion = ''; + token = ''; + translations = { + connectionError: 'There appears to be a problem with your internet connection.', + unknownError: 'We received an unexpected status code from the server.', + }; + userAgent: string|null = null; + url = ''; + urlVersion = '/api/v4'; + + getAbsoluteUrl(baseUrl: string) { + if (typeof baseUrl !== 'string' || !baseUrl.startsWith('/')) { + return baseUrl; + } + return this.getUrl() + baseUrl; + } + + getOptions(options: Options) { + const newOptions: Options = {...options}; + + const headers: {[x: string]: string} = { + [ClientConstants.HEADER_REQUESTED_WITH]: 'XMLHttpRequest', + ...this.defaultHeaders, + }; + + if (this.token) { + headers[ClientConstants.HEADER_AUTH] = `${ClientConstants.HEADER_BEARER} ${this.token}`; + } + + const csrfToken = this.csrf || ''; + if (options.method && options.method.toLowerCase() !== 'get' && csrfToken) { + headers[ClientConstants.HEADER_X_CSRF_TOKEN] = csrfToken; + } + + if (this.includeCookies) { + newOptions.credentials = 'include'; + } + + if (this.userAgent) { + headers[ClientConstants.HEADER_USER_AGENT] = this.userAgent; + } + + if (newOptions.headers) { + Object.assign(headers, newOptions.headers); + } + + return { + ...newOptions, + headers, + }; + } + + getServerVersion() { + return this.serverVersion; + } + + getToken() { + return this.token; + } + + getUrl() { + return this.url; + } + + getUrlVersion() { + return this.urlVersion; + } + + getWebSocketUrl = () => { + return `${this.getBaseRoute()}/websocket`; + } + + setAcceptLanguage(locale: string) { + this.defaultHeaders['Accept-Language'] = locale; + } + + setCSRF(csrfToken: string) { + this.csrf = csrfToken; + } + + setDiagnosticId(diagnosticId: string) { + this.diagnosticId = diagnosticId; + } + + setEnableLogging(enable: boolean) { + this.enableLogging = enable; + } + + setIncludeCookies(include: boolean) { + this.includeCookies = include; + } + + setManagedConfig(config: any) { + this.managedConfig = config; + } + + setUserAgent(userAgent: string) { + this.userAgent = userAgent; + } + + setToken(token: string) { + this.token = token; + } + + setUrl(url: string) { + this.url = url.replace(/\/+$/, ''); + } + + // Routes + getBaseRoute() { + return `${this.url}${this.urlVersion}`; + } + + getUsersRoute() { + return `${this.getBaseRoute()}/users`; + } + + getUserRoute(userId: string) { + return `${this.getUsersRoute()}/${userId}`; + } + + getTeamsRoute() { + return `${this.getBaseRoute()}/teams`; + } + + getTeamRoute(teamId: string) { + return `${this.getTeamsRoute()}/${teamId}`; + } + + getTeamNameRoute(teamName: string) { + return `${this.getTeamsRoute()}/name/${teamName}`; + } + + getTeamMembersRoute(teamId: string) { + return `${this.getTeamRoute(teamId)}/members`; + } + + getTeamMemberRoute(teamId: string, userId: string) { + return `${this.getTeamMembersRoute(teamId)}/${userId}`; + } + + getChannelsRoute() { + return `${this.getBaseRoute()}/channels`; + } + + getChannelRoute(channelId: string) { + return `${this.getChannelsRoute()}/${channelId}`; + } + + getChannelMembersRoute(channelId: string) { + return `${this.getChannelRoute(channelId)}/members`; + } + + getChannelMemberRoute(channelId: string, userId: string) { + return `${this.getChannelMembersRoute(channelId)}/${userId}`; + } + + getPostsRoute() { + return `${this.getBaseRoute()}/posts`; + } + + getPostRoute(postId: string) { + return `${this.getPostsRoute()}/${postId}`; + } + + getReactionsRoute() { + return `${this.getBaseRoute()}/reactions`; + } + + getCommandsRoute() { + return `${this.getBaseRoute()}/commands`; + } + + getFilesRoute() { + return `${this.getBaseRoute()}/files`; + } + + getFileRoute(fileId: string) { + return `${this.getFilesRoute()}/${fileId}`; + } + + getPreferencesRoute(userId: string) { + return `${this.getUserRoute(userId)}/preferences`; + } + + getIncomingHooksRoute() { + return `${this.getBaseRoute()}/hooks/incoming`; + } + + getIncomingHookRoute(hookId: string) { + return `${this.getBaseRoute()}/hooks/incoming/${hookId}`; + } + + getOutgoingHooksRoute() { + return `${this.getBaseRoute()}/hooks/outgoing`; + } + + getOutgoingHookRoute(hookId: string) { + return `${this.getBaseRoute()}/hooks/outgoing/${hookId}`; + } + + getOAuthRoute() { + return `${this.url}/oauth`; + } + + getOAuthAppsRoute() { + return `${this.getBaseRoute()}/oauth/apps`; + } + + getOAuthAppRoute(appId: string) { + return `${this.getOAuthAppsRoute()}/${appId}`; + } + + getEmojisRoute() { + return `${this.getBaseRoute()}/emoji`; + } + + getEmojiRoute(emojiId: string) { + return `${this.getEmojisRoute()}/${emojiId}`; + } + + getBrandRoute() { + return `${this.getBaseRoute()}/brand`; + } + + getBrandImageUrl(timestamp: string) { + return `${this.getBrandRoute()}/image?t=${timestamp}`; + } + + getDataRetentionRoute() { + return `${this.getBaseRoute()}/data_retention`; + } + + getRolesRoute() { + return `${this.getBaseRoute()}/roles`; + } + + getTimezonesRoute() { + return `${this.getBaseRoute()}/system/timezones`; + } + + getRedirectLocationRoute() { + return `${this.getBaseRoute()}/redirect_location`; + } + + getBotsRoute() { + return `${this.getBaseRoute()}/bots`; + } + + getBotRoute(botUserId: string) { + return `${this.getBotsRoute()}/${botUserId}`; + } + + getAppsProxyRoute() { + return `${this.url}/plugins/com.mattermost.apps`; + } + + // Client Helpers + handleRedirectProtocol = (url: string, response: RNFetchBlobFetchRepsonse) => { + const serverUrl = this.getUrl(); + const parsed = urlParse(url); + const {redirects} = response.rnfbRespInfo; + if (redirects) { + const redirectUrl = urlParse(redirects[redirects.length - 1]); + + if (serverUrl === parsed.origin && parsed.host === redirectUrl.host && parsed.protocol !== redirectUrl.protocol) { + this.setUrl(serverUrl.replace(parsed.protocol, redirectUrl.protocol)); + } + } + }; + + doFetch = async (url: string, options: Options) => { + const {data} = await this.doFetchWithResponse(url, options); + + return data; + }; + + doFetchWithResponse = async (url: string, options: Options) => { + const response = await fetch(url, this.getOptions(options)); + const headers = parseAndMergeNestedHeaders(response.headers); + + let data; + try { + data = await response.json(); + } catch (err) { + throw new ClientError(this.getUrl(), { + message: 'Received invalid response from the server.', + intl: { + id: 'mobile.request.invalid_response', + defaultMessage: 'Received invalid response from the server.', + }, + url, + }); + } + + if (headers.has(ClientConstants.HEADER_X_VERSION_ID) && !headers.get('Cache-Control')) { + const serverVersion = headers.get(ClientConstants.HEADER_X_VERSION_ID); + if (serverVersion && this.serverVersion !== serverVersion) { + this.serverVersion = serverVersion; + } + } + + if (headers.has(ClientConstants.HEADER_X_CLUSTER_ID)) { + const clusterId = headers.get(ClientConstants.HEADER_X_CLUSTER_ID); + if (clusterId && this.clusterId !== clusterId) { + this.clusterId = clusterId; + } + } + + if (response.ok) { + return { + response, + headers, + data, + }; + } + + const msg = data.message || ''; + + if (this.logToConsole) { + console.error(msg); // eslint-disable-line no-console + } + + throw new ClientError(this.getUrl(), { + message: msg, + server_error_id: data.id, + status_code: data.status_code, + url, + }); + }; +} + +function parseAndMergeNestedHeaders(originalHeaders: any) { + const headers = new Map(); + let nestedHeaders = new Map(); + originalHeaders.forEach((val: string, key: string) => { + const capitalizedKey = key.replace(/\b[a-z]/g, (l) => l.toUpperCase()); + let realVal = val; + if (val && val.match(/\n\S+:\s\S+/)) { + const nestedHeaderStrings = val.split('\n'); + realVal = nestedHeaderStrings.shift() as string; + const moreNestedHeaders = new Map( + nestedHeaderStrings.map((h: any) => h.split(/:\s/)), + ); + nestedHeaders = new Map([...nestedHeaders, ...moreNestedHeaders]); + } + headers.set(capitalizedKey, realVal); + }); + return new Map([...headers, ...nestedHeaders]); +} diff --git a/app/client/rest/bots.ts b/app/client/rest/bots.ts new file mode 100644 index 000000000..664432401 --- /dev/null +++ b/app/client/rest/bots.ts @@ -0,0 +1,39 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import type {Bot} from '@mm-redux/types/bots'; + +export interface ClientBotsMix { + getBot: (botUserId: string) => Promise; + getBots: (page?: number, perPage?: number) => Promise; + getBotsIncludeDeleted: (page?: number, perPage?: number) => Promise; +} + +const PER_PAGE_DEFAULT = 60; + +const ClientBots = (superclass: any) => class extends superclass { + getBot = async (botUserId: string) => { + return this.doFetch( + `${this.getBotRoute(botUserId)}`, + {method: 'get'}, + ); + } + + getBots = async (page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getBotsRoute()}${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + } + + getBotsIncludeDeleted = async (page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getBotsRoute()}${buildQueryString({include_deleted: true, page, per_page: perPage})}`, + {method: 'get'}, + ); + } +}; + +export default ClientBots; diff --git a/app/client/rest/channels.ts b/app/client/rest/channels.ts new file mode 100644 index 000000000..4df26f460 --- /dev/null +++ b/app/client/rest/channels.ts @@ -0,0 +1,308 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {analytics} from '@init/analytics'; +import {Channel, ChannelMemberCountByGroup, ChannelMembership, ChannelNotifyProps, ChannelStats} from '@mm-redux/types/channels'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientChannelsMix { + getAllChannels: (page?: number, perPage?: number, notAssociatedToGroup?: string, excludeDefaultChannels?: boolean, includeTotalCount?: boolean) => Promise; + createChannel: (channel: Channel) => Promise; + createDirectChannel: (userIds: string[]) => Promise; + createGroupChannel: (userIds: string[]) => Promise; + deleteChannel: (channelId: string) => Promise; + unarchiveChannel: (channelId: string) => Promise; + updateChannel: (channel: Channel) => Promise; + convertChannelToPrivate: (channelId: string) => Promise; + updateChannelPrivacy: (channelId: string, privacy: any) => Promise; + patchChannel: (channelId: string, channelPatch: Partial) => Promise; + updateChannelNotifyProps: (props: ChannelNotifyProps & {channel_id: string, user_id: string}) => Promise; + getChannel: (channelId: string) => Promise; + getChannelByName: (teamId: string, channelName: string, includeDeleted?: boolean) => Promise; + getChannelByNameAndTeamName: (teamName: string, channelName: string, includeDeleted?: boolean) => Promise; + getChannels: (teamId: string, page?: number, perPage?: number) => Promise; + getArchivedChannels: (teamId: string, page?: number, perPage?: number) => Promise; + getMyChannels: (teamId: string, includeDeleted?: boolean) => Promise; + getMyChannelMember: (channelId: string) => Promise; + getMyChannelMembers: (teamId: string) => Promise; + getChannelMembers: (channelId: string, page?: number, perPage?: number) => Promise; + getChannelTimezones: (channelId: string) => Promise; + getChannelMember: (channelId: string, userId: string) => Promise; + getChannelMembersByIds: (channelId: string, userIds: string[]) => Promise; + addToChannel: (userId: string, channelId: string, postRootId?: string) => Promise; + removeFromChannel: (userId: string, channelId: string) => Promise; + getChannelStats: (channelId: string) => Promise; + getChannelMemberCountsByGroup: (channelId: string, includeTimezones: boolean) => Promise; + viewMyChannel: (channelId: string, prevChannelId?: string) => Promise; + autocompleteChannels: (teamId: string, name: string) => Promise; + autocompleteChannelsForSearch: (teamId: string, name: string) => Promise; + searchChannels: (teamId: string, term: string) => Promise; + searchArchivedChannels: (teamId: string, term: string) => Promise; +} + +const ClientChannels = (superclass: any) => class extends superclass { + getAllChannels = async (page = 0, perPage = PER_PAGE_DEFAULT, notAssociatedToGroup = '', excludeDefaultChannels = false, includeTotalCount = false) => { + const queryData = { + page, + per_page: perPage, + not_associated_to_group: notAssociatedToGroup, + exclude_default_channels: excludeDefaultChannels, + include_total_count: includeTotalCount, + }; + return this.doFetch( + `${this.getChannelsRoute()}${buildQueryString(queryData)}`, + {method: 'get'}, + ); + }; + + createChannel = async (channel: Channel) => { + analytics.trackAPI('api_channels_create', {team_id: channel.team_id}); + + return this.doFetch( + `${this.getChannelsRoute()}`, + {method: 'post', body: JSON.stringify(channel)}, + ); + }; + + createDirectChannel = async (userIds: string[]) => { + analytics.trackAPI('api_channels_create_direct'); + + return this.doFetch( + `${this.getChannelsRoute()}/direct`, + {method: 'post', body: JSON.stringify(userIds)}, + ); + }; + + createGroupChannel = async (userIds: string[]) => { + analytics.trackAPI('api_channels_create_group'); + + return this.doFetch( + `${this.getChannelsRoute()}/group`, + {method: 'post', body: JSON.stringify(userIds)}, + ); + }; + + deleteChannel = async (channelId: string) => { + analytics.trackAPI('api_channels_delete', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}`, + {method: 'delete'}, + ); + }; + + unarchiveChannel = async (channelId: string) => { + analytics.trackAPI('api_channels_unarchive', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/restore`, + {method: 'post'}, + ); + }; + + updateChannel = async (channel: Channel) => { + analytics.trackAPI('api_channels_update', {channel_id: channel.id}); + + return this.doFetch( + `${this.getChannelRoute(channel.id)}`, + {method: 'put', body: JSON.stringify(channel)}, + ); + }; + + convertChannelToPrivate = async (channelId: string) => { + analytics.trackAPI('api_channels_convert_to_private', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/convert`, + {method: 'post'}, + ); + }; + + updateChannelPrivacy = async (channelId: string, privacy: any) => { + analytics.trackAPI('api_channels_update_privacy', {channel_id: channelId, privacy}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/privacy`, + {method: 'put', body: JSON.stringify({privacy})}, + ); + }; + + patchChannel = async (channelId: string, channelPatch: Partial) => { + analytics.trackAPI('api_channels_patch', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/patch`, + {method: 'put', body: JSON.stringify(channelPatch)}, + ); + }; + + updateChannelNotifyProps = async (props: ChannelNotifyProps & {channel_id: string, user_id: string}) => { + analytics.trackAPI('api_users_update_channel_notifications', {channel_id: props.channel_id}); + + return this.doFetch( + `${this.getChannelMemberRoute(props.channel_id, props.user_id)}/notify_props`, + {method: 'put', body: JSON.stringify(props)}, + ); + }; + + getChannel = async (channelId: string) => { + analytics.trackAPI('api_channel_get', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}`, + {method: 'get'}, + ); + }; + + getChannelByName = async (teamId: string, channelName: string, includeDeleted = false) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/name/${channelName}?include_deleted=${includeDeleted}`, + {method: 'get'}, + ); + }; + + getChannelByNameAndTeamName = async (teamName: string, channelName: string, includeDeleted = false) => { + analytics.trackAPI('api_channel_get_by_name_and_teamName', {channel_name: channelName, team_name: teamName, include_deleted: includeDeleted}); + + return this.doFetch( + `${this.getTeamNameRoute(teamName)}/channels/name/${channelName}?include_deleted=${includeDeleted}`, + {method: 'get'}, + ); + }; + + getChannels = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getArchivedChannels = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/deleted${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getMyChannels = async (teamId: string, includeDeleted = false) => { + return this.doFetch( + `${this.getUserRoute('me')}/teams/${teamId}/channels${buildQueryString({include_deleted: includeDeleted})}`, + {method: 'get'}, + ); + }; + + getMyChannelMember = async (channelId: string) => { + return this.doFetch( + `${this.getChannelMemberRoute(channelId, 'me')}`, + {method: 'get'}, + ); + }; + + getMyChannelMembers = async (teamId: string) => { + return this.doFetch( + `${this.getUserRoute('me')}/teams/${teamId}/channels/members`, + {method: 'get'}, + ); + }; + + getChannelMembers = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getChannelMembersRoute(channelId)}${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getChannelTimezones = async (channelId: string) => { + return this.doFetch( + `${this.getChannelRoute(channelId)}/timezones`, + {method: 'get'}, + ); + }; + + getChannelMember = async (channelId: string, userId: string) => { + return this.doFetch( + `${this.getChannelMemberRoute(channelId, userId)}`, + {method: 'get'}, + ); + }; + + getChannelMembersByIds = async (channelId: string, userIds: string[]) => { + return this.doFetch( + `${this.getChannelMembersRoute(channelId)}/ids`, + {method: 'post', body: JSON.stringify(userIds)}, + ); + }; + + addToChannel = async (userId: string, channelId: string, postRootId = '') => { + analytics.trackAPI('api_channels_add_member', {channel_id: channelId}); + + const member = {user_id: userId, channel_id: channelId, post_root_id: postRootId}; + return this.doFetch( + `${this.getChannelMembersRoute(channelId)}`, + {method: 'post', body: JSON.stringify(member)}, + ); + }; + + removeFromChannel = async (userId: string, channelId: string) => { + analytics.trackAPI('api_channels_remove_member', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelMemberRoute(channelId, userId)}`, + {method: 'delete'}, + ); + }; + + getChannelStats = async (channelId: string) => { + return this.doFetch( + `${this.getChannelRoute(channelId)}/stats`, + {method: 'get'}, + ); + }; + + getChannelMemberCountsByGroup = async (channelId: string, includeTimezones: boolean) => { + return this.doFetch( + `${this.getChannelRoute(channelId)}/member_counts_by_group?include_timezones=${includeTimezones}`, + {method: 'get'}, + ); + }; + + viewMyChannel = async (channelId: string, prevChannelId?: string) => { + const data = {channel_id: channelId, prev_channel_id: prevChannelId}; + return this.doFetch( + `${this.getChannelsRoute()}/members/me/view`, + {method: 'post', body: JSON.stringify(data)}, + ); + }; + + autocompleteChannels = async (teamId: string, name: string) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/autocomplete${buildQueryString({name})}`, + {method: 'get'}, + ); + }; + + autocompleteChannelsForSearch = async (teamId: string, name: string) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/search_autocomplete${buildQueryString({name})}`, + {method: 'get'}, + ); + }; + + searchChannels = async (teamId: string, term: string) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/search`, + {method: 'post', body: JSON.stringify({term})}, + ); + }; + + searchArchivedChannels = async (teamId: string, term: string) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/channels/search_archived`, + {method: 'post', body: JSON.stringify({term})}, + ); + }; +}; + +export default ClientChannels; diff --git a/app/client/rest/constants.ts b/app/client/rest/constants.ts new file mode 100644 index 000000000..c1b260485 --- /dev/null +++ b/app/client/rest/constants.ts @@ -0,0 +1,14 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export const HEADER_AUTH = 'Authorization'; +export const HEADER_BEARER = 'BEARER'; +export const HEADER_REQUESTED_WITH = 'X-Requested-With'; +export const HEADER_USER_AGENT = 'User-Agent'; +export const HEADER_X_CLUSTER_ID = 'X-Cluster-Id'; +export const HEADER_X_CSRF_TOKEN = 'X-CSRF-Token'; +export const HEADER_TOKEN = 'Token'; +export const HEADER_X_VERSION_ID = 'X-Version-Id'; +export const DEFAULT_LIMIT_BEFORE = 30; +export const DEFAULT_LIMIT_AFTER = 30; +export const PER_PAGE_DEFAULT = 60; diff --git a/app/client/rest/emojis.ts b/app/client/rest/emojis.ts new file mode 100644 index 000000000..7d2e1b239 --- /dev/null +++ b/app/client/rest/emojis.ts @@ -0,0 +1,101 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import FormData from 'form-data'; + +import {analytics} from '@init/analytics'; +import {CustomEmoji} from '@mm-redux/types/emojis'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientEmojisMix { + createCustomEmoji: (emoji: CustomEmoji, imageData: any) => Promise; + getCustomEmoji: (id: string) => Promise; + getCustomEmojiByName: (name: string) => Promise; + getCustomEmojis: (page?: number, perPage?: number, sort?: string) => Promise; + deleteCustomEmoji: (emojiId: string) => Promise; + getSystemEmojiImageUrl: (filename: string) => string; + getCustomEmojiImageUrl: (id: string) => string; + searchCustomEmoji: (term: string, options?: Record) => Promise; + autocompleteCustomEmoji: (name: string) => Promise; +} + +const ClientEmojis = (superclass: any) => class extends superclass { + createCustomEmoji = async (emoji: CustomEmoji, imageData: any) => { + analytics.trackAPI('api_emoji_custom_add'); + + const formData = new FormData(); + formData.append('image', imageData); + formData.append('emoji', JSON.stringify(emoji)); + const request: any = { + method: 'post', + body: formData, + }; + + if (formData.getBoundary) { + request.headers = { + 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, + }; + } + + return this.doFetch( + `${this.getEmojisRoute()}`, + request, + ); + }; + + getCustomEmoji = async (id: string) => { + return this.doFetch( + `${this.getEmojisRoute()}/${id}`, + {method: 'get'}, + ); + }; + + getCustomEmojiByName = async (name: string) => { + return this.doFetch( + `${this.getEmojisRoute()}/name/${name}`, + {method: 'get'}, + ); + }; + + getCustomEmojis = async (page = 0, perPage = PER_PAGE_DEFAULT, sort = '') => { + return this.doFetch( + `${this.getEmojisRoute()}${buildQueryString({page, per_page: perPage, sort})}`, + {method: 'get'}, + ); + }; + + deleteCustomEmoji = async (emojiId: string) => { + analytics.trackAPI('api_emoji_custom_delete'); + + return this.doFetch( + `${this.getEmojiRoute(emojiId)}`, + {method: 'delete'}, + ); + }; + + getSystemEmojiImageUrl = (filename: string) => { + return `${this.url}/static/emoji/${filename}.png`; + }; + + getCustomEmojiImageUrl = (id: string) => { + return `${this.getEmojiRoute(id)}/image`; + }; + + searchCustomEmoji = async (term: string, options = {}) => { + return this.doFetch( + `${this.getEmojisRoute()}/search`, + {method: 'post', body: JSON.stringify({term, ...options})}, + ); + }; + + autocompleteCustomEmoji = async (name: string) => { + return this.doFetch( + `${this.getEmojisRoute()}/autocomplete${buildQueryString({name})}`, + {method: 'get'}, + ); + }; +}; + +export default ClientEmojis; diff --git a/app/client/rest/error.ts b/app/client/rest/error.ts new file mode 100644 index 000000000..0bf146ec6 --- /dev/null +++ b/app/client/rest/error.ts @@ -0,0 +1,26 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {cleanUrlForLogging} from '@mm-redux/utils/sentry'; + +export default class ClientError extends Error { + url: string; + intl: { defaultMessage: string; id: string } | { defaultMessage: string; id: string } | { id: string; defaultMessage: string; values: any } | { id: string; defaultMessage: string }; + server_error_id: any; + status_code: any; + details: Error; + constructor(baseUrl: string, data: any) { + super(data.message + ': ' + cleanUrlForLogging(baseUrl, data.url)); + + this.message = data.message; + this.url = data.url; + this.intl = data.intl; + this.server_error_id = data.server_error_id; + this.status_code = data.status_code; + this.details = data.details; + + // Ensure message is treated as a property of this class when object spreading. Without this, + // copying the object by using `{...error}` would not include the message. + Object.defineProperty(this, 'message', {enumerable: true}); + } +} diff --git a/app/client/rest/files.ts b/app/client/rest/files.ts new file mode 100644 index 000000000..7bb120f08 --- /dev/null +++ b/app/client/rest/files.ts @@ -0,0 +1,47 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export interface ClientFilesMix { + getFileUrl: (fileId: string, timestamp: number) => string; + getFileThumbnailUrl: (fileId: string, timestamp: number) => string; + getFilePreviewUrl: (fileId: string, timestamp: number) => string; + getFilePublicLink: (fileId: string) => Promise; +} + +const ClientFiles = (superclass: any) => class extends superclass { + getFileUrl(fileId: string, timestamp: number) { + let url = `${this.getFileRoute(fileId)}`; + if (timestamp) { + url += `?${timestamp}`; + } + + return url; + } + + getFileThumbnailUrl(fileId: string, timestamp: number) { + let url = `${this.getFileRoute(fileId)}/thumbnail`; + if (timestamp) { + url += `?${timestamp}`; + } + + return url; + } + + getFilePreviewUrl(fileId: string, timestamp: number) { + let url = `${this.getFileRoute(fileId)}/preview`; + if (timestamp) { + url += `?${timestamp}`; + } + + return url; + } + + getFilePublicLink = async (fileId: string) => { + return this.doFetch( + `${this.getFileRoute(fileId)}/link`, + {method: 'get'}, + ); + } +}; + +export default ClientFiles; diff --git a/app/client/rest/general.ts b/app/client/rest/general.ts new file mode 100644 index 000000000..19e058b1f --- /dev/null +++ b/app/client/rest/general.ts @@ -0,0 +1,98 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {Config} from '@mm-redux/types/config'; +import {Role} from '@mm-redux/types/roles'; +import {Dictionary} from '@mm-redux/types/utilities'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import ClientError from './error'; + +export interface ClientGeneralMix { + getOpenGraphMetadata: (url: string) => Promise; + ping: () => Promise; + logClientError: (message: string, level?: string) => Promise; + getClientConfigOld: () => Promise; + getClientLicenseOld: () => Promise; + getTimezones: () => Promise; + getDataRetentionPolicy: () => Promise; + getRolesByNames: (rolesNames: string[]) => Promise; + getRedirectLocation: (urlParam: string) => Promise>; +} + +const ClientGeneral = (superclass: any) => class extends superclass { + getOpenGraphMetadata = async (url: string) => { + return this.doFetch( + `${this.getBaseRoute()}/opengraph`, + {method: 'post', body: JSON.stringify({url})}, + ); + }; + + ping = async () => { + return this.doFetch( + `${this.getBaseRoute()}/system/ping?time=${Date.now()}`, + {method: 'get'}, + ); + }; + + logClientError = async (message: string, level = 'ERROR') => { + const url = `${this.getBaseRoute()}/logs`; + + if (!this.enableLogging) { + throw new ClientError(this.getUrl(), { + message: 'Logging disabled.', + url, + }); + } + + return this.doFetch( + url, + {method: 'post', body: JSON.stringify({message, level})}, + ); + }; + + getClientConfigOld = async () => { + return this.doFetch( + `${this.getBaseRoute()}/config/client?format=old`, + {method: 'get'}, + ); + }; + + getClientLicenseOld = async () => { + return this.doFetch( + `${this.getBaseRoute()}/license/client?format=old`, + {method: 'get'}, + ); + }; + + getTimezones = async () => { + return this.doFetch( + `${this.getTimezonesRoute()}`, + {method: 'get'}, + ); + }; + + getDataRetentionPolicy = () => { + return this.doFetch( + `${this.getDataRetentionRoute()}/policy`, + {method: 'get'}, + ); + }; + + getRolesByNames = async (rolesNames: string[]) => { + return this.doFetch( + `${this.getRolesRoute()}/names`, + {method: 'post', body: JSON.stringify(rolesNames)}, + ); + }; + + getRedirectLocation = async (urlParam: string) => { + if (!urlParam.length) { + return Promise.resolve(); + } + const url = `${this.getRedirectLocationRoute()}${buildQueryString({url: urlParam})}`; + return this.doFetch(url, {method: 'get'}); + }; +}; + +export default ClientGeneral; diff --git a/app/client/rest/groups.ts b/app/client/rest/groups.ts new file mode 100644 index 000000000..7d23fbd75 --- /dev/null +++ b/app/client/rest/groups.ts @@ -0,0 +1,53 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {Group} from '@mm-redux/types/groups'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientGroupsMix { + getGroups: (filterAllowReference?: boolean, page?: number, perPage?: number) => Promise; + getGroupsByUserId: (userID: string) => Promise; + getAllGroupsAssociatedToTeam: (teamID: string, filterAllowReference?: boolean) => Promise; + getAllGroupsAssociatedToChannelsInTeam: (teamID: string, filterAllowReference?: boolean) => Promise; + getAllGroupsAssociatedToChannel: (channelID: string, filterAllowReference?: boolean) => Promise; +} + +const ClientGroups = (superclass: any) => class extends superclass { + getGroups = async (filterAllowReference = false, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getBaseRoute()}/groups${buildQueryString({filter_allow_reference: filterAllowReference, page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getGroupsByUserId = async (userID: string) => { + return this.doFetch( + `${this.getUsersRoute()}/${userID}/groups`, + {method: 'get'}, + ); + } + getAllGroupsAssociatedToTeam = async (teamID: string, filterAllowReference = false) => { + return this.doFetch( + `${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, + {method: 'get'}, + ); + }; + + getAllGroupsAssociatedToChannelsInTeam = async (teamID: string, filterAllowReference = false) => { + return this.doFetch( + `${this.getBaseRoute()}/teams/${teamID}/groups_by_channels${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, + {method: 'get'}, + ); + }; + + getAllGroupsAssociatedToChannel = async (channelID: string, filterAllowReference = false) => { + return this.doFetch( + `${this.getBaseRoute()}/channels/${channelID}/groups${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, + {method: 'get'}, + ); + }; +}; + +export default ClientGroups; diff --git a/app/mm-redux/client/client4.test.js b/app/client/rest/index.test.js similarity index 96% rename from app/mm-redux/client/client4.test.js rename to app/client/rest/index.test.js index c52bad7ac..e585f3371 100644 --- a/app/mm-redux/client/client4.test.js +++ b/app/client/rest/index.test.js @@ -4,7 +4,8 @@ import assert from 'assert'; import nock from 'nock'; -import {ClientError, HEADER_X_VERSION_ID} from '@mm-redux/client/client4'; +import {HEADER_X_VERSION_ID} from '@client/rest/constants'; +import ClientError from '@client/rest/error'; import TestHelper from 'test/test_helper'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; diff --git a/app/client/rest/index.ts b/app/client/rest/index.ts new file mode 100644 index 000000000..611648c4e --- /dev/null +++ b/app/client/rest/index.ts @@ -0,0 +1,56 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import mix from '@utils/mix'; + +import {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './constants'; +import ClientApps, {ClientAppsMix} from './apps'; +import ClientBase from './base'; +import ClientBots, {ClientBotsMix} from './bots'; +import ClientChannels, {ClientChannelsMix} from './channels'; +import ClientEmojis, {ClientEmojisMix} from './emojis'; +import ClientFiles, {ClientFilesMix} from './files'; +import ClientGeneral, {ClientGeneralMix} from './general'; +import ClientGroups, {ClientGroupsMix} from './groups'; +import ClientIntegrations, {ClientIntegrationsMix} from './integrations'; +import ClientPosts, {ClientPostsMix} from './posts'; +import ClientPreferences, {ClientPreferencesMix} from './preferences'; +import ClientTeams, {ClientTeamsMix} from './teams'; +import ClientTos, {ClientTosMix} from './tos'; +import ClientUsers, {ClientUsersMix} from './users'; + +interface Client extends ClientBase, + ClientAppsMix, + ClientBotsMix, + ClientChannelsMix, + ClientEmojisMix, + ClientFilesMix, + ClientGeneralMix, + ClientGroupsMix, + ClientIntegrationsMix, + ClientPostsMix, + ClientPreferencesMix, + ClientTeamsMix, + ClientTosMix, + ClientUsersMix +{} + +class Client extends mix(ClientBase).with( + ClientApps, + ClientBots, + ClientChannels, + ClientEmojis, + ClientFiles, + ClientGeneral, + ClientGroups, + ClientIntegrations, + ClientPosts, + ClientPreferences, + ClientTeams, + ClientTos, + ClientUsers, +) {} + +const Client4 = new Client(); + +export {Client4, Client, DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID}; diff --git a/app/client/rest/integrations.ts b/app/client/rest/integrations.ts new file mode 100644 index 000000000..7d2ad546f --- /dev/null +++ b/app/client/rest/integrations.ts @@ -0,0 +1,68 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {analytics} from '@init/analytics'; +import {Command, DialogSubmission} from '@mm-redux/types/integrations'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientIntegrationsMix { + getCommandsList: (teamId: string) => Promise; + getCommandAutocompleteSuggestionsList: (userInput: string, teamId: string, commandArgs?: Record) => Promise; + getAutocompleteCommandsList: (teamId: string, page?: number, perPage?: number) => Promise; + executeCommand: (command: Command, commandArgs?: Record) => Promise; + addCommand: (command: Command) => Promise; + submitInteractiveDialog: (data: DialogSubmission) => Promise; +} + +const ClientIntegrations = (superclass: any) => class extends superclass { + getCommandsList = async (teamId: string) => { + return this.doFetch( + `${this.getCommandsRoute()}?team_id=${teamId}`, + {method: 'get'}, + ); + }; + + getCommandAutocompleteSuggestionsList = async (userInput: string, teamId: string, commandArgs: {}) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/commands/autocomplete_suggestions${buildQueryString({...commandArgs, user_input: userInput})}`, + {method: 'get'}, + ); + }; + + getAutocompleteCommandsList = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/commands/autocomplete${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + executeCommand = async (command: Command, commandArgs = {}) => { + analytics.trackAPI('api_integrations_used'); + + return this.doFetch( + `${this.getCommandsRoute()}/execute`, + {method: 'post', body: JSON.stringify({command, ...commandArgs})}, + ); + }; + + addCommand = async (command: Command) => { + analytics.trackAPI('api_integrations_created'); + + return this.doFetch( + `${this.getCommandsRoute()}`, + {method: 'post', body: JSON.stringify(command)}, + ); + }; + + submitInteractiveDialog = async (data: DialogSubmission) => { + analytics.trackAPI('api_interactive_messages_dialog_submitted'); + return this.doFetch( + `${this.getBaseRoute()}/actions/dialogs/submit`, + {method: 'post', body: JSON.stringify(data)}, + ); + }; +}; + +export default ClientIntegrations; diff --git a/app/client/rest/posts.ts b/app/client/rest/posts.ts new file mode 100644 index 000000000..d6c99a4b5 --- /dev/null +++ b/app/client/rest/posts.ts @@ -0,0 +1,237 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {analytics} from '@init/analytics'; +import {FileInfo} from '@mm-redux/types/files'; +import {Post} from '@mm-redux/types/posts'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientPostsMix { + createPost: (post: Post) => Promise; + updatePost: (post: Post) => Promise; + getPost: (postId: string) => Promise; + patchPost: (postPatch: Partial & {id: string}) => Promise; + deletePost: (postId: string) => Promise; + getPostThread: (postId: string) => Promise; + getPosts: (channelId: string, page?: number, perPage?: number) => Promise; + getPostsSince: (channelId: string, since: number) => Promise; + getPostsBefore: (channelId: string, postId: string, page?: number, perPage?: number) => Promise; + getPostsAfter: (channelId: string, postId: string, page?: number, perPage?: number) => Promise; + getFileInfosForPost: (postId: string) => Promise; + getFlaggedPosts: (userId: string, channelId?: string, teamId?: string, page?: number, perPage?: number) => Promise; + getPinnedPosts: (channelId: string) => Promise; + markPostAsUnread: (userId: string, postId: string) => Promise; + pinPost: (postId: string) => Promise; + unpinPost: (postId: string) => Promise; + addReaction: (userId: string, postId: string, emojiName: string) => Promise; + removeReaction: (userId: string, postId: string, emojiName: string) => Promise; + getReactionsForPost: (postId: string) => Promise; + searchPostsWithParams: (teamId: string, params: any) => Promise; + searchPosts: (teamId: string, terms: string, isOrSearch: boolean) => Promise; + doPostAction: (postId: string, actionId: string, selectedOption?: string) => Promise; + doPostActionWithCookie: (postId: string, actionId: string, actionCookie: string, selectedOption?: string) => Promise; +} + +const ClientPosts = (superclass: any) => class extends superclass { + createPost = async (post: Post) => { + analytics.trackAPI('api_posts_create', {channel_id: post.channel_id}); + + if (post.root_id != null && post.root_id !== '') { + analytics.trackAPI('api_posts_replied', {channel_id: post.channel_id}); + } + + return this.doFetch( + `${this.getPostsRoute()}`, + {method: 'post', body: JSON.stringify(post)}, + ); + }; + + updatePost = async (post: Post) => { + analytics.trackAPI('api_posts_update', {channel_id: post.channel_id}); + + return this.doFetch( + `${this.getPostRoute(post.id)}`, + {method: 'put', body: JSON.stringify(post)}, + ); + }; + + getPost = async (postId: string) => { + return this.doFetch( + `${this.getPostRoute(postId)}`, + {method: 'get'}, + ); + }; + + patchPost = async (postPatch: Partial & {id: string}) => { + analytics.trackAPI('api_posts_patch', {channel_id: postPatch.channel_id}); + + return this.doFetch( + `${this.getPostRoute(postPatch.id)}/patch`, + {method: 'put', body: JSON.stringify(postPatch)}, + ); + }; + + deletePost = async (postId: string) => { + analytics.trackAPI('api_posts_delete'); + + return this.doFetch( + `${this.getPostRoute(postId)}`, + {method: 'delete'}, + ); + }; + + getPostThread = async (postId: string) => { + return this.doFetch( + `${this.getPostRoute(postId)}/thread`, + {method: 'get'}, + ); + }; + + getPosts = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getChannelRoute(channelId)}/posts${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getPostsSince = async (channelId: string, since: number) => { + return this.doFetch( + `${this.getChannelRoute(channelId)}/posts${buildQueryString({since})}`, + {method: 'get'}, + ); + }; + + getPostsBefore = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + analytics.trackAPI('api_posts_get_before', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/posts${buildQueryString({before: postId, page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getPostsAfter = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + analytics.trackAPI('api_posts_get_after', {channel_id: channelId}); + + return this.doFetch( + `${this.getChannelRoute(channelId)}/posts${buildQueryString({after: postId, page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getFileInfosForPost = async (postId: string) => { + return this.doFetch( + `${this.getPostRoute(postId)}/files/info`, + {method: 'get'}, + ); + }; + + getFlaggedPosts = async (userId: string, channelId = '', teamId = '', page = 0, perPage = PER_PAGE_DEFAULT) => { + analytics.trackAPI('api_posts_get_flagged', {team_id: teamId}); + + return this.doFetch( + `${this.getUserRoute(userId)}/posts/flagged${buildQueryString({channel_id: channelId, team_id: teamId, page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getPinnedPosts = async (channelId: string) => { + analytics.trackAPI('api_posts_get_pinned', {channel_id: channelId}); + return this.doFetch( + `${this.getChannelRoute(channelId)}/pinned`, + {method: 'get'}, + ); + }; + + markPostAsUnread = async (userId: string, postId: string) => { + analytics.trackAPI('api_post_set_unread_post'); + + return this.doFetch( + `${this.getUserRoute(userId)}/posts/${postId}/set_unread`, + {method: 'post'}, + ); + } + + pinPost = async (postId: string) => { + analytics.trackAPI('api_posts_pin'); + + return this.doFetch( + `${this.getPostRoute(postId)}/pin`, + {method: 'post'}, + ); + }; + + unpinPost = async (postId: string) => { + analytics.trackAPI('api_posts_unpin'); + + return this.doFetch( + `${this.getPostRoute(postId)}/unpin`, + {method: 'post'}, + ); + }; + + addReaction = async (userId: string, postId: string, emojiName: string) => { + analytics.trackAPI('api_reactions_save', {post_id: postId}); + + return this.doFetch( + `${this.getReactionsRoute()}`, + {method: 'post', body: JSON.stringify({user_id: userId, post_id: postId, emoji_name: emojiName})}, + ); + }; + + removeReaction = async (userId: string, postId: string, emojiName: string) => { + analytics.trackAPI('api_reactions_delete', {post_id: postId}); + + return this.doFetch( + `${this.getUserRoute(userId)}/posts/${postId}/reactions/${emojiName}`, + {method: 'delete'}, + ); + }; + + getReactionsForPost = async (postId: string) => { + return this.doFetch( + `${this.getPostRoute(postId)}/reactions`, + {method: 'get'}, + ); + }; + + searchPostsWithParams = async (teamId: string, params: any) => { + analytics.trackAPI('api_posts_search', {team_id: teamId}); + + return this.doFetch( + `${this.getTeamRoute(teamId)}/posts/search`, + {method: 'post', body: JSON.stringify(params)}, + ); + }; + + searchPosts = async (teamId: string, terms: string, isOrSearch: boolean) => { + return this.searchPostsWithParams(teamId, {terms, is_or_search: isOrSearch}); + }; + + doPostAction = async (postId: string, actionId: string, selectedOption = '') => { + return this.doPostActionWithCookie(postId, actionId, '', selectedOption); + }; + + doPostActionWithCookie = async (postId: string, actionId: string, actionCookie: string, selectedOption = '') => { + if (selectedOption) { + analytics.trackAPI('api_interactive_messages_menu_selected'); + } else { + analytics.trackAPI('api_interactive_messages_button_clicked'); + } + + const msg: any = { + selected_option: selectedOption, + }; + if (actionCookie !== '') { + msg.cookie = actionCookie; + } + return this.doFetch( + `${this.getPostRoute(postId)}/actions/${encodeURIComponent(actionId)}`, + {method: 'post', body: JSON.stringify(msg)}, + ); + }; +}; + +export default ClientPosts; diff --git a/app/client/rest/preferences.ts b/app/client/rest/preferences.ts new file mode 100644 index 000000000..5666f36a0 --- /dev/null +++ b/app/client/rest/preferences.ts @@ -0,0 +1,35 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import type {PreferenceType} from '@mm-redux/types/preferences'; + +export interface ClientPreferencesMix { + savePreferences: (userId: string, preferences: PreferenceType[]) => Promise; + deletePreferences: (userId: string, preferences: PreferenceType[]) => Promise; + getMyPreferences: () => Promise; +} + +const ClientPreferences = (superclass: any) => class extends superclass { + savePreferences = async (userId: string, preferences: PreferenceType[]) => { + return this.doFetch( + `${this.getPreferencesRoute(userId)}`, + {method: 'put', body: JSON.stringify(preferences)}, + ); + }; + + getMyPreferences = async () => { + return this.doFetch( + `${this.getPreferencesRoute('me')}`, + {method: 'get'}, + ); + }; + + deletePreferences = async (userId: string, preferences: PreferenceType[]) => { + return this.doFetch( + `${this.getPreferencesRoute(userId)}/delete`, + {method: 'post', body: JSON.stringify(preferences)}, + ); + }; +}; + +export default ClientPreferences; diff --git a/app/client/rest/teams.ts b/app/client/rest/teams.ts new file mode 100644 index 000000000..35d7b0e10 --- /dev/null +++ b/app/client/rest/teams.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {analytics} from '@init/analytics'; +import {Team, TeamMembership, TeamUnread} from '@mm-redux/types/teams'; +import {buildQueryString} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientTeamsMix { + createTeam: (team: Team) => Promise; + deleteTeam: (teamId: string) => Promise; + updateTeam: (team: Team) => Promise; + patchTeam: (team: Partial & {id: string}) => Promise; + getTeams: (page?: number, perPage?: number, includeTotalCount?: boolean) => Promise; + getTeam: (teamId: string) => Promise; + getTeamByName: (teamName: string) => Promise; + getMyTeams: () => Promise; + getTeamsForUser: (userId: string) => Promise; + getMyTeamMembers: () => Promise; + getMyTeamUnreads: () => Promise; + getTeamMembers: (teamId: string, page?: number, perPage?: number) => Promise; + getTeamMember: (teamId: string, userId: string) => Promise; + addToTeam: (teamId: string, userId: string) => Promise; + joinTeam: (inviteId: string) => Promise; + removeFromTeam: (teamId: string, userId: string) => Promise; + getTeamStats: (teamId: string) => Promise; + getTeamIconUrl: (teamId: string, lastTeamIconUpdate: number) => string; +} + +const ClientTeams = (superclass: any) => class extends superclass { + createTeam = async (team: Team) => { + analytics.trackAPI('api_teams_create'); + + return this.doFetch( + `${this.getTeamsRoute()}`, + {method: 'post', body: JSON.stringify(team)}, + ); + }; + + deleteTeam = async (teamId: string) => { + analytics.trackAPI('api_teams_delete'); + + return this.doFetch( + `${this.getTeamRoute(teamId)}`, + {method: 'delete'}, + ); + }; + + updateTeam = async (team: Team) => { + analytics.trackAPI('api_teams_update_name', {team_id: team.id}); + + return this.doFetch( + `${this.getTeamRoute(team.id)}`, + {method: 'put', body: JSON.stringify(team)}, + ); + }; + + patchTeam = async (team: Partial & {id: string}) => { + analytics.trackAPI('api_teams_patch_name', {team_id: team.id}); + + return this.doFetch( + `${this.getTeamRoute(team.id)}/patch`, + {method: 'put', body: JSON.stringify(team)}, + ); + }; + + getTeams = async (page = 0, perPage = PER_PAGE_DEFAULT, includeTotalCount = false) => { + return this.doFetch( + `${this.getTeamsRoute()}${buildQueryString({page, per_page: perPage, include_total_count: includeTotalCount})}`, + {method: 'get'}, + ); + }; + + getTeam = async (teamId: string) => { + return this.doFetch( + this.getTeamRoute(teamId), + {method: 'get'}, + ); + }; + + getTeamByName = async (teamName: string) => { + analytics.trackAPI('api_teams_get_team_by_name'); + + return this.doFetch( + this.getTeamNameRoute(teamName), + {method: 'get'}, + ); + }; + + getMyTeams = async () => { + return this.doFetch( + `${this.getUserRoute('me')}/teams`, + {method: 'get'}, + ); + }; + + getTeamsForUser = async (userId: string) => { + return this.doFetch( + `${this.getUserRoute(userId)}/teams`, + {method: 'get'}, + ); + }; + + getMyTeamMembers = async () => { + return this.doFetch( + `${this.getUserRoute('me')}/teams/members`, + {method: 'get'}, + ); + }; + + getMyTeamUnreads = async () => { + return this.doFetch( + `${this.getUserRoute('me')}/teams/unread`, + {method: 'get'}, + ); + }; + + getTeamMembers = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getTeamMembersRoute(teamId)}${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getTeamMember = async (teamId: string, userId: string) => { + return this.doFetch( + `${this.getTeamMemberRoute(teamId, userId)}`, + {method: 'get'}, + ); + }; + + addToTeam = async (teamId: string, userId: string) => { + analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); + + const member = {user_id: userId, team_id: teamId}; + return this.doFetch( + `${this.getTeamMembersRoute(teamId)}`, + {method: 'post', body: JSON.stringify(member)}, + ); + }; + + joinTeam = async (inviteId: string) => { + const query = buildQueryString({invite_id: inviteId}); + return this.doFetch( + `${this.getTeamsRoute()}/members/invite${query}`, + {method: 'post'}, + ); + }; + + removeFromTeam = async (teamId: string, userId: string) => { + analytics.trackAPI('api_teams_remove_members', {team_id: teamId}); + + return this.doFetch( + `${this.getTeamMemberRoute(teamId, userId)}`, + {method: 'delete'}, + ); + }; + + getTeamStats = async (teamId: string) => { + return this.doFetch( + `${this.getTeamRoute(teamId)}/stats`, + {method: 'get'}, + ); + }; + + getTeamIconUrl = (teamId: string, lastTeamIconUpdate: number) => { + const params: any = {}; + if (lastTeamIconUpdate) { + params._ = lastTeamIconUpdate; + } + + return `${this.getTeamRoute(teamId)}/image${buildQueryString(params)}`; + }; +}; + +export default ClientTeams; diff --git a/app/client/rest/tos.ts b/app/client/rest/tos.ts new file mode 100644 index 000000000..997080bcf --- /dev/null +++ b/app/client/rest/tos.ts @@ -0,0 +1,25 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export interface ClientTosMix { + updateMyTermsOfServiceStatus: (termsOfServiceId: string, accepted: boolean) => Promise; + getTermsOfService: () => Promise; +} + +const ClientTos = (superclass: any) => class extends superclass { + updateMyTermsOfServiceStatus = async (termsOfServiceId: string, accepted: boolean) => { + return this.doFetch( + `${this.getUserRoute('me')}/terms_of_service`, + {method: 'post', body: JSON.stringify({termsOfServiceId, accepted})}, + ); + } + + getTermsOfService = async () => { + return this.doFetch( + `${this.getBaseRoute()}/terms_of_service`, + {method: 'get'}, + ); + } +}; + +export default ClientTos; diff --git a/app/client/rest/users.ts b/app/client/rest/users.ts new file mode 100644 index 000000000..bcc59ce5d --- /dev/null +++ b/app/client/rest/users.ts @@ -0,0 +1,398 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {analytics} from '@init/analytics'; +import {General} from '@mm-redux/constants'; +import {UserProfile, UserStatus} from '@mm-redux/types/users'; +import {buildQueryString, isMinimumServerVersion} from '@mm-redux/utils/helpers'; + +import {PER_PAGE_DEFAULT} from './constants'; + +export interface ClientUsersMix { + createUser: (user: UserProfile, token: string, inviteId: string) => Promise; + patchMe: (userPatch: Partial) => Promise; + patchUser: (userPatch: Partial & {id: string}) => Promise; + updateUser: (user: UserProfile) => Promise; + demoteUserToGuest: (userId: string) => Promise; + getKnownUsers: () => Promise; + sendPasswordResetEmail: (email: string) => Promise; + setDefaultProfileImage: (userId: string) => Promise; + login: (loginId: string, password: string, token?: string, deviceId?: string, ldapOnly?: boolean) => Promise; + loginById: (id: string, password: string, token?: string, deviceId?: string) => Promise; + logout: () => Promise; + getProfiles: (page?: number, perPage?: number, options?: Record) => Promise; + getProfilesByIds: (userIds: string[], options?: Record) => Promise; + getProfilesByUsernames: (usernames: string[]) => Promise; + getProfilesInTeam: (teamId: string, page?: number, perPage?: number, sort?: string, options?: Record) => Promise; + getProfilesNotInTeam: (teamId: string, groupConstrained: boolean, page?: number, perPage?: number) => Promise; + getProfilesWithoutTeam: (page?: number, perPage?: number, options?: Record) => Promise; + getProfilesInChannel: (channelId: string, page?: number, perPage?: number, sort?: string) => Promise; + getProfilesInGroupChannels: (channelsIds: string[]) => Promise<{[x: string]: UserProfile[]}>; + getProfilesNotInChannel: (teamId: string, channelId: string, groupConstrained: boolean, page?: number, perPage?: number) => Promise; + getMe: () => Promise; + getUser: (userId: string) => Promise; + getUserByUsername: (username: string) => Promise; + getUserByEmail: (email: string) => Promise; + getProfilePictureUrl: (userId: string, lastPictureUpdate: number) => string; + getDefaultProfilePictureUrl: (userId: string) => string; + autocompleteUsers: (name: string, teamId: string, channelId: string, options?: Record) => Promise<{users: UserProfile[], out_of_channel?: UserProfile[]}>; + getSessions: (userId: string) => Promise; + checkUserMfa: (loginId: string) => Promise<{mfa_required: boolean}>; + attachDevice: (deviceId: string) => Promise; + searchUsers: (term: string, options: any) => Promise; + getStatusesByIds: (userIds: string[]) => Promise; + getStatus: (userId: string) => Promise; + updateStatus: (status: UserStatus) => Promise; +} + +const ClientUsers = (superclass: any) => class extends superclass { + createUser = async (user: UserProfile, token: string, inviteId: string) => { + analytics.trackAPI('api_users_create'); + + const queryParams: any = {}; + + if (token) { + queryParams.t = token; + } + + if (inviteId) { + queryParams.iid = inviteId; + } + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString(queryParams)}`, + {method: 'post', body: JSON.stringify(user)}, + ); + } + + patchMe = async (userPatch: Partial) => { + return this.doFetch( + `${this.getUserRoute('me')}/patch`, + {method: 'put', body: JSON.stringify(userPatch)}, + ); + } + + patchUser = async (userPatch: Partial & {id: string}) => { + analytics.trackAPI('api_users_patch'); + + return this.doFetch( + `${this.getUserRoute(userPatch.id)}/patch`, + {method: 'put', body: JSON.stringify(userPatch)}, + ); + } + + updateUser = async (user: UserProfile) => { + analytics.trackAPI('api_users_update'); + + return this.doFetch( + `${this.getUserRoute(user.id)}`, + {method: 'put', body: JSON.stringify(user)}, + ); + } + + demoteUserToGuest = async (userId: string) => { + analytics.trackAPI('api_users_demote_user_to_guest'); + + return this.doFetch( + `${this.getUserRoute(userId)}/demote`, + {method: 'post'}, + ); + } + + getKnownUsers = async () => { + analytics.trackAPI('api_get_known_users'); + + return this.doFetch( + `${this.getUsersRoute()}/known`, + {method: 'get'}, + ); + } + + sendPasswordResetEmail = async (email: string) => { + analytics.trackAPI('api_users_send_password_reset'); + + return this.doFetch( + `${this.getUsersRoute()}/password/reset/send`, + {method: 'post', body: JSON.stringify({email})}, + ); + } + + setDefaultProfileImage = async (userId: string) => { + analytics.trackAPI('api_users_set_default_profile_picture'); + + return this.doFetch( + `${this.getUserRoute(userId)}/image`, + {method: 'delete'}, + ); + }; + + login = async (loginId: string, password: string, token = '', deviceId = '', ldapOnly = false) => { + analytics.trackAPI('api_users_login'); + + if (ldapOnly) { + analytics.trackAPI('api_users_login_ldap'); + } + + const body: any = { + device_id: deviceId, + login_id: loginId, + password, + token, + }; + + if (ldapOnly) { + body.ldap_only = 'true'; + } + + const {data} = await this.doFetchWithResponse( + `${this.getUsersRoute()}/login`, + { + method: 'post', + body: JSON.stringify(body), + headers: {'Cache-Control': 'no-store'}, + }, + ); + + return data; + }; + + loginById = async (id: string, password: string, token = '', deviceId = '') => { + analytics.trackAPI('api_users_login'); + const body: any = { + device_id: deviceId, + id, + password, + token, + }; + + const {data} = await this.doFetchWithResponse( + `${this.getUsersRoute()}/login`, + {method: 'post', body: JSON.stringify(body)}, + ); + + return data; + }; + + logout = async () => { + analytics.trackAPI('api_users_logout'); + + const {response} = await this.doFetchWithResponse( + `${this.getUsersRoute()}/logout`, + {method: 'post'}, + ); + + if (response.ok) { + this.token = ''; + } + + this.serverVersion = ''; + + return response; + }; + + getProfiles = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { + analytics.trackAPI('api_profiles_get'); + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString({page, per_page: perPage, ...options})}`, + {method: 'get'}, + ); + }; + + getProfilesByIds = async (userIds: string[], options = {}) => { + analytics.trackAPI('api_profiles_get_by_ids'); + + return this.doFetch( + `${this.getUsersRoute()}/ids${buildQueryString(options)}`, + {method: 'post', body: JSON.stringify(userIds)}, + ); + }; + + getProfilesByUsernames = async (usernames: string[]) => { + analytics.trackAPI('api_profiles_get_by_usernames'); + + return this.doFetch( + `${this.getUsersRoute()}/usernames`, + {method: 'post', body: JSON.stringify(usernames)}, + ); + }; + + getProfilesInTeam = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '', options = {}) => { + analytics.trackAPI('api_profiles_get_in_team', {team_id: teamId, sort}); + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString({...options, in_team: teamId, page, per_page: perPage, sort})}`, + {method: 'get'}, + ); + }; + + getProfilesNotInTeam = async (teamId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { + analytics.trackAPI('api_profiles_get_not_in_team', {team_id: teamId, group_constrained: groupConstrained}); + + const queryStringObj: any = {not_in_team: teamId, page, per_page: perPage}; + if (groupConstrained) { + queryStringObj.group_constrained = true; + } + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, + {method: 'get'}, + ); + }; + + getProfilesWithoutTeam = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { + analytics.trackAPI('api_profiles_get_without_team'); + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString({...options, without_team: 1, page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getProfilesInChannel = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '') => { + analytics.trackAPI('api_profiles_get_in_channel', {channel_id: channelId}); + + const serverVersion = this.getServerVersion(); + let queryStringObj; + if (isMinimumServerVersion(serverVersion, 4, 7)) { + queryStringObj = {in_channel: channelId, page, per_page: perPage, sort}; + } else { + queryStringObj = {in_channel: channelId, page, per_page: perPage}; + } + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, + {method: 'get'}, + ); + }; + + getProfilesInGroupChannels = async (channelsIds: string[]) => { + analytics.trackAPI('api_profiles_get_in_group_channels', {channelsIds}); + + return this.doFetch( + `${this.getUsersRoute()}/group_channels`, + {method: 'post', body: JSON.stringify(channelsIds)}, + ); + }; + + getProfilesNotInChannel = async (teamId: string, channelId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { + analytics.trackAPI('api_profiles_get_not_in_channel', {team_id: teamId, channel_id: channelId, group_constrained: groupConstrained}); + + const queryStringObj: any = {in_team: teamId, not_in_channel: channelId, page, per_page: perPage}; + if (groupConstrained) { + queryStringObj.group_constrained = true; + } + + return this.doFetch( + `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, + {method: 'get'}, + ); + }; + + getMe = async () => { + return this.doFetch( + `${this.getUserRoute('me')}`, + {method: 'get'}, + ); + }; + + getUser = async (userId: string) => { + return this.doFetch( + `${this.getUserRoute(userId)}`, + {method: 'get'}, + ); + }; + + getUserByUsername = async (username: string) => { + return this.doFetch( + `${this.getUsersRoute()}/username/${username}`, + {method: 'get'}, + ); + }; + + getUserByEmail = async (email: string) => { + return this.doFetch( + `${this.getUsersRoute()}/email/${email}`, + {method: 'get'}, + ); + }; + + getProfilePictureUrl = (userId: string, lastPictureUpdate: number) => { + const params: any = {}; + + if (lastPictureUpdate) { + params._ = lastPictureUpdate; + } + + return `${this.getUserRoute(userId)}/image${buildQueryString(params)}`; + }; + + getDefaultProfilePictureUrl = (userId: string) => { + return `${this.getUserRoute(userId)}/image/default`; + }; + + autocompleteUsers = async (name: string, teamId: string, channelId: string, options = { + limit: General.AUTOCOMPLETE_LIMIT_DEFAULT, + }) => { + return this.doFetch(`${this.getUsersRoute()}/autocomplete${buildQueryString({ + in_team: teamId, + in_channel: channelId, + name, + limit: options.limit, + })}`, { + method: 'get', + }); + }; + + getSessions = async (userId: string) => { + return this.doFetch( + `${this.getUserRoute(userId)}/sessions`, + {method: 'get'}, + ); + }; + + checkUserMfa = async (loginId: string) => { + return this.doFetch( + `${this.getUsersRoute()}/mfa`, + {method: 'post', body: JSON.stringify({login_id: loginId})}, + ); + }; + + attachDevice = async (deviceId: string) => { + return this.doFetch( + `${this.getUsersRoute()}/sessions/device`, + {method: 'put', body: JSON.stringify({device_id: deviceId})}, + ); + }; + + searchUsers = async (term: string, options: any) => { + analytics.trackAPI('api_search_users'); + + return this.doFetch( + `${this.getUsersRoute()}/search`, + {method: 'post', body: JSON.stringify({term, ...options})}, + ); + }; + + getStatusesByIds = async (userIds: string[]) => { + return this.doFetch( + `${this.getUsersRoute()}/status/ids`, + {method: 'post', body: JSON.stringify(userIds)}, + ); + }; + + getStatus = async (userId: string) => { + return this.doFetch( + `${this.getUserRoute(userId)}/status`, + {method: 'get'}, + ); + }; + + updateStatus = async (status: UserStatus) => { + return this.doFetch( + `${this.getUserRoute(status.user_id)}/status`, + {method: 'put', body: JSON.stringify(status)}, + ); + }; +}; + +export default ClientUsers; diff --git a/app/client/websocket.ts b/app/client/websocket/index.ts similarity index 100% rename from app/client/websocket.ts rename to app/client/websocket/index.ts diff --git a/app/components/autocomplete/slash_suggestion/app_command_parser/tests/app_command_parser_test_dependencies.ts b/app/components/autocomplete/slash_suggestion/app_command_parser/tests/app_command_parser_test_dependencies.ts index 415f483f3..329167a3e 100644 --- a/app/components/autocomplete/slash_suggestion/app_command_parser/tests/app_command_parser_test_dependencies.ts +++ b/app/components/autocomplete/slash_suggestion/app_command_parser/tests/app_command_parser_test_dependencies.ts @@ -6,7 +6,7 @@ export {thunk}; const configureStore = require('redux-mock-store').default; export {configureStore}; -export {Client4} from '@mm-redux/client'; +export {Client4} from '@client/rest'; export type {AppBinding, AppForm} from '@mm-redux/types/apps'; export {AppFieldTypes} from '@mm-redux/constants/apps'; diff --git a/app/components/autocomplete/slash_suggestion/slash_suggestion.tsx b/app/components/autocomplete/slash_suggestion/slash_suggestion.tsx index d5587e3b0..382ad95f1 100644 --- a/app/components/autocomplete/slash_suggestion/slash_suggestion.tsx +++ b/app/components/autocomplete/slash_suggestion/slash_suggestion.tsx @@ -9,7 +9,7 @@ import { } from 'react-native'; import {analytics} from '@init/analytics'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; import {Command, AutocompleteSuggestion, CommandArgs} from '@mm-redux/types/integrations'; import {Theme} from '@mm-redux/types/preferences'; diff --git a/app/components/emoji/index.js b/app/components/emoji/index.js index c74a71575..a602c8b18 100644 --- a/app/components/emoji/index.js +++ b/app/components/emoji/index.js @@ -6,7 +6,7 @@ import {connect} from 'react-redux'; import {getCustomEmojisByName} from '@mm-redux/selectors/entities/emojis'; import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; import {getConfig} from '@mm-redux/selectors/entities/general'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; import {BuiltInEmojis, EmojiIndicesByAlias, Emojis} from 'app/utils/emojis'; diff --git a/app/components/file_attachment_list/file_attachment_image.js b/app/components/file_attachment_list/file_attachment_image.js index 7110e66d3..9befdeafe 100644 --- a/app/components/file_attachment_list/file_attachment_image.js +++ b/app/components/file_attachment_list/file_attachment_image.js @@ -9,7 +9,7 @@ import { } from 'react-native'; import ProgressiveImage from '@components/progressive_image'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {changeOpacity} from '@utils/theme'; import FileAttachmentIcon from './file_attachment_icon'; diff --git a/app/components/file_attachment_list/file_attachment_image.test.js b/app/components/file_attachment_list/file_attachment_image.test.js index 0ab9cc069..12dc54530 100644 --- a/app/components/file_attachment_list/file_attachment_image.test.js +++ b/app/components/file_attachment_list/file_attachment_image.test.js @@ -3,7 +3,7 @@ import React from 'react'; import {shallow} from 'enzyme'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import FileAttachmentImage from './file_attachment_image.js'; diff --git a/app/components/file_attachment_list/file_attachment_list.js b/app/components/file_attachment_list/file_attachment_list.js index 8a52301f8..45a3c4783 100644 --- a/app/components/file_attachment_list/file_attachment_list.js +++ b/app/components/file_attachment_list/file_attachment_list.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import {StyleSheet, View, DeviceEventEmitter} from 'react-native'; import ImageViewPort from '@components/image_viewport'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {isDocument, isGif, isImage, isVideo} from '@utils/file'; import {getViewPortWidth, openGalleryAtIndex} from '@utils/images'; import {preventDoubleTap} from '@utils/tap'; diff --git a/app/components/post_draft/uploads/upload_item/upload_item.js b/app/components/post_draft/uploads/upload_item/upload_item.js index f6f48a8a1..debf06dbb 100644 --- a/app/components/post_draft/uploads/upload_item/upload_item.js +++ b/app/components/post_draft/uploads/upload_item/upload_item.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import {StyleSheet, TouchableOpacity, View} from 'react-native'; import RNFetchBlob from 'rn-fetch-blob'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import mattermostBucket from 'app/mattermost_bucket'; import FileAttachmentImage from '@components/file_attachment_list/file_attachment_image'; diff --git a/app/components/post_profile_picture/index.js b/app/components/post_profile_picture/index.js index c4cff6bb5..61a54b80e 100644 --- a/app/components/post_profile_picture/index.js +++ b/app/components/post_profile_picture/index.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import {isSystemMessage} from '@mm-redux/utils/post_utils'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {getConfig} from '@mm-redux/selectors/entities/general'; diff --git a/app/components/profile_picture/profile_picture.js b/app/components/profile_picture/profile_picture.js index b8274dcd2..7fc2fe53b 100644 --- a/app/components/profile_picture/profile_picture.js +++ b/app/components/profile_picture/profile_picture.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import {Platform, View} from 'react-native'; import FastImage from 'react-native-fast-image'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import CompassIcon from '@components/compass_icon'; import UserStatus from '@components/user_status'; diff --git a/app/components/profile_picture_button.js b/app/components/profile_picture_button.js index 5c22d1a6d..da1e6284d 100644 --- a/app/components/profile_picture_button.js +++ b/app/components/profile_picture_button.js @@ -4,7 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {t} from 'app/utils/i18n'; diff --git a/app/components/profile_picture_button.test.js b/app/components/profile_picture_button.test.js index 3b6a7cc89..828f2b454 100644 --- a/app/components/profile_picture_button.test.js +++ b/app/components/profile_picture_button.test.js @@ -7,7 +7,7 @@ import Preferences from '@mm-redux/constants/preferences'; import ProfilePictureButton from './profile_picture_button.js'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; describe('profile_picture_button', () => { const baseProps = { diff --git a/app/components/root/root.js b/app/components/root/root.js index a2d1a3121..22a609fe3 100644 --- a/app/components/root/root.js +++ b/app/components/root/root.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import {IntlProvider} from 'react-intl'; import {Platform} from 'react-native'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {resetToTeams} from 'app/actions/navigation'; diff --git a/app/components/team_icon/team_icon.js b/app/components/team_icon/team_icon.js index bd0cdde8f..569ec1497 100644 --- a/app/components/team_icon/team_icon.js +++ b/app/components/team_icon/team_icon.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import {Text, View} from 'react-native'; import FastImage from 'react-native-fast-image'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {makeStyleSheetFromTheme} from 'app/utils/theme'; diff --git a/app/init/credentials.js b/app/init/credentials.js index e48d1eaab..493488d81 100644 --- a/app/init/credentials.js +++ b/app/init/credentials.js @@ -4,7 +4,7 @@ import AsyncStorage from '@react-native-community/async-storage'; import * as KeyChain from 'react-native-keychain'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import mattermostManaged from 'app/mattermost_managed'; import EphemeralStore from 'app/store/ephemeral_store'; diff --git a/app/init/fetch.js b/app/init/fetch.js index 83f03d28f..822d8daeb 100644 --- a/app/init/fetch.js +++ b/app/init/fetch.js @@ -7,8 +7,9 @@ import RNFetchBlob from 'rn-fetch-blob'; import urlParse from 'url-parse'; import LocalConfig from '@assets/config'; -import {Client4} from '@mm-redux/client'; -import {ClientError, HEADER_X_VERSION_ID} from '@mm-redux/client/client4'; +import {Client4} from '@client/rest'; +import {HEADER_TOKEN, HEADER_X_CLUSTER_ID, HEADER_X_VERSION_ID} from '@client/rest/constants'; +import ClientError from '@client/rest/error'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {General} from '@mm-redux/constants'; import {t} from '@utils/i18n'; @@ -18,8 +19,6 @@ import mattermostManaged from 'app/mattermost_managed'; /* eslint-disable no-throw-literal */ -export const HEADER_X_CLUSTER_ID = 'X-Cluster-Id'; -export const HEADER_TOKEN = 'Token'; const DEFAULT_TIMEOUT = 10000; let managedConfig; diff --git a/app/init/fetch.test.js b/app/init/fetch.test.js index 5257e849b..0f26e460b 100644 --- a/app/init/fetch.test.js +++ b/app/init/fetch.test.js @@ -1,16 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; -import {HEADER_X_VERSION_ID} from '@mm-redux/client/client4'; +import '@init/fetch'; +import {Client4} from '@client/rest'; +import {HEADER_X_CLUSTER_ID, HEADER_X_VERSION_ID, HEADER_TOKEN} from '@client/rest/constants'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {General} from '@mm-redux/constants'; -import { - HEADER_X_CLUSTER_ID, - HEADER_TOKEN, -} from 'app/init/fetch'; - describe('Fetch', () => { beforeAll(() => { global.fetch = jest.fn(() => Promise.resolve()); diff --git a/app/init/global_event_handler.js b/app/init/global_event_handler.js index a75321af1..c01fbb611 100644 --- a/app/init/global_event_handler.js +++ b/app/init/global_event_handler.js @@ -23,7 +23,7 @@ import {setAppState, setServerVersion} from '@mm-redux/actions/general'; import {getTeams} from '@mm-redux/actions/teams'; import {autoUpdateTimezone} from '@mm-redux/actions/timezone'; import {close as closeWebSocket} from '@actions/websocket'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import {getConfig} from '@mm-redux/selectors/entities/general'; import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels'; diff --git a/app/mm-redux/action_types/channels.ts b/app/mm-redux/action_types/channels.ts index 3925d2007..27ad2bb2e 100644 --- a/app/mm-redux/action_types/channels.ts +++ b/app/mm-redux/action_types/channels.ts @@ -71,13 +71,6 @@ export default keyMirror({ INCREMENT_UNREAD_MENTION_COUNT: null, DECREMENT_UNREAD_MENTION_COUNT: null, - UPDATED_CHANNEL_SCHEME: null, - UPDATED_CHANNEL_MEMBER_SCHEME_ROLES: null, - - RECEIVED_CHANNEL_MEMBERS_MINUS_GROUP_MEMBERS: null, - - RECEIVED_CHANNEL_MODERATIONS: null, - RECEIVED_CHANNEL_MEMBER_COUNTS_BY_GROUP: null, RECEIVED_TOTAL_CHANNEL_COUNT: null, diff --git a/app/mm-redux/action_types/index.ts b/app/mm-redux/action_types/index.ts index dba4c1d29..9d3753db6 100644 --- a/app/mm-redux/action_types/index.ts +++ b/app/mm-redux/action_types/index.ts @@ -12,10 +12,8 @@ import PreferenceTypes from './preferences'; import IntegrationTypes from './integrations'; import EmojiTypes from './emojis'; import GifTypes from './gifs'; -import JobTypes from './jobs'; import SearchTypes from './search'; import RoleTypes from './roles'; -import SchemeTypes from './schemes'; import GroupTypes from './groups'; import BotTypes from './bots'; import PluginTypes from './plugins'; @@ -34,10 +32,8 @@ export { IntegrationTypes, EmojiTypes, GifTypes, - JobTypes, SearchTypes, RoleTypes, - SchemeTypes, GroupTypes, BotTypes, PluginTypes, diff --git a/app/mm-redux/action_types/integrations.ts b/app/mm-redux/action_types/integrations.ts index 7b545bf84..9f1df197e 100644 --- a/app/mm-redux/action_types/integrations.ts +++ b/app/mm-redux/action_types/integrations.ts @@ -4,22 +4,12 @@ import keyMirror from '@mm-redux/utils/key_mirror'; export default keyMirror({ - RECEIVED_INCOMING_HOOK: null, - RECEIVED_INCOMING_HOOKS: null, - DELETED_INCOMING_HOOK: null, - RECEIVED_OUTGOING_HOOK: null, - RECEIVED_OUTGOING_HOOKS: null, - DELETED_OUTGOING_HOOK: null, - RECEIVED_CUSTOM_TEAM_COMMANDS: null, RECEIVED_COMMAND: null, RECEIVED_COMMANDS: null, RECEIVED_COMMAND_SUGGESTIONS: null, RECEIVED_COMMAND_SUGGESTIONS_FAILURE: null, RECEIVED_COMMAND_TOKEN: null, DELETED_COMMAND: null, - RECEIVED_OAUTH_APP: null, - RECEIVED_OAUTH_APPS: null, - DELETED_OAUTH_APP: null, RECEIVED_DIALOG_TRIGGER_ID: null, RECEIVED_DIALOG: null, diff --git a/app/mm-redux/action_types/jobs.ts b/app/mm-redux/action_types/jobs.ts deleted file mode 100644 index f3888e954..000000000 --- a/app/mm-redux/action_types/jobs.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import keyMirror from '@mm-redux/utils/key_mirror'; - -export default keyMirror({ - CREATE_JOB_REQUEST: null, - CREATE_JOB_SUCCESS: null, - CREATE_JOB_FAILURE: null, - - CANCEL_JOB_REQUEST: null, - CANCEL_JOB_SUCCESS: null, - CANCEL_JOB_FAILURE: null, - - GET_JOB_REQUEST: null, - GET_JOB_SUCCESS: null, - GET_JOB_FAILURE: null, - - GET_JOBS_REQUEST: null, - GET_JOBS_SUCCESS: null, - GET_JOBS_FAILURE: null, - - RECEIVED_JOB: null, - RECEIVED_JOBS: null, - RECEIVED_JOBS_BY_TYPE: null, -}); diff --git a/app/mm-redux/action_types/roles.ts b/app/mm-redux/action_types/roles.ts index ebd4dd580..ed069032e 100644 --- a/app/mm-redux/action_types/roles.ts +++ b/app/mm-redux/action_types/roles.ts @@ -7,18 +7,6 @@ export default keyMirror({ ROLES_BY_NAMES_SUCCESS: null, ROLES_BY_NAMES_FAILURE: null, - ROLE_BY_NAME_REQUEST: null, - ROLE_BY_NAME_SUCCESS: null, - ROLE_BY_NAME_FAILURE: null, - - ROLE_BY_ID_REQUEST: null, - ROLE_BY_ID_SUCCESS: null, - ROLE_BY_ID_FAILURE: null, - - EDIT_ROLE_REQUEST: null, - EDIT_ROLE_SUCCESS: null, - EDIT_ROLE_FAILURE: null, - RECEIVED_ROLES: null, RECEIVED_ROLE: null, ROLE_DELETED: null, diff --git a/app/mm-redux/action_types/schemes.ts b/app/mm-redux/action_types/schemes.ts deleted file mode 100644 index 2f5a5d87f..000000000 --- a/app/mm-redux/action_types/schemes.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import keyMirror from '@mm-redux/utils/key_mirror'; - -export default keyMirror({ - RECEIVED_SCHEME: null, - - RECEIVED_SCHEMES: null, - - CREATED_SCHEME: null, - - DELETED_SCHEME: null, - - PATCHED_SCHEME: null, - - RECEIVED_SCHEME_TEAMS: null, - - RECEIVED_SCHEME_CHANNELS: null, -}); diff --git a/app/mm-redux/action_types/teams.ts b/app/mm-redux/action_types/teams.ts index 994446cb3..951df1dee 100644 --- a/app/mm-redux/action_types/teams.ts +++ b/app/mm-redux/action_types/teams.ts @@ -16,10 +16,6 @@ export default keyMirror({ CREATE_TEAM_SUCCESS: null, CREATE_TEAM_FAILURE: null, - GET_TEAM_MEMBERS_REQUEST: null, - GET_TEAM_MEMBERS_SUCCESS: null, - GET_TEAM_MEMBERS_FAILURE: null, - JOIN_TEAM_REQUEST: null, JOIN_TEAM_SUCCESS: null, JOIN_TEAM_FAILURE: null, @@ -50,10 +46,6 @@ export default keyMirror({ RECEIVED_TEAM_STATS: null, RECEIVED_MY_TEAM_UNREADS: null, LEAVE_TEAM: null, - UPDATED_TEAM_SCHEME: null, - UPDATED_TEAM_MEMBER_SCHEME_ROLES: null, - - RECEIVED_TEAM_MEMBERS_MINUS_GROUP_MEMBERS: null, RECEIVED_TOTAL_TEAM_COUNT: null, }); diff --git a/app/mm-redux/action_types/users.ts b/app/mm-redux/action_types/users.ts index 83c29b2d5..b5a04742f 100644 --- a/app/mm-redux/action_types/users.ts +++ b/app/mm-redux/action_types/users.ts @@ -52,7 +52,6 @@ export default keyMirror({ RECEIVED_PROFILE_NOT_IN_CHANNEL: null, RECEIVED_SESSIONS: null, RECEIVED_REVOKED_SESSION: null, - RECEIVED_AUDITS: null, RECEIVED_STATUS: null, RECEIVED_STATUSES: null, RECEIVED_AUTOCOMPLETE_IN_CHANNEL: null, diff --git a/app/mm-redux/actions/apps.ts b/app/mm-redux/actions/apps.ts index 3b61c2279..9503bd1eb 100644 --- a/app/mm-redux/actions/apps.ts +++ b/app/mm-redux/actions/apps.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {AppsTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {ActionFunc} from '@mm-redux/types/actions'; diff --git a/app/mm-redux/actions/bots.test.js b/app/mm-redux/actions/bots.test.js index 18e3010e8..d672a4357 100644 --- a/app/mm-redux/actions/bots.test.js +++ b/app/mm-redux/actions/bots.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import nock from 'nock'; import * as BotActions from '@mm-redux/actions/bots'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; @@ -51,82 +51,4 @@ describe('Actions.Bots', () => { const botsResult = state.entities.bots.accounts[bot.user_id]; assert.equal(bot.username, botsResult.username); }); - - it('createBot', async () => { - const bot = TestHelper.fakeBot(); - nock(Client4.getBaseRoute()). - post('/bots'). - reply(200, bot); - await store.dispatch(BotActions.createBot(bot)); - - const state = store.getState(); - const botsResult = state.entities.bots.accounts[bot.user_id]; - assert.equal(bot.username, botsResult.username); - }); - - it('patchBot', async () => { - const bot = TestHelper.fakeBot(); - nock(Client4.getBaseRoute()). - post('/bots'). - reply(200, bot); - await store.dispatch(BotActions.createBot(bot)); - - bot.username = 'mynewusername'; - - nock(Client4.getBaseRoute()). - put(`/bots/${bot.user_id}`). - reply(200, bot); - await store.dispatch(BotActions.patchBot(bot.user_id, bot)); - - const state = store.getState(); - const botsResult = state.entities.bots.accounts[bot.user_id]; - assert.equal(bot.username, botsResult.username); - }); - - it('disableBot', async () => { - const bot = TestHelper.fakeBot(); - nock(Client4.getBaseRoute()). - post('/bots'). - reply(200, bot); - await store.dispatch(BotActions.createBot(bot)); - - // Disable the bot by setting delete_at to a value > 0 - bot.delete_at = 1507840900065; - nock(Client4.getBotRoute(bot.user_id)). - post('/disable'). - reply(200, bot); - await store.dispatch(BotActions.disableBot(bot.user_id)); - - const state = store.getState(); - const botsResult = state.entities.bots.accounts[bot.user_id]; - assert.equal(bot.delete_at, botsResult.delete_at); - - bot.delete_at = 0; - nock(Client4.getBotRoute(bot.user_id)). - post('/enable'). - reply(200, bot); - await store.dispatch(BotActions.enableBot(bot.user_id)); - - const state2 = store.getState(); - const botsResult2 = state2.entities.bots.accounts[bot.user_id]; - assert.equal(bot.delete_at, botsResult2.delete_at); - }); - - it('assignBot', async () => { - const bot = TestHelper.fakeBot(); - nock(Client4.getBaseRoute()). - post('/bots'). - reply(200, bot); - await store.dispatch(BotActions.createBot(bot)); - - bot.owner_id = TestHelper.generateId(); - nock(Client4.getBotRoute(bot.user_id)). - post('/assign/' + bot.owner_id). - reply(200, bot); - await store.dispatch(BotActions.assignBot(bot.user_id, bot.owner_id)); - - const state = store.getState(); - const botsResult = state.entities.bots.accounts[bot.user_id]; - assert.equal(bot.owner_id, botsResult.owner_id); - }); }); diff --git a/app/mm-redux/actions/bots.ts b/app/mm-redux/actions/bots.ts index cb357711d..673b875b1 100644 --- a/app/mm-redux/actions/bots.ts +++ b/app/mm-redux/actions/bots.ts @@ -1,36 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {BotTypes} from '@mm-redux/action_types'; import {bindClientFunc} from './helpers'; import {ActionFunc} from '@mm-redux/types/actions'; -import {Bot, BotPatch} from '@mm-redux/types/bots'; const BOTS_PER_PAGE_DEFAULT = 20; -export function createBot(bot: Bot): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createBot, - onSuccess: BotTypes.RECEIVED_BOT_ACCOUNT, - params: [ - bot, - ], - }); -} - -export function patchBot(botUserId: string, botPatch: BotPatch): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.patchBot, - onSuccess: BotTypes.RECEIVED_BOT_ACCOUNT, - params: [ - botUserId, - botPatch, - ], - }); -} - export function loadBot(botUserId: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.getBot, @@ -51,34 +29,3 @@ export function loadBots(page = 0, perPage = BOTS_PER_PAGE_DEFAULT): ActionFunc ], }); } - -export function disableBot(botUserId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.disableBot, - onSuccess: BotTypes.RECEIVED_BOT_ACCOUNT, - params: [ - botUserId, - ], - }); -} - -export function enableBot(botUserId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.enableBot, - onSuccess: BotTypes.RECEIVED_BOT_ACCOUNT, - params: [ - botUserId, - ], - }); -} - -export function assignBot(botUserId: string, newOwnerId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.assignBot, - onSuccess: BotTypes.RECEIVED_BOT_ACCOUNT, - params: [ - botUserId, - newOwnerId, - ], - }); -} diff --git a/app/mm-redux/actions/channels.test.js b/app/mm-redux/actions/channels.test.js index 0789fa5e4..7680d0b95 100644 --- a/app/mm-redux/actions/channels.test.js +++ b/app/mm-redux/actions/channels.test.js @@ -5,11 +5,9 @@ import assert from 'assert'; import nock from 'nock'; import * as Actions from '@mm-redux/actions/channels'; -import {addUserToTeam} from '@mm-redux/actions/teams'; import {getProfilesByIds, login} from '@mm-redux/actions/users'; -import {createIncomingHook, createOutgoingHook} from '@mm-redux/actions/integrations'; -import {Client4} from '@mm-redux/client'; -import {General, RequestStatus, Preferences, Permissions} from '../constants'; +import {Client4} from '@client/rest'; +import {General, RequestStatus, Preferences} from '../constants'; import {getPreferenceKey} from '@mm-redux/utils/preference_utils'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; @@ -450,57 +448,11 @@ describe('Actions.Channels', () => { await store.dispatch(Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)); - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, { - id: TestHelper.generateId(), - create_at: 1507840900004, - update_at: 1507840900004, - delete_at: 0, - user_id: TestHelper.basicUser.id, - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'TestIncomingHook', - description: 'Some description.', - }); - const incomingHook = await store.dispatch(createIncomingHook({channel_id: secondChannel.id, display_name: 'test', description: 'test'})); - - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, { - id: TestHelper.generateId(), - token: TestHelper.generateId(), - create_at: 1507841118796, - update_at: 1507841118796, - delete_at: 0, - creator_id: TestHelper.basicUser.id, - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - trigger_words: ['testword'], - trigger_when: 0, - callback_urls: ['http://notarealurl'], - display_name: 'TestOutgoingHook', - description: '', - content_type: 'application/x-www-form-urlencoded', - }); - const outgoingHook = await store.dispatch(createOutgoingHook({ - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'TestOutgoingHook', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://notarealurl']}, - )); - nock(Client4.getBaseRoute()). delete(`/channels/${secondChannel.id}`). reply(200, OK_RESPONSE); await store.dispatch(Actions.deleteChannel(secondChannel.id)); - - const {incomingHooks, outgoingHooks} = store.getState().entities.integrations; - - assert.ifError(incomingHooks[incomingHook.id]); - assert.ifError(outgoingHooks[outgoingHook.id]); }); it('unarchiveChannel', async () => { @@ -550,57 +502,11 @@ describe('Actions.Channels', () => { await store.dispatch(Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)); - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, { - id: TestHelper.generateId(), - create_at: 1507840900004, - update_at: 1507840900004, - delete_at: 1609090954545, - user_id: TestHelper.basicUser.id, - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'TestIncomingHook', - description: 'Some description.', - }); - const incomingHook = await store.dispatch(createIncomingHook({channel_id: secondChannel.id, display_name: 'test', description: 'test'})); - - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, { - id: TestHelper.generateId(), - token: TestHelper.generateId(), - create_at: 1507841118796, - update_at: 1507841118796, - delete_at: 1609090954545, - creator_id: TestHelper.basicUser.id, - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - trigger_words: ['testword'], - trigger_when: 0, - callback_urls: ['http://notarealurl'], - display_name: 'TestOutgoingHook', - description: '', - content_type: 'application/x-www-form-urlencoded', - }); - const outgoingHook = await store.dispatch(createOutgoingHook({ - channel_id: secondChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'TestOutgoingHook', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://notarealurl']}, - )); - nock(Client4.getBaseRoute()). delete(`/channels/${secondChannel.id}`). reply(200, OK_RESPONSE); await store.dispatch(Actions.unarchiveChannel(secondChannel.id)); - - const {incomingHooks, outgoingHooks} = store.getState().entities.integrations; - - assert.ifError(incomingHooks[incomingHook.id]); - assert.ifError(outgoingHooks[outgoingHook.id]); }); describe('viewChannel', () => { @@ -1615,60 +1521,6 @@ describe('Actions.Channels', () => { assert.ok(store.getState().entities.channels.totalCount === mockTotalCount); }); - it('searchAllChannels', async () => { - const userClient = TestHelper.createClient(); - - nock(Client4.getBaseRoute()). - post('/users'). - query(true). - reply(201, TestHelper.fakeUserWithId()); - - const user = await TestHelper.basicClient4.createUser( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id, - ); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, user); - - await userClient.login(user.email, 'password1'); - - nock(Client4.getBaseRoute()). - post('/channels'). - reply(201, TestHelper.fakeChannelWithId(TestHelper.basicTeam.id)); - - const userChannel = await userClient.createChannel( - TestHelper.fakeChannel(TestHelper.basicTeam.id), - ); - - nock(Client4.getBaseRoute()). - post('/channels/search'). - reply(200, [TestHelper.basicChannel, userChannel]); - - await store.dispatch(Actions.searchAllChannels('test', 0)); - - const moreRequest = store.getState().requests.channels.getAllChannels; - if (moreRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(moreRequest.error)); - } - - nock(Client4.getBaseRoute()). - post('/channels/search'). - reply(200, {channels: [TestHelper.basicChannel, userChannel], total_count: 2}); - - const response = await store.dispatch(Actions.searchAllChannels('test', '', false, 0, 100)); - - const paginatedRequest = store.getState().requests.channels.getAllChannels; - if (paginatedRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(paginatedRequest.error)); - } - - assert.ok(response.data.channels.length === 2); - }); - it('searchArchivedChannels', async () => { const userClient = TestHelper.createClient(); @@ -1901,38 +1753,6 @@ describe('Actions.Channels', () => { assert.ok(stats[channelId].member_count >= 1, 'incorrect member count for channel'); }); - it('updateChannelMemberRoles', async () => { - nock(Client4.getBaseRoute()). - post('/users'). - reply(201, TestHelper.fakeUserWithId()); - - const user = await TestHelper.basicClient4.createUser(TestHelper.fakeUser()); - - nock(Client4.getTeamsRoute()). - post(`/${TestHelper.basicChannel.id}/members`). - reply(201, {team_id: TestHelper.basicTeam.id, roles: 'channel_user', user_id: user.id}); - - await store.dispatch(addUserToTeam(TestHelper.basicTeam.id, user.id)); - nock(Client4.getBaseRoute()). - post(`/channels/${TestHelper.basicChannel.id}/members`). - reply(201, {channel_id: TestHelper.basicChannel.id, roles: 'channel_user', user_id: user.id}); - - await store.dispatch(Actions.addChannelMember(TestHelper.basicChannel.id, user.id)); - - const roles = General.CHANNEL_USER_ROLE + ' ' + General.CHANNEL_ADMIN_ROLE; - - nock(Client4.getBaseRoute()). - put(`/channels/${TestHelper.basicChannel.id}/members/${user.id}/roles`). - reply(200, {roles}); - await store.dispatch(Actions.updateChannelMemberRoles(TestHelper.basicChannel.id, user.id, roles)); - - const members = store.getState().entities.channels.membersInChannel; - - assert.ok(members[TestHelper.basicChannel.id]); - assert.ok(members[TestHelper.basicChannel.id][user.id]); - assert.ok(members[TestHelper.basicChannel.id][user.id].roles === roles); - }); - it('updateChannelHeader', async () => { nock(Client4.getBaseRoute()). get(`/channels/${TestHelper.basicChannel.id}`). @@ -2158,73 +1978,6 @@ describe('Actions.Channels', () => { assert.deepEqual(result, {data: [TestHelper.basicChannel]}); }); - it('updateChannelScheme', async () => { - TestHelper.mockLogin(); - await store.dispatch(login(TestHelper.basicChannelMember.email, 'password1')); - - nock(Client4.getBaseRoute()). - post('/channels'). - reply(201, TestHelper.fakeChannelWithId(TestHelper.basicTeam.id)); - - await store.dispatch(Actions.createChannel(TestHelper.fakeChannel(TestHelper.basicTeam.id), TestHelper.basicUser.id)); - - const createRequest = store.getState().requests.channels.createChannel; - - if (createRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(createRequest.error)); - } - - const {channels} = store.getState().entities.channels; - const schemeId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'; - const {id} = channels[Object.keys(channels)[0]]; - - nock(Client4.getBaseRoute()). - put('/channels/' + id + '/scheme'). - reply(200, OK_RESPONSE); - - await store.dispatch(Actions.updateChannelScheme(id, schemeId)); - const updated = store.getState().entities.channels.channels[id]; - assert.ok(updated); - assert.equal(updated.scheme_id, schemeId); - }); - - it('updateChannelMemberSchemeRoles', async () => { - TestHelper.mockLogin(); - await store.dispatch(login(TestHelper.basicChannelMember.email, 'password1')); - - nock(Client4.getBaseRoute()). - post('/channels'). - reply(201, TestHelper.fakeChannelWithId(TestHelper.basicTeam.id)); - - const userId = TestHelper.basicChannelMember.id; - - await store.dispatch(Actions.createChannel(TestHelper.fakeChannel(TestHelper.basicTeam.id), userId)); - - const {channels} = store.getState().entities.channels; - const channelId = channels[Object.keys(channels)[0]].id; - - nock(Client4.getBaseRoute()). - put(`/channels/${channelId}/members/${userId}/schemeRoles`). - reply(200, OK_RESPONSE); - - await store.dispatch(Actions.updateChannelMemberSchemeRoles(channelId, userId, true, true)); - const update1 = store.getState().entities.channels.membersInChannel[channelId][userId]; - assert.ok(update1); - assert.equal(update1.scheme_admin, true); - assert.equal(update1.scheme_user, true); - - nock(Client4.getBaseRoute()). - put(`/channels/${channelId}/members/${userId}/schemeRoles`). - reply(200, OK_RESPONSE); - - await store.dispatch(Actions.updateChannelMemberSchemeRoles(channelId, userId, false, false)); - - const update2 = store.getState().entities.channels.membersInChannel[channelId][userId]; - assert.ok(update2); - assert.equal(update2.scheme_admin, false); - assert.equal(update2.scheme_user, false); - }); - it('markGroupChannelOpen', async () => { const channelId = TestHelper.generateId(); const now = new Date().getTime(); @@ -2266,65 +2019,6 @@ describe('Actions.Channels', () => { assert.deepEqual(response, data); }); - it('membersMinusGroupMembers', async () => { - const channelID = 'cid10000000000000000000000'; - const groupIDs = ['gid10000000000000000000000', 'gid20000000000000000000000']; - const page = 7; - const perPage = 63; - - nock(Client4.getBaseRoute()).get( - `/channels/${channelID}/members_minus_group_members?group_ids=${groupIDs.join(',')}&page=${page}&per_page=${perPage}`). - reply(200, {users: [], total_count: 0}); - - const {error} = await Actions.membersMinusGroupMembers(channelID, groupIDs, page, perPage)(store.dispatch, store.getState); - - assert.equal(error, null); - }); - - it('getChannelModerations', async () => { - const channelID = 'cid10000000000000000000000'; - - nock(Client4.getBaseRoute()).get( - `/channels/${channelID}/moderations`). - reply(200, [{ - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST, - roles: { - members: true, - guests: false, - }, - }]); - - const {error} = await store.dispatch(Actions.getChannelModerations(channelID)); - const moderations = store.getState().entities.channels.channelModerations[channelID]; - - assert.equal(error, null); - assert.equal(moderations[0].name, Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST); - assert.equal(moderations[0].roles.members, true); - assert.equal(moderations[0].roles.guests, false); - }); - - it('patchChannelModerations', async () => { - const channelID = 'cid10000000000000000000000'; - - nock(Client4.getBaseRoute()).put( - `/channels/${channelID}/moderations/patch`). - reply(200, [{ - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_REACTIONS, - roles: { - members: true, - guests: false, - }, - }]); - - const {error} = await store.dispatch(Actions.patchChannelModerations(channelID, {})); - const moderations = store.getState().entities.channels.channelModerations[channelID]; - - assert.equal(error, null); - assert.equal(moderations[0].name, Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_REACTIONS); - assert.equal(moderations[0].roles.members, true); - assert.equal(moderations[0].roles.guests, false); - }); - it('getChannelMemberCountsByGroup', async () => { const channelID = 'cid10000000000000000000000'; diff --git a/app/mm-redux/actions/channels.ts b/app/mm-redux/actions/channels.ts index abc78fce5..5441af9fe 100644 --- a/app/mm-redux/actions/channels.ts +++ b/app/mm-redux/actions/channels.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Preferences} from '../constants'; import {ChannelTypes, PreferenceTypes, TeamTypes, UserTypes} from '@mm-redux/action_types'; import {savePreferences, deletePreferences} from './preferences'; @@ -17,7 +17,7 @@ import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; import {Action, ActionFunc, batchActions, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; -import {Channel, ChannelNotifyProps, ChannelMembership, ChannelModerationPatch} from '@mm-redux/types/channels'; +import {Channel, ChannelNotifyProps, ChannelMembership} from '@mm-redux/types/channels'; import {PreferenceType} from '@mm-redux/types/preferences'; @@ -1102,45 +1102,6 @@ export function searchChannels(teamId: string, term: string, archived?: boolean) }; } -export function searchAllChannels(term: string, notAssociatedToGroup = '', excludeDefaultChannels = false, page?: number, perPage?: number): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - dispatch({type: ChannelTypes.GET_ALL_CHANNELS_REQUEST, data: null}); - - let response; - try { - response = await Client4.searchAllChannels(term, notAssociatedToGroup, excludeDefaultChannels, page, perPage); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(batchActions([ - {type: ChannelTypes.GET_ALL_CHANNELS_FAILURE, error}, - logError(error), - ])); - return {error}; - } - - const channels = response.channels || response; - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_ALL_CHANNELS, - data: channels, - }, - { - type: ChannelTypes.GET_ALL_CHANNELS_SUCCESS, - }, - ])); - - return {data: response}; - }; -} - -export function searchGroupChannels(term: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.searchGroupChannels, - params: [term], - }); -} - export function getChannelStats(channelId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let stat; @@ -1220,28 +1181,6 @@ export function removeChannelMember(channelId: string, userId: string): ActionFu }; } -export function updateChannelMemberRoles(channelId: string, userId: string, roles: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateChannelMemberRoles(channelId, userId, roles); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const membersInChannel = getState().entities.channels.membersInChannel[channelId]; - if (membersInChannel && membersInChannel[userId]) { - dispatch({ - type: ChannelTypes.RECEIVED_CHANNEL_MEMBER, - data: {...membersInChannel[userId], roles}, - }); - } - - return {data: true}; - }; -} - export function updateChannelHeader(channelId: string, header: string): ActionFunc { return async (dispatch: DispatchFunc) => { analytics.trackAction('action_channels_update_header', {channel_id: channelId}); @@ -1461,65 +1400,6 @@ export function unfavoriteChannel(channelId: string): ActionFunc { }; } -export function updateChannelScheme(channelId: string, schemeId: string) { - return bindClientFunc({ - clientFunc: async () => { - await Client4.updateChannelScheme(channelId, schemeId); - return {channelId, schemeId}; - }, - onSuccess: ChannelTypes.UPDATED_CHANNEL_SCHEME, - }); -} - -export function updateChannelMemberSchemeRoles(channelId: string, userId: string, isSchemeUser: boolean, isSchemeAdmin: boolean) { - return bindClientFunc({ - clientFunc: async () => { - await Client4.updateChannelMemberSchemeRoles(channelId, userId, isSchemeUser, isSchemeAdmin); - return {channelId, userId, isSchemeUser, isSchemeAdmin}; - }, - onSuccess: ChannelTypes.UPDATED_CHANNEL_MEMBER_SCHEME_ROLES, - }); -} - -export function membersMinusGroupMembers(channelID: string, groupIDs: Array, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.channelMembersMinusGroupMembers, - onSuccess: ChannelTypes.RECEIVED_CHANNEL_MEMBERS_MINUS_GROUP_MEMBERS, - params: [ - channelID, - groupIDs, - page, - perPage, - ], - }); -} - -export function getChannelModerations(channelId: string): ActionFunc { - return bindClientFunc({ - clientFunc: async () => { - const moderations = await Client4.getChannelModerations(channelId); - return {channelId, moderations}; - }, - onSuccess: ChannelTypes.RECEIVED_CHANNEL_MODERATIONS, - params: [ - channelId, - ], - }); -} - -export function patchChannelModerations(channelId: string, patch: Array): ActionFunc { - return bindClientFunc({ - clientFunc: async () => { - const moderations = await Client4.patchChannelModerations(channelId, patch); - return {channelId, moderations}; - }, - onSuccess: ChannelTypes.RECEIVED_CHANNEL_MODERATIONS, - params: [ - channelId, - ], - }); -} - export function getChannelMemberCountsByGroup(channelId: string, includeTimezones: boolean): ActionFunc { return async (dispatch: DispatchFunc) => { let channelMemberCountsByGroup; @@ -1562,7 +1442,6 @@ export default { autocompleteChannels, autocompleteChannelsForSearch, searchChannels, - searchGroupChannels, getChannelStats, addChannelMember, removeChannelMember, @@ -1572,6 +1451,4 @@ export default { markChannelAsUnread, favoriteChannel, unfavoriteChannel, - membersMinusGroupMembers, - getChannelModerations, }; diff --git a/app/mm-redux/actions/emojis.test.js b/app/mm-redux/actions/emojis.test.js index 46022081c..27646ae56 100644 --- a/app/mm-redux/actions/emojis.test.js +++ b/app/mm-redux/actions/emojis.test.js @@ -6,7 +6,7 @@ import assert from 'assert'; import nock from 'nock'; import * as Actions from '@mm-redux/actions/emojis'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {GeneralTypes} from '@mm-redux/action_types'; import TestHelper from 'test/test_helper'; diff --git a/app/mm-redux/actions/emojis.ts b/app/mm-redux/actions/emojis.ts index c256bb833..bfaf5048c 100644 --- a/app/mm-redux/actions/emojis.ts +++ b/app/mm-redux/actions/emojis.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {EmojiTypes} from '@mm-redux/action_types'; import {General, Emoji} from '../constants'; import {getProfilesByIds} from './users'; diff --git a/app/mm-redux/actions/errors.test.js b/app/mm-redux/actions/errors.test.js index 95283e0a7..6613d0c29 100644 --- a/app/mm-redux/actions/errors.test.js +++ b/app/mm-redux/actions/errors.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import nock from 'nock'; import {logError} from '@mm-redux/actions/errors'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; diff --git a/app/mm-redux/actions/errors.ts b/app/mm-redux/actions/errors.ts index 69e566309..714415956 100644 --- a/app/mm-redux/actions/errors.ts +++ b/app/mm-redux/actions/errors.ts @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {ErrorTypes} from '@mm-redux/action_types'; import {serializeError, ErrorObject} from 'serialize-error'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import EventEmitter from '@mm-redux/utils/event_emitter'; import {DispatchFunc, ActionFunc} from '@mm-redux/types/actions'; import {Error} from '@mm-redux/types/errors'; diff --git a/app/mm-redux/actions/files.test.js b/app/mm-redux/actions/files.test.js index 8c6188f55..bc2ac0085 100644 --- a/app/mm-redux/actions/files.test.js +++ b/app/mm-redux/actions/files.test.js @@ -1,17 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import fs from 'fs'; import assert from 'assert'; import nock from 'nock'; import * as Actions from '@mm-redux/actions/files'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; -const FormData = require('form-data'); - describe('Actions.Files', () => { let store; beforeAll(async () => { @@ -26,52 +23,6 @@ describe('Actions.Files', () => { await TestHelper.tearDown(); }); - it('getFilesForPost', async () => { - const {basicClient4, basicChannel} = TestHelper; - const testFileName = 'test.png'; - const testImageData = fs.createReadStream(`test/assets/images/${testFileName}`); - const clientId = TestHelper.generateId(); - - const imageFormData = new FormData(); - imageFormData.append('files', testImageData); - imageFormData.append('channel_id', basicChannel.id); - imageFormData.append('client_ids', clientId); - const formBoundary = imageFormData.getBoundary(); - - nock(Client4.getBaseRoute()). - post('/files'). - reply(201, {file_infos: [{id: TestHelper.generateId(), user_id: TestHelper.basicUser.id, create_at: 1507921547541, update_at: 1507921547541, delete_at: 0, name: 'test.png', extension: 'png', size: 258428, mime_type: 'image/png', width: 600, height: 600, has_preview_image: true}], client_ids: [TestHelper.generateId()]}); - - const fileUploadResp = await basicClient4. - uploadFile(imageFormData, formBoundary); - const fileId = fileUploadResp.file_infos[0].id; - - const fakePostForFile = TestHelper.fakePost(basicChannel.id); - fakePostForFile.file_ids = [fileId]; - - nock(Client4.getBaseRoute()). - post('/posts'). - reply(201, {...TestHelper.fakePostWithId(), ...fakePostForFile}); - const postForFile = await basicClient4.createPost(fakePostForFile); - - nock(Client4.getBaseRoute()). - get(`/posts/${postForFile.id}/files/info`). - reply(200, [{id: fileId, user_id: TestHelper.basicUser.id, create_at: 1507921547541, update_at: 1507921547541, delete_at: 0, name: 'test.png', extension: 'png', size: 258428, mime_type: 'image/png', width: 600, height: 600, has_preview_image: true}]); - - await Actions.getFilesForPost(postForFile.id)(store.dispatch, store.getState); - - const {files: allFiles, fileIdsByPostId} = store.getState().entities.files; - - assert.ok(allFiles); - assert.ok(allFiles[fileId]); - assert.equal(allFiles[fileId].id, fileId); - assert.equal(allFiles[fileId].name, testFileName); - - assert.ok(fileIdsByPostId); - assert.ok(fileIdsByPostId[postForFile.id]); - assert.equal(fileIdsByPostId[postForFile.id][0], fileId); - }); - it('getFilePublicLink', async () => { const fileId = 't1izsr9uspgi3ynggqu6xxjn9y'; nock(Client4.getBaseRoute()). diff --git a/app/mm-redux/actions/files.ts b/app/mm-redux/actions/files.ts index a4b911d9f..14d2d12f5 100644 --- a/app/mm-redux/actions/files.ts +++ b/app/mm-redux/actions/files.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {FileTypes} from '@mm-redux/action_types'; import {DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions'; diff --git a/app/mm-redux/actions/general.test.js b/app/mm-redux/actions/general.test.js index 8aab12cb2..56d2b0188 100644 --- a/app/mm-redux/actions/general.test.js +++ b/app/mm-redux/actions/general.test.js @@ -7,7 +7,7 @@ import nock from 'nock'; import {FormattedError} from './helpers.ts'; import {GeneralTypes} from '@mm-redux/action_types'; import * as Actions from '@mm-redux/actions/general'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; diff --git a/app/mm-redux/actions/general.ts b/app/mm-redux/actions/general.ts index 96b3744f9..c432ea4af 100644 --- a/app/mm-redux/actions/general.ts +++ b/app/mm-redux/actions/general.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {GeneralTypes} from '@mm-redux/action_types'; diff --git a/app/mm-redux/actions/helpers.test.js b/app/mm-redux/actions/helpers.test.js index 9832c6b60..bc978a60a 100644 --- a/app/mm-redux/actions/helpers.test.js +++ b/app/mm-redux/actions/helpers.test.js @@ -4,8 +4,8 @@ import assert from 'assert'; import {forceLogoutIfNecessary} from '@mm-redux/actions/helpers'; -import {Client4} from '@mm-redux/client'; -import {ClientError} from '@mm-redux/client/client4'; +import {Client4} from '@client/rest'; +import ClientError from '@client/rest/error'; import configureStore, {mockDispatch} from 'test/test_store'; describe('Actions.Helpers', () => { diff --git a/app/mm-redux/actions/helpers.ts b/app/mm-redux/actions/helpers.ts index 2f173907b..514623122 100644 --- a/app/mm-redux/actions/helpers.ts +++ b/app/mm-redux/actions/helpers.ts @@ -3,7 +3,7 @@ import {logout} from '@actions/views/user'; import {UserTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Client4Error} from '@mm-redux/types/client4'; import {getCurrentUserId, getUsers} from '@mm-redux/selectors/entities/users'; import {batchActions, Action, ActionFunc, GenericAction, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; diff --git a/app/mm-redux/actions/index.ts b/app/mm-redux/actions/index.ts index 178979b75..abbb464a2 100644 --- a/app/mm-redux/actions/index.ts +++ b/app/mm-redux/actions/index.ts @@ -10,11 +10,9 @@ import * as general from './general'; import * as gifs from './gifs'; import * as helpers from './helpers'; import * as integrations from './integrations'; -import * as jobs from './jobs'; import * as posts from './posts'; import * as preferences from './preferences'; import * as roles from './roles'; -import * as schemes from './schemes'; import * as search from './search'; import * as teams from './teams'; import * as timezone from './timezone'; @@ -30,11 +28,9 @@ export { gifs, integrations, helpers, - jobs, posts, preferences, roles, - schemes, search, teams, timezone, diff --git a/app/mm-redux/actions/integrations.test.js b/app/mm-redux/actions/integrations.test.js index 1595bb2d3..f5a092049 100644 --- a/app/mm-redux/actions/integrations.test.js +++ b/app/mm-redux/actions/integrations.test.js @@ -6,13 +6,11 @@ import nock from 'nock'; import * as Actions from '@mm-redux/actions/integrations'; import * as TeamsActions from '@mm-redux/actions/teams'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; -const OK_RESPONSE = {status: 'OK'}; - describe('Actions.Integrations', () => { let store; beforeAll(async () => { @@ -27,294 +25,6 @@ describe('Actions.Integrations', () => { await TestHelper.tearDown(); }); - it('createIncomingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, TestHelper.testIncomingHook()); - - const {data: created} = await Actions.createIncomingHook( - { - channel_id: TestHelper.basicChannel.id, - display_name: 'test', - description: 'test', - }, - )(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.incomingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('getIncomingWebhook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, TestHelper.testIncomingHook()); - - const {data: created} = await Actions.createIncomingHook( - { - channel_id: TestHelper.basicChannel.id, - display_name: 'test', - description: 'test', - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get(`/hooks/incoming/${created.id}`). - reply(200, created); - - await Actions.getIncomingHook(created.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.incomingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('getIncomingWebhooks', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, TestHelper.testIncomingHook()); - - const {data: created} = await Actions.createIncomingHook( - { - channel_id: TestHelper.basicChannel.id, - display_name: 'test', - description: 'test', - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/hooks/incoming'). - query(true). - reply(200, [created]); - - await Actions.getIncomingHooks(TestHelper.basicTeam.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.incomingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('removeIncomingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, TestHelper.testIncomingHook()); - - const {data: created} = await Actions.createIncomingHook( - { - channel_id: TestHelper.basicChannel.id, - display_name: 'test', - description: 'test', - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - delete(`/hooks/incoming/${created.id}`). - reply(200, OK_RESPONSE); - - await Actions.removeIncomingHook(created.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.incomingHooks; - assert.ok(!hooks[created.id]); - }); - - it('updateIncomingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/incoming'). - reply(201, TestHelper.testIncomingHook()); - - const {data: created} = await Actions.createIncomingHook( - { - channel_id: TestHelper.basicChannel.id, - display_name: 'test', - description: 'test', - }, - )(store.dispatch, store.getState); - - const updated = {...created}; - updated.display_name = 'test2'; - - nock(Client4.getBaseRoute()). - put(`/hooks/incoming/${created.id}`). - reply(200, updated); - await Actions.updateIncomingHook(updated)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.incomingHooks; - assert.ok(hooks[created.id]); - assert.ok(hooks[created.id].display_name === updated.display_name); - }); - - it('createOutgoingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('getOutgoingWebhook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get(`/hooks/outgoing/${created.id}`). - reply(200, TestHelper.testOutgoingHook()); - - await Actions.getOutgoingHook(created.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('getOutgoingWebhooks', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/hooks/outgoing'). - query(true). - reply(200, [TestHelper.testOutgoingHook()]); - - await Actions.getOutgoingHooks(TestHelper.basicChannel.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(hooks); - assert.ok(hooks[created.id]); - }); - - it('removeOutgoingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - delete(`/hooks/outgoing/${created.id}`). - reply(200, OK_RESPONSE); - - await Actions.removeOutgoingHook(created.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(!hooks[created.id]); - }); - - it('updateOutgoingHook', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - const updated = {...created}; - updated.display_name = 'test2'; - nock(Client4.getBaseRoute()). - put(`/hooks/outgoing/${created.id}`). - reply(200, updated); - await Actions.updateOutgoingHook(updated)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(hooks[created.id]); - assert.ok(hooks[created.id].display_name === updated.display_name); - }); - - it('regenOutgoingHookToken', async () => { - nock(Client4.getBaseRoute()). - post('/hooks/outgoing'). - reply(201, TestHelper.testOutgoingHook()); - - const {data: created} = await Actions.createOutgoingHook( - { - channel_id: TestHelper.basicChannel.id, - team_id: TestHelper.basicTeam.id, - display_name: 'test', - trigger_words: [TestHelper.generateId()], - callback_urls: ['http://localhost/notarealendpoint'], - }, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - post(`/hooks/outgoing/${created.id}/regen_token`). - reply(200, {...created, token: TestHelper.generateId()}); - await Actions.regenOutgoingHookToken(created.id)(store.dispatch, store.getState); - - const state = store.getState(); - - const hooks = state.entities.integrations.outgoingHooks; - assert.ok(hooks[created.id]); - assert.ok(hooks[created.id].token !== created.token); - }); - it('getCommands', async () => { const noTeamCommands = store.getState().entities.integrations.commands; const noSystemCommands = store.getState().entities.integrations.systemCommands; @@ -393,54 +103,6 @@ describe('Actions.Integrations', () => { assert.equal(Object.keys({...teamCommands, ...systemCommands}).length, 2); }); - it('getCustomTeamCommands', async () => { - nock(Client4.getBaseRoute()). - post('/teams'). - reply(201, TestHelper.fakeTeamWithId()); - - const {data: team} = await TeamsActions.createTeam( - TestHelper.fakeTeam(), - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/commands'). - query(true). - reply(200, []); - - await Actions.getCustomTeamCommands( - team.id, - )(store.dispatch, store.getState); - - const noCommands = store.getState().entities.integrations.commands; - assert.equal(Object.keys(noCommands).length, 0); - - const command = TestHelper.testCommand(team.id); - - nock(Client4.getBaseRoute()). - post('/commands'). - reply(201, {...command, token: TestHelper.generateId(), id: TestHelper.generateId()}); - - const {data: created} = await Actions.addCommand( - command, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/commands'). - query(true). - reply(200, []); - - await Actions.getCustomTeamCommands( - team.id, - )(store.dispatch, store.getState); - - const {commands} = store.getState().entities.integrations; - assert.ok(commands[created.id]); - assert.equal(Object.keys(commands).length, 1); - const actual = commands[created.id]; - const expected = created; - assert.equal(JSON.stringify(actual), JSON.stringify(expected)); - }); - it('executeCommand', async () => { nock(Client4.getBaseRoute()). post('/teams'). @@ -500,259 +162,6 @@ describe('Actions.Integrations', () => { assert.equal(actual.url, expected.url); }); - it('regenCommandToken', async () => { - nock(Client4.getBaseRoute()). - post('/teams'). - reply(201, TestHelper.fakeTeamWithId()); - - const {data: team} = await TeamsActions.createTeam( - TestHelper.fakeTeam(), - )(store.dispatch, store.getState); - - const command = TestHelper.testCommand(team.id); - - nock(Client4.getBaseRoute()). - post('/commands'). - reply(201, {...command, token: TestHelper.generateId(), id: TestHelper.generateId()}); - - const {data: created} = await Actions.addCommand( - command, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - put(`/commands/${created.id}/regen_token`). - reply(200, {...created, token: TestHelper.generateId()}); - - await Actions.regenCommandToken( - created.id, - )(store.dispatch, store.getState); - - const {commands} = store.getState().entities.integrations; - assert.ok(commands[created.id]); - const updated = commands[created.id]; - - assert.equal(updated.id, created.id); - assert.notEqual(updated.token, created.token); - assert.equal(updated.create_at, created.create_at); - assert.equal(updated.update_at, created.update_at); - assert.equal(updated.delete_at, created.delete_at); - assert.equal(updated.creator_id, created.creator_id); - assert.equal(updated.team_id, created.team_id); - assert.equal(updated.trigger, created.trigger); - assert.equal(updated.method, created.method); - assert.equal(updated.username, created.username); - assert.equal(updated.icon_url, created.icon_url); - assert.equal(updated.auto_complete, created.auto_complete); - assert.equal(updated.auto_complete_desc, created.auto_complete_desc); - assert.equal(updated.auto_complete_hint, created.auto_complete_hint); - assert.equal(updated.display_name, created.display_name); - assert.equal(updated.description, created.description); - assert.equal(updated.url, created.url); - }); - - it('editCommand', async () => { - nock(Client4.getBaseRoute()). - post('/teams'). - reply(201, TestHelper.fakeTeamWithId()); - - const {data: team} = await TeamsActions.createTeam( - TestHelper.fakeTeam(), - )(store.dispatch, store.getState); - - const command = TestHelper.testCommand(team.id); - - nock(Client4.getBaseRoute()). - post('/commands'). - reply(201, {...command, token: TestHelper.generateId(), id: TestHelper.generateId()}); - - const {data: created} = await Actions.addCommand( - command, - )(store.dispatch, store.getState); - - const expected = Object.assign({}, created); - expected.trigger = 'modified'; - expected.method = 'G'; - expected.username = 'modified'; - expected.auto_complete = false; - - nock(Client4.getBaseRoute()). - put(`/commands/${expected.id}`). - reply(200, {...expected, update_at: 123}); - - await Actions.editCommand( - expected, - )(store.dispatch, store.getState); - - const {commands} = store.getState().entities.integrations; - assert.ok(commands[created.id]); - const actual = commands[created.id]; - - assert.notEqual(actual.update_at, expected.update_at); - expected.update_at = actual.update_at; - assert.equal(JSON.stringify(actual), JSON.stringify(expected)); - }); - - it('deleteCommand', async () => { - nock(Client4.getBaseRoute()). - post('/teams'). - reply(201, TestHelper.fakeTeamWithId()); - - const {data: team} = await TeamsActions.createTeam( - TestHelper.fakeTeam(), - )(store.dispatch, store.getState); - - const command = TestHelper.testCommand(team.id); - - nock(Client4.getBaseRoute()). - post('/commands'). - reply(201, {...command, token: TestHelper.generateId(), id: TestHelper.generateId()}); - - const {data: created} = await Actions.addCommand( - command, - )(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - delete(`/commands/${created.id}`). - reply(200, OK_RESPONSE); - - await Actions.deleteCommand( - created.id, - )(store.dispatch, store.getState); - - const {commands} = store.getState().entities.integrations; - assert.ok(!commands[created.id]); - }); - - it('addOAuthApp', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps[created.id]); - }); - - it('getOAuthApp', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get(`/oauth/apps/${created.id}`). - reply(200, created); - - await Actions.getOAuthApp(created.id)(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps[created.id]); - }); - - it('editOAuthApp', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - const expected = Object.assign({}, created); - expected.name = 'modified'; - expected.description = 'modified'; - expected.homepage = 'https://modified.com'; - expected.icon_url = 'https://modified.com/icon'; - expected.callback_urls = ['https://modified.com/callback1', 'https://modified.com/callback2']; - expected.is_trusted = true; - - const nockReply = Object.assign({}, expected); - nockReply.update_at += 1; - nock(Client4.getBaseRoute()). - put(`/oauth/apps/${created.id}`).reply(200, nockReply); - - await Actions.editOAuthApp(expected)(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps[created.id]); - - const actual = oauthApps[created.id]; - - assert.notEqual(actual.update_at, expected.update_at); - expected.update_at = actual.update_at; - assert.equal(JSON.stringify(actual), JSON.stringify(expected)); - }); - - it('getOAuthApps', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/oauth/apps'). - query(true). - reply(200, [created]); - - await Actions.getOAuthApps()(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps); - }); - - it('getAuthorizedOAuthApps', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - const user = TestHelper.basicUser; - nock(Client4.getBaseRoute()). - get(`/users/${user.id}/oauth/apps/authorized`). - reply(200, [created]); - - await Actions.getAuthorizedOAuthApps()(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps); - }); - - it('deleteOAuthApp', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - delete(`/oauth/apps/${created.id}`). - reply(200, OK_RESPONSE); - - await Actions.deleteOAuthApp(created.id)(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(!oauthApps[created.id]); - }); - - it('regenOAuthAppSecret', async () => { - nock(Client4.getBaseRoute()). - post('/oauth/apps'). - reply(201, TestHelper.fakeOAuthAppWithId()); - - const {data: created} = await Actions.addOAuthApp(TestHelper.fakeOAuthApp())(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - post(`/oauth/apps/${created.id}/regen_secret`). - reply(200, {...created, client_secret: TestHelper.generateId()}); - - await Actions.regenOAuthAppSecret(created.id)(store.dispatch, store.getState); - - const {oauthApps} = store.getState().entities.integrations; - assert.ok(oauthApps[created.id].client_secret !== created.client_secret); - }); - it('submitInteractiveDialog', async () => { nock(Client4.getBaseRoute()). post('/actions/dialogs/submit'). diff --git a/app/mm-redux/actions/integrations.ts b/app/mm-redux/actions/integrations.ts index ffecfdcc8..cb6ddabd9 100644 --- a/app/mm-redux/actions/integrations.ts +++ b/app/mm-redux/actions/integrations.ts @@ -5,15 +5,14 @@ import {Alert} from 'react-native'; import {IntegrationTypes} from '@mm-redux/action_types'; import {General} from '../constants'; -import {Client4} from '@mm-redux/client'; -import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; +import {Client4} from '@client/rest'; import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; import {analytics} from '@init/analytics'; import {batchActions, DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions'; -import {Command, CommandArgs, DialogSubmission, IncomingWebhook, OAuthApp, OutgoingWebhook} from '@mm-redux/types/integrations'; +import {Command, CommandArgs, DialogSubmission} from '@mm-redux/types/integrations'; import {logError} from './errors'; import {bindClientFunc, forceLogoutIfNecessary, requestSuccess, requestFailure} from './helpers'; @@ -28,145 +27,6 @@ import * as DraftUtils from '@utils/draft'; import {permalinkBadTeam} from '@utils/general'; import {getURLAndMatch, tryOpenURL} from '@utils/url'; -export function createIncomingHook(hook: IncomingWebhook): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createIncomingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_INCOMING_HOOK], - params: [ - hook, - ], - }); -} - -export function getIncomingHook(hookId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getIncomingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_INCOMING_HOOK], - params: [ - hookId, - ], - }); -} - -export function getIncomingHooks(teamId = '', page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getIncomingWebhooks, - onSuccess: [IntegrationTypes.RECEIVED_INCOMING_HOOKS], - params: [ - teamId, - page, - perPage, - ], - }); -} - -export function removeIncomingHook(hookId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.removeIncomingWebhook(hookId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - { - type: IntegrationTypes.DELETED_INCOMING_HOOK, - data: {id: hookId}, - }, - ])); - - return {data: true}; - }; -} - -export function updateIncomingHook(hook: IncomingWebhook): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.updateIncomingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_INCOMING_HOOK], - params: [ - hook, - ], - }); -} - -export function createOutgoingHook(hook: OutgoingWebhook): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createOutgoingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_OUTGOING_HOOK], - params: [ - hook, - ], - }); -} - -export function getOutgoingHook(hookId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getOutgoingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_OUTGOING_HOOK], - params: [ - hookId, - ], - }); -} - -export function getOutgoingHooks(channelId = '', teamId = '', page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getOutgoingWebhooks, - onSuccess: [IntegrationTypes.RECEIVED_OUTGOING_HOOKS], - params: [ - channelId, - teamId, - page, - perPage, - ], - }); -} - -export function removeOutgoingHook(hookId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.removeOutgoingWebhook(hookId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - { - type: IntegrationTypes.DELETED_OUTGOING_HOOK, - data: {id: hookId}, - }, - ])); - - return {data: true}; - }; -} - -export function updateOutgoingHook(hook: OutgoingWebhook): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.updateOutgoingWebhook, - onSuccess: [IntegrationTypes.RECEIVED_OUTGOING_HOOK], - params: [ - hook, - ], - }); -} - -export function regenOutgoingHookToken(hookId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.regenOutgoingHookToken, - onSuccess: [IntegrationTypes.RECEIVED_OUTGOING_HOOK], - params: [ - hookId, - ], - }); -} - export function getCommands(teamId: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.getCommandsList, @@ -206,16 +66,6 @@ export function getCommandAutocompleteSuggestions(userInput: string, teamId: str }; } -export function getCustomTeamCommands(teamId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getCustomTeamCommands, - onSuccess: [IntegrationTypes.RECEIVED_CUSTOM_TEAM_COMMANDS], - params: [ - teamId, - ], - }); -} - export function addCommand(command: Command): ActionFunc { return bindClientFunc({ clientFunc: Client4.addCommand, @@ -226,16 +76,6 @@ export function addCommand(command: Command): ActionFunc { }); } -export function editCommand(command: Command): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.editCommand, - onSuccess: [IntegrationTypes.RECEIVED_COMMAND], - params: [ - command, - ], - }); -} - export function executeCommand(command: string, args: CommandArgs): ActionFunc { return bindClientFunc({ clientFunc: Client4.executeCommand, @@ -246,154 +86,6 @@ export function executeCommand(command: string, args: CommandArgs): ActionFunc { }); } -export function regenCommandToken(id: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let res; - try { - res = await Client4.regenCommandToken(id); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - { - type: IntegrationTypes.RECEIVED_COMMAND_TOKEN, - data: { - id, - token: res.token, - }, - }, - ])); - - return {data: true}; - }; -} - -export function deleteCommand(id: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.deleteCommand(id); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - { - type: IntegrationTypes.DELETED_COMMAND, - data: {id}, - }, - ])); - - return {data: true}; - }; -} - -export function addOAuthApp(app: OAuthApp): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createOAuthApp, - onSuccess: [IntegrationTypes.RECEIVED_OAUTH_APP], - params: [ - app, - ], - }); -} - -export function editOAuthApp(app: OAuthApp): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.editOAuthApp, - onSuccess: IntegrationTypes.RECEIVED_OAUTH_APP, - params: [ - app, - ], - }); -} - -export function getOAuthApps(page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getOAuthApps, - onSuccess: [IntegrationTypes.RECEIVED_OAUTH_APPS], - params: [ - page, - perPage, - ], - }); -} - -export function getOAuthApp(appId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getOAuthApp, - onSuccess: [IntegrationTypes.RECEIVED_OAUTH_APP], - params: [ - appId, - ], - }); -} - -export function getAuthorizedOAuthApps(): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - const state = getState(); - const currentUserId = getCurrentUserId(state); - - let data; - try { - data = await Client4.getAuthorizedOAuthApps(currentUserId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - - return {error}; - } - - return {data}; - }; -} - -export function deauthorizeOAuthApp(clientId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.deauthorizeOAuthApp, - params: [clientId], - }); -} - -export function deleteOAuthApp(id: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.deleteOAuthApp(id); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - { - type: IntegrationTypes.DELETED_OAUTH_APP, - data: {id}, - }, - ])); - - return {data: true}; - }; -} - -export function regenOAuthAppSecret(appId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.regenOAuthAppSecret, - onSuccess: [IntegrationTypes.RECEIVED_OAUTH_APP], - params: [ - appId, - ], - }); -} - export function submitInteractiveDialog(submission: DialogSubmission): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); diff --git a/app/mm-redux/actions/jobs.test.js b/app/mm-redux/actions/jobs.test.js deleted file mode 100644 index 3bdd6c712..000000000 --- a/app/mm-redux/actions/jobs.test.js +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import assert from 'assert'; -import nock from 'nock'; - -import * as Actions from '@mm-redux/actions/jobs'; -import {Client4} from '@mm-redux/client'; - -import {RequestStatus} from '../constants'; -import TestHelper from 'test/test_helper'; -import configureStore from 'test/test_store'; - -const OK_RESPONSE = {status: 'OK'}; - -describe('Actions.Jobs', () => { - let store; - beforeAll(async () => { - await TestHelper.initBasic(Client4); - }); - - beforeEach(async () => { - store = await configureStore(); - }); - - afterAll(async () => { - await TestHelper.tearDown(); - }); - - it('createJob', async () => { - const job = { - type: 'data_retention', - }; - - nock(Client4.getBaseRoute()). - post('/jobs'). - reply(201, { - id: 'six4h67ja7ntdkek6g13dp3wka', - create_at: 1491399241953, - type: 'data_retention', - status: 'pending', - data: {}, - }); - - await Actions.createJob(job)(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.jobs.createJob; - if (request.status === RequestStatus.FAILURE) { - throw new Error('createJob request failed'); - } - - const jobs = state.entities.jobs.jobs; - assert.ok(jobs.six4h67ja7ntdkek6g13dp3wka); - }); - - it('getJob', async () => { - nock(Client4.getBaseRoute()). - get('/jobs/six4h67ja7ntdkek6g13dp3wka'). - reply(200, { - id: 'six4h67ja7ntdkek6g13dp3wka', - create_at: 1491399241953, - type: 'data_retention', - status: 'pending', - data: {}, - }); - - await Actions.getJob('six4h67ja7ntdkek6g13dp3wka')(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.jobs.getJob; - if (request.status === RequestStatus.FAILURE) { - throw new Error('getJob request failed'); - } - - const jobs = state.entities.jobs.jobs; - assert.ok(jobs.six4h67ja7ntdkek6g13dp3wka); - }); - - it('cancelJob', async () => { - nock(Client4.getBaseRoute()). - post('/jobs/six4h67ja7ntdkek6g13dp3wka/cancel'). - reply(200, OK_RESPONSE); - - await Actions.cancelJob('six4h67ja7ntdkek6g13dp3wka')(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.jobs.cancelJob; - if (request.status === RequestStatus.FAILURE) { - throw new Error('cancelJob request failed'); - } - }); - - it('getJobs', async () => { - nock(Client4.getBaseRoute()). - get('/jobs'). - query(true). - reply(200, [{ - id: 'six4h67ja7ntdkek6g13dp3wka', - create_at: 1491399241953, - type: 'data_retention', - status: 'pending', - data: {}, - }]); - - await Actions.getJobs()(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.jobs.getJobs; - if (request.status === RequestStatus.FAILURE) { - throw new Error('getJobs request failed'); - } - - const jobs = state.entities.jobs.jobs; - assert.ok(jobs.six4h67ja7ntdkek6g13dp3wka); - }); - - it('getJobsByType', async () => { - nock(Client4.getBaseRoute()). - get('/jobs/type/data_retention'). - query(true). - reply(200, [{ - id: 'six4h67ja7ntdkek6g13dp3wka', - create_at: 1491399241953, - type: 'data_retention', - status: 'pending', - data: {}, - }]); - - await Actions.getJobsByType('data_retention')(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.jobs.getJobs; - if (request.status === RequestStatus.FAILURE) { - throw new Error('getJobsByType request failed'); - } - - const jobs = state.entities.jobs.jobs; - assert.ok(jobs.six4h67ja7ntdkek6g13dp3wka); - - const jobsByType = state.entities.jobs.jobsByTypeList; - assert.ok(jobsByType.data_retention); - assert.ok(jobsByType.data_retention.length === 1); - }); -}); diff --git a/app/mm-redux/actions/jobs.ts b/app/mm-redux/actions/jobs.ts deleted file mode 100644 index 15823b779..000000000 --- a/app/mm-redux/actions/jobs.ts +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {JobTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; -import {General} from '../constants'; - -import {ActionFunc} from '@mm-redux/types/actions'; -import {JobType, Job} from '@mm-redux/types/jobs'; - -import {bindClientFunc} from './helpers'; -export function createJob(job: Job): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createJob, - onRequest: JobTypes.CREATE_JOB_REQUEST, - onSuccess: [JobTypes.RECEIVED_JOB, JobTypes.CREATE_JOB_SUCCESS], - onFailure: JobTypes.CREATE_JOB_FAILURE, - params: [ - job, - ], - }); -} - -export function getJob(id: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getJob, - onRequest: JobTypes.GET_JOB_REQUEST, - onSuccess: [JobTypes.RECEIVED_JOB, JobTypes.GET_JOB_SUCCESS], - onFailure: JobTypes.GET_JOB_FAILURE, - params: [ - id, - ], - }); -} - -export function getJobs(page = 0, perPage: number = General.JOBS_CHUNK_SIZE): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getJobs, - onRequest: JobTypes.GET_JOBS_REQUEST, - onSuccess: [JobTypes.RECEIVED_JOBS, JobTypes.GET_JOBS_SUCCESS], - onFailure: JobTypes.GET_JOBS_FAILURE, - params: [ - page, - perPage, - ], - }); -} - -export function getJobsByType(type: JobType, page = 0, perPage: number = General.JOBS_CHUNK_SIZE): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getJobsByType, - onRequest: JobTypes.GET_JOBS_REQUEST, - onSuccess: [JobTypes.RECEIVED_JOBS, JobTypes.RECEIVED_JOBS_BY_TYPE, JobTypes.GET_JOBS_SUCCESS], - onFailure: JobTypes.GET_JOBS_FAILURE, - params: [ - type, - page, - perPage, - ], - }); -} - -export function cancelJob(job: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.cancelJob, - onRequest: JobTypes.CANCEL_JOB_REQUEST, - onSuccess: JobTypes.CANCEL_JOB_SUCCESS, - onFailure: JobTypes.CANCEL_JOB_FAILURE, - params: [ - job, - ], - }); -} diff --git a/app/mm-redux/actions/posts.test.js b/app/mm-redux/actions/posts.test.js index f1b2c263a..426f33a92 100644 --- a/app/mm-redux/actions/posts.test.js +++ b/app/mm-redux/actions/posts.test.js @@ -9,7 +9,7 @@ import * as Actions from '@mm-redux/actions/posts'; import {getChannelStats} from '@mm-redux/actions/channels'; import {login} from '@mm-redux/actions/users'; import {createCustomEmoji} from '@mm-redux/actions/emojis'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Preferences, Posts, RequestStatus} from '../constants'; import {ChannelTypes, PostTypes} from '@mm-redux/action_types'; import TestHelper from 'test/test_helper'; @@ -343,31 +343,6 @@ describe('Actions.Posts', () => { assert.ok(!reactions[post1.id]); }); - it('getPostsUnread', async () => { - const {dispatch, getState} = store; - const channelId = TestHelper.basicChannel.id; - const post = TestHelper.fakePostWithId(channelId); - const userId = getState().entities.users.currentUserId; - const response = { - posts: { - [post.id]: post, - }, - order: [post.id], - next_post_id: '', - prev_post_id: '', - }; - - nock(Client4.getUsersRoute()). - get(`/${userId}/channels/${channelId}/posts/unread`). - query(true). - reply(200, response); - - await Actions.getPostsUnread(channelId)(dispatch, getState); - const {posts} = getState().entities.posts; - - assert.ok(posts[post.id]); - }); - it('getPostThread', async () => { const channelId = TestHelper.basicChannel.id; const post = {id: TestHelper.generateId(), channel_id: channelId, message: ''}; diff --git a/app/mm-redux/actions/posts.ts b/app/mm-redux/actions/posts.ts index c1be1623d..c162ae561 100644 --- a/app/mm-redux/actions/posts.ts +++ b/app/mm-redux/actions/posts.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General, Preferences, Posts} from '@mm-redux/constants'; import {WebsocketEvents} from '@constants'; import {PostTypes, ChannelTypes, FileTypes, IntegrationTypes} from '@mm-redux/action_types'; @@ -728,33 +728,6 @@ export function getPosts(channelId: string, page = 0, perPage = Posts.POST_CHUNK }; } -export function getPostsUnread(channelId: string) { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - const userId = getCurrentUserId(getState()); - let posts; - try { - posts = await Client4.getPostsUnread(channelId, userId); - getProfilesAndStatusesForPosts(posts.posts, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch(batchActions([ - receivedPosts(posts), - receivedPostsInChannel(posts, channelId, posts.next_post_id === '', posts.prev_post_id === ''), - ])); - dispatch({ - type: PostTypes.RECEIVED_POSTS, - data: posts, - channelId, - }); - - return {data: posts}; - }; -} - export function getPostsSince(channelId: string, since: number) { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let posts; diff --git a/app/mm-redux/actions/preferences.test.js b/app/mm-redux/actions/preferences.test.js index 5e5c92f19..cee88fd8e 100644 --- a/app/mm-redux/actions/preferences.test.js +++ b/app/mm-redux/actions/preferences.test.js @@ -6,7 +6,7 @@ import nock from 'nock'; import * as Actions from '@mm-redux/actions/preferences'; import {login} from '@mm-redux/actions/users'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Preferences} from '../constants'; import TestHelper from 'test/test_helper'; diff --git a/app/mm-redux/actions/preferences.ts b/app/mm-redux/actions/preferences.ts index b494e480a..464d9485b 100644 --- a/app/mm-redux/actions/preferences.ts +++ b/app/mm-redux/actions/preferences.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Preferences} from '../constants'; import {PreferenceTypes} from '@mm-redux/action_types'; import {getMyPreferences as getMyPreferencesSelector, makeGetCategory} from '@mm-redux/selectors/entities/preferences'; diff --git a/app/mm-redux/actions/roles.test.js b/app/mm-redux/actions/roles.test.js index 5c9e7a2fc..9d1f2ac0a 100644 --- a/app/mm-redux/actions/roles.test.js +++ b/app/mm-redux/actions/roles.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import nock from 'nock'; import * as Actions from '@mm-redux/actions/roles'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {RequestStatus} from '../constants'; import TestHelper from 'test/test_helper'; @@ -44,43 +44,6 @@ describe('Actions.Roles', () => { assert.deepEqual(roles.system_admin.permissions, TestHelper.basicRoles.system_admin.permissions); }); - it('getRoleByName', async () => { - nock(Client4.getRolesRoute()). - get('/name/system_admin'). - reply(200, TestHelper.basicRoles.system_admin); - await Actions.getRoleByName('system_admin')(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.roles.getRolesByNames; - const {roles} = state.entities.roles; - - if (request.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(request.error)); - } - - assert.equal(roles.system_admin.name, 'system_admin'); - assert.deepEqual(roles.system_admin.permissions, TestHelper.basicRoles.system_admin.permissions); - }); - - it('getRole', async () => { - nock(Client4.getRolesRoute()). - get('/' + TestHelper.basicRoles.system_admin.id). - reply(200, TestHelper.basicRoles.system_admin); - - await Actions.getRole(TestHelper.basicRoles.system_admin.id)(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.roles.getRole; - const {roles} = state.entities.roles; - - if (request.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(request.error)); - } - - assert.equal(roles.system_admin.name, 'system_admin'); - assert.deepEqual(roles.system_admin.permissions, TestHelper.basicRoles.system_admin.permissions); - }); - it('loadRolesIfNeeded', async () => { const mock1 = nock(Client4.getRolesRoute()). post('/names', JSON.stringify(['existing_role'])). @@ -106,14 +69,4 @@ describe('Actions.Roles', () => { assert(!mock1.isDone()); assert(mock2.isDone()); }); - - it('editRole', async () => { - const roleId = TestHelper.basicRoles.system_admin.id; - const mock = nock(Client4.getRolesRoute()). - put('/' + roleId + '/patch', JSON.stringify({id: roleId, test: 'test'})). - reply(200, {}); - - await Actions.editRole({id: roleId, test: 'test'})(store.dispatch, store.state); - assert(mock.isDone()); - }); }); diff --git a/app/mm-redux/actions/roles.ts b/app/mm-redux/actions/roles.ts index 5cd29dfae..75a8d5fda 100644 --- a/app/mm-redux/actions/roles.ts +++ b/app/mm-redux/actions/roles.ts @@ -1,62 +1,22 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {RoleTypes} from '@mm-redux/action_types'; import {getRoles} from '@mm-redux/selectors/entities/roles_helpers'; import {DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions'; -import {Role} from '@mm-redux/types/roles'; import {bindClientFunc} from './helpers'; export function getRolesByNames(rolesNames: Array) { return bindClientFunc({ clientFunc: Client4.getRolesByNames, - onRequest: RoleTypes.ROLES_BY_NAMES_REQUEST, onSuccess: [RoleTypes.RECEIVED_ROLES, RoleTypes.ROLES_BY_NAMES_SUCCESS], - onFailure: RoleTypes.ROLES_BY_NAMES_FAILURE, params: [ rolesNames, ], }); } -export function getRoleByName(roleName: string) { - return bindClientFunc({ - clientFunc: Client4.getRoleByName, - onRequest: RoleTypes.ROLE_BY_NAME_REQUEST, - onSuccess: [RoleTypes.RECEIVED_ROLE, RoleTypes.ROLE_BY_NAME_SUCCESS], - onFailure: RoleTypes.ROLE_BY_NAME_FAILURE, - params: [ - roleName, - ], - }); -} - -export function getRole(roleId: string) { - return bindClientFunc({ - clientFunc: Client4.getRole, - onRequest: RoleTypes.ROLE_BY_ID_REQUEST, - onSuccess: [RoleTypes.RECEIVED_ROLE, RoleTypes.ROLE_BY_ID_SUCCESS], - onFailure: RoleTypes.ROLE_BY_ID_FAILURE, - params: [ - roleId, - ], - }); -} - -export function editRole(role: Role) { - return bindClientFunc({ - clientFunc: Client4.patchRole, - onRequest: RoleTypes.EDIT_ROLE_REQUEST, - onSuccess: [RoleTypes.RECEIVED_ROLE, RoleTypes.EDIT_ROLE_SUCCESS], - onFailure: RoleTypes.EDIT_ROLE_FAILURE, - params: [ - role.id, - role, - ], - }); -} - export function loadRolesIfNeeded(roles: Iterable): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); diff --git a/app/mm-redux/actions/schemes.test.js b/app/mm-redux/actions/schemes.test.js deleted file mode 100644 index e37e018c0..000000000 --- a/app/mm-redux/actions/schemes.test.js +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import assert from 'assert'; -import nock from 'nock'; - -import * as Actions from '@mm-redux/actions/schemes'; -import {Client4} from '@mm-redux/client'; - -import TestHelper from 'test/test_helper'; -import configureStore from 'test/test_store'; - -describe('Actions.Schemes', () => { - let store; - - beforeAll(async () => { - await TestHelper.initBasic(Client4); - }); - - beforeEach(async () => { - store = await configureStore(); - }); - - afterAll(async () => { - await TestHelper.tearDown(); - }); - - it('getSchemes', async () => { - const mockScheme = TestHelper.basicScheme; - - nock(Client4.getBaseRoute()). - get('/schemes'). - query(true). - reply(200, [mockScheme]); - - await Actions.getSchemes()(store.dispatch, store.getState); - const {schemes} = store.getState().entities.schemes; - - assert.ok(Object.keys(schemes).length > 0); - }); - - it('createScheme', async () => { - const mockScheme = TestHelper.basicScheme; - - nock(Client4.getBaseRoute()). - post('/schemes'). - reply(201, mockScheme); - await Actions.createScheme(TestHelper.mockScheme())(store.dispatch, store.getState); - - const {schemes} = store.getState().entities.schemes; - - const schemeId = Object.keys(schemes)[0]; - assert.strictEqual(Object.keys(schemes).length, 1); - assert.strictEqual(mockScheme.id, schemeId); - }); - - it('getScheme', async () => { - nock(Client4.getBaseRoute()). - get('/schemes/' + TestHelper.basicScheme.id). - reply(200, TestHelper.basicScheme); - - await Actions.getScheme(TestHelper.basicScheme.id)(store.dispatch, store.getState); - - const state = store.getState(); - const {schemes} = state.entities.schemes; - - assert.equal(schemes[TestHelper.basicScheme.id].name, TestHelper.basicScheme.name); - }); - - it('patchScheme', async () => { - const patchData = {name: 'The Updated Scheme', description: 'This is a scheme created by unit tests'}; - const scheme = { - ...TestHelper.basicScheme, - ...patchData, - }; - - nock(Client4.getBaseRoute()). - put('/schemes/' + TestHelper.basicScheme.id + '/patch'). - reply(200, scheme); - - await Actions.patchScheme(TestHelper.basicScheme.id, scheme)(store.dispatch, store.getState); - - const state = store.getState(); - const {schemes} = state.entities.schemes; - - const updated = schemes[TestHelper.basicScheme.id]; - assert.ok(updated); - assert.strictEqual(updated.name, patchData.name); - assert.strictEqual(updated.description, patchData.description); - }); - - it('deleteScheme', async () => { - nock(Client4.getBaseRoute()). - delete('/schemes/' + TestHelper.basicScheme.id). - reply(200, {status: 'OK'}); - - await Actions.deleteScheme(TestHelper.basicScheme.id)(store.dispatch, store.getState); - - const state = store.getState(); - const {schemes} = state.entities.schemes; - - assert.notStrictEqual(schemes, {}); - }); -}); diff --git a/app/mm-redux/actions/schemes.ts b/app/mm-redux/actions/schemes.ts deleted file mode 100644 index 0c06db41f..000000000 --- a/app/mm-redux/actions/schemes.ts +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; -import {SchemeTypes} from '@mm-redux/action_types'; -import {General} from '../constants'; - -import {Scheme, SchemeScope, SchemePatch} from '@mm-redux/types/schemes'; - -import {ActionFunc, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; - -import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; -import {logError} from './errors'; -export function getScheme(schemeId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getScheme, - onSuccess: [SchemeTypes.RECEIVED_SCHEME], - params: [ - schemeId, - ], - }); -} - -export function getSchemes(scope: SchemeScope, page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getSchemes, - onSuccess: [SchemeTypes.RECEIVED_SCHEMES], - params: [ - scope, - page, - perPage, - ], - }); -} - -export function createScheme(scheme: Scheme): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createScheme, - onSuccess: [SchemeTypes.CREATED_SCHEME], - params: [ - scheme, - ], - }); -} - -export function deleteScheme(schemeId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data = null; - try { - data = await Client4.deleteScheme(schemeId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({type: SchemeTypes.DELETED_SCHEME, data: {schemeId}}); - - return {data}; - }; -} - -export function patchScheme(schemeId: string, scheme: SchemePatch): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.patchScheme, - onSuccess: [SchemeTypes.PATCHED_SCHEME], - params: [ - schemeId, - scheme, - ], - }); -} - -export function getSchemeTeams(schemeId: string, page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getSchemeTeams, - onSuccess: [SchemeTypes.RECEIVED_SCHEME_TEAMS], - params: [ - schemeId, - page, - perPage, - ], - }); -} - -export function getSchemeChannels(schemeId: string, page = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getSchemeChannels, - onSuccess: [SchemeTypes.RECEIVED_SCHEME_CHANNELS], - params: [ - schemeId, - page, - perPage, - ], - }); -} diff --git a/app/mm-redux/actions/search.test.js b/app/mm-redux/actions/search.test.js index 5e903f4ee..6598b5a0e 100644 --- a/app/mm-redux/actions/search.test.js +++ b/app/mm-redux/actions/search.test.js @@ -5,7 +5,7 @@ import assert from 'assert'; import nock from 'nock'; import * as Actions from '@mm-redux/actions/search'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; diff --git a/app/mm-redux/actions/search.ts b/app/mm-redux/actions/search.ts index 3208e8104..41f838f4e 100644 --- a/app/mm-redux/actions/search.ts +++ b/app/mm-redux/actions/search.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {SearchTypes} from '@mm-redux/action_types'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; import {getCurrentUserId, getCurrentUserMentionKeys} from '@mm-redux/selectors/entities/users'; diff --git a/app/mm-redux/actions/teams.test.js b/app/mm-redux/actions/teams.test.js index 4f3dad2ff..572103c2e 100644 --- a/app/mm-redux/actions/teams.test.js +++ b/app/mm-redux/actions/teams.test.js @@ -3,12 +3,11 @@ import assert from 'assert'; import nock from 'nock'; -import fs from 'fs'; import * as Actions from '@mm-redux/actions/teams'; import {login} from '@mm-redux/actions/users'; -import {Client4} from '@mm-redux/client'; -import {General, RequestStatus} from '../constants'; +import {Client4} from '@client/rest'; +import {RequestStatus} from '../constants'; import {GeneralTypes} from '@mm-redux/action_types'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; @@ -336,19 +335,6 @@ describe('Actions.Teams', () => { assert.ok(Object.prototype.hasOwnProperty.call(member, 'mention_count')); }); - it('getTeamMembersForUser', async () => { - nock(Client4.getUserRoute(TestHelper.basicUser.id)). - get('/teams/members'). - reply(200, [{user_id: TestHelper.basicUser.id, team_id: TestHelper.basicTeam.id}]); - await Actions.getTeamMembersForUser(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const membersInTeam = store.getState().entities.teams.membersInTeam; - - assert.ok(membersInTeam); - assert.ok(membersInTeam[TestHelper.basicTeam.id]); - assert.ok(membersInTeam[TestHelper.basicTeam.id][TestHelper.basicUser.id]); - }); - it('getTeamMember', async () => { nock(Client4.getBaseRoute()). post('/users'). @@ -406,44 +392,6 @@ describe('Actions.Teams', () => { assert.ok(membersInTeam[TestHelper.basicTeam.id][user2.id]); }); - it('getTeamMembersByIds', async () => { - nock(Client4.getBaseRoute()). - post('/users'). - query(true). - reply(201, TestHelper.fakeUserWithId()); - const user1 = await TestHelper.basicClient4.createUser( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id, - ); - - nock(Client4.getBaseRoute()). - post('/users'). - query(true). - reply(201, TestHelper.fakeUserWithId()); - const user2 = await TestHelper.basicClient4.createUser( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id, - ); - - nock(Client4.getBaseRoute()). - post(`/teams/${TestHelper.basicTeam.id}/members/ids`). - reply(200, [{user_id: user1.id, team_id: TestHelper.basicTeam.id}, {user_id: user2.id, team_id: TestHelper.basicTeam.id}]); - await Actions.getTeamMembersByIds( - TestHelper.basicTeam.id, - [user1.id, user2.id], - )(store.dispatch, store.getState); - - const members = store.getState().entities.teams.membersInTeam; - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id][user1.id]); - assert.ok(members[TestHelper.basicTeam.id][user2.id]); - }); - it('getTeamStats', async () => { nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). get('/stats'). @@ -475,33 +423,6 @@ describe('Actions.Teams', () => { assert.ok(members[TestHelper.basicTeam.id][user.id]); }); - it('addUsersToTeam', async () => { - nock(Client4.getBaseRoute()). - post('/users'). - reply(201, TestHelper.fakeUserWithId()); - const user = await TestHelper.basicClient4.createUser(TestHelper.fakeUser()); - - nock(Client4.getBaseRoute()). - post('/users'). - reply(201, TestHelper.fakeUserWithId()); - const user2 = await TestHelper.basicClient4.createUser(TestHelper.fakeUser()); - - nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). - post('/members/batch'). - reply(201, [{user_id: user.id, team_id: TestHelper.basicTeam.id}, {user_id: user2.id, team_id: TestHelper.basicTeam.id}]); - await Actions.addUsersToTeam(TestHelper.basicTeam.id, [user.id, user2.id])(store.dispatch, store.getState); - - const members = store.getState().entities.teams.membersInTeam; - const profilesInTeam = store.getState().entities.users.profilesInTeam; - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id][user.id]); - assert.ok(members[TestHelper.basicTeam.id][user2.id]); - assert.ok(profilesInTeam[TestHelper.basicTeam.id]); - assert.ok(profilesInTeam[TestHelper.basicTeam.id].has(user.id)); - assert.ok(profilesInTeam[TestHelper.basicTeam.id].has(user2.id)); - }); - describe('removeUserFromTeam', () => { const team = {id: 'team'}; const user = {id: 'user'}; @@ -597,174 +518,4 @@ describe('Actions.Teams', () => { expect(state.entities.channels.currentChannelId).toBe(''); }); }); - - it('updateTeamMemberRoles', async () => { - nock(Client4.getBaseRoute()). - post('/users'). - reply(201, TestHelper.fakeUserWithId()); - const user = await TestHelper.basicClient4.createUser(TestHelper.fakeUser()); - - nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). - post('/members'). - reply(201, {user_id: user.id, team_id: TestHelper.basicTeam.id}); - await Actions.addUserToTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); - - const roles = General.TEAM_USER_ROLE + ' ' + General.TEAM_ADMIN_ROLE; - - nock(Client4.getBaseRoute()). - put(`/teams/${TestHelper.basicTeam.id}/members/${user.id}/roles`). - reply(200, {user_id: user.id, team_id: TestHelper.basicTeam.id, roles}); - await Actions.updateTeamMemberRoles(TestHelper.basicTeam.id, user.id, roles)(store.dispatch, store.getState); - - const members = store.getState().entities.teams.membersInTeam; - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id][user.id]); - assert.ok(members[TestHelper.basicTeam.id][user.id].roles === roles); - }); - - it('sendEmailInvitesToTeam', async () => { - nock(Client4.getTeamRoute(TestHelper.basicTeam.id)). - post('/invite/email'). - reply(200, OK_RESPONSE); - const {data} = await Actions.sendEmailInvitesToTeam(TestHelper.basicTeam.id, ['fakeemail1@example.com', 'fakeemail2@example.com'])(store.dispatch, store.getState); - assert.deepEqual(data, OK_RESPONSE); - }); - - it('checkIfTeamExists', async () => { - nock(Client4.getBaseRoute()). - get(`/teams/name/${TestHelper.basicTeam.name}/exists`). - reply(200, {exists: true}); - - let {data: exists} = await Actions.checkIfTeamExists(TestHelper.basicTeam.name)(store.dispatch, store.getState); - - assert.ok(exists === true); - - nock(Client4.getBaseRoute()). - get('/teams/name/junk/exists'). - reply(200, {exists: false}); - const {data} = await Actions.checkIfTeamExists('junk')(store.dispatch, store.getState); - exists = data; - - assert.ok(exists === false); - }); - - it('setTeamIcon', async () => { - TestHelper.mockLogin(); - await login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const team = TestHelper.basicTeam; - const imageData = fs.createReadStream('test/assets/images/test.png'); - - nock(Client4.getTeamRoute(team.id)). - post('/image'). - reply(200, OK_RESPONSE); - - const {data} = await Actions.setTeamIcon(team.id, imageData)(store.dispatch, store.getState); - assert.deepEqual(data, OK_RESPONSE); - }); - - it('removeTeamIcon', async () => { - TestHelper.mockLogin(); - await login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const team = TestHelper.basicTeam; - - nock(Client4.getTeamRoute(team.id)). - delete('/image'). - reply(200, OK_RESPONSE); - - const {data} = await Actions.removeTeamIcon(team.id)(store.dispatch, store.getState); - assert.deepEqual(data, OK_RESPONSE); - }); - - it('updateTeamScheme', async () => { - TestHelper.mockLogin(); - await login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const schemeId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'; - const {id} = TestHelper.basicTeam; - - nock(Client4.getBaseRoute()). - put('/teams/' + id + '/scheme'). - reply(200, OK_RESPONSE); - - await Actions.updateTeamScheme(id, schemeId)(store.dispatch, store.getState); - - const state = store.getState(); - const {teams} = state.entities.teams; - - const updated = teams[id]; - assert.ok(updated); - assert.equal(updated.scheme_id, schemeId); - }); - - it('membersMinusGroupMembers', async () => { - const teamID = 'tid10000000000000000000000'; - const groupIDs = ['gid10000000000000000000000', 'gid20000000000000000000000']; - const page = 4; - const perPage = 63; - - nock(Client4.getBaseRoute()).get( - `/teams/${teamID}/members_minus_group_members?group_ids=${groupIDs.join(',')}&page=${page}&per_page=${perPage}`). - reply(200, {users: [], total_count: 0}); - - const {error} = await Actions.membersMinusGroupMembers(teamID, groupIDs, page, perPage)(store.dispatch, store.getState); - - assert.equal(error, null); - }); - - it('searchTeams', async () => { - const userClient = TestHelper.createClient(); - - nock(Client4.getBaseRoute()). - post('/users'). - query(true). - reply(201, TestHelper.fakeUserWithId()); - - const user = await TestHelper.basicClient4.createUser( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id, - ); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, user); - - await userClient.login(user.email, 'password1'); - - nock(Client4.getBaseRoute()). - post('/teams'). - reply(201, TestHelper.fakeTeamWithId()); - - const userTeam = await userClient.createTeam( - TestHelper.fakeTeam(), - ); - - nock(Client4.getBaseRoute()). - post('/teams/search'). - reply(200, [TestHelper.basicTeam, userTeam]); - - await store.dispatch(Actions.searchTeams('test', 0)); - - const moreRequest = store.getState().requests.teams.getTeams; - if (moreRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(moreRequest.error)); - } - - nock(Client4.getBaseRoute()). - post('/teams/search'). - reply(200, {teams: [TestHelper.basicTeam, userTeam], total_count: 2}); - - const response = await store.dispatch(Actions.searchTeams('test', '', false, true)); - - const paginatedRequest = store.getState().requests.teams.getTeams; - if (paginatedRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(paginatedRequest.error)); - } - - assert.ok(response.data.teams.length === 2); - }); }); diff --git a/app/mm-redux/actions/teams.ts b/app/mm-redux/actions/teams.ts index 54c132b9e..64526987b 100644 --- a/app/mm-redux/actions/teams.ts +++ b/app/mm-redux/actions/teams.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '../constants'; import {ChannelTypes, RoleTypes, TeamTypes, UserTypes} from '@mm-redux/action_types'; import EventEmitter from '@mm-redux/utils/event_emitter'; @@ -12,14 +12,13 @@ import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; import {GetStateFunc, DispatchFunc, ActionFunc, ActionResult, batchActions, Action} from '@mm-redux/types/actions'; -import {Team, TeamMembership, TeamMemberWithError} from '@mm-redux/types/teams'; +import {Team} from '@mm-redux/types/teams'; import {selectChannel} from './channels'; import {logError} from './errors'; import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; import {getProfilesByIds, getStatusesByIds} from './users'; import {loadRolesIfNeeded} from './roles'; -import {UserProfile} from '@mm-redux/types/users'; async function getProfilesAndStatusesForMembers(userIds: string[], dispatch: DispatchFunc, getState: GetStateFunc) { const { @@ -103,13 +102,10 @@ export function getTeams(page = 0, perPage: number = General.TEAMS_CHUNK_SIZE, i return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let data; - dispatch({type: TeamTypes.GET_TEAMS_REQUEST, data}); - try { data = await Client4.getTeams(page, perPage, includeTotalCount); } catch (error) { forceLogoutIfNecessary(error, dispatch, getState); - dispatch({type: TeamTypes.GET_TEAMS_FAILURE, data}); dispatch(logError(error)); return {error}; } @@ -117,7 +113,7 @@ export function getTeams(page = 0, perPage: number = General.TEAMS_CHUNK_SIZE, i const actions: Action[] = [ { type: TeamTypes.RECEIVED_TEAMS_LIST, - data: includeTotalCount ? data.teams : data, + data: (includeTotalCount ? data.teams : data), }, { type: TeamTypes.GET_TEAMS_SUCCESS, @@ -138,38 +134,6 @@ export function getTeams(page = 0, perPage: number = General.TEAMS_CHUNK_SIZE, i }; } -export function searchTeams(term: string, page?: number, perPage?: number): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - dispatch({type: TeamTypes.GET_TEAMS_REQUEST, data: null}); - - let response; - try { - response = await Client4.searchTeams(term, page, perPage); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(batchActions([ - {type: TeamTypes.GET_TEAMS_FAILURE, error}, - logError(error), - ])); - return {error}; - } - - const teams = response.teams || response; - - dispatch(batchActions([ - { - type: TeamTypes.RECEIVED_TEAMS_LIST, - data: teams, - }, - { - type: TeamTypes.GET_TEAMS_SUCCESS, - }, - ], 'BATCH_SEARCH_TEAMS')); - - return {data: response}; - }; -} - export function createTeam(team: Team): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let created; @@ -263,16 +227,6 @@ export function patchTeam(team: Team): ActionFunc { }); } -export function regenerateTeamInviteId(teamId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.regenerateTeamInviteId, - onSuccess: TeamTypes.REGENERATED_TEAM_INVITE_ID, - params: [ - teamId, - ], - }); -} - export function getMyTeamMembers(): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const getMyTeamMembersFunc = bindClientFunc({ @@ -301,9 +255,7 @@ export function getMyTeamMembers(): ActionFunc { export function getTeamMembers(teamId: string, page = 0, perPage: number = General.TEAMS_CHUNK_SIZE): ActionFunc { return bindClientFunc({ clientFunc: Client4.getTeamMembers, - onRequest: TeamTypes.GET_TEAM_MEMBERS_REQUEST, - onSuccess: [TeamTypes.RECEIVED_MEMBERS_IN_TEAM, TeamTypes.GET_TEAM_MEMBERS_SUCCESS], - onFailure: TeamTypes.GET_TEAM_MEMBERS_FAILURE, + onSuccess: TeamTypes.RECEIVED_MEMBERS_IN_TEAM, params: [ teamId, page, @@ -336,30 +288,6 @@ export function getTeamMember(teamId: string, userId: string): ActionFunc { }; } -export function getTeamMembersByIds(teamId: string, userIds: Array): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let members; - try { - const membersRequest = Client4.getTeamMembersByIds(teamId, userIds); - - getProfilesAndStatusesForMembers(userIds, dispatch, getState); - - members = await membersRequest; - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({ - type: TeamTypes.RECEIVED_MEMBERS_IN_TEAM, - data: members, - }); - - return {data: members}; - }; -} - export function getTeamsForUser(userId: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.getTeamsForUser, @@ -372,16 +300,6 @@ export function getTeamsForUser(userId: string): ActionFunc { }); } -export function getTeamMembersForUser(userId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getTeamMembersForUser, - onSuccess: TeamTypes.RECEIVED_TEAM_MEMBERS, - params: [ - userId, - ], - }); -} - export function getTeamStats(teamId: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.getTeamStats, @@ -392,19 +310,6 @@ export function getTeamStats(teamId: string): ActionFunc { }); } -export function addUserToTeamFromInvite(token: string, inviteId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.addToTeamFromInvite, - onRequest: TeamTypes.ADD_TO_TEAM_FROM_INVITE_REQUEST, - onSuccess: TeamTypes.ADD_TO_TEAM_FROM_INVITE_SUCCESS, - onFailure: TeamTypes.ADD_TO_TEAM_FROM_INVITE_FAILURE, - params: [ - token, - inviteId, - ], - }); -} - export function addUserToTeam(teamId: string, userId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let member; @@ -458,66 +363,6 @@ export function addUserToTeam(teamId: string, userId: string): ActionFunc { }; } -export function addUsersToTeam(teamId: string, userIds: Array): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let members; - try { - members = await Client4.addUsersToTeam(teamId, userIds); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const profiles: Partial[] = []; - members.forEach((m: TeamMembership) => profiles.push({id: m.user_id})); - - dispatch(batchActions([ - { - type: UserTypes.RECEIVED_PROFILES_LIST_IN_TEAM, - data: profiles, - id: teamId, - }, - { - type: TeamTypes.RECEIVED_MEMBERS_IN_TEAM, - data: members, - }, - ], 'BATCH_ADD_USERS_TO_TEAM')); - - return {data: members}; - }; -} - -export function addUsersToTeamGracefully(teamId: string, userIds: Array): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let result: Array; - try { - result = await Client4.addUsersToTeamGracefully(teamId, userIds); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const addedMembers = result ? result.filter((m) => !m.error) : []; - const profiles: Partial[] = addedMembers.map((m) => ({id: m.user_id})); - const members = addedMembers.map((m) => m.member); - dispatch(batchActions([ - { - type: UserTypes.RECEIVED_PROFILES_LIST_IN_TEAM, - data: profiles, - id: teamId, - }, - { - type: TeamTypes.RECEIVED_MEMBERS_IN_TEAM, - data: members, - }, - ], 'BATCH_ADD_USERS_TO_TEAM_GRACEFULLY')); - - return {data: result}; - }; -} - export function removeUserFromTeam(teamId: string, userId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { try { @@ -572,98 +417,6 @@ export function removeUserFromTeam(teamId: string, userId: string): ActionFunc { }; } -export function updateTeamMemberRoles(teamId: string, userId: string, roles: string[]): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateTeamMemberRoles(teamId, userId, roles); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const membersInTeam = getState().entities.teams.membersInTeam[teamId]; - if (membersInTeam && membersInTeam[userId]) { - dispatch({ - type: TeamTypes.RECEIVED_MEMBER_IN_TEAM, - data: {...membersInTeam[userId], roles}, - }); - } - - return {data: true}; - }; -} - -export function sendEmailInvitesToTeam(teamId: string, emails: Array): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.sendEmailInvitesToTeam, - params: [ - teamId, - emails, - ], - }); -} - -export function sendEmailGuestInvitesToChannels(teamId: string, channelIds: Array, emails: Array, message: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.sendEmailGuestInvitesToChannels, - params: [ - teamId, - channelIds, - emails, - message, - ], - }); -} -export function sendEmailInvitesToTeamGracefully(teamId: string, emails: Array): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.sendEmailInvitesToTeamGracefully, - params: [ - teamId, - emails, - ], - }); -} - -export function sendEmailGuestInvitesToChannelsGracefully(teamId: string, channelIds: Array, emails: Array, message: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.sendEmailGuestInvitesToChannelsGracefully, - params: [ - teamId, - channelIds, - emails, - message, - ], - }); -} - -export function getTeamInviteInfo(inviteId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getTeamInviteInfo, - onRequest: TeamTypes.TEAM_INVITE_INFO_REQUEST, - onSuccess: TeamTypes.TEAM_INVITE_INFO_SUCCESS, - onFailure: TeamTypes.TEAM_INVITE_INFO_FAILURE, - params: [ - inviteId, - ], - }); -} - -export function checkIfTeamExists(teamName: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data; - try { - data = await Client4.checkIfTeamExists(teamName); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - return {data: data.exists}; - }; -} - export function joinTeam(inviteId: string, teamId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { dispatch({type: TeamTypes.JOIN_TEAM_REQUEST, data: null}); @@ -696,66 +449,3 @@ export function joinTeam(inviteId: string, teamId: string): ActionFunc { return {data: true}; }; } - -export function setTeamIcon(teamId: string, imageData: any): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.setTeamIcon, - params: [ - teamId, - imageData, - ], - }); -} - -export function removeTeamIcon(teamId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.removeTeamIcon, - params: [ - teamId, - ], - }); -} - -export function updateTeamScheme(teamId: string, schemeId: string): ActionFunc { - return bindClientFunc({ - clientFunc: async () => { - await Client4.updateTeamScheme(teamId, schemeId); - return {teamId, schemeId}; - }, - onSuccess: TeamTypes.UPDATED_TEAM_SCHEME, - }); -} - -export function updateTeamMemberSchemeRoles( - teamId: string, - userId: string, - isSchemeUser: boolean, - isSchemeAdmin: boolean, -): ActionFunc { - return bindClientFunc({ - clientFunc: async () => { - await Client4.updateTeamMemberSchemeRoles(teamId, userId, isSchemeUser, isSchemeAdmin); - return {teamId, userId, isSchemeUser, isSchemeAdmin}; - }, - onSuccess: TeamTypes.UPDATED_TEAM_MEMBER_SCHEME_ROLES, - }); -} - -export function invalidateAllEmailInvites(): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.invalidateAllEmailInvites, - }); -} - -export function membersMinusGroupMembers(teamID: string, groupIDs: Array, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.teamMembersMinusGroupMembers, - onSuccess: TeamTypes.RECEIVED_TEAM_MEMBERS_MINUS_GROUP_MEMBERS, - params: [ - teamID, - groupIDs, - page, - perPage, - ], - }); -} diff --git a/app/mm-redux/actions/users.test.js b/app/mm-redux/actions/users.test.js index 0ae67bb5f..6f2f1ebfe 100644 --- a/app/mm-redux/actions/users.test.js +++ b/app/mm-redux/actions/users.test.js @@ -3,12 +3,11 @@ import assert from 'assert'; import nock from 'nock'; -import fs from 'fs'; import {NavigationTypes} from '@constants'; import {logout} from '@actions/views/user'; import * as Actions from '@mm-redux/actions/users'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {RequestStatus} from '../constants'; import TestHelper from 'test/test_helper'; import configureStore from 'test/test_store'; @@ -18,7 +17,6 @@ import EventEmitter from '@mm-redux/utils/event_emitter'; import initialState from '@store/initial_state'; const OK_RESPONSE = {status: 'OK'}; -const UNAUTHORIZED = {status_code: 401}; describe('Actions.Users', () => { let store; @@ -486,17 +484,6 @@ describe('Actions.Users', () => { assert.equal(Object.keys(statuses).length, 1); }); - it('getTotalUsersStats', async () => { - nock(Client4.getBaseRoute(TestHelper.basicUser.id)). - get('/users/stats'). - reply(200, {total_users_count: 2605}); - await Actions.getTotalUsersStats()(store.dispatch, store.getState); - - const {stats} = store.getState().entities.users; - - assert.equal(stats.total_users_count, 2605); - }); - it('getStatus', async () => { const user = TestHelper.basicUser; @@ -538,162 +525,6 @@ describe('Actions.Users', () => { assert.equal(sessions[0].user_id, TestHelper.basicUser.id); }); - it('revokeSession', async () => { - nock(Client4.getBaseRoute()). - get(`/users/${TestHelper.basicUser.id}/sessions`). - reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]); - - await Actions.getSessions(TestHelper.basicUser.id)(store.dispatch, store.getState); - - let sessions = store.getState().entities.users.mySessions; - - const sessionsLength = sessions.length; - - nock(Client4.getBaseRoute()). - post(`/users/${TestHelper.basicUser.id}/sessions/revoke`). - reply(200, OK_RESPONSE); - await Actions.revokeSession(TestHelper.basicUser.id, sessions[0].id)(store.dispatch, store.getState); - - sessions = store.getState().entities.users.mySessions; - assert.ok(sessions.length === sessionsLength - 1); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, TestHelper.basicUser); - await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - }); - - it('revokeSession and logout', async () => { - nock(Client4.getBaseRoute()). - get(`/users/${TestHelper.basicUser.id}/sessions`). - reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]); - - await Actions.getSessions(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const sessions = store.getState().entities.users.mySessions; - - nock(Client4.getBaseRoute()). - post(`/users/${TestHelper.basicUser.id}/sessions/revoke`). - reply(200, OK_RESPONSE); - - const {data: revokeSessionResponse} = await Actions.revokeSession(TestHelper.basicUser.id, sessions[0].id)(store.dispatch, store.getState); - assert.deepEqual(revokeSessionResponse, true); - - nock(Client4.getBaseRoute()). - get('/users'). - reply(401, {}); - - await Actions.getProfiles(0)(store.dispatch, store.getState); - - const basicUser = TestHelper.basicUser; - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, basicUser); - const response = await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - assert.deepEqual(response.email, basicUser.email); - }); - - it('revokeAllSessionsForCurrentUser', async () => { - const user = TestHelper.basicUser; - nock(Client4.getBaseRoute()). - post('/users/logout'). - reply(200, OK_RESPONSE); - await TestHelper.basicClient4.logout(); - let sessions = store.getState().entities.users.mySessions; - - assert.strictEqual(sessions.length, 0); - - TestHelper.mockLogin(); - await store.dispatch(Actions.loginById(user.id, 'password1')); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, TestHelper.basicUser); - await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - - nock(Client4.getBaseRoute()). - get(`/users/${user.id}/sessions`). - reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}, {id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]); - await store.dispatch(Actions.getSessions(user.id)); - - sessions = store.getState().entities.users.mySessions; - assert.ok(sessions.length > 1); - - nock(Client4.getBaseRoute()). - post(`/users/${user.id}/sessions/revoke/all`). - reply(200, OK_RESPONSE); - const {data} = await store.dispatch(Actions.revokeAllSessionsForUser(user.id)); - assert.deepEqual(data, true); - - nock(Client4.getBaseRoute()). - get('/users'). - query(true). - reply(401, UNAUTHORIZED); - await store.dispatch(Actions.getProfiles(0)); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, TestHelper.basicUser); - await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - }); - - it('revokeSessionsForAllUsers', async () => { - const user = TestHelper.basicUser; - - nock(Client4.getBaseRoute()). - post('/roles/names'). - reply(200, []); - - nock(Client4.getBaseRoute()). - post('/users/logout'). - reply(200, OK_RESPONSE); - await TestHelper.basicClient4.logout(); - let sessions = store.getState().entities.users.mySessions; - - assert.strictEqual(sessions.length, 0); - - TestHelper.mockLogin(); - await store.dispatch(Actions.loginById(user.id, 'password1')); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, TestHelper.basicUser); - await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - - nock(Client4.getBaseRoute()). - get(`/users/${user.id}/sessions`). - reply(200, [{id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}, {id: TestHelper.generateId(), create_at: 1507756921338, expires_at: 1510348921338, last_activity_at: 1507821125630, user_id: TestHelper.basicUser.id, device_id: '', roles: 'system_admin system_user'}]); - await store.dispatch(Actions.getSessions(user.id)); - - sessions = store.getState().entities.users.mySessions; - assert.ok(sessions.length > 1); - - nock(Client4.getBaseRoute()). - post('/users/sessions/revoke/all'). - reply(200, OK_RESPONSE); - const {data} = await store.dispatch(Actions.revokeSessionsForAllUsers(user.id)); - assert.deepEqual(data, true); - - nock(Client4.getBaseRoute()). - post('/users/login'). - reply(200, TestHelper.basicUser); - await TestHelper.basicClient4.login(TestHelper.basicUser.email, 'password1'); - }); - - it('getUserAudits', async () => { - nock(Client4.getBaseRoute()). - get(`/users/${TestHelper.basicUser.id}/audits`). - query(true). - reply(200, [{id: TestHelper.generateId(), create_at: 1497285546645, user_id: TestHelper.basicUser.id, action: '/api/v4/users/login', extra_info: 'success', ip_address: '::1', session_id: ''}]); - - await Actions.getUserAudits(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const audits = store.getState().entities.users.myAudits; - - assert.ok(audits.length); - assert.equal(audits[0].user_id, TestHelper.basicUser.id); - }); - it('autocompleteUsers', async () => { nock(Client4.getBaseRoute()). post('/users'). @@ -825,62 +656,6 @@ describe('Actions.Users', () => { assert.equal(updateNotifyProps.mention_keys, ''); }); - it('updateUserRoles', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - put(`/users/${currentUserId}/roles`). - reply(200, OK_RESPONSE); - - await Actions.updateUserRoles(currentUserId, 'system_user system_admin')(store.dispatch, store.getState); - - const {profiles} = store.getState().entities.users; - const currentUserRoles = profiles[currentUserId].roles; - - assert.equal(currentUserRoles, 'system_user system_admin'); - }); - - it('updateUserMfa', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - put(`/users/${currentUserId}/mfa`). - reply(200, OK_RESPONSE); - - await Actions.updateUserMfa(currentUserId, false, '')(store.dispatch, store.getState); - - const {profiles} = store.getState().entities.users; - const currentUserMfa = profiles[currentUserId].mfa_active; - - assert.equal(currentUserMfa, false); - }); - - it('updateUserPassword', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const beforeTime = new Date().getTime(); - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - put(`/users/${currentUserId}/password`). - reply(200, OK_RESPONSE); - - await Actions.updateUserPassword(currentUserId, 'password1', 'password1')(store.dispatch, store.getState); - - const {profiles} = store.getState().entities.users; - const currentUser = profiles[currentUserId]; - - assert.ok(currentUser); - assert.ok(currentUser.last_password_update_at > beforeTime); - }); - it('checkMfa', async () => { const user = TestHelper.basicUser; @@ -900,68 +675,6 @@ describe('Actions.Users', () => { assert.ok(!mfaRequired); }); - it('generateMfaSecret', async () => { - const response = {secret: 'somesecret', qr_code: 'someqrcode'}; - - nock(Client4.getBaseRoute()). - post('/users/me/mfa/generate'). - reply(200, response); - - const {data} = await Actions.generateMfaSecret('me')(store.dispatch, store.getState); - - assert.deepEqual(data, response); - }); - - it('updateUserActive', async () => { - nock(Client4.getBaseRoute()). - post('/users'). - reply(200, TestHelper.fakeUserWithId()); - - const {data: user} = await store.dispatch(Actions.createUser(TestHelper.fakeUser())); - - const beforeTime = new Date().getTime(); - - nock(Client4.getBaseRoute()). - put(`/users/${user.id}/active`). - reply(200, OK_RESPONSE); - await store.dispatch(Actions.updateUserActive(user.id, false)); - - const {profiles} = store.getState().entities.users; - - assert.ok(profiles[user.id]); - assert.ok(profiles[user.id].delete_at > beforeTime); - }); - - it('verifyUserEmail', async () => { - nock(Client4.getBaseRoute()). - post('/users/email/verify'). - reply(200, OK_RESPONSE); - - const {data} = await Actions.verifyUserEmail('sometoken')(store.dispatch, store.getState); - - assert.deepEqual(data, OK_RESPONSE); - }); - - it('sendVerificationEmail', async () => { - nock(Client4.getBaseRoute()). - post('/users/email/verify/send'). - reply(200, OK_RESPONSE); - - const {data} = await Actions.sendVerificationEmail(TestHelper.basicUser.email)(store.dispatch, store.getState); - - assert.deepEqual(data, OK_RESPONSE); - }); - - it('resetUserPassword', async () => { - nock(Client4.getBaseRoute()). - post('/users/password/reset'). - reply(200, OK_RESPONSE); - - const {data} = await Actions.resetUserPassword('sometoken', 'newpassword')(store.dispatch, store.getState); - - assert.deepEqual(data, OK_RESPONSE); - }); - it('sendPasswordResetEmail', async () => { nock(Client4.getBaseRoute()). post('/users/password/reset/send'). @@ -972,28 +685,6 @@ describe('Actions.Users', () => { assert.deepEqual(data, OK_RESPONSE); }); - it('uploadProfileImage', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const testImageData = fs.createReadStream('test/assets/images/test.png'); - - const beforeTime = new Date().getTime(); - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${TestHelper.basicUser.id}/image`). - reply(200, OK_RESPONSE); - - await Actions.uploadProfileImage(currentUserId, testImageData)(store.dispatch, store.getState); - - const {profiles} = store.getState().entities.users; - const currentUser = profiles[currentUserId]; - - assert.ok(currentUser); - assert.ok(currentUser.last_picture_update > beforeTime); - }); - it('setDefaultProfileImage', async () => { TestHelper.mockLogin(); await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); @@ -1013,265 +704,6 @@ describe('Actions.Users', () => { assert.equal(currentUser.last_picture_update, 0); }); - it('switchEmailToOAuth', async () => { - nock(Client4.getBaseRoute()). - post('/users/login/switch'). - reply(200, {follow_link: '/login'}); - - const {data} = await Actions.switchEmailToOAuth('gitlab', TestHelper.basicUser.email, TestHelper.basicUser.password)(store.dispatch, store.getState); - assert.deepEqual(data, {follow_link: '/login'}); - }); - - it('switchOAuthToEmail', async () => { - nock(Client4.getBaseRoute()). - post('/users/login/switch'). - reply(200, {follow_link: '/login'}); - - const {data} = await Actions.switchOAuthToEmail('gitlab', TestHelper.basicUser.email, TestHelper.basicUser.password)(store.dispatch, store.getState); - - assert.deepEqual(data, {follow_link: '/login'}); - }); - - it('switchEmailToLdap', async () => { - nock(Client4.getBaseRoute()). - post('/users/login/switch'). - reply(200, {follow_link: '/login'}); - - const {data} = await Actions.switchEmailToLdap(TestHelper.basicUser.email, TestHelper.basicUser.password, 'someid', 'somepassword')(store.dispatch, store.getState); - - assert.deepEqual(data, {follow_link: '/login'}); - }); - - it('switchLdapToEmail', (done) => { - async function test() { - nock(Client4.getBaseRoute()). - post('/users/login/switch'). - reply(200, {follow_link: '/login'}); - - const {data} = await Actions.switchLdapToEmail('somepassword', TestHelper.basicUser.email, TestHelper.basicUser.password)(store.dispatch, store.getState); - assert.deepEqual(data, {follow_link: '/login'}); - - done(); - } - - test(); - }); - - it('createUserAccessToken', (done) => { - async function test() { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - const {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[data.id]); - assert.ok(!myUserAccessTokens[data.id].token); - done(); - } - - test(); - }); - - it('getUserAccessToken', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get(`/users/tokens/${data.id}`). - reply(200, {id: data.id, description: 'test token', user_id: currentUserId}); - - await Actions.getUserAccessToken(data.id)(store.dispatch, store.getState); - - const {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[data.id]); - assert.ok(!myUserAccessTokens[data.id].token); - }); - - it('getUserAccessTokens', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get('/users/tokens'). - query(true). - reply(200, [{id: data.id, description: 'test token', user_id: currentUserId}]); - - await Actions.getUserAccessTokens()(store.dispatch, store.getState); - - const {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[data.id]); - assert.ok(!myUserAccessTokens[data.id].token); - }); - - it('getUserAccessTokensForUser', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - nock(Client4.getBaseRoute()). - get(`/users/${currentUserId}/tokens`). - query(true). - reply(200, [{id: data.id, description: 'test token', user_id: currentUserId}]); - - await Actions.getUserAccessTokensForUser(currentUserId)(store.dispatch, store.getState); - - const {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[data.id]); - assert.ok(!myUserAccessTokens[data.id].token); - }); - - it('revokeUserAccessToken', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - let {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[data.id]); - assert.ok(!myUserAccessTokens[data.id].token); - - nock(Client4.getBaseRoute()). - post('/users/tokens/revoke'). - reply(200, OK_RESPONSE); - - await Actions.revokeUserAccessToken(data.id)(store.dispatch, store.getState); - - myUserAccessTokens = store.getState().entities.users.myUserAccessTokens; - - assert.ok(myUserAccessTokens); - assert.ok(!myUserAccessTokens[data.id]); - }); - - it('disableUserAccessToken', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - const testId = data.id; - - let {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[testId]); - assert.ok(!myUserAccessTokens[testId].token); - - nock(Client4.getBaseRoute()). - post('/users/tokens/disable'). - reply(200, OK_RESPONSE); - - await Actions.disableUserAccessToken(testId)(store.dispatch, store.getState); - - myUserAccessTokens = store.getState().entities.users.myUserAccessTokens; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[testId]); - assert.ok(!myUserAccessTokens[testId].is_active); - assert.ok(!myUserAccessTokens[testId].token); - }); - - it('enableUserAccessToken', async () => { - TestHelper.mockLogin(); - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - const {data} = await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - const testId = data.id; - - let {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[testId]); - assert.ok(!myUserAccessTokens[testId].token); - - nock(Client4.getBaseRoute()). - post('/users/tokens/enable'). - reply(200, OK_RESPONSE); - - await Actions.enableUserAccessToken(testId)(store.dispatch, store.getState); - - myUserAccessTokens = store.getState().entities.users.myUserAccessTokens; - - assert.ok(myUserAccessTokens); - assert.ok(myUserAccessTokens[testId]); - assert.ok(myUserAccessTokens[testId].is_active); - assert.ok(!myUserAccessTokens[testId].token); - }); - - it('clearUserAccessTokens', async () => { - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const currentUserId = store.getState().entities.users.currentUserId; - - nock(Client4.getBaseRoute()). - post(`/users/${currentUserId}/tokens`). - reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId}); - - await Actions.createUserAccessToken(currentUserId, 'test token')(store.dispatch, store.getState); - - await Actions.clearUserAccessTokens()(store.dispatch, store.getState); - - const {myUserAccessTokens} = store.getState().entities.users; - - assert.ok(Object.values(myUserAccessTokens).length === 0); - }); - describe('checkForModifiedUsers', () => { test('should request users by IDs that have changed since the last websocket disconnect', async () => { const lastDisconnectAt = 1500; diff --git a/app/mm-redux/actions/users.ts b/app/mm-redux/actions/users.ts index eae41538c..ae89ba907 100644 --- a/app/mm-redux/actions/users.ts +++ b/app/mm-redux/actions/users.ts @@ -3,7 +3,7 @@ import {Action, ActionFunc, ActionResult, batchActions, DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; import {UserProfile, UserStatus} from '@mm-redux/types/users'; import {TeamMembership} from '@mm-redux/types/teams'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '../constants'; import {UserTypes, TeamTypes} from '@mm-redux/action_types'; import {getAllCustomEmojis} from './emojis'; @@ -41,15 +41,6 @@ export function checkMfa(loginId: string): ActionFunc { }; } -export function generateMfaSecret(userId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.generateMfaSecret, - params: [ - userId, - ], - }); -} - export function createUser(user: UserProfile, token: string, inviteId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { let created; @@ -93,7 +84,7 @@ export function login(loginId: string, password: string, mfaToken = '', ldapOnly return {error}; } - return completeLogin(data)(dispatch, getState); + return dispatch(completeLogin(data)); }; } @@ -117,7 +108,7 @@ export function loginById(id: string, password: string, mfaToken = ''): ActionFu return {error}; } - return completeLogin(data)(dispatch, getState); + return dispatch(completeLogin(data)); }; } @@ -244,13 +235,6 @@ export function loadMe(): ActionFunc { }; } -export function getTotalUsersStats(): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getTotalUsersStats, - onSuccess: UserTypes.RECEIVED_USER_STATS, - }); -} - export function getProfiles(page = 0, perPage: number = General.PROFILE_CHUNK_SIZE, options: any = {}): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const {currentUserId} = getState().entities.users; @@ -285,8 +269,8 @@ export function getMissingProfilesByIds(userIds: Array): ActionFunc { }); if (missingIds.length > 0) { - getStatusesByIds(missingIds)(dispatch, getState); - return getProfilesByIds(missingIds)(dispatch, getState); + dispatch(getStatusesByIds(missingIds)); + return dispatch(getProfilesByIds(missingIds)); } return {data: []}; @@ -309,7 +293,7 @@ export function getMissingProfilesByUsernames(usernames: Array): ActionF }); if (missingUsernames.length > 0) { - return getProfilesByUsernames(missingUsernames)(dispatch, getState); + return dispatch(getProfilesByUsernames(missingUsernames)); } return {data: []}; @@ -605,13 +589,6 @@ export function getTermsOfService(): ActionFunc { }); } -export function promoteGuestToUser(userId: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.promoteGuestToUser, - params: [userId], - }); -} - export function demoteUserToGuest(userId: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.demoteUserToGuest, @@ -619,15 +596,6 @@ export function demoteUserToGuest(userId: string): ActionFunc { }); } -export function createTermsOfService(text: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.createTermsOfService, - params: [ - text, - ], - }); -} - export function getUser(id: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.getUser, @@ -665,8 +633,8 @@ export function getUserByEmail(email: string): ActionFunc { // statuses, we are only making one call for 75 ids. // We could maybe clean it up somewhat by storing the array of ids in redux state possbily? let ids: Array = []; -const debouncedGetStatusesByIds = debounce(async (dispatch: DispatchFunc, getState: GetStateFunc) => { - getStatusesByIds([...new Set(ids)])(dispatch, getState); +const debouncedGetStatusesByIds = debounce(async (dispatch: DispatchFunc) => { + dispatch(getStatusesByIds([...new Set(ids)])); }, 20, false, () => { ids = []; }); @@ -724,64 +692,6 @@ export function getSessions(userId: string): ActionFunc { }); } -export function revokeSession(userId: string, sessionId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.revokeSession(userId, sessionId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({ - type: UserTypes.RECEIVED_REVOKED_SESSION, - sessionId, - data: null, - }); - - return {data: true}; - }; -} - -export function revokeAllSessionsForUser(userId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.revokeAllSessionsForUser(userId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - const data = {isCurrentUser: userId === getCurrentUserId(getState())}; - dispatch(batchActions([ - { - type: UserTypes.REVOKE_ALL_USER_SESSIONS_SUCCESS, - data, - }, - ])); - - return {data: true}; - }; -} - -export function revokeSessionsForAllUsers(): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.revokeSessionsForAllUsers(); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - dispatch({ - type: UserTypes.REVOKE_SESSIONS_FOR_ALL_USERS_SUCCESS, - data: null, - }); - return {data: true}; - }; -} - export function loadProfilesForDirect(): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); @@ -802,11 +712,11 @@ export function loadProfilesForDirect(): ActionFunc { if (member.mention_count > 0 && isDirectChannel(channel)) { const otherUserId = getUserIdFromChannelName(currentUserId, channel.name); if (!isDirectChannelVisible(profiles[otherUserId] || otherUserId, config, myPreferences, channel)) { - makeDirectChannelVisibleIfNecessary(otherUserId)(dispatch, getState); + dispatch(makeDirectChannelVisibleIfNecessary(otherUserId)); } } else if ((member.mention_count > 0 || member.msg_count < channel.total_msg_count) && isGroupChannel(channel) && !isGroupChannelVisible(config, myPreferences, channel)) { - makeGroupMessageVisibleIfNecessary(channel.id)(dispatch, getState); + dispatch(makeGroupMessageVisibleIfNecessary(channel.id)); } } } @@ -815,18 +725,6 @@ export function loadProfilesForDirect(): ActionFunc { }; } -export function getUserAudits(userId: string, page = 0, perPage: number = General.AUDITS_CHUNK_SIZE): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getUserAudits, - onSuccess: UserTypes.RECEIVED_AUDITS, - params: [ - userId, - page, - perPage, - ], - }); -} - export function autocompleteUsers(term: string, teamId = '', channelId = '', options: { limit: number; } = { @@ -967,7 +865,7 @@ export function startPeriodicStatusUpdates(): ActionFunc { return; } - getStatusesByIds(userIds)(dispatch, getState); + dispatch(getStatusesByIds(userIds)); }, General.STATUS_INTERVAL, ); @@ -1027,106 +925,6 @@ export function patchUser(user: UserProfile): ActionFunc { }; } -export function updateUserRoles(userId: string, roles: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateUserRoles(userId, roles); - } catch (error) { - return {error}; - } - - const profile = getState().entities.users.profiles[userId]; - if (profile) { - dispatch({type: UserTypes.RECEIVED_PROFILE, data: {...profile, roles}}); - } - - return {data: true}; - }; -} - -export function updateUserMfa(userId: string, activate: boolean, code = ''): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateUserMfa(userId, activate, code); - } catch (error) { - dispatch(logError(error)); - return {error}; - } - - const profile = getState().entities.users.profiles[userId]; - if (profile) { - dispatch({type: UserTypes.RECEIVED_PROFILE, data: {...profile, mfa_active: activate}}); - } - - return {data: true}; - }; -} - -export function updateUserPassword(userId: string, currentPassword: string, newPassword: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateUserPassword(userId, currentPassword, newPassword); - } catch (error) { - dispatch(logError(error)); - return {error}; - } - - const profile = getState().entities.users.profiles[userId]; - if (profile) { - dispatch({type: UserTypes.RECEIVED_PROFILE, data: {...profile, last_password_update_at: new Date().getTime()}}); - } - - return {data: true}; - }; -} - -export function updateUserActive(userId: string, active: boolean): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.updateUserActive(userId, active); - } catch (error) { - dispatch(logError(error)); - return {error}; - } - - const profile = getState().entities.users.profiles[userId]; - if (profile) { - const deleteAt = active ? 0 : new Date().getTime(); - dispatch({type: UserTypes.RECEIVED_PROFILE, data: {...profile, delete_at: deleteAt}}); - } - - return {data: true}; - }; -} - -export function verifyUserEmail(token: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.verifyUserEmail, - params: [ - token, - ], - }); -} - -export function sendVerificationEmail(email: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.sendVerificationEmail, - params: [ - email, - ], - }); -} - -export function resetUserPassword(token: string, newPassword: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.resetUserPassword, - params: [ - token, - newPassword, - ], - }); -} - export function sendPasswordResetEmail(email: string): ActionFunc { return bindClientFunc({ clientFunc: Client4.sendPasswordResetEmail, @@ -1154,239 +952,6 @@ export function setDefaultProfileImage(userId: string): ActionFunc { }; } -export function uploadProfileImage(userId: string, imageData: any): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.uploadProfileImage(userId, imageData); - } catch (error) { - return {error}; - } - - const profile = getState().entities.users.profiles[userId]; - if (profile) { - dispatch({type: UserTypes.RECEIVED_PROFILE, data: {...profile, last_picture_update: new Date().getTime()}}); - } - - return {data: true}; - }; -} - -export function switchEmailToOAuth(service: string, email: string, password: string, mfaCode = ''): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.switchEmailToOAuth, - params: [ - service, - email, - password, - mfaCode, - ], - }); -} - -export function switchOAuthToEmail(currentService: string, email: string, password: string): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.switchOAuthToEmail, - params: [ - currentService, - email, - password, - ], - }); -} - -export function switchEmailToLdap(email: string, emailPassword: string, ldapId: string, ldapPassword: string, mfaCode = ''): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.switchEmailToLdap, - params: [ - email, - emailPassword, - ldapId, - ldapPassword, - mfaCode, - ], - }); -} - -export function switchLdapToEmail(ldapPassword: string, email: string, emailPassword: string, mfaCode = ''): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.switchLdapToEmail, - params: [ - ldapPassword, - email, - emailPassword, - mfaCode, - ], - }); -} - -export function createUserAccessToken(userId: string, description: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data; - - try { - data = await Client4.createUserAccessToken(userId, description); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const actions: Action[] = []; - - const {currentUserId} = getState().entities.users; - if (userId === currentUserId) { - actions.push( - { - type: UserTypes.RECEIVED_MY_USER_ACCESS_TOKEN, - data: {...data, token: ''}, - }, - ); - } - - dispatch(batchActions(actions)); - - return {data}; - }; -} - -export function getUserAccessToken(tokenId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data; - try { - data = await Client4.getUserAccessToken(tokenId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const actions: Action[] = []; - - const {currentUserId} = getState().entities.users; - if (data.user_id === currentUserId) { - actions.push( - { - type: UserTypes.RECEIVED_MY_USER_ACCESS_TOKEN, - data, - }, - ); - } - - dispatch(batchActions(actions)); - - return {data}; - }; -} - -export function getUserAccessTokens(page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data; - - try { - data = await Client4.getUserAccessTokens(page, perPage); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - return {data}; - }; -} - -export function getUserAccessTokensForUser(userId: string, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - let data; - try { - data = await Client4.getUserAccessTokensForUser(userId, page, perPage); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - const actions: Action[] = []; - - const {currentUserId} = getState().entities.users; - if (userId === currentUserId) { - actions.push( - { - type: UserTypes.RECEIVED_MY_USER_ACCESS_TOKENS, - data, - }, - ); - } - - dispatch(batchActions(actions)); - - return {data}; - }; -} - -export function revokeUserAccessToken(tokenId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.revokeUserAccessToken(tokenId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({ - type: UserTypes.REVOKED_USER_ACCESS_TOKEN, - data: tokenId, - }); - - return {data: true}; - }; -} - -export function disableUserAccessToken(tokenId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.disableUserAccessToken(tokenId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({ - type: UserTypes.DISABLED_USER_ACCESS_TOKEN, - data: tokenId, - }); - - return {data: true}; - }; -} - -export function enableUserAccessToken(tokenId: string): ActionFunc { - return async (dispatch: DispatchFunc, getState: GetStateFunc) => { - try { - await Client4.enableUserAccessToken(tokenId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch, getState); - dispatch(logError(error)); - return {error}; - } - - dispatch({ - type: UserTypes.ENABLED_USER_ACCESS_TOKEN, - data: tokenId, - }); - - return {data: true}; - }; -} - -export function clearUserAccessTokens(): ActionFunc { - return async (dispatch) => { - dispatch({type: UserTypes.CLEAR_MY_USER_ACCESS_TOKENS, data: null}); - return {data: true}; - }; -} - export function checkForModifiedUsers() { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); @@ -1405,7 +970,6 @@ export function checkForModifiedUsers() { export default { checkMfa, - generateMfaSecret, login, getProfiles, getProfilesByIds, @@ -1418,37 +982,13 @@ export default { getStatus, getStatusesByIds, getSessions, - getTotalUsersStats, loadProfilesForDirect, - revokeSession, - revokeAllSessionsForUser, - revokeSessionsForAllUsers, - getUserAudits, searchProfiles, startPeriodicStatusUpdates, stopPeriodicStatusUpdates, updateMe, - updateUserRoles, - updateUserMfa, - updateUserPassword, - updateUserActive, - verifyUserEmail, - sendVerificationEmail, - resetUserPassword, sendPasswordResetEmail, - uploadProfileImage, - switchEmailToOAuth, - switchOAuthToEmail, - switchEmailToLdap, - switchLdapToEmail, getTermsOfService, - createTermsOfService, updateMyTermsOfServiceStatus, - createUserAccessToken, - getUserAccessToken, - getUserAccessTokensForUser, - revokeUserAccessToken, - disableUserAccessToken, - enableUserAccessToken, checkForModifiedUsers, }; diff --git a/app/mm-redux/client/client4.ts b/app/mm-redux/client/client4.ts deleted file mode 100644 index e8aa71dc0..000000000 --- a/app/mm-redux/client/client4.ts +++ /dev/null @@ -1,3178 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {analytics} from '@init/analytics'; -import {buildQueryString, isMinimumServerVersion} from '@mm-redux/utils/helpers'; -import {cleanUrlForLogging} from '@mm-redux/utils/sentry'; -import {UserProfile, UserStatus} from '@mm-redux/types/users'; -import {Team} from '@mm-redux/types/teams'; -import {Channel, ChannelModerationPatch} from '@mm-redux/types/channels'; -import {Post} from '@mm-redux/types/posts'; -import {Job} from '@mm-redux/types/jobs'; -import {Role} from '@mm-redux/types/roles'; -import {Scheme} from '@mm-redux/types/schemes'; -import {Options} from '@mm-redux/types/client4'; -import {PreferenceType} from '@mm-redux/types/preferences'; -import {IncomingWebhook, OutgoingWebhook, Command, OAuthApp, DialogSubmission} from '@mm-redux/types/integrations'; -import {CustomEmoji} from '@mm-redux/types/emojis'; -import {Config} from '@mm-redux/types/config'; -import {Bot, BotPatch} from '@mm-redux/types/bots'; -import {SyncablePatch} from '@mm-redux/types/groups'; -import {AppCallRequest, AppCallType} from '@mm-redux/types/apps'; - -import fetch from './fetch_etag'; -import {General} from '../constants'; - -const FormData = require('form-data'); -const HEADER_AUTH = 'Authorization'; -const HEADER_BEARER = 'BEARER'; -const HEADER_REQUESTED_WITH = 'X-Requested-With'; -const HEADER_USER_AGENT = 'User-Agent'; -const HEADER_X_CLUSTER_ID = 'X-Cluster-Id'; -const HEADER_X_CSRF_TOKEN = 'X-CSRF-Token'; -export const HEADER_X_VERSION_ID = 'X-Version-Id'; -const PER_PAGE_DEFAULT = 60; -const LOGS_PER_PAGE_DEFAULT = 10000; -export const DEFAULT_LIMIT_BEFORE = 30; -export const DEFAULT_LIMIT_AFTER = 30; - -/* eslint-disable no-throw-literal */ - -export default class Client4 { - logToConsole = false; - serverVersion = ''; - clusterId = ''; - token = ''; - csrf = ''; - url = ''; - urlVersion = '/api/v4'; - userAgent: string|null = null; - enableLogging = false; - defaultHeaders: {[x: string]: string} = {}; - diagnosticId = ''; - includeCookies = true; - translations = { - connectionError: 'There appears to be a problem with your internet connection.', - unknownError: 'We received an unexpected status code from the server.', - }; - - getUrl() { - return this.url; - } - - getAbsoluteUrl(baseUrl: string) { - if (typeof baseUrl !== 'string' || !baseUrl.startsWith('/')) { - return baseUrl; - } - return this.getUrl() + baseUrl; - } - - setUrl(url: string) { - this.url = url.replace(/\/+$/, ''); - } - - setUserAgent(userAgent: string) { - this.userAgent = userAgent; - } - - getToken() { - return this.token; - } - - setToken(token: string) { - this.token = token; - } - - setCSRF(csrfToken: string) { - this.csrf = csrfToken; - } - - setAcceptLanguage(locale: string) { - this.defaultHeaders['Accept-Language'] = locale; - } - - setEnableLogging(enable: boolean) { - this.enableLogging = enable; - } - - setIncludeCookies(include: boolean) { - this.includeCookies = include; - } - - setDiagnosticId(diagnosticId: string) { - this.diagnosticId = diagnosticId; - } - - getServerVersion() { - return this.serverVersion; - } - - getUrlVersion() { - return this.urlVersion; - } - - getBaseRoute() { - return `${this.url}${this.urlVersion}`; - } - - getUsersRoute() { - return `${this.getBaseRoute()}/users`; - } - - getUserRoute(userId: string) { - return `${this.getUsersRoute()}/${userId}`; - } - - getTeamsRoute() { - return `${this.getBaseRoute()}/teams`; - } - - getTeamRoute(teamId: string) { - return `${this.getTeamsRoute()}/${teamId}`; - } - - getTeamSchemeRoute(teamId: string) { - return `${this.getTeamRoute(teamId)}/scheme`; - } - - getTeamNameRoute(teamName: string) { - return `${this.getTeamsRoute()}/name/${teamName}`; - } - - getTeamMembersRoute(teamId: string) { - return `${this.getTeamRoute(teamId)}/members`; - } - - getTeamMemberRoute(teamId: string, userId: string) { - return `${this.getTeamMembersRoute(teamId)}/${userId}`; - } - - getChannelsRoute() { - return `${this.getBaseRoute()}/channels`; - } - - getChannelRoute(channelId: string) { - return `${this.getChannelsRoute()}/${channelId}`; - } - - getChannelMembersRoute(channelId: string) { - return `${this.getChannelRoute(channelId)}/members`; - } - - getChannelMemberRoute(channelId: string, userId: string) { - return `${this.getChannelMembersRoute(channelId)}/${userId}`; - } - - getChannelSchemeRoute(channelId: string) { - return `${this.getChannelRoute(channelId)}/scheme`; - } - - getPostsRoute() { - return `${this.getBaseRoute()}/posts`; - } - - getPostRoute(postId: string) { - return `${this.getPostsRoute()}/${postId}`; - } - - getReactionsRoute() { - return `${this.getBaseRoute()}/reactions`; - } - - getCommandsRoute() { - return `${this.getBaseRoute()}/commands`; - } - - getFilesRoute() { - return `${this.getBaseRoute()}/files`; - } - - getFileRoute(fileId: string) { - return `${this.getFilesRoute()}/${fileId}`; - } - - getPreferencesRoute(userId: string) { - return `${this.getUserRoute(userId)}/preferences`; - } - - getIncomingHooksRoute() { - return `${this.getBaseRoute()}/hooks/incoming`; - } - - getIncomingHookRoute(hookId: string) { - return `${this.getBaseRoute()}/hooks/incoming/${hookId}`; - } - - getOutgoingHooksRoute() { - return `${this.getBaseRoute()}/hooks/outgoing`; - } - - getOutgoingHookRoute(hookId: string) { - return `${this.getBaseRoute()}/hooks/outgoing/${hookId}`; - } - - getOAuthRoute() { - return `${this.url}/oauth`; - } - - getOAuthAppsRoute() { - return `${this.getBaseRoute()}/oauth/apps`; - } - - getOAuthAppRoute(appId: string) { - return `${this.getOAuthAppsRoute()}/${appId}`; - } - - getEmojisRoute() { - return `${this.getBaseRoute()}/emoji`; - } - - getEmojiRoute(emojiId: string) { - return `${this.getEmojisRoute()}/${emojiId}`; - } - - getBrandRoute() { - return `${this.getBaseRoute()}/brand`; - } - - getBrandImageUrl(timestamp: string) { - return `${this.getBrandRoute()}/image?t=${timestamp}`; - } - - getDataRetentionRoute() { - return `${this.getBaseRoute()}/data_retention`; - } - - getJobsRoute() { - return `${this.getBaseRoute()}/jobs`; - } - - getPluginsRoute() { - return `${this.getBaseRoute()}/plugins`; - } - - getPluginRoute(pluginId: string) { - return `${this.getPluginsRoute()}/${pluginId}`; - } - - getPluginsMarketplaceRoute() { - return `${this.getPluginsRoute()}/marketplace`; - } - - getRolesRoute() { - return `${this.getBaseRoute()}/roles`; - } - - getTimezonesRoute() { - return `${this.getBaseRoute()}/system/timezones`; - } - - getSchemesRoute() { - return `${this.getBaseRoute()}/schemes`; - } - - getRedirectLocationRoute() { - return `${this.getBaseRoute()}/redirect_location`; - } - - getBotsRoute() { - return `${this.getBaseRoute()}/bots`; - } - - getBotRoute(botUserId: string) { - return `${this.getBotsRoute()}/${botUserId}`; - } - - getCSRFFromCookie() { - // NOT NEEDED IN THE MOBILE APP - // if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') { - // const cookies = document.cookie.split(';'); - // for (let i = 0; i < cookies.length; i++) { - // const cookie = cookies[i].trim(); - // if (cookie.startsWith('MMCSRF=')) { - // return cookie.replace('MMCSRF=', ''); - // } - // } - // } - return ''; - } - - getOptions(options: Options) { - const newOptions: Options = {...options}; - - const headers: {[x: string]: string} = { - [HEADER_REQUESTED_WITH]: 'XMLHttpRequest', - ...this.defaultHeaders, - }; - - if (this.token) { - headers[HEADER_AUTH] = `${HEADER_BEARER} ${this.token}`; - } - - const csrfToken = this.csrf || this.getCSRFFromCookie(); - if (options.method && options.method.toLowerCase() !== 'get' && csrfToken) { - headers[HEADER_X_CSRF_TOKEN] = csrfToken; - } - - if (this.includeCookies) { - newOptions.credentials = 'include'; - } - - if (this.userAgent) { - headers[HEADER_USER_AGENT] = this.userAgent; - } - - if (newOptions.headers) { - Object.assign(headers, newOptions.headers); - } - - return { - ...newOptions, - headers, - }; - } - - // User Routes - - createUser = async (user: UserProfile, token: string, inviteId: string) => { - analytics.trackAPI('api_users_create'); - - const queryParams: any = {}; - - if (token) { - queryParams.t = token; - } - - if (inviteId) { - queryParams.iid = inviteId; - } - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString(queryParams)}`, - {method: 'post', body: JSON.stringify(user)}, - ); - } - - patchMe = async (userPatch: Partial) => { - return this.doFetch( - `${this.getUserRoute('me')}/patch`, - {method: 'put', body: JSON.stringify(userPatch)}, - ); - } - - patchUser = async (userPatch: Partial & {id: string}) => { - analytics.trackAPI('api_users_patch'); - - return this.doFetch( - `${this.getUserRoute(userPatch.id)}/patch`, - {method: 'put', body: JSON.stringify(userPatch)}, - ); - } - - updateUser = async (user: UserProfile) => { - analytics.trackAPI('api_users_update'); - - return this.doFetch( - `${this.getUserRoute(user.id)}`, - {method: 'put', body: JSON.stringify(user)}, - ); - } - - promoteGuestToUser = async (userId: string) => { - analytics.trackAPI('api_users_promote_guest_to_user'); - - return this.doFetch( - `${this.getUserRoute(userId)}/promote`, - {method: 'post'}, - ); - } - - demoteUserToGuest = async (userId: string) => { - analytics.trackAPI('api_users_demote_user_to_guest'); - - return this.doFetch( - `${this.getUserRoute(userId)}/demote`, - {method: 'post'}, - ); - } - - updateUserRoles = async (userId: string, roles: string) => { - analytics.trackAPI('api_users_update_roles'); - - return this.doFetch( - `${this.getUserRoute(userId)}/roles`, - {method: 'put', body: JSON.stringify({roles})}, - ); - }; - updateUserMfa = async (userId: string, activate: boolean, code: string) => { - const body: any = { - activate, - }; - - if (activate) { - body.code = code; - } - - return this.doFetch( - `${this.getUserRoute(userId)}/mfa`, - {method: 'put', body: JSON.stringify(body)}, - ); - } - - updateUserPassword = async (userId: string, currentPassword: string, newPassword: string) => { - analytics.trackAPI('api_users_newpassword'); - - return this.doFetch( - `${this.getUserRoute(userId)}/password`, - {method: 'put', body: JSON.stringify({current_password: currentPassword, new_password: newPassword})}, - ); - } - - resetUserPassword = async (token: string, newPassword: string) => { - analytics.trackAPI('api_users_reset_password'); - - return this.doFetch( - `${this.getUsersRoute()}/password/reset`, - {method: 'post', body: JSON.stringify({token, new_password: newPassword})}, - ); - } - - getKnownUsers = async () => { - analytics.trackAPI('api_get_known_users'); - - return this.doFetch( - `${this.getUsersRoute()}/known`, - {method: 'get'}, - ); - } - - sendPasswordResetEmail = async (email: string) => { - analytics.trackAPI('api_users_send_password_reset'); - - return this.doFetch( - `${this.getUsersRoute()}/password/reset/send`, - {method: 'post', body: JSON.stringify({email})}, - ); - } - - updateUserActive = async (userId: string, active: boolean) => { - analytics.trackAPI('api_users_update_active'); - - return this.doFetch( - `${this.getUserRoute(userId)}/active`, - {method: 'put', body: JSON.stringify({active})}, - ); - } - - uploadProfileImage = async (userId: string, imageData: any) => { - analytics.trackAPI('api_users_update_profile_picture'); - - const formData = new FormData(); - formData.append('image', imageData); - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getUserRoute(userId)}/image`, - request, - ); - }; - - setDefaultProfileImage = async (userId: string) => { - analytics.trackAPI('api_users_set_default_profile_picture'); - - return this.doFetch( - `${this.getUserRoute(userId)}/image`, - {method: 'delete'}, - ); - }; - - verifyUserEmail = async (token: string) => { - return this.doFetch( - `${this.getUsersRoute()}/email/verify`, - {method: 'post', body: JSON.stringify({token})}, - ); - } - - updateMyTermsOfServiceStatus = async (termsOfServiceId: string, accepted: boolean) => { - return this.doFetch( - `${this.getUserRoute('me')}/terms_of_service`, - {method: 'post', body: JSON.stringify({termsOfServiceId, accepted})}, - ); - } - - getTermsOfService = async () => { - return this.doFetch( - `${this.getBaseRoute()}/terms_of_service`, - {method: 'get'}, - ); - } - - createTermsOfService = async (text: string) => { - return this.doFetch( - `${this.getBaseRoute()}/terms_of_service`, - {method: 'post', body: JSON.stringify({text})}, - ); - } - - sendVerificationEmail = async (email: string) => { - return this.doFetch( - `${this.getUsersRoute()}/email/verify/send`, - {method: 'post', body: JSON.stringify({email})}, - ); - } - - login = async (loginId: string, password: string, token = '', deviceId = '', ldapOnly = false) => { - analytics.trackAPI('api_users_login'); - - if (ldapOnly) { - analytics.trackAPI('api_users_login_ldap'); - } - - const body: any = { - device_id: deviceId, - login_id: loginId, - password, - token, - }; - - if (ldapOnly) { - body.ldap_only = 'true'; - } - - const {data} = await this.doFetchWithResponse( - `${this.getUsersRoute()}/login`, - { - method: 'post', - body: JSON.stringify(body), - headers: {'Cache-Control': 'no-store'}, - }, - ); - - return data; - }; - - loginById = async (id: string, password: string, token = '', deviceId = '') => { - analytics.trackAPI('api_users_login'); - const body: any = { - device_id: deviceId, - id, - password, - token, - }; - - const {data} = await this.doFetchWithResponse( - `${this.getUsersRoute()}/login`, - {method: 'post', body: JSON.stringify(body)}, - ); - - return data; - }; - - logout = async () => { - analytics.trackAPI('api_users_logout'); - - const {response} = await this.doFetchWithResponse( - `${this.getUsersRoute()}/logout`, - {method: 'post'}, - ); - - if (response.ok) { - this.token = ''; - } - - this.serverVersion = ''; - - return response; - }; - - getProfiles = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { - analytics.trackAPI('api_profiles_get'); - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString({page, per_page: perPage, ...options})}`, - {method: 'get'}, - ); - }; - - getProfilesByIds = async (userIds: string[], options = {}) => { - analytics.trackAPI('api_profiles_get_by_ids'); - - return this.doFetch( - `${this.getUsersRoute()}/ids${buildQueryString(options)}`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - getProfilesByUsernames = async (usernames: string[]) => { - analytics.trackAPI('api_profiles_get_by_usernames'); - - return this.doFetch( - `${this.getUsersRoute()}/usernames`, - {method: 'post', body: JSON.stringify(usernames)}, - ); - }; - - getProfilesInTeam = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '', options = {}) => { - analytics.trackAPI('api_profiles_get_in_team', {team_id: teamId, sort}); - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString({...options, in_team: teamId, page, per_page: perPage, sort})}`, - {method: 'get'}, - ); - }; - - getProfilesNotInTeam = async (teamId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_profiles_get_not_in_team', {team_id: teamId, group_constrained: groupConstrained}); - - const queryStringObj: any = {not_in_team: teamId, page, per_page: perPage}; - if (groupConstrained) { - queryStringObj.group_constrained = true; - } - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, - {method: 'get'}, - ); - }; - - getProfilesWithoutTeam = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { - analytics.trackAPI('api_profiles_get_without_team'); - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString({...options, without_team: 1, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getProfilesInChannel = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '') => { - analytics.trackAPI('api_profiles_get_in_channel', {channel_id: channelId}); - - const serverVersion = this.getServerVersion(); - let queryStringObj; - if (isMinimumServerVersion(serverVersion, 4, 7)) { - queryStringObj = {in_channel: channelId, page, per_page: perPage, sort}; - } else { - queryStringObj = {in_channel: channelId, page, per_page: perPage}; - } - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, - {method: 'get'}, - ); - }; - - getProfilesInGroupChannels = async (channelsIds: string[]) => { - analytics.trackAPI('api_profiles_get_in_group_channels', {channelsIds}); - - return this.doFetch( - `${this.getUsersRoute()}/group_channels`, - {method: 'post', body: JSON.stringify(channelsIds)}, - ); - }; - - getProfilesNotInChannel = async (teamId: string, channelId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_profiles_get_not_in_channel', {team_id: teamId, channel_id: channelId, group_constrained: groupConstrained}); - - const queryStringObj: any = {in_team: teamId, not_in_channel: channelId, page, per_page: perPage}; - if (groupConstrained) { - queryStringObj.group_constrained = true; - } - - return this.doFetch( - `${this.getUsersRoute()}${buildQueryString(queryStringObj)}`, - {method: 'get'}, - ); - }; - - getMe = async () => { - return this.doFetch( - `${this.getUserRoute('me')}`, - {method: 'get'}, - ); - }; - - getUser = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}`, - {method: 'get'}, - ); - }; - - getUserByUsername = async (username: string) => { - return this.doFetch( - `${this.getUsersRoute()}/username/${username}`, - {method: 'get'}, - ); - }; - - getUserByEmail = async (email: string) => { - return this.doFetch( - `${this.getUsersRoute()}/email/${email}`, - {method: 'get'}, - ); - }; - - getProfilePictureUrl = (userId: string, lastPictureUpdate: number) => { - const params: any = {}; - - if (lastPictureUpdate) { - params._ = lastPictureUpdate; - } - - return `${this.getUserRoute(userId)}/image${buildQueryString(params)}`; - }; - getDefaultProfilePictureUrl = (userId: string) => { - return `${this.getUserRoute(userId)}/image/default`; - }; - autocompleteUsers = async (name: string, teamId: string, channelId: string, options = { - limit: General.AUTOCOMPLETE_LIMIT_DEFAULT, - }) => { - return this.doFetch(`${this.getUsersRoute()}/autocomplete${buildQueryString({ - in_team: teamId, - in_channel: channelId, - name, - limit: options.limit, - })}`, { - method: 'get', - }); - }; - getSessions = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/sessions`, - {method: 'get'}, - ); - }; - - revokeSession = async (userId: string, sessionId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/sessions/revoke`, - {method: 'post', body: JSON.stringify({session_id: sessionId})}, - ); - }; - - revokeAllSessionsForUser = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/sessions/revoke/all`, - {method: 'post'}, - ); - }; - - revokeSessionsForAllUsers = async () => { - return this.doFetch( - `${this.getUsersRoute()}/sessions/revoke/all`, - {method: 'post'}, - ); - }; - - getUserAudits = async (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getUserRoute(userId)}/audits${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - checkUserMfa = async (loginId: string) => { - return this.doFetch( - `${this.getUsersRoute()}/mfa`, - {method: 'post', body: JSON.stringify({login_id: loginId})}, - ); - }; - - generateMfaSecret = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/mfa/generate`, - {method: 'post'}, - ); - }; - - attachDevice = async (deviceId: string) => { - return this.doFetch( - `${this.getUsersRoute()}/sessions/device`, - {method: 'put', body: JSON.stringify({device_id: deviceId})}, - ); - }; - - searchUsers = (term: string, options: any) => { - analytics.trackAPI('api_search_users'); - - return this.doFetch( - `${this.getUsersRoute()}/search`, - {method: 'post', body: JSON.stringify({term, ...options})}, - ); - }; - - getStatusesByIds = async (userIds: string[]) => { - return this.doFetch( - `${this.getUsersRoute()}/status/ids`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - getStatus = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/status`, - {method: 'get'}, - ); - }; - - updateStatus = async (status: UserStatus) => { - return this.doFetch( - `${this.getUserRoute(status.user_id)}/status`, - {method: 'put', body: JSON.stringify(status)}, - ); - }; - - switchEmailToOAuth = async (service: string, email: string, password: string, mfaCode = '') => { - analytics.trackAPI('api_users_email_to_oauth'); - - return this.doFetch( - `${this.getUsersRoute()}/login/switch`, - {method: 'post', body: JSON.stringify({current_service: 'email', new_service: service, email, password, mfa_code: mfaCode})}, - ); - }; - - switchOAuthToEmail = async (currentService: string, email: string, password: string) => { - analytics.trackAPI('api_users_oauth_to_email'); - - return this.doFetch( - `${this.getUsersRoute()}/login/switch`, - {method: 'post', body: JSON.stringify({current_service: currentService, new_service: 'email', email, new_password: password})}, - ); - }; - - switchEmailToLdap = async (email: string, emailPassword: string, ldapId: string, ldapPassword: string, mfaCode = '') => { - analytics.trackAPI('api_users_email_to_ldap'); - - return this.doFetch( - `${this.getUsersRoute()}/login/switch`, - {method: 'post', body: JSON.stringify({current_service: 'email', new_service: 'ldap', email, password: emailPassword, ldap_id: ldapId, new_password: ldapPassword, mfa_code: mfaCode})}, - ); - }; - - switchLdapToEmail = async (ldapPassword: string, email: string, emailPassword: string, mfaCode = '') => { - analytics.trackAPI('api_users_ldap_to_email'); - - return this.doFetch( - `${this.getUsersRoute()}/login/switch`, - {method: 'post', body: JSON.stringify({current_service: 'ldap', new_service: 'email', email, password: ldapPassword, new_password: emailPassword, mfa_code: mfaCode})}, - ); - }; - - getAuthorizedOAuthApps = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/oauth/apps/authorized`, - {method: 'get'}, - ); - } - - authorizeOAuthApp = async (responseType: string, clientId: string, redirectUri: string, state: string, scope: string) => { - return this.doFetch( - `${this.url}/oauth/authorize`, - {method: 'post', body: JSON.stringify({client_id: clientId, response_type: responseType, redirect_uri: redirectUri, state, scope})}, - ); - } - - deauthorizeOAuthApp = async (clientId: string) => { - return this.doFetch( - `${this.url}/oauth/deauthorize`, - {method: 'post', body: JSON.stringify({client_id: clientId})}, - ); - } - - createUserAccessToken = async (userId: string, description: string) => { - analytics.trackAPI('api_users_create_access_token'); - - return this.doFetch( - `${this.getUserRoute(userId)}/tokens`, - {method: 'post', body: JSON.stringify({description})}, - ); - } - - getUserAccessToken = async (tokenId: string) => { - return this.doFetch( - `${this.getUsersRoute()}/tokens/${tokenId}`, - {method: 'get'}, - ); - } - - getUserAccessTokensForUser = async (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getUserRoute(userId)}/tokens${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - } - - getUserAccessTokens = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getUsersRoute()}/tokens${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - } - - revokeUserAccessToken = async (tokenId: string) => { - analytics.trackAPI('api_users_revoke_access_token'); - - return this.doFetch( - `${this.getUsersRoute()}/tokens/revoke`, - {method: 'post', body: JSON.stringify({token_id: tokenId})}, - ); - } - - disableUserAccessToken = async (tokenId: string) => { - return this.doFetch( - `${this.getUsersRoute()}/tokens/disable`, - {method: 'post', body: JSON.stringify({token_id: tokenId})}, - ); - } - - enableUserAccessToken = async (tokenId: string) => { - return this.doFetch( - `${this.getUsersRoute()}/tokens/enable`, - {method: 'post', body: JSON.stringify({token_id: tokenId})}, - ); - } - - // Team Routes - - createTeam = async (team: Team) => { - analytics.trackAPI('api_teams_create'); - - return this.doFetch( - `${this.getTeamsRoute()}`, - {method: 'post', body: JSON.stringify(team)}, - ); - }; - - deleteTeam = async (teamId: string) => { - analytics.trackAPI('api_teams_delete'); - - return this.doFetch( - `${this.getTeamRoute(teamId)}`, - {method: 'delete'}, - ); - }; - - updateTeam = async (team: Team) => { - analytics.trackAPI('api_teams_update_name', {team_id: team.id}); - - return this.doFetch( - `${this.getTeamRoute(team.id)}`, - {method: 'put', body: JSON.stringify(team)}, - ); - }; - - patchTeam = async (team: Partial & {id: string}) => { - analytics.trackAPI('api_teams_patch_name', {team_id: team.id}); - - return this.doFetch( - `${this.getTeamRoute(team.id)}/patch`, - {method: 'put', body: JSON.stringify(team)}, - ); - }; - - regenerateTeamInviteId = async (teamId: string) => { - analytics.trackAPI('api_teams_regenerate_invite_id', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/regenerate_invite_id`, - {method: 'post'}, - ); - }; - - updateTeamScheme = async (teamId: string, schemeId: string) => { - const patch = {scheme_id: schemeId}; - - analytics.trackAPI('api_teams_update_scheme', {team_id: teamId, ...patch}); - - return this.doFetch( - `${this.getTeamSchemeRoute(teamId)}`, - {method: 'put', body: JSON.stringify(patch)}, - ); - }; - - checkIfTeamExists = async (teamName: string) => { - return this.doFetch( - `${this.getTeamNameRoute(teamName)}/exists`, - {method: 'get'}, - ); - }; - - getTeams = async (page = 0, perPage = PER_PAGE_DEFAULT, includeTotalCount = false) => { - return this.doFetch( - `${this.getTeamsRoute()}${buildQueryString({page, per_page: perPage, include_total_count: includeTotalCount})}`, - {method: 'get'}, - ); - }; - - searchTeams = (term: string, page?: number, perPage?: number) => { - analytics.trackAPI('api_search_teams'); - - return this.doFetch( - `${this.getTeamsRoute()}/search`, - {method: 'post', body: JSON.stringify({term, page, per_page: perPage})}, - ); - }; - - getTeam = async (teamId: string) => { - return this.doFetch( - this.getTeamRoute(teamId), - {method: 'get'}, - ); - }; - - getTeamByName = async (teamName: string) => { - analytics.trackAPI('api_teams_get_team_by_name'); - - return this.doFetch( - this.getTeamNameRoute(teamName), - {method: 'get'}, - ); - }; - - getMyTeams = async () => { - return this.doFetch( - `${this.getUserRoute('me')}/teams`, - {method: 'get'}, - ); - }; - - getTeamsForUser = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/teams`, - {method: 'get'}, - ); - }; - - getMyTeamMembers = async () => { - return this.doFetch( - `${this.getUserRoute('me')}/teams/members`, - {method: 'get'}, - ); - }; - - getMyTeamUnreads = async () => { - return this.doFetch( - `${this.getUserRoute('me')}/teams/unread`, - {method: 'get'}, - ); - }; - - getTeamMembers = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getTeamMembersRoute(teamId)}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getTeamMembersForUser = async (userId: string) => { - return this.doFetch( - `${this.getUserRoute(userId)}/teams/members`, - {method: 'get'}, - ); - }; - - getTeamMember = async (teamId: string, userId: string) => { - return this.doFetch( - `${this.getTeamMemberRoute(teamId, userId)}`, - {method: 'get'}, - ); - }; - - getTeamMembersByIds = async (teamId: string, userIds: string[]) => { - return this.doFetch( - `${this.getTeamMembersRoute(teamId)}/ids`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - addToTeam = async (teamId: string, userId: string) => { - analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); - - const member = {user_id: userId, team_id: teamId}; - return this.doFetch( - `${this.getTeamMembersRoute(teamId)}`, - {method: 'post', body: JSON.stringify(member)}, - ); - }; - - addToTeamFromInvite = async (token = '', inviteId = '') => { - analytics.trackAPI('api_teams_invite_members'); - - const query = buildQueryString({token, invite_id: inviteId}); - return this.doFetch( - `${this.getTeamsRoute()}/members/invite${query}`, - {method: 'post'}, - ); - }; - - addUsersToTeam = async (teamId: string, userIds: string[]) => { - analytics.trackAPI('api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); - - const members: any = []; - userIds.forEach((id) => members.push({team_id: teamId, user_id: id})); - return this.doFetch( - `${this.getTeamMembersRoute(teamId)}/batch`, - {method: 'post', body: JSON.stringify(members)}, - ); - }; - - addUsersToTeamGracefully = async (teamId: string, userIds: string[]) => { - analytics.trackAPI('api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); - - const members: any = []; - userIds.forEach((id) => members.push({team_id: teamId, user_id: id})); - return this.doFetch( - `${this.getTeamMembersRoute(teamId)}/batch?graceful=true`, - {method: 'post', body: JSON.stringify(members)}, - ); - }; - - joinTeam = async (inviteId: string) => { - const query = buildQueryString({invite_id: inviteId}); - return this.doFetch( - `${this.getTeamsRoute()}/members/invite${query}`, - {method: 'post'}, - ); - }; - - removeFromTeam = async (teamId: string, userId: string) => { - analytics.trackAPI('api_teams_remove_members', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamMemberRoute(teamId, userId)}`, - {method: 'delete'}, - ); - }; - - getTeamStats = async (teamId: string) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/stats`, - {method: 'get'}, - ); - }; - - getTotalUsersStats = async () => { - return this.doFetch( - `${this.getUsersRoute()}/stats`, - {method: 'get'}, - ); - }; - - invalidateAllEmailInvites = async () => { - return this.doFetch( - `${this.getTeamsRoute()}/invites/email`, - {method: 'delete'}, - ); - }; - - getTeamInviteInfo = async (inviteId: string) => { - return this.doFetch( - `${this.getTeamsRoute()}/invite/${inviteId}`, - {method: 'get'}, - ); - }; - - updateTeamMemberRoles = async (teamId: string, userId: string, roles: string[]) => { - analytics.trackAPI('api_teams_update_member_roles', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamMemberRoute(teamId, userId)}/roles`, - {method: 'put', body: JSON.stringify({roles})}, - ); - }; - - sendEmailInvitesToTeam = async (teamId: string, emails: string[]) => { - analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/invite/email`, - {method: 'post', body: JSON.stringify(emails)}, - ); - }; - - sendEmailGuestInvitesToChannels = async (teamId: string, channelIds: string[], emails: string[], message: string) => { - analytics.trackAPI('api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/invite-guests/email`, - {method: 'post', body: JSON.stringify({emails, channels: channelIds, message})}, - ); - }; - - sendEmailInvitesToTeamGracefully = async (teamId: string, emails: string[]) => { - analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/invite/email?graceful=true`, - {method: 'post', body: JSON.stringify(emails)}, - ); - }; - - sendEmailGuestInvitesToChannelsGracefully = async (teamId: string, channelIds: string[], emails: string[], message: string) => { - analytics.trackAPI('api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/invite-guests/email?graceful=true`, - {method: 'post', body: JSON.stringify({emails, channels: channelIds, message})}, - ); - }; - - importTeam = async (teamId: string, file: any, importFrom: string) => { - const formData = new FormData(); - formData.append('file', file, file.name); - formData.append('filesize', file.size); - formData.append('importFrom', importFrom); - - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getTeamRoute(teamId)}/import`, - request, - ); - }; - - getTeamIconUrl = (teamId: string, lastTeamIconUpdate: number) => { - const params: any = {}; - if (lastTeamIconUpdate) { - params._ = lastTeamIconUpdate; - } - - return `${this.getTeamRoute(teamId)}/image${buildQueryString(params)}`; - }; - - setTeamIcon = async (teamId: string, imageData: any) => { - analytics.trackAPI('api_team_set_team_icon'); - - const formData = new FormData(); - formData.append('image', imageData); - - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getTeamRoute(teamId)}/image`, - request, - ); - }; - - removeTeamIcon = async (teamId: string) => { - analytics.trackAPI('api_team_remove_team_icon'); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/image`, - {method: 'delete'}, - ); - }; - - updateTeamMemberSchemeRoles = async (teamId: string, userId: string, isSchemeUser: boolean, isSchemeAdmin: boolean) => { - const body = {scheme_user: isSchemeUser, scheme_admin: isSchemeAdmin}; - return this.doFetch( - `${this.getTeamRoute(teamId)}/members/${userId}/schemeRoles`, - {method: 'put', body: JSON.stringify(body)}, - ); - }; - - // Channel Routes - - getAllChannels = async (page = 0, perPage = PER_PAGE_DEFAULT, notAssociatedToGroup = '', excludeDefaultChannels = false, includeTotalCount = false) => { - const queryData = { - page, - per_page: perPage, - not_associated_to_group: notAssociatedToGroup, - exclude_default_channels: excludeDefaultChannels, - include_total_count: includeTotalCount, - }; - return this.doFetch( - `${this.getChannelsRoute()}${buildQueryString(queryData)}`, - {method: 'get'}, - ); - }; - - createChannel = async (channel: Channel) => { - analytics.trackAPI('api_channels_create', {team_id: channel.team_id}); - - return this.doFetch( - `${this.getChannelsRoute()}`, - {method: 'post', body: JSON.stringify(channel)}, - ); - }; - - createDirectChannel = async (userIds: string[]) => { - analytics.trackAPI('api_channels_create_direct'); - - return this.doFetch( - `${this.getChannelsRoute()}/direct`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - createGroupChannel = async (userIds: string[]) => { - analytics.trackAPI('api_channels_create_group'); - - return this.doFetch( - `${this.getChannelsRoute()}/group`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - deleteChannel = async (channelId: string) => { - analytics.trackAPI('api_channels_delete', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}`, - {method: 'delete'}, - ); - }; - - unarchiveChannel = async (channelId: string) => { - analytics.trackAPI('api_channels_unarchive', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/restore`, - {method: 'post'}, - ); - }; - - updateChannel = async (channel: Channel) => { - analytics.trackAPI('api_channels_update', {channel_id: channel.id}); - - return this.doFetch( - `${this.getChannelRoute(channel.id)}`, - {method: 'put', body: JSON.stringify(channel)}, - ); - }; - - convertChannelToPrivate = async (channelId: string) => { - analytics.trackAPI('api_channels_convert_to_private', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/convert`, - {method: 'post'}, - ); - }; - - updateChannelPrivacy = async (channelId: string, privacy: any) => { - analytics.trackAPI('api_channels_update_privacy', {channel_id: channelId, privacy}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/privacy`, - {method: 'put', body: JSON.stringify({privacy})}, - ); - }; - - patchChannel = async (channelId: string, channelPatch: Partial) => { - analytics.trackAPI('api_channels_patch', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/patch`, - {method: 'put', body: JSON.stringify(channelPatch)}, - ); - }; - - updateChannelNotifyProps = async (props: any) => { - analytics.trackAPI('api_users_update_channel_notifications', {channel_id: props.channel_id}); - - return this.doFetch( - `${this.getChannelMemberRoute(props.channel_id, props.user_id)}/notify_props`, - {method: 'put', body: JSON.stringify(props)}, - ); - }; - - updateChannelScheme = async (channelId: string, schemeId: string) => { - const patch = {scheme_id: schemeId}; - - analytics.trackAPI('api_channels_update_scheme', {channel_id: channelId, ...patch}); - - return this.doFetch( - `${this.getChannelSchemeRoute(channelId)}`, - {method: 'put', body: JSON.stringify(patch)}, - ); - }; - - getChannel = async (channelId: string) => { - analytics.trackAPI('api_channel_get', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}`, - {method: 'get'}, - ); - }; - - getChannelByName = async (teamId: string, channelName: string, includeDeleted = false) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/name/${channelName}?include_deleted=${includeDeleted}`, - {method: 'get'}, - ); - }; - - getChannelByNameAndTeamName = async (teamName: string, channelName: string, includeDeleted = false) => { - analytics.trackAPI('api_channel_get_by_name_and_teamName', {channel_name: channelName, team_name: teamName, include_deleted: includeDeleted}); - - return this.doFetch( - `${this.getTeamNameRoute(teamName)}/channels/name/${channelName}?include_deleted=${includeDeleted}`, - {method: 'get'}, - ); - }; - - getChannels = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - getArchivedChannels = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/deleted${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getMyChannels = async (teamId: string, includeDeleted = false) => { - return this.doFetch( - `${this.getUserRoute('me')}/teams/${teamId}/channels${buildQueryString({include_deleted: includeDeleted})}`, - {method: 'get'}, - ); - }; - - getMyChannelMember = async (channelId: string) => { - return this.doFetch( - `${this.getChannelMemberRoute(channelId, 'me')}`, - {method: 'get'}, - ); - }; - - getMyChannelMembers = async (teamId: string) => { - return this.doFetch( - `${this.getUserRoute('me')}/teams/${teamId}/channels/members`, - {method: 'get'}, - ); - }; - - getChannelMembers = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getChannelMembersRoute(channelId)}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getChannelTimezones = async (channelId: string) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/timezones`, - {method: 'get'}, - ); - }; - - getChannelMember = async (channelId: string, userId: string) => { - return this.doFetch( - `${this.getChannelMemberRoute(channelId, userId)}`, - {method: 'get'}, - ); - }; - - getChannelMembersByIds = async (channelId: string, userIds: string[]) => { - return this.doFetch( - `${this.getChannelMembersRoute(channelId)}/ids`, - {method: 'post', body: JSON.stringify(userIds)}, - ); - }; - - addToChannel = async (userId: string, channelId: string, postRootId = '') => { - analytics.trackAPI('api_channels_add_member', {channel_id: channelId}); - - const member = {user_id: userId, channel_id: channelId, post_root_id: postRootId}; - return this.doFetch( - `${this.getChannelMembersRoute(channelId)}`, - {method: 'post', body: JSON.stringify(member)}, - ); - }; - - removeFromChannel = async (userId: string, channelId: string) => { - analytics.trackAPI('api_channels_remove_member', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelMemberRoute(channelId, userId)}`, - {method: 'delete'}, - ); - }; - - updateChannelMemberRoles = async (channelId: string, userId: string, roles: string) => { - return this.doFetch( - `${this.getChannelMemberRoute(channelId, userId)}/roles`, - {method: 'put', body: JSON.stringify({roles})}, - ); - }; - - getChannelStats = async (channelId: string) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/stats`, - {method: 'get'}, - ); - }; - - getChannelModerations = async (channelId: string) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/moderations`, - {method: 'get'}, - ); - }; - - patchChannelModerations = async (channelId: string, channelModerationsPatch: Array) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/moderations/patch`, - {method: 'put', body: JSON.stringify(channelModerationsPatch)}, - ); - }; - - getChannelMemberCountsByGroup = async (channelId: string, includeTimezones: boolean) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/member_counts_by_group?include_timezones=${includeTimezones}`, - {method: 'get'}, - ); - }; - - viewMyChannel = async (channelId: string, prevChannelId?: string) => { - const data = {channel_id: channelId, prev_channel_id: prevChannelId}; - return this.doFetch( - `${this.getChannelsRoute()}/members/me/view`, - {method: 'post', body: JSON.stringify(data)}, - ); - }; - - autocompleteChannels = async (teamId: string, name: string) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/autocomplete${buildQueryString({name})}`, - {method: 'get'}, - ); - }; - - autocompleteChannelsForSearch = async (teamId: string, name: string) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/search_autocomplete${buildQueryString({name})}`, - {method: 'get'}, - ); - }; - - searchChannels = async (teamId: string, term: string) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/search`, - {method: 'post', body: JSON.stringify({term})}, - ); - }; - - searchArchivedChannels = async (teamId: string, term: string) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/channels/search_archived`, - {method: 'post', body: JSON.stringify({term})}, - ); - }; - - searchAllChannels = async (term: string, notAssociatedToGroup = '', excludeDefaultChannels = false, page?: number, perPage?: number) => { - const body = { - term, - not_associated_to_group: notAssociatedToGroup, - exclude_default_channels: excludeDefaultChannels, - page, - per_page: perPage, - }; - return this.doFetch( - `${this.getChannelsRoute()}/search`, - {method: 'post', body: JSON.stringify(body)}, - ); - }; - - searchGroupChannels = async (term: string) => { - return this.doFetch( - `${this.getChannelsRoute()}/group/search`, - {method: 'post', body: JSON.stringify({term})}, - ); - }; - - updateChannelMemberSchemeRoles = async (channelId: string, userId: string, isSchemeUser: boolean, isSchemeAdmin: boolean) => { - const body = {scheme_user: isSchemeUser, scheme_admin: isSchemeAdmin}; - return this.doFetch( - `${this.getChannelRoute(channelId)}/members/${userId}/schemeRoles`, - {method: 'put', body: JSON.stringify(body)}, - ); - }; - - // Post Routes - - createPost = async (post: Post) => { - analytics.trackAPI('api_posts_create', {channel_id: post.channel_id}); - - if (post.root_id != null && post.root_id !== '') { - analytics.trackAPI('api_posts_replied', {channel_id: post.channel_id}); - } - - return this.doFetch( - `${this.getPostsRoute()}`, - {method: 'post', body: JSON.stringify(post)}, - ); - }; - - updatePost = async (post: Post) => { - analytics.trackAPI('api_posts_update', {channel_id: post.channel_id}); - - return this.doFetch( - `${this.getPostRoute(post.id)}`, - {method: 'put', body: JSON.stringify(post)}, - ); - }; - - getPost = async (postId: string) => { - return this.doFetch( - `${this.getPostRoute(postId)}`, - {method: 'get'}, - ); - }; - - patchPost = async (postPatch: Partial & {id: string}) => { - analytics.trackAPI('api_posts_patch', {channel_id: postPatch.channel_id}); - - return this.doFetch( - `${this.getPostRoute(postPatch.id)}/patch`, - {method: 'put', body: JSON.stringify(postPatch)}, - ); - }; - - deletePost = async (postId: string) => { - analytics.trackAPI('api_posts_delete'); - - return this.doFetch( - `${this.getPostRoute(postId)}`, - {method: 'delete'}, - ); - }; - - getPostThread = async (postId: string) => { - return this.doFetch( - `${this.getPostRoute(postId)}/thread`, - {method: 'get'}, - ); - }; - - getPosts = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/posts${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getPostsUnread = async (channelId: string, userId: string, limitAfter = DEFAULT_LIMIT_AFTER, limitBefore = DEFAULT_LIMIT_BEFORE) => { - return this.doFetch( - `${this.getUserRoute(userId)}/channels/${channelId}/posts/unread${buildQueryString({limit_after: limitAfter, limit_before: limitBefore})}`, - {method: 'get'}, - ); - }; - - getPostsSince = async (channelId: string, since: number) => { - return this.doFetch( - `${this.getChannelRoute(channelId)}/posts${buildQueryString({since})}`, - {method: 'get'}, - ); - }; - - getPostsBefore = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_posts_get_before', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/posts${buildQueryString({before: postId, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getPostsAfter = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_posts_get_after', {channel_id: channelId}); - - return this.doFetch( - `${this.getChannelRoute(channelId)}/posts${buildQueryString({after: postId, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getFileInfosForPost = async (postId: string) => { - return this.doFetch( - `${this.getPostRoute(postId)}/files/info`, - {method: 'get'}, - ); - }; - - getFlaggedPosts = async (userId: string, channelId = '', teamId = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_posts_get_flagged', {team_id: teamId}); - - return this.doFetch( - `${this.getUserRoute(userId)}/posts/flagged${buildQueryString({channel_id: channelId, team_id: teamId, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getPinnedPosts = async (channelId: string) => { - analytics.trackAPI('api_posts_get_pinned', {channel_id: channelId}); - return this.doFetch( - `${this.getChannelRoute(channelId)}/pinned`, - {method: 'get'}, - ); - }; - - markPostAsUnread = async (userId: string, postId: string) => { - analytics.trackAPI('api_post_set_unread_post'); - - return this.doFetch( - `${this.getUserRoute(userId)}/posts/${postId}/set_unread`, - {method: 'post'}, - ); - } - - pinPost = async (postId: string) => { - analytics.trackAPI('api_posts_pin'); - - return this.doFetch( - `${this.getPostRoute(postId)}/pin`, - {method: 'post'}, - ); - }; - - unpinPost = async (postId: string) => { - analytics.trackAPI('api_posts_unpin'); - - return this.doFetch( - `${this.getPostRoute(postId)}/unpin`, - {method: 'post'}, - ); - }; - - addReaction = async (userId: string, postId: string, emojiName: string) => { - analytics.trackAPI('api_reactions_save', {post_id: postId}); - - return this.doFetch( - `${this.getReactionsRoute()}`, - {method: 'post', body: JSON.stringify({user_id: userId, post_id: postId, emoji_name: emojiName})}, - ); - }; - - removeReaction = async (userId: string, postId: string, emojiName: string) => { - analytics.trackAPI('api_reactions_delete', {post_id: postId}); - - return this.doFetch( - `${this.getUserRoute(userId)}/posts/${postId}/reactions/${emojiName}`, - {method: 'delete'}, - ); - }; - - getReactionsForPost = async (postId: string) => { - return this.doFetch( - `${this.getPostRoute(postId)}/reactions`, - {method: 'get'}, - ); - }; - - searchPostsWithParams = async (teamId: string, params: any) => { - analytics.trackAPI('api_posts_search', {team_id: teamId}); - - return this.doFetch( - `${this.getTeamRoute(teamId)}/posts/search`, - {method: 'post', body: JSON.stringify(params)}, - ); - }; - - searchPosts = async (teamId: string, terms: string, isOrSearch: boolean) => { - return this.searchPostsWithParams(teamId, {terms, is_or_search: isOrSearch}); - }; - - getOpenGraphMetadata = async (url: string) => { - return this.doFetch( - `${this.getBaseRoute()}/opengraph`, - {method: 'post', body: JSON.stringify({url})}, - ); - }; - - doPostAction = async (postId: string, actionId: string, selectedOption = '') => { - return this.doPostActionWithCookie(postId, actionId, '', selectedOption); - }; - - doPostActionWithCookie = async (postId: string, actionId: string, actionCookie: string, selectedOption = '') => { - if (selectedOption) { - analytics.trackAPI('api_interactive_messages_menu_selected'); - } else { - analytics.trackAPI('api_interactive_messages_button_clicked'); - } - - const msg: any = { - selected_option: selectedOption, - }; - if (actionCookie !== '') { - msg.cookie = actionCookie; - } - return this.doFetch( - `${this.getPostRoute(postId)}/actions/${encodeURIComponent(actionId)}`, - {method: 'post', body: JSON.stringify(msg)}, - ); - }; - - // Files Routes - - getFileUrl(fileId: string, timestamp: number) { - let url = `${this.getFileRoute(fileId)}`; - if (timestamp) { - url += `?${timestamp}`; - } - - return url; - } - - getFileThumbnailUrl(fileId: string, timestamp: number) { - let url = `${this.getFileRoute(fileId)}/thumbnail`; - if (timestamp) { - url += `?${timestamp}`; - } - - return url; - } - - getFilePreviewUrl(fileId: string, timestamp: number) { - let url = `${this.getFileRoute(fileId)}/preview`; - if (timestamp) { - url += `?${timestamp}`; - } - - return url; - } - - uploadFile = async (fileFormData: any, formBoundary: string) => { - analytics.trackAPI('api_files_upload'); - const request: any = { - method: 'post', - body: fileFormData, - }; - - if (formBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formBoundary}`, - }; - } - - return this.doFetch( - `${this.getFilesRoute()}`, - request, - ); - }; - - getFilePublicLink = async (fileId: string) => { - return this.doFetch( - `${this.getFileRoute(fileId)}/link`, - {method: 'get'}, - ); - } - - // Preference Routes - - savePreferences = async (userId: string, preferences: PreferenceType[]) => { - return this.doFetch( - `${this.getPreferencesRoute(userId)}`, - {method: 'put', body: JSON.stringify(preferences)}, - ); - }; - - getMyPreferences = async () => { - return this.doFetch( - `${this.getPreferencesRoute('me')}`, - {method: 'get'}, - ); - }; - - deletePreferences = async (userId: string, preferences: PreferenceType[]) => { - return this.doFetch( - `${this.getPreferencesRoute(userId)}/delete`, - {method: 'post', body: JSON.stringify(preferences)}, - ); - }; - - // General Routes - - ping = async () => { - return this.doFetch( - `${this.getBaseRoute()}/system/ping?time=${Date.now()}`, - {method: 'get'}, - ); - }; - - logClientError = async (message: string, level = 'ERROR') => { - const url = `${this.getBaseRoute()}/logs`; - - if (!this.enableLogging) { - throw new ClientError(this.getUrl(), { - message: 'Logging disabled.', - url, - }); - } - - return this.doFetch( - url, - {method: 'post', body: JSON.stringify({message, level})}, - ); - }; - - getClientConfigOld = async () => { - return this.doFetch( - `${this.getBaseRoute()}/config/client?format=old`, - {method: 'get'}, - ); - }; - - getClientLicenseOld = async () => { - return this.doFetch( - `${this.getBaseRoute()}/license/client?format=old`, - {method: 'get'}, - ); - }; - - getTranslations = async (url: string) => { - return this.doFetch( - url, - {method: 'get'}, - ); - }; - - getWebSocketUrl = () => { - return `${this.getBaseRoute()}/websocket`; - } - - webrtcToken = async () => { - return this.doFetch( - `${this.getBaseRoute()}/webrtc/token`, - {method: 'get'}, - ); - }; - - // Integration Routes - - createIncomingWebhook = async (hook: IncomingWebhook) => { - analytics.trackAPI('api_integrations_created', {team_id: hook.team_id}); - - return this.doFetch( - `${this.getIncomingHooksRoute()}`, - {method: 'post', body: JSON.stringify(hook)}, - ); - }; - - getIncomingWebhook = async (hookId: string) => { - return this.doFetch( - `${this.getIncomingHookRoute(hookId)}`, - {method: 'get'}, - ); - }; - - getIncomingWebhooks = async (teamId = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - const queryParams: any = { - page, - per_page: perPage, - }; - - if (teamId) { - queryParams.team_id = teamId; - } - - return this.doFetch( - `${this.getIncomingHooksRoute()}${buildQueryString(queryParams)}`, - {method: 'get'}, - ); - }; - - removeIncomingWebhook = async (hookId: string) => { - analytics.trackAPI('api_integrations_deleted'); - - return this.doFetch( - `${this.getIncomingHookRoute(hookId)}`, - {method: 'delete'}, - ); - }; - - updateIncomingWebhook = async (hook: IncomingWebhook) => { - analytics.trackAPI('api_integrations_updated', {team_id: hook.team_id}); - - return this.doFetch( - `${this.getIncomingHookRoute(hook.id)}`, - {method: 'put', body: JSON.stringify(hook)}, - ); - }; - - createOutgoingWebhook = async (hook: OutgoingWebhook) => { - analytics.trackAPI('api_integrations_created', {team_id: hook.team_id}); - - return this.doFetch( - `${this.getOutgoingHooksRoute()}`, - {method: 'post', body: JSON.stringify(hook)}, - ); - }; - - getOutgoingWebhook = async (hookId: string) => { - return this.doFetch( - `${this.getOutgoingHookRoute(hookId)}`, - {method: 'get'}, - ); - }; - - getOutgoingWebhooks = async (channelId = '', teamId = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - const queryParams: any = { - page, - per_page: perPage, - }; - - if (channelId) { - queryParams.channel_id = channelId; - } - - if (teamId) { - queryParams.team_id = teamId; - } - - return this.doFetch( - `${this.getOutgoingHooksRoute()}${buildQueryString(queryParams)}`, - {method: 'get'}, - ); - }; - - removeOutgoingWebhook = async (hookId: string) => { - analytics.trackAPI('api_integrations_deleted'); - - return this.doFetch( - `${this.getOutgoingHookRoute(hookId)}`, - {method: 'delete'}, - ); - }; - - updateOutgoingWebhook = async (hook: OutgoingWebhook) => { - analytics.trackAPI('api_integrations_updated', {team_id: hook.team_id}); - - return this.doFetch( - `${this.getOutgoingHookRoute(hook.id)}`, - {method: 'put', body: JSON.stringify(hook)}, - ); - }; - - regenOutgoingHookToken = async (id: string) => { - return this.doFetch( - `${this.getOutgoingHookRoute(id)}/regen_token`, - {method: 'post'}, - ); - }; - - getCommandsList = async (teamId: string) => { - return this.doFetch( - `${this.getCommandsRoute()}?team_id=${teamId}`, - {method: 'get'}, - ); - }; - - getAutocompleteCommandsList = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/commands/autocomplete${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getCustomTeamCommands = async (teamId: string) => { - return this.doFetch( - `${this.getCommandsRoute()}?team_id=${teamId}&custom_only=true`, - {method: 'get'}, - ); - }; - - executeCommand = async (command: Command, commandArgs = {}) => { - analytics.trackAPI('api_integrations_used'); - - return this.doFetch( - `${this.getCommandsRoute()}/execute`, - {method: 'post', body: JSON.stringify({command, ...commandArgs})}, - ); - }; - - addCommand = async (command: Command) => { - analytics.trackAPI('api_integrations_created'); - - return this.doFetch( - `${this.getCommandsRoute()}`, - {method: 'post', body: JSON.stringify(command)}, - ); - }; - - editCommand = async (command: Command) => { - analytics.trackAPI('api_integrations_created'); - - return this.doFetch( - `${this.getCommandsRoute()}/${command.id}`, - {method: 'put', body: JSON.stringify(command)}, - ); - }; - - regenCommandToken = async (id: string) => { - return this.doFetch( - `${this.getCommandsRoute()}/${id}/regen_token`, - {method: 'put'}, - ); - }; - - deleteCommand = async (id: string) => { - analytics.trackAPI('api_integrations_deleted'); - - return this.doFetch( - `${this.getCommandsRoute()}/${id}`, - {method: 'delete'}, - ); - }; - - createOAuthApp = async (app: OAuthApp) => { - analytics.trackAPI('api_apps_register'); - - return this.doFetch( - `${this.getOAuthAppsRoute()}`, - {method: 'post', body: JSON.stringify(app)}, - ); - }; - - editOAuthApp = async (app: OAuthApp) => { - return this.doFetch( - `${this.getOAuthAppsRoute()}/${app.id}`, - {method: 'put', body: JSON.stringify(app)}, - ); - }; - - getOAuthApps = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getOAuthAppsRoute()}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getOAuthApp = async (appId: string) => { - return this.doFetch( - `${this.getOAuthAppRoute(appId)}`, - {method: 'get'}, - ); - }; - - getOAuthAppInfo = async (appId: string) => { - return this.doFetch( - `${this.getOAuthAppRoute(appId)}/info`, - {method: 'get'}, - ); - }; - - deleteOAuthApp = async (appId: string) => { - analytics.trackAPI('api_apps_delete'); - - return this.doFetch( - `${this.getOAuthAppRoute(appId)}`, - {method: 'delete'}, - ); - }; - - regenOAuthAppSecret = async (appId: string) => { - return this.doFetch( - `${this.getOAuthAppRoute(appId)}/regen_secret`, - {method: 'post'}, - ); - }; - - submitInteractiveDialog = async (data: DialogSubmission) => { - analytics.trackAPI('api_interactive_messages_dialog_submitted'); - return this.doFetch( - `${this.getBaseRoute()}/actions/dialogs/submit`, - {method: 'post', body: JSON.stringify(data)}, - ); - }; - - // Emoji Routes - - createCustomEmoji = async (emoji: CustomEmoji, imageData: any) => { - analytics.trackAPI('api_emoji_custom_add'); - - const formData = new FormData(); - formData.append('image', imageData); - formData.append('emoji', JSON.stringify(emoji)); - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getEmojisRoute()}`, - request, - ); - }; - - getCustomEmoji = async (id: string) => { - return this.doFetch( - `${this.getEmojisRoute()}/${id}`, - {method: 'get'}, - ); - }; - - getCustomEmojiByName = async (name: string) => { - return this.doFetch( - `${this.getEmojisRoute()}/name/${name}`, - {method: 'get'}, - ); - }; - - getCustomEmojis = async (page = 0, perPage = PER_PAGE_DEFAULT, sort = '') => { - return this.doFetch( - `${this.getEmojisRoute()}${buildQueryString({page, per_page: perPage, sort})}`, - {method: 'get'}, - ); - }; - - deleteCustomEmoji = async (emojiId: string) => { - analytics.trackAPI('api_emoji_custom_delete'); - - return this.doFetch( - `${this.getEmojiRoute(emojiId)}`, - {method: 'delete'}, - ); - }; - - getSystemEmojiImageUrl = (filename: string) => { - return `${this.url}/static/emoji/${filename}.png`; - }; - - getCustomEmojiImageUrl = (id: string) => { - return `${this.getEmojiRoute(id)}/image`; - }; - - searchCustomEmoji = async (term: string, options = {}) => { - return this.doFetch( - `${this.getEmojisRoute()}/search`, - {method: 'post', body: JSON.stringify({term, ...options})}, - ); - }; - - autocompleteCustomEmoji = async (name: string) => { - return this.doFetch( - `${this.getEmojisRoute()}/autocomplete${buildQueryString({name})}`, - {method: 'get'}, - ); - }; - - // Timezone Routes - - getTimezones = async () => { - return this.doFetch( - `${this.getTimezonesRoute()}`, - {method: 'get'}, - ); - }; - - // Data Retention - - getDataRetentionPolicy = () => { - return this.doFetch( - `${this.getDataRetentionRoute()}/policy`, - {method: 'get'}, - ); - }; - - // Jobs Routes - - getJob = async (id: string) => { - return this.doFetch( - `${this.getJobsRoute()}/${id}`, - {method: 'get'}, - ); - }; - - getJobs = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getJobsRoute()}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getJobsByType = async (type: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getJobsRoute()}/type/${type}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - createJob = async (job: Job) => { - return this.doFetch( - `${this.getJobsRoute()}`, - {method: 'post', body: JSON.stringify(job)}, - ); - }; - - cancelJob = async (id: string) => { - return this.doFetch( - `${this.getJobsRoute()}/${id}/cancel`, - {method: 'post'}, - ); - }; - - // Admin Routes - - getLogs = async (page = 0, perPage = LOGS_PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBaseRoute()}/logs${buildQueryString({page, logs_per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getAudits = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBaseRoute()}/audits${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getConfig = async () => { - return this.doFetch( - `${this.getBaseRoute()}/config`, - {method: 'get'}, - ); - }; - - updateConfig = async (config: Config) => { - return this.doFetch( - `${this.getBaseRoute()}/config`, - {method: 'put', body: JSON.stringify(config)}, - ); - }; - - reloadConfig = async () => { - return this.doFetch( - `${this.getBaseRoute()}/config/reload`, - {method: 'post'}, - ); - }; - - getEnvironmentConfig = async () => { - return this.doFetch( - `${this.getBaseRoute()}/config/environment`, - {method: 'get'}, - ); - }; - - testEmail = async (config: Config) => { - return this.doFetch( - `${this.getBaseRoute()}/email/test`, - {method: 'post', body: JSON.stringify(config)}, - ); - }; - - testSiteURL = async (siteURL: string) => { - return this.doFetch( - `${this.getBaseRoute()}/site_url/test`, - {method: 'post', body: JSON.stringify({site_url: siteURL})}, - ); - }; - - testS3Connection = async (config: Config) => { - return this.doFetch( - `${this.getBaseRoute()}/file/s3_test`, - {method: 'post', body: JSON.stringify(config)}, - ); - }; - - invalidateCaches = async () => { - return this.doFetch( - `${this.getBaseRoute()}/caches/invalidate`, - {method: 'post'}, - ); - }; - - recycleDatabase = async () => { - return this.doFetch( - `${this.getBaseRoute()}/database/recycle`, - {method: 'post'}, - ); - }; - - createComplianceReport = async (job: Job) => { - return this.doFetch( - `${this.getBaseRoute()}/compliance/reports`, - {method: 'post', body: JSON.stringify(job)}, - ); - }; - - getComplianceReport = async (reportId: string) => { - return this.doFetch( - `${this.getBaseRoute()}/compliance/reports/${reportId}`, - {method: 'get'}, - ); - }; - - getComplianceReports = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBaseRoute()}/compliance/reports${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - uploadBrandImage = async (imageData: any) => { - const formData = new FormData(); - formData.append('image', imageData); - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getBrandRoute()}/image`, - request, - ); - }; - - deleteBrandImage = async () => { - return this.doFetch( - `${this.getBrandRoute()}/image`, - {method: 'delete'}, - ); - }; - - getClusterStatus = async () => { - return this.doFetch( - `${this.getBaseRoute()}/cluster/status`, - {method: 'get'}, - ); - }; - - testLdap = async () => { - return this.doFetch( - `${this.getBaseRoute()}/ldap/test`, - {method: 'post'}, - ); - }; - - syncLdap = async () => { - return this.doFetch( - `${this.getBaseRoute()}/ldap/sync`, - {method: 'post'}, - ); - }; - - getLdapGroups = async (page = 0, perPage = PER_PAGE_DEFAULT, opts = {}) => { - const query = {page, per_page: perPage, ...opts}; - return this.doFetch( - `${this.getBaseRoute()}/ldap/groups${buildQueryString(query)}`, - {method: 'get'}, - ); - }; - - linkLdapGroup = async (key: string) => { - return this.doFetch( - `${this.getBaseRoute()}/ldap/groups/${encodeURI(key)}/link`, - {method: 'post'}, - ); - }; - - unlinkLdapGroup = async (key: string) => { - return this.doFetch( - `${this.getBaseRoute()}/ldap/groups/${encodeURI(key)}/link`, - {method: 'delete'}, - ); - }; - - getSamlCertificateStatus = async () => { - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/status`, - {method: 'get'}, - ); - }; - - uploadPublicSamlCertificate = async (fileData: any) => { - const formData = new FormData(); - formData.append('certificate', fileData); - - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/public`, - { - method: 'post', - body: formData, - }, - ); - }; - - uploadPrivateSamlCertificate = async (fileData: any) => { - const formData = new FormData(); - formData.append('certificate', fileData); - - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/private`, - { - method: 'post', - body: formData, - }, - ); - }; - - uploadIdpSamlCertificate = async (fileData: any) => { - const formData = new FormData(); - formData.append('certificate', fileData); - - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/idp`, - { - method: 'post', - body: formData, - }, - ); - }; - - deletePublicSamlCertificate = async () => { - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/public`, - {method: 'delete'}, - ); - }; - - deletePrivateSamlCertificate = async () => { - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/private`, - {method: 'delete'}, - ); - }; - - deleteIdpSamlCertificate = async () => { - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/idp`, - {method: 'delete'}, - ); - }; - - testElasticsearch = async (config: Config) => { - return this.doFetch( - `${this.getBaseRoute()}/elasticsearch/test`, - {method: 'post', body: JSON.stringify(config)}, - ); - }; - - purgeElasticsearchIndexes = async () => { - return this.doFetch( - `${this.getBaseRoute()}/elasticsearch/purge_indexes`, - {method: 'post'}, - ); - }; - - uploadLicense = async (fileData: any) => { - analytics.trackAPI('api_license_upload'); - - const formData = new FormData(); - formData.append('license', fileData); - - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - `${this.getBaseRoute()}/license`, - request, - ); - }; - - removeLicense = async () => { - return this.doFetch( - `${this.getBaseRoute()}/license`, - {method: 'delete'}, - ); - }; - - getAnalytics = async (name = 'standard', teamId = '') => { - return this.doFetch( - `${this.getBaseRoute()}/analytics/old${buildQueryString({name, team_id: teamId})}`, - {method: 'get'}, - ); - }; - - // Role Routes - - getRole = async (roleId: string) => { - return this.doFetch( - `${this.getRolesRoute()}/${roleId}`, - {method: 'get'}, - ); - }; - - getRoleByName = async (roleName: string) => { - return this.doFetch( - `${this.getRolesRoute()}/name/${roleName}`, - {method: 'get'}, - ); - }; - - getRolesByNames = async (rolesNames: string[]) => { - return this.doFetch( - `${this.getRolesRoute()}/names`, - {method: 'post', body: JSON.stringify(rolesNames)}, - ); - }; - - patchRole = async (roleId: string, rolePatch: Partial) => { - return this.doFetch( - `${this.getRolesRoute()}/${roleId}/patch`, - {method: 'put', body: JSON.stringify(rolePatch)}, - ); - }; - - // Scheme Routes - - getSchemes = async (scope = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getSchemesRoute()}${buildQueryString({scope, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - createScheme = async (scheme: Scheme) => { - analytics.trackAPI('api_schemes_create'); - - return this.doFetch( - `${this.getSchemesRoute()}`, - {method: 'post', body: JSON.stringify(scheme)}, - ); - }; - - getScheme = async (schemeId: string) => { - return this.doFetch( - `${this.getSchemesRoute()}/${schemeId}`, - {method: 'get'}, - ); - }; - - deleteScheme = async (schemeId: string) => { - analytics.trackAPI('api_schemes_delete'); - - return this.doFetch( - `${this.getSchemesRoute()}/${schemeId}`, - {method: 'delete'}, - ); - }; - - patchScheme = async (schemeId: string, schemePatch: Partial) => { - analytics.trackAPI('api_schemes_patch', {scheme_id: schemeId}); - - return this.doFetch( - `${this.getSchemesRoute()}/${schemeId}/patch`, - {method: 'put', body: JSON.stringify(schemePatch)}, - ); - }; - - getSchemeTeams = async (schemeId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getSchemesRoute()}/${schemeId}/teams${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getSchemeChannels = async (schemeId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getSchemesRoute()}/${schemeId}/channels${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - // Plugin Routes - EXPERIMENTAL - SUBJECT TO CHANGE - - uploadPlugin = async (fileData: any, force = false) => { - analytics.trackAPI('api_plugin_upload'); - - const formData = new FormData(); - if (force) { - formData.append('force', 'true'); - } - formData.append('plugin', fileData); - - const request: any = { - method: 'post', - body: formData, - }; - - if (formData.getBoundary) { - request.headers = { - 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, - }; - } - - return this.doFetch( - this.getPluginsRoute(), - request, - ); - }; - - installPluginFromUrl = async (pluginDownloadUrl: string, force = false) => { - analytics.trackAPI('api_install_plugin'); - - const queryParams = {plugin_download_url: pluginDownloadUrl, force}; - - return this.doFetch( - `${this.getPluginsRoute()}/install_from_url${buildQueryString(queryParams)}`, - {method: 'post'}, - ); - }; - - getPlugins = async () => { - return this.doFetch( - this.getPluginsRoute(), - {method: 'get'}, - ); - }; - - getMarketplacePlugins = async (filter: string, localOnly = false) => { - return this.doFetch( - `${this.getPluginsMarketplaceRoute()}${buildQueryString({filter: filter || '', local_only: localOnly})}`, - {method: 'get'}, - ); - } - - installMarketplacePlugin = async (id: string, version: string) => { - analytics.trackAPI('api_install_marketplace_plugin'); - - return this.doFetch( - `${this.getPluginsMarketplaceRoute()}`, - {method: 'post', body: JSON.stringify({id, version})}, - ); - } - - getPluginStatuses = async () => { - return this.doFetch( - `${this.getPluginsRoute()}/statuses`, - {method: 'get'}, - ); - }; - - removePlugin = async (pluginId: string) => { - return this.doFetch( - this.getPluginRoute(pluginId), - {method: 'delete'}, - ); - }; - - getWebappPlugins = async () => { - return this.doFetch( - `${this.getPluginsRoute()}/webapp`, - {method: 'get'}, - ); - }; - - enablePlugin = async (pluginId: string) => { - return this.doFetch( - `${this.getPluginRoute(pluginId)}/enable`, - {method: 'post'}, - ); - }; - - disablePlugin = async (pluginId: string) => { - return this.doFetch( - `${this.getPluginRoute(pluginId)}/disable`, - {method: 'post'}, - ); - }; - - getCommandAutocompleteSuggestionsList = (userInput: string, teamId: string, commandArgs: {}) => { - return this.doFetch( - `${this.getTeamRoute(teamId)}/commands/autocomplete_suggestions${buildQueryString({...commandArgs, user_input: userInput})}`, - {method: 'get'}, - ); - }; - - // Groups - - linkGroupSyncable = async (groupID: string, syncableID: string, syncableType: string, patch: SyncablePatch) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}/${syncableType}s/${syncableID}/link`, - {method: 'post', body: JSON.stringify(patch)}, - ); - }; - - unlinkGroupSyncable = async (groupID: string, syncableID: string, syncableType: string) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}/${syncableType}s/${syncableID}/link`, - {method: 'delete'}, - ); - }; - - getGroupSyncables = async (groupID: string, syncableType: string) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}/${syncableType}s`, - {method: 'get'}, - ); - }; - - getGroupMembers = async (groupID: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}/members${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getGroup = async (groupID: string) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}`, - {method: 'get'}, - ); - }; - - getGroups = async (filterAllowReference = false, page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBaseRoute()}/groups${buildQueryString({filter_allow_reference: filterAllowReference, page, per_page: perPage})}`, - {method: 'get'}, - ); - }; - - getGroupsByUserId = async (userID: string) => { - return this.doFetch( - `${this.getUsersRoute()}/${userID}/groups`, - {method: 'get'}, - ); - } - - getGroupsNotAssociatedToTeam = async (teamID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_groups_get_not_associated_to_team', {team_id: teamID}); - return this.doFetch( - `${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_team: teamID, page, per_page: perPage, q, include_member_count: true})}`, - {method: 'get'}, - ); - }; - - getGroupsNotAssociatedToChannel = async (channelID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - analytics.trackAPI('api_groups_get_not_associated_to_channel', {channel_id: channelID}); - return this.doFetch( - `${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_channel: channelID, page, per_page: perPage, q, include_member_count: true})}`, - {method: 'get'}, - ); - }; - - getGroupsAssociatedToTeam = async (teamID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT, filterAllowReference = false) => { - analytics.trackAPI('api_groups_get_associated_to_team', {team_id: teamID}); - - return this.doFetch( - `${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true, filter_allow_reference: filterAllowReference})}`, - {method: 'get'}, - ); - }; - - getGroupsAssociatedToChannel = async (channelID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT, filterAllowReference = false) => { - analytics.trackAPI('api_groups_get_associated_to_channel', {channel_id: channelID}); - - return this.doFetch( - `${this.getBaseRoute()}/channels/${channelID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true, filter_allow_reference: filterAllowReference})}`, - {method: 'get'}, - ); - }; - - getAllGroupsAssociatedToTeam = async (teamID: string, filterAllowReference = false) => { - return this.doFetch( - `${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, - {method: 'get'}, - ); - }; - - getAllGroupsAssociatedToChannelsInTeam = async (teamID: string, filterAllowReference = false) => { - return this.doFetch( - `${this.getBaseRoute()}/teams/${teamID}/groups_by_channels${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, - {method: 'get'}, - ); - }; - - getAllGroupsAssociatedToChannel = async (channelID: string, filterAllowReference = false) => { - return this.doFetch( - `${this.getBaseRoute()}/channels/${channelID}/groups${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`, - {method: 'get'}, - ); - }; - - patchGroupSyncable = async (groupID: string, syncableID: string, syncableType: string, patch: SyncablePatch) => { - return this.doFetch( - `${this.getBaseRoute()}/groups/${groupID}/${syncableType}s/${syncableID}/patch`, - {method: 'put', body: JSON.stringify(patch)}, - ); - }; - - // Redirect Location - - getRedirectLocation = async (urlParam: string) => { - if (!urlParam.length) { - return Promise.resolve(); - } - const url = `${this.getRedirectLocationRoute()}${buildQueryString({url: urlParam})}`; - return this.doFetch(url, {method: 'get'}); - }; - - // Bot Routes - - createBot = async (bot: Bot) => { - return this.doFetch( - `${this.getBotsRoute()}`, - {method: 'post', body: JSON.stringify(bot)}, - ); - } - - patchBot = async (botUserId: string, botPatch: BotPatch) => { - return this.doFetch( - `${this.getBotRoute(botUserId)}`, - {method: 'put', body: JSON.stringify(botPatch)}, - ); - } - - getBot = async (botUserId: string) => { - return this.doFetch( - `${this.getBotRoute(botUserId)}`, - {method: 'get'}, - ); - } - - getBots = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBotsRoute()}${buildQueryString({page, per_page: perPage})}`, - {method: 'get'}, - ); - } - - getBotsIncludeDeleted = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBotsRoute()}${buildQueryString({include_deleted: true, page, per_page: perPage})}`, - {method: 'get'}, - ); - } - - getBotsOrphaned = async (page = 0, perPage = PER_PAGE_DEFAULT) => { - return this.doFetch( - `${this.getBotsRoute()}${buildQueryString({only_orphaned: true, page, per_page: perPage})}`, - {method: 'get'}, - ); - } - - disableBot = async (botUserId: string) => { - return this.doFetch( - `${this.getBotRoute(botUserId)}/disable`, - {method: 'post'}, - ); - } - - enableBot = async (botUserId: string) => { - return this.doFetch( - `${this.getBotRoute(botUserId)}/enable`, - {method: 'post'}, - ); - } - - assignBot = async (botUserId: string, newOwnerId: string) => { - return this.doFetch( - `${this.getBotRoute(botUserId)}/assign/${newOwnerId}`, - {method: 'post'}, - ); - } - - teamMembersMinusGroupMembers = async (teamID: string, groupIDs: string[], page: number, perPage: number) => { - const query = `group_ids=${groupIDs.join(',')}&page=${page}&per_page=${perPage}`; - return this.doFetch( - `${this.getTeamRoute(teamID)}/members_minus_group_members?${query}`, - {method: 'get'}, - ); - } - - channelMembersMinusGroupMembers = async (channelID: string, groupIDs: string[], page: number, perPage: number) => { - const query = `group_ids=${groupIDs.join(',')}&page=${page}&per_page=${perPage}`; - return this.doFetch( - `${this.getChannelRoute(channelID)}/members_minus_group_members?${query}`, - {method: 'get'}, - ); - } - - getSamlMetadataFromIdp = async (samlMetadataURL: string) => { - return this.doFetch( - `${this.getBaseRoute()}/saml/metadatafromidp`, {method: 'post', body: JSON.stringify({saml_metadata_url: samlMetadataURL})}, - ); - }; - - setSamlIdpCertificateFromMetadata = async (certData: string) => { - const request: any = { - method: 'post', - body: certData, - }; - - request.headers = { - 'Content-Type': 'application/x-pem-file', - }; - - return this.doFetch( - `${this.getBaseRoute()}/saml/certificate/idp`, - request, - ); - }; - - // Apps - - getAppsProxyRoute() { - return `${this.url}/plugins/com.mattermost.apps`; - } - - executeAppCall = async (call: AppCallRequest, type: AppCallType) => { - const callCopy = { - ...call, - path: `${call.path}/${type}`, - context: { - ...call.context, - user_agent: 'mobile', - }, - }; - - return this.doFetch( - `${this.getAppsProxyRoute()}/api/v1/call`, - {method: 'post', body: JSON.stringify(callCopy)}, - ); - } - - getAppsBindings = async (userID: string, channelID: string) => { - return this.doFetch( - this.getAppsProxyRoute() + `/api/v1/bindings?user_id=${userID}&channel_id=${channelID}&user_agent_type=mobile`, - {method: 'get'}, - ); - } - - // Client Helpers - - doFetch = async (url: string, options: Options) => { - const {data} = await this.doFetchWithResponse(url, options); - - return data; - }; - - doFetchWithResponse = async (url: string, options: Options) => { - const response = await fetch(url, this.getOptions(options)); - const headers = parseAndMergeNestedHeaders(response.headers); - - let data; - try { - data = await response.json(); - } catch (err) { - throw new ClientError(this.getUrl(), { - message: 'Received invalid response from the server.', - intl: { - id: 'mobile.request.invalid_response', - defaultMessage: 'Received invalid response from the server.', - }, - url, - }); - } - - if (headers.has(HEADER_X_VERSION_ID) && !headers.get('Cache-Control')) { - const serverVersion = headers.get(HEADER_X_VERSION_ID); - if (serverVersion && this.serverVersion !== serverVersion) { - this.serverVersion = serverVersion; - } - } - - if (headers.has(HEADER_X_CLUSTER_ID)) { - const clusterId = headers.get(HEADER_X_CLUSTER_ID); - if (clusterId && this.clusterId !== clusterId) { - this.clusterId = clusterId; - } - } - - if (response.ok) { - return { - response, - headers, - data, - }; - } - - const msg = data.message || ''; - - if (this.logToConsole) { - console.error(msg); // eslint-disable-line no-console - } - - throw new ClientError(this.getUrl(), { - message: msg, - server_error_id: data.id, - status_code: data.status_code, - url, - }); - }; -} - -function parseAndMergeNestedHeaders(originalHeaders: any) { - const headers = new Map(); - let nestedHeaders = new Map(); - originalHeaders.forEach((val: string, key: string) => { - const capitalizedKey = key.replace(/\b[a-z]/g, (l) => l.toUpperCase()); - let realVal = val; - if (val && val.match(/\n\S+:\s\S+/)) { - const nestedHeaderStrings = val.split('\n'); - realVal = nestedHeaderStrings.shift() as string; - const moreNestedHeaders = new Map( - nestedHeaderStrings.map((h: any) => h.split(/:\s/)), - ); - nestedHeaders = new Map([...nestedHeaders, ...moreNestedHeaders]); - } - headers.set(capitalizedKey, realVal); - }); - return new Map([...headers, ...nestedHeaders]); -} - -export class ClientError extends Error { - url: string; - intl: { defaultMessage: string; id: string } | { defaultMessage: string; id: string } | { id: string; defaultMessage: string; values: any } | { id: string; defaultMessage: string }; - server_error_id: any; - status_code: any; - details: Error; - constructor(baseUrl: string, data: any) { - super(data.message + ': ' + cleanUrlForLogging(baseUrl, data.url)); - - this.message = data.message; - this.url = data.url; - this.intl = data.intl; - this.server_error_id = data.server_error_id; - this.status_code = data.status_code; - this.details = data.details; - - // Ensure message is treated as a property of this class when object spreading. Without this, - // copying the object by using `{...error}` would not include the message. - Object.defineProperty(this, 'message', {enumerable: true}); - } -} diff --git a/app/mm-redux/client/fetch_etag.ts b/app/mm-redux/client/fetch_etag.ts deleted file mode 100644 index 90eddba28..000000000 --- a/app/mm-redux/client/fetch_etag.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {Options} from '@mm-redux/types/client4'; - -const data: {[x: string]: any} = {}; -const etags: {[x: string]: string} = {}; -export default ((url?: string, options: Options = {headers: {}}) => { - url = url || options.url; // eslint-disable-line no-param-reassign - - if (options.method === 'GET' || !options.method) { - const etag = etags[url!]; - const cachedResponse = data[`${url}${etag}`]; // ensure etag is for url - if (etag) { - options.headers!['If-None-Match'] = etag; - } - - return fetch(url!, options). - then((response) => { - if (response.status === 304) { - return cachedResponse.clone(); - } - - if (response.status === 200) { - const responseEtag = response.headers.get('Etag'); - - if (responseEtag) { - data[`${url}${responseEtag}`] = response.clone(); - etags[url!] = responseEtag; - } - } - - return response; - }); - } - - // all other requests go straight to fetch - return Reflect.apply(fetch, undefined, [url, options]); -}); diff --git a/app/mm-redux/client/index.ts b/app/mm-redux/client/index.ts deleted file mode 100644 index f1e500cfd..000000000 --- a/app/mm-redux/client/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import ClientClass4, {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './client4'; -const Client4 = new ClientClass4(); -export {Client4, DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID}; diff --git a/app/mm-redux/constants/general.ts b/app/mm-redux/constants/general.ts index c4f59027d..c16392748 100644 --- a/app/mm-redux/constants/general.ts +++ b/app/mm-redux/constants/general.ts @@ -6,11 +6,9 @@ export default { PAGE_SIZE_DEFAULT: 60, PAGE_SIZE_MAXIMUM: 200, LOGS_PAGE_SIZE_DEFAULT: 10000, - AUDITS_CHUNK_SIZE: 100, PROFILE_CHUNK_SIZE: 100, CHANNELS_CHUNK_SIZE: 50, TEAMS_CHUNK_SIZE: 50, - JOBS_CHUNK_SIZE: 50, SEARCH_TIMEOUT_MILLISECONDS: 100, STATUS_INTERVAL: 60000, AUTOCOMPLETE_LIMIT_DEFAULT: 25, diff --git a/app/mm-redux/reducers/entities/channels.test.js b/app/mm-redux/reducers/entities/channels.test.js index 973a9cf34..0391b4153 100644 --- a/app/mm-redux/reducers/entities/channels.test.js +++ b/app/mm-redux/reducers/entities/channels.test.js @@ -6,8 +6,6 @@ import deepFreeze from '@mm-redux/utils/deep_freeze'; import channelsReducer, * as Reducers from './channels'; -import {Permissions} from '../../constants'; - describe('channels', () => { describe('RECEIVED_CHANNEL_DELETED', () => { test('should mark channel as deleted', () => { @@ -28,7 +26,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -66,7 +63,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -102,7 +98,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -139,7 +134,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -174,7 +168,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -213,7 +206,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -249,7 +241,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -288,7 +279,6 @@ describe('channels', () => { id: 'channel2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -323,7 +313,6 @@ describe('channels', () => { memberId2: 'member-data-2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -357,7 +346,6 @@ describe('channels', () => { memberId2: 'member-data-2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -390,7 +378,6 @@ describe('channels', () => { memberId2: 'member-data-2', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -469,7 +456,6 @@ describe('channels', () => { team_id: 'team', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -499,98 +485,6 @@ describe('channels', () => { }); }); - describe('RECEIVED_CHANNEL_MODERATIONS', () => { - test('Should add new channel moderations', () => { - const state = deepFreeze({ - channelsInTeam: {}, - currentChannelId: '', - groupsAssociatedToChannel: {}, - myMembers: {}, - stats: {}, - totalCount: 0, - membersInChannel: {}, - channels: { - channel1: { - id: 'channel1', - team_id: 'team', - }, - }, - channelModerations: {}, - channelMemberCountsByGroup: {}, - }); - - const nextState = channelsReducer(state, { - type: ChannelTypes.RECEIVED_CHANNEL_MODERATIONS, - sync: true, - currentChannelId: 'channel1', - teamId: 'team', - data: { - channelId: 'channel1', - moderations: [ - { - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST, - roles: { - members: true, - }, - }, - ], - }, - }); - - expect(nextState.channelModerations.channel1[0].name).toEqual(Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST); - expect(nextState.channelModerations.channel1[0].roles.members).toEqual(true); - }); - test('Should replace existing channel moderations', () => { - const state = deepFreeze({ - channelsInTeam: {}, - currentChannelId: '', - groupsAssociatedToChannel: {}, - myMembers: {}, - stats: {}, - totalCount: 0, - membersInChannel: {}, - channels: { - channel1: { - id: 'channel1', - team_id: 'team', - }, - }, - channelModerations: { - channel1: [{ - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST, - roles: { - members: true, - }, - }], - }, - channelMemberCountsByGroup: {}, - }); - - const nextState = channelsReducer(state, { - type: ChannelTypes.RECEIVED_CHANNEL_MODERATIONS, - sync: true, - currentChannelId: 'channel1', - teamId: 'team', - data: { - channelId: 'channel1', - moderations: [ - { - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_REACTIONS, - roles: { - members: true, - guests: false, - }, - }, - ], - }, - }); - - expect(nextState.channelModerations.channel1[0].name).toEqual(Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_REACTIONS); - expect(nextState.channelModerations.channel1[0].roles.members).toEqual(true); - expect(nextState.channelModerations.channel1[0].roles.guests).toEqual(false); - }); - }); - describe('RECEIVED_CHANNEL_MEMBER_COUNTS_BY_GROUP', () => { test('Should add new channel member counts', () => { const state = deepFreeze({ @@ -607,7 +501,6 @@ describe('channels', () => { team_id: 'team', }, }, - channelModerations: {}, channelMemberCountsByGroup: {}, }); @@ -655,7 +548,6 @@ describe('channels', () => { team_id: 'team', }, }, - channelModerations: {}, channelMemberCountsByGroup: { 'group-1': { group_id: 'group-1', diff --git a/app/mm-redux/reducers/entities/channels.ts b/app/mm-redux/reducers/entities/channels.ts index 49b2edb4a..841855340 100644 --- a/app/mm-redux/reducers/entities/channels.ts +++ b/app/mm-redux/reducers/entities/channels.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {combineReducers} from 'redux'; -import {ChannelTypes, UserTypes, SchemeTypes, GroupTypes} from '@mm-redux/action_types'; +import {ChannelTypes, UserTypes, GroupTypes} from '@mm-redux/action_types'; import {General} from '../../constants'; import {GenericAction} from '@mm-redux/types/actions'; import {Channel, ChannelMembership, ChannelStats, ChannelMemberCountByGroup, ChannelMemberCountsByGroup} from '@mm-redux/types/channels'; @@ -59,8 +59,7 @@ function channels(state: IDMappedObjects = {}, action: GenericAction) { [action.data.id]: action.data, }; case ChannelTypes.RECEIVED_CHANNELS: - case ChannelTypes.RECEIVED_ALL_CHANNELS: - case SchemeTypes.RECEIVED_SCHEME_CHANNELS: { + case ChannelTypes.RECEIVED_ALL_CHANNELS: { const nextState = {...state}; for (const channel of action.data) { @@ -155,17 +154,6 @@ function channels(state: IDMappedObjects = {}, action: GenericAction) { }, }; } - case ChannelTypes.UPDATED_CHANNEL_SCHEME: { - const {channelId, schemeId} = action.data; - const channel = state[channelId]; - - if (!channel) { - return state; - } - - return {...state, [channelId]: {...channel, scheme_id: schemeId}}; - } - case ChannelTypes.RECEIVED_MY_CHANNELS_WITH_MEMBERS: { // Used by the mobile app const nextState = {...state}; const myChannels: Array = action.data.channels; @@ -349,9 +337,6 @@ function myMembers(state: RelationOneToOne = {}, act return state; } - case ChannelTypes.UPDATED_CHANNEL_MEMBER_SCHEME_ROLES: { - return updateChannelMemberSchemeRoles(state, action); - } case ChannelTypes.POST_UNREAD_SUCCESS: { const data = action.data; const channelState = state[data.channelId]; @@ -455,9 +440,6 @@ function membersInChannel(state: RelationOneToOne = {}, a } } -export function channelModerations(state: any = {}, action: GenericAction) { - switch (action.type) { - case ChannelTypes.RECEIVED_CHANNEL_MODERATIONS: { - const {channelId, moderations} = action.data; - return { - ...state, - [channelId]: moderations, - }; - } - default: - return state; - } -} - export function channelMemberCountsByGroup(state: any = {}, action: GenericAction) { switch (action.type) { case ChannelTypes.RECEIVED_CHANNEL_MEMBER_COUNTS_BY_GROUP: { @@ -718,9 +664,6 @@ export default combineReducers({ // object where every key is the channel id, if present means a user requested to mark that channel as unread. manuallyUnread, - // object where every key is the channel id and has an object with the channel moderations - channelModerations, - // object where every key is the channel id containing one or several object(s) with a mapping of channelMemberCountsByGroup, }); diff --git a/app/mm-redux/reducers/entities/index.ts b/app/mm-redux/reducers/entities/index.ts index 5e58d7aa7..f21f2d422 100644 --- a/app/mm-redux/reducers/entities/index.ts +++ b/app/mm-redux/reducers/entities/index.ts @@ -14,10 +14,8 @@ import typing from './typing'; import integrations from './integrations'; import emojis from './emojis'; import gifs from './gifs'; -import jobs from './jobs'; import search from './search'; import roles from './roles'; -import schemes from './schemes'; import groups from './groups'; import bots from './bots'; import channelCategories from './channel_categories'; @@ -35,10 +33,8 @@ export default combineReducers({ integrations, emojis, gifs, - jobs, search, roles, - schemes, groups, bots, channelCategories, diff --git a/app/mm-redux/reducers/entities/integrations.ts b/app/mm-redux/reducers/entities/integrations.ts index 22dd436d8..85f80366c 100644 --- a/app/mm-redux/reducers/entities/integrations.ts +++ b/app/mm-redux/reducers/entities/integrations.ts @@ -2,97 +2,14 @@ // See LICENSE.txt for license information. import {combineReducers} from 'redux'; -import {IntegrationTypes, ChannelTypes} from '@mm-redux/action_types'; +import {IntegrationTypes} from '@mm-redux/action_types'; import {GenericAction} from '@mm-redux/types/actions'; -import {Command, IncomingWebhook, OutgoingWebhook, OAuthApp, AutocompleteSuggestion} from '@mm-redux/types/integrations'; +import {Command, AutocompleteSuggestion} from '@mm-redux/types/integrations'; import {Dictionary, IDMappedObjects} from '@mm-redux/types/utilities'; -function incomingHooks(state: IDMappedObjects = {}, action: GenericAction) { - switch (action.type) { - case IntegrationTypes.RECEIVED_INCOMING_HOOK: { - const nextState = {...state}; - nextState[action.data.id] = action.data; - return nextState; - } - case IntegrationTypes.RECEIVED_INCOMING_HOOKS: { - const nextState = {...state}; - for (const hook of action.data) { - nextState[hook.id] = hook; - } - return nextState; - } - case IntegrationTypes.DELETED_INCOMING_HOOK: { - const nextState = {...state}; - Reflect.deleteProperty(nextState, action.data.id); - return nextState; - } - case ChannelTypes.RECEIVED_CHANNEL_DELETED: { - const nextState = {...state}; - let deleted = false; - Object.keys(nextState).forEach((id) => { - if (nextState[id].channel_id === action.data.id) { - deleted = true; - Reflect.deleteProperty(nextState, id); - } - }); - - if (deleted) { - return nextState; - } - - return state; - } - - default: - return state; - } -} - -function outgoingHooks(state: IDMappedObjects = {}, action: GenericAction) { - switch (action.type) { - case IntegrationTypes.RECEIVED_OUTGOING_HOOK: { - const nextState = {...state}; - nextState[action.data.id] = action.data; - return nextState; - } - case IntegrationTypes.RECEIVED_OUTGOING_HOOKS: { - const nextState = {...state}; - for (const hook of action.data) { - nextState[hook.id] = hook; - } - return nextState; - } - case IntegrationTypes.DELETED_OUTGOING_HOOK: { - const nextState = {...state}; - Reflect.deleteProperty(nextState, action.data.id); - return nextState; - } - case ChannelTypes.RECEIVED_CHANNEL_DELETED: { - const nextState = {...state}; - let deleted = false; - Object.keys(nextState).forEach((id) => { - if (nextState[id].channel_id === action.data.id) { - deleted = true; - Reflect.deleteProperty(nextState, id); - } - }); - - if (deleted) { - return nextState; - } - - return state; - } - - default: - return state; - } -} - function commands(state: IDMappedObjects = {}, action: GenericAction) { switch (action.type) { - case IntegrationTypes.RECEIVED_COMMANDS: - case IntegrationTypes.RECEIVED_CUSTOM_TEAM_COMMANDS: { + case IntegrationTypes.RECEIVED_COMMANDS: { const nextState = {...state}; for (const command of action.data) { if (command.id) { @@ -170,31 +87,6 @@ function commandAutocompleteSuggestions(state: Array = [ } } -function oauthApps(state: IDMappedObjects = {}, action: GenericAction) { - switch (action.type) { - case IntegrationTypes.RECEIVED_OAUTH_APPS: { - const nextState = {...state}; - for (const app of action.data) { - nextState[app.id] = app; - } - return nextState; - } - case IntegrationTypes.RECEIVED_OAUTH_APP: - return { - ...state, - [action.data.id]: action.data, - }; - case IntegrationTypes.DELETED_OAUTH_APP: { - const nextState = {...state}; - Reflect.deleteProperty(nextState, action.data.id); - return nextState; - } - - default: - return state; - } -} - function dialogTriggerId(state = '', action: GenericAction) { switch (action.type) { case IntegrationTypes.RECEIVED_DIALOG_TRIGGER_ID: @@ -215,18 +107,9 @@ function dialog(state = '', action: GenericAction) { export default combineReducers({ - // object where every key is the hook id and has an object with the incoming hook details - incomingHooks, - - // object where every key is the hook id and has an object with the outgoing hook details - outgoingHooks, - // object to represent installed slash commands for a current team commands, - // object to represent registered oauth apps with app id as the key - oauthApps, - // object to represent built-in slash commands systemCommands, diff --git a/app/mm-redux/reducers/entities/jobs.ts b/app/mm-redux/reducers/entities/jobs.ts deleted file mode 100644 index 9fb2650ac..000000000 --- a/app/mm-redux/reducers/entities/jobs.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {combineReducers} from 'redux'; -import {JobTypes} from '@mm-redux/action_types'; -import {JobsState, JobType, Job, JobsByType} from '@mm-redux/types/jobs'; -import {GenericAction} from '@mm-redux/types/actions'; -import {IDMappedObjects} from '@mm-redux/types/utilities'; - -function jobs(state: IDMappedObjects = {}, action: GenericAction): IDMappedObjects { - switch (action.type) { - case JobTypes.RECEIVED_JOB: { - const nextState = {...state}; - nextState[action.data.id] = action.data; - return nextState; - } - case JobTypes.RECEIVED_JOBS: { - const nextState = {...state}; - for (const job of action.data) { - nextState[job.id] = job; - } - return nextState; - } - default: - return state; - } -} - -function jobsByTypeList(state: JobsByType = {}, action: GenericAction): JobsByType { - switch (action.type) { - case JobTypes.RECEIVED_JOBS_BY_TYPE: { - const nextState = {...state}; - if (action.data && action.data.length && action.data.length > 0) { - nextState[action.data[0].type as JobType] = action.data; - } - return nextState; - } - default: - return state; - } -} - -export default (combineReducers({ - - // object where every key is the job id and has an object with the job details - jobs, - - // object where every key is a job type and contains a list of jobs. - jobsByTypeList, -}) as (b: JobsState, a: GenericAction) => JobsState); diff --git a/app/mm-redux/reducers/entities/schemes.ts b/app/mm-redux/reducers/entities/schemes.ts deleted file mode 100644 index 5957dfd85..000000000 --- a/app/mm-redux/reducers/entities/schemes.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {combineReducers} from 'redux'; -import {SchemeTypes} from '@mm-redux/action_types'; -import {GenericAction} from '@mm-redux/types/actions'; -import {SchemesState, Scheme} from '@mm-redux/types/schemes'; - -function schemes(state: { - [x: string]: Scheme; -} = {}, action: GenericAction): { - [x: string]: Scheme; - } { - switch (action.type) { - case SchemeTypes.CREATED_SCHEME: - case SchemeTypes.PATCHED_SCHEME: - case SchemeTypes.RECEIVED_SCHEME: { - return { - ...state, - [action.data.id]: action.data, - }; - } - - case SchemeTypes.RECEIVED_SCHEMES: { - const nextState = {...state}; - for (const scheme of action.data) { - nextState[scheme.id] = scheme; - } - return nextState; - } - - case SchemeTypes.DELETED_SCHEME: { - const nextState = {...state}; - Reflect.deleteProperty(nextState, action.data.schemeId); - return nextState; - } - - default: - return state; - } -} - -export default (combineReducers({ - schemes, -}) as (b: SchemesState, a: GenericAction) => SchemesState); diff --git a/app/mm-redux/reducers/entities/teams.ts b/app/mm-redux/reducers/entities/teams.ts index 2f6ebbf27..302792666 100644 --- a/app/mm-redux/reducers/entities/teams.ts +++ b/app/mm-redux/reducers/entities/teams.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {combineReducers} from 'redux'; -import {ChannelTypes, TeamTypes, UserTypes, SchemeTypes, GroupTypes} from '@mm-redux/action_types'; +import {ChannelTypes, TeamTypes, UserTypes, GroupTypes} from '@mm-redux/action_types'; import {teamListToMap} from '@mm-redux/utils/team_utils'; import {Team, TeamMembership, TeamUnread} from '@mm-redux/types/teams'; import {UserProfile} from '@mm-redux/types/users'; @@ -21,7 +21,6 @@ function currentTeamId(state = '', action: GenericAction) { function teams(state: IDMappedObjects = {}, action: GenericAction) { switch (action.type) { case TeamTypes.RECEIVED_TEAMS_LIST: - case SchemeTypes.RECEIVED_SCHEME_TEAMS: return Object.assign({}, state, teamListToMap(action.data)); case UserTypes.LOGIN: // Used by the mobile app return Object.assign({}, state, teamListToMap(action.data.teams)); @@ -48,17 +47,6 @@ function teams(state: IDMappedObjects = {}, action: GenericAction) { return state; } - case TeamTypes.UPDATED_TEAM_SCHEME: { - const {teamId, schemeId} = action.data; - const team = state[teamId]; - - if (!team) { - return state; - } - - return {...state, [teamId]: {...team, scheme_id: schemeId}}; - } - default: return state; } @@ -205,10 +193,6 @@ function myMembers(state: RelationOneToOne = {}, action: G Reflect.deleteProperty(nextState, data.id); return nextState; } - case TeamTypes.UPDATED_TEAM_MEMBER_SCHEME_ROLES: { - return updateMyTeamMemberSchemeRoles(state, action); - } - case ChannelTypes.POST_UNREAD_SUCCESS: { const {teamId, deltaMsgs, mentionCount, msgCount} = action.data; @@ -318,9 +302,6 @@ function membersInTeam(state: RelationOneToOne>, action: GenericAction) { - const {teamId, userId, isSchemeUser, isSchemeAdmin} = action.data; - const team = state[teamId]; - if (team) { - const member = team[userId]; - if (member) { - return { - ...state, - [teamId]: { - ...state[teamId], - [userId]: { - ...state[teamId][userId], - scheme_user: isSchemeUser, - scheme_admin: isSchemeAdmin, - }, - }, - }; - } - } - return state; -} - -function updateMyTeamMemberSchemeRoles(state: RelationOneToOne, action: GenericAction) { - const {teamId, isSchemeUser, isSchemeAdmin} = action.data; - const member = state[teamId]; - if (member) { - return { - ...state, - [teamId]: { - ...state[teamId], - scheme_user: isSchemeUser, - scheme_admin: isSchemeAdmin, - }, - }; - } - return state; -} - function totalCount(state = 0, action: GenericAction) { switch (action.type) { case TeamTypes.RECEIVED_TOTAL_TEAM_COUNT: { diff --git a/app/mm-redux/reducers/entities/users.ts b/app/mm-redux/reducers/entities/users.ts index 65d8de110..0a04e2eab 100644 --- a/app/mm-redux/reducers/entities/users.ts +++ b/app/mm-redux/reducers/entities/users.ts @@ -141,16 +141,6 @@ function mySessions(state: Array<{id: string}> = [], action: GenericAction) { } } -function myAudits(state = [], action: GenericAction) { - switch (action.type) { - case UserTypes.RECEIVED_AUDITS: - return [...action.data]; - - default: - return state; - } -} - function profiles(state: IDMappedObjects = {}, action: GenericAction) { switch (action.type) { case UserTypes.RECEIVED_ME: @@ -518,20 +508,6 @@ function myUserAccessTokens(state: any = {}, action: GenericAction) { } } -function stats(state = {}, action: GenericAction) { - switch (action.type) { - case UserTypes.RECEIVED_USER_STATS: { - const stat = action.data; - return { - ...state, - ...stat, - }; - } - default: - return state; - } -} - export default combineReducers({ // the current selected user @@ -540,9 +516,6 @@ export default combineReducers({ // array with the user's sessions mySessions, - // array with the user's audits - myAudits, - // object where every key is the token id and has a user access token as a value myUserAccessTokens, @@ -569,7 +542,4 @@ export default combineReducers({ // object where every key is the user id and has a value with a flag determining if their status was set manually isManualStatus, - - // Total user stats - stats, }); diff --git a/app/mm-redux/reducers/requests/index.ts b/app/mm-redux/reducers/requests/index.ts index 1f78e2aa2..ffcc2896c 100644 --- a/app/mm-redux/reducers/requests/index.ts +++ b/app/mm-redux/reducers/requests/index.ts @@ -9,7 +9,6 @@ import general from './general'; import posts from './posts'; import teams from './teams'; import users from './users'; -import jobs from './jobs'; import search from './search'; import roles from './roles'; @@ -20,7 +19,6 @@ export default combineReducers({ posts, teams, users, - jobs, search, roles, }); diff --git a/app/mm-redux/reducers/requests/jobs.ts b/app/mm-redux/reducers/requests/jobs.ts deleted file mode 100644 index 2fc2dec3d..000000000 --- a/app/mm-redux/reducers/requests/jobs.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {combineReducers} from 'redux'; -import {JobTypes} from '@mm-redux/action_types'; - -import {GenericAction} from '@mm-redux/types/actions'; -import {JobsRequestsStatuses, RequestStatusType} from '@mm-redux/types/requests'; - -import {handleRequest, initialRequestState} from './helpers'; - -function createJob(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - JobTypes.CREATE_JOB_REQUEST, - JobTypes.CREATE_JOB_SUCCESS, - JobTypes.CREATE_JOB_FAILURE, - state, - action, - ); -} - -function getJob(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - JobTypes.GET_JOB_REQUEST, - JobTypes.GET_JOB_SUCCESS, - JobTypes.GET_JOB_FAILURE, - state, - action, - ); -} - -function getJobs(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - JobTypes.GET_JOBS_REQUEST, - JobTypes.GET_JOBS_SUCCESS, - JobTypes.GET_JOBS_FAILURE, - state, - action, - ); -} - -function cancelJob(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - JobTypes.CANCEL_JOB_REQUEST, - JobTypes.CANCEL_JOB_SUCCESS, - JobTypes.CANCEL_JOB_FAILURE, - state, - action, - ); -} - -export default (combineReducers({ - createJob, - getJob, - getJobs, - cancelJob, -}) as (b: JobsRequestsStatuses, a: GenericAction) => JobsRequestsStatuses); diff --git a/app/mm-redux/reducers/requests/roles.ts b/app/mm-redux/reducers/requests/roles.ts index 5330040ab..52066c28b 100644 --- a/app/mm-redux/reducers/requests/roles.ts +++ b/app/mm-redux/reducers/requests/roles.ts @@ -18,39 +18,6 @@ function getRolesByNames(state: RequestStatusType = initialRequestState(), actio ); } -function getRoleByName(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - RoleTypes.ROLE_BY_NAME_REQUEST, - RoleTypes.ROLE_BY_NAME_SUCCESS, - RoleTypes.ROLE_BY_NAME_FAILURE, - state, - action, - ); -} - -function getRole(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - RoleTypes.ROLE_BY_ID_REQUEST, - RoleTypes.ROLE_BY_ID_SUCCESS, - RoleTypes.ROLE_BY_ID_FAILURE, - state, - action, - ); -} - -function editRole(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { - return handleRequest( - RoleTypes.EDIT_ROLE_REQUEST, - RoleTypes.EDIT_ROLE_SUCCESS, - RoleTypes.EDIT_ROLE_FAILURE, - state, - action, - ); -} - export default (combineReducers({ getRolesByNames, - getRoleByName, - getRole, - editRole, }) as (b: RolesRequestsStatuses, a: GenericAction) => RolesRequestsStatuses); diff --git a/app/mm-redux/selectors/entities/channels.test.js b/app/mm-redux/selectors/entities/channels.test.js index 678ea3bab..f1f8e4dcf 100644 --- a/app/mm-redux/selectors/entities/channels.test.js +++ b/app/mm-redux/selectors/entities/channels.test.js @@ -7,7 +7,7 @@ import deepFreezeAndThrowOnMutation from '@mm-redux/utils/deep_freeze'; import TestHelper from 'test/test_helper'; import {sortChannelsByDisplayName, getDirectChannelName} from '@mm-redux/utils/channel_utils'; import * as Selectors from '@mm-redux/selectors/entities/channels'; -import {General, Preferences, Permissions} from '../../constants'; +import {General, Preferences} from '../../constants'; const sortUsernames = (a, b) => a.localeCompare(b, General.DEFAULT_LOCALE, {numeric: true}); @@ -3789,29 +3789,6 @@ test('Selectors.Channels.isManuallyUnread', () => { assert.equal(Selectors.isManuallyUnread(state, 'channel3'), false); }); -test('Selectors.Channels.getChannelModerations', () => { - const moderations = [{ - name: Permissions.CHANNEL_MODERATED_PERMISSIONS.CREATE_POST, - roles: { - members: true, - }, - }]; - - const state = { - entities: { - channels: { - channelModerations: { - channel1: moderations, - }, - }, - }, - }; - - assert.equal(Selectors.getChannelModerations(state, 'channel1'), moderations); - assert.equal(Selectors.getChannelModerations(state, undefined), undefined); - assert.equal(Selectors.getChannelModerations(state, 'undefined'), undefined); -}); - test('Selectors.Channels.getChannelMemberCountsByGroup', () => { const memberCounts = { 'group-1': { diff --git a/app/mm-redux/selectors/entities/channels.ts b/app/mm-redux/selectors/entities/channels.ts index c3ced7863..6827bf8d8 100644 --- a/app/mm-redux/selectors/entities/channels.ts +++ b/app/mm-redux/selectors/entities/channels.ts @@ -14,7 +14,7 @@ import {createIdsSelector} from '@mm-redux/utils/helpers'; export {getCurrentChannelId, getMyChannelMemberships, getMyCurrentChannelMembership}; import {GlobalState} from '@mm-redux/types/store'; -import {Channel, ChannelStats, ChannelMembership, ChannelModeration, ChannelMemberCountsByGroup} from '@mm-redux/types/channels'; +import {Channel, ChannelStats, ChannelMembership, ChannelMemberCountsByGroup} from '@mm-redux/types/channels'; import {UsersState, UserProfile} from '@mm-redux/types/users'; import {PreferenceType} from '@mm-redux/types/preferences'; import {Post} from '@mm-redux/types/posts'; @@ -930,10 +930,6 @@ export function isManuallyUnread(state: GlobalState, channelId?: string): boolea return Boolean(state.entities.channels.manuallyUnread[channelId]); } -export function getChannelModerations(state: GlobalState, channelId: string): Array { - return state.entities.channels.channelModerations[channelId]; -} - export function getChannelMemberCountsByGroup(state: GlobalState, channelId: string): ChannelMemberCountsByGroup { return state.entities.channels.channelMemberCountsByGroup[channelId] || {}; } diff --git a/app/mm-redux/selectors/entities/jobs.ts b/app/mm-redux/selectors/entities/jobs.ts deleted file mode 100644 index 8ee6fb281..000000000 --- a/app/mm-redux/selectors/entities/jobs.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {createSelector} from 'reselect'; -import {GlobalState} from '@mm-redux/types/store'; -import {JobType, Job, JobsByType} from '@mm-redux/types/jobs'; -import {IDMappedObjects} from '@mm-redux/types/utilities'; -export function getAllJobs(state: GlobalState): IDMappedObjects { - return state.entities.jobs.jobs; -} - -export function getJobsByType(state: GlobalState): JobsByType { - return state.entities.jobs.jobsByTypeList; -} - -export function makeGetJobsByType(type: JobType): (state: GlobalState) => Array { - return createSelector( - getJobsByType, - (jobsByType) => { - return jobsByType[type] || []; - }, - ); -} diff --git a/app/mm-redux/selectors/entities/schemes.test.js b/app/mm-redux/selectors/entities/schemes.test.js deleted file mode 100644 index 612cca0e9..000000000 --- a/app/mm-redux/selectors/entities/schemes.test.js +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import assert from 'assert'; - -import deepFreezeAndThrowOnMutation from '@mm-redux/utils/deep_freeze'; -import TestHelper from 'test/test_helper'; -import * as Selectors from '@mm-redux/selectors/entities/schemes'; -import {ScopeTypes} from '@mm-redux/constants/schemes'; - -describe('Selectors.Schemes', () => { - const scheme1 = TestHelper.mockSchemeWithId(); - scheme1.scope = ScopeTypes.CHANNEL; - - const scheme2 = TestHelper.mockSchemeWithId(); - scheme2.scope = ScopeTypes.TEAM; - - const schemes = {}; - schemes[scheme1.id] = scheme1; - schemes[scheme2.id] = scheme2; - - const channel1 = TestHelper.fakeChannelWithId(); - channel1.scheme_id = scheme1.id; - - const channel2 = TestHelper.fakeChannelWithId(); - - const channels = {}; - channels[channel1.id] = channel1; - channels[channel2.id] = channel2; - - const team1 = TestHelper.fakeTeamWithId(); - team1.scheme_id = scheme2.id; - - const team2 = TestHelper.fakeTeamWithId(); - - const teams = {}; - teams[team1.id] = team1; - teams[team2.id] = team2; - - const testState = deepFreezeAndThrowOnMutation({ - entities: { - schemes: {schemes}, - channels: {channels}, - teams: {teams}, - }, - }); - - it('getSchemes', () => { - assert.deepEqual(Selectors.getSchemes(testState), schemes); - }); - - it('getScheme', () => { - assert.equal(Selectors.getScheme(testState, scheme1.id), scheme1); - }); - - it('makeGetSchemeChannels', () => { - const getSchemeChannels = Selectors.makeGetSchemeChannels(); - const results = getSchemeChannels(testState, {schemeId: scheme1.id}); - assert.equal(results.length, 1); - assert.equal(results[0].name, channel1.name); - }); - - it('makeGetSchemeChannels with team scope scheme', () => { - const getSchemeChannels = Selectors.makeGetSchemeChannels(); - const results = getSchemeChannels(testState, {schemeId: scheme2.id}); - assert.equal(results.length, 0); - }); - - it('makeGetSchemeTeams', () => { - const getSchemeTeams = Selectors.makeGetSchemeTeams(); - const results = getSchemeTeams(testState, {schemeId: scheme2.id}); - assert.equal(results.length, 1); - assert.equal(results[0].name, team1.name); - }); - - it('getSchemeTeams with channel scope scheme', () => { - const getSchemeTeams = Selectors.makeGetSchemeTeams(); - const results = getSchemeTeams(testState, {schemeId: scheme1.id}); - assert.equal(results.length, 0); - }); -}); diff --git a/app/mm-redux/selectors/entities/schemes.ts b/app/mm-redux/selectors/entities/schemes.ts deleted file mode 100644 index cda02e7ee..000000000 --- a/app/mm-redux/selectors/entities/schemes.ts +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {ScopeTypes} from '@mm-redux/constants/schemes'; - -import {createSelector} from 'reselect'; -import {getAllChannels} from '@mm-redux/selectors/entities/channels'; -import {getTeams} from '@mm-redux/selectors/entities/teams'; -import {GlobalState} from '@mm-redux/types/store'; -import {Scheme} from '@mm-redux/types/schemes'; -import {Channel} from '@mm-redux/types/channels'; -import {Team} from '@mm-redux/types/teams'; - -export function getSchemes(state: GlobalState): { - [x: string]: Scheme; -} { - return state.entities.schemes.schemes; -} - -export function getScheme(state: GlobalState, id: string): Scheme { - const schemes = getSchemes(state); - return schemes[id]; -} - -export function makeGetSchemeChannels() { - return (createSelector( - getAllChannels, - (state: GlobalState, props: {schemeId: string}) => getScheme(state, props.schemeId), - (allChannels, scheme) => { - if (!scheme) { - return []; - } - - if (scheme.scope === ScopeTypes.TEAM) { - const msg = `Not implemented: scheme '${scheme.id}' is team-scope but 'getSchemeChannels' only accepts channel-scoped schemes.`; - console.log(msg); // eslint-disable-line no-console - return []; - } - - const schemeChannels: Array = []; - - Object.entries(allChannels).forEach((item: [string, Channel]) => { - const [, channel] = item; - if (channel.scheme_id === scheme.id) { - schemeChannels.push(channel); - } - }); - - return schemeChannels; - }) as (b: GlobalState, a: { - schemeId: string; - }) => Array); -} - -export function makeGetSchemeTeams() { - return (createSelector( - getTeams, - (state: GlobalState, props: {schemeId: string}) => getScheme(state, props.schemeId), - (allTeams, scheme) => { - if (!scheme) { - return []; - } - - if (scheme.scope === ScopeTypes.CHANNEL) { - const msg = `Error: scheme '${scheme.id}' is channel-scoped but 'getSchemeChannels' only accepts team-scoped schemes.`; - console.log(msg); // eslint-disable-line no-console - return []; - } - - const schemeTeams: Array = []; - - Object.entries(allTeams).forEach((item: [string, Team]) => { - const [, team] = item; - if (team.scheme_id === scheme.id) { - schemeTeams.push(team); - } - }); - - return schemeTeams; - }) as (b: GlobalState, a: { - schemeId: string; - }) => Array); -} diff --git a/app/mm-redux/selectors/entities/users.test.js b/app/mm-redux/selectors/entities/users.test.js index 470df3ab5..4e65fc05f 100644 --- a/app/mm-redux/selectors/entities/users.test.js +++ b/app/mm-redux/selectors/entities/users.test.js @@ -61,16 +61,6 @@ describe('Selectors.Users', () => { roles: '', }]; - const userAudits = [{ - action: 'test_user_action', - create_at: 1535007018934, - extra_info: 'success', - id: 'test_id', - ip_address: '::1', - session_id: '', - user_id: 'test_user_id', - }]; - const myPreferences = {}; myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user2.id}`] = {category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, name: user2.id, value: 'true'}; myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user3.id}`] = {category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, name: user3.id, value: 'false'}; @@ -86,7 +76,6 @@ describe('Selectors.Users', () => { profilesInChannel, profilesNotInChannel, mySessions: userSessions, - myAudits: userAudits, }, teams: { currentTeamId: team1.id, @@ -124,10 +113,6 @@ describe('Selectors.Users', () => { assert.deepEqual(Selectors.getUserSessions(testState), userSessions); }); - it('getUserAudits', () => { - assert.deepEqual(Selectors.getUserAudits(testState), userAudits); - }); - it('getUser', () => { assert.deepEqual(Selectors.getUser(testState, user1.id), user1); }); diff --git a/app/mm-redux/selectors/entities/users.ts b/app/mm-redux/selectors/entities/users.ts index a3915222a..bda311add 100644 --- a/app/mm-redux/selectors/entities/users.ts +++ b/app/mm-redux/selectors/entities/users.ts @@ -44,10 +44,6 @@ export function getUserSessions(state: GlobalState): Array { return state.entities.users.mySessions; } -export function getUserAudits(state: GlobalState): Array { - return state.entities.users.myAudits; -} - export function getUser(state: GlobalState, id: $ID): UserProfile { return state.entities.users.profiles[id]; } @@ -291,10 +287,6 @@ export function getStatusForUserId(state: GlobalState, userId: $ID) return getUserStatuses(state)[userId]; } -export function getTotalUsersStats(state: GlobalState): any { - return state.entities.users.stats; -} - export function searchProfiles(state: GlobalState, term: string, skipCurrent = false, filters?: Filters): Array { const users = getUsers(state); const profiles = filterProfilesMatchingTerm(Object.keys(users).map((key) => users[key]), term); diff --git a/app/mm-redux/types/channels.ts b/app/mm-redux/types/channels.ts index 5403b88db..a74afcf65 100644 --- a/app/mm-redux/types/channels.ts +++ b/app/mm-redux/types/channels.ts @@ -74,7 +74,6 @@ export type ChannelsState = { groupsAssociatedToChannel: any; totalCount: number; manuallyUnread: RelationOneToOne; - channelModerations: RelationOneToOne>; channelMemberCountsByGroup: RelationOneToOne; }; diff --git a/app/mm-redux/types/index.ts b/app/mm-redux/types/index.ts index 5e33439ec..becd28972 100644 --- a/app/mm-redux/types/index.ts +++ b/app/mm-redux/types/index.ts @@ -10,13 +10,11 @@ import * as files from './files'; import * as general from './general'; import * as groups from './groups'; import * as integrations from './integrations'; -import * as jobs from './jobs'; import * as posts from './posts'; import * as preferences from './preferences'; import * as reactions from './reactions'; import * as requests from './requests'; import * as roles from './roles'; -import * as schemes from './schemes'; import * as search from './search'; import * as store from './store'; import * as teams from './teams'; @@ -41,13 +39,11 @@ export { groups, typing, integrations, - jobs, utilities, posts, preferences, roles, client4, - schemes, search, teams, requests, diff --git a/app/mm-redux/types/jobs.ts b/app/mm-redux/types/jobs.ts deleted file mode 100644 index cdde5fc57..000000000 --- a/app/mm-redux/types/jobs.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -import {IDMappedObjects} from './utilities'; -export type JobType = 'data_retention' | 'elasticsearch_post_indexing' | 'ldap_sync' | 'message_export'; -export type JobStatus = 'pending' | 'in_progress' | 'success' | 'error' | 'cancel_requested' | 'canceled'; -export type Job = { - id: string; - type: JobType; - priority: number; - create_at: number; - start_at: number; - last_activity_at: number; - status: JobStatus; - progress: number; - data: any; -}; -export type JobsByType = { - [x in JobType]?: Array; -}; -export type JobsState = { - jobs: IDMappedObjects; - jobsByTypeList: JobsByType; -}; diff --git a/app/mm-redux/types/posts.ts b/app/mm-redux/types/posts.ts index 9ae5a4587..192089e1b 100644 --- a/app/mm-redux/types/posts.ts +++ b/app/mm-redux/types/posts.ts @@ -117,3 +117,7 @@ export type PostProps = { disable_group_highlight?: boolean; mentionHighlightDisabled: boolean; } + +export type PostResponse = PostOrderBlock & { + posts: IDMappedObjects; +}; diff --git a/app/mm-redux/types/requests.ts b/app/mm-redux/types/requests.ts index 4b335b345..a02bf9b22 100644 --- a/app/mm-redux/types/requests.ts +++ b/app/mm-redux/types/requests.ts @@ -39,7 +39,6 @@ export type UsersRequestsStatuses = { }; export type EmojisRequestsStatuses = { - createCustomEmoji: RequestStatusType; getCustomEmojis: RequestStatusType; deleteCustomEmoji: RequestStatusType; getAllCustomEmojis: RequestStatusType; @@ -53,15 +52,6 @@ export type FilesRequestsStatuses = { export type RolesRequestsStatuses = { getRolesByNames: RequestStatusType; getRoleByName: RequestStatusType; - getRole: RequestStatusType; - editRole: RequestStatusType; -}; - -export type JobsRequestsStatuses = { - createJob: RequestStatusType; - getJob: RequestStatusType; - getJobs: RequestStatusType; - cancelJob: RequestStatusType; }; export type SearchRequestsStatuses = { diff --git a/app/mm-redux/types/schemes.ts b/app/mm-redux/types/schemes.ts deleted file mode 100644 index 9f2d5e318..000000000 --- a/app/mm-redux/types/schemes.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -export type SchemeScope = 'team' | 'channel'; -export type Scheme = { - id: string; - name: string; - description: string; - display_name: string; - create_at: number; - update_at: number; - delete_at: number; - scope: SchemeScope; - default_team_admin_role: string; - default_team_user_role: string; - default_channel_admin_role: string; - default_channel_user_role: string; -}; -export type SchemesState = { - schemes: { - [x: string]: Scheme; - }; -}; -export type SchemePatch = { - name?: string; - description?: string; -}; diff --git a/app/mm-redux/types/store.ts b/app/mm-redux/types/store.ts index 0ff85ec1a..4671be495 100644 --- a/app/mm-redux/types/store.ts +++ b/app/mm-redux/types/store.ts @@ -6,15 +6,13 @@ import {UsersState} from './users'; import {TeamsState} from './teams'; import {ChannelsState} from './channels'; import {PostsState} from './posts'; -import {JobsState} from './jobs'; import {SearchState} from './search'; import {IntegrationsState} from './integrations'; import {FilesState} from './files'; import {EmojisState} from './emojis'; -import {SchemesState} from './schemes'; import {Typing} from './typing'; import {GroupsState} from './groups'; -import {ChannelsRequestsStatuses, GeneralRequestsStatuses, PostsRequestsStatuses, TeamsRequestsStatuses, UsersRequestsStatuses, FilesRequestsStatuses, RolesRequestsStatuses, JobsRequestsStatuses} from './requests'; +import {ChannelsRequestsStatuses, GeneralRequestsStatuses, PostsRequestsStatuses, TeamsRequestsStatuses, UsersRequestsStatuses, FilesRequestsStatuses, RolesRequestsStatuses} from './requests'; import {Role} from './roles'; import {PreferenceType} from './preferences'; import {Bot} from './bots'; @@ -37,7 +35,6 @@ export type GlobalState = { [x: string]: PreferenceType; }; }; - jobs: JobsState; search: SearchState; integrations: IntegrationsState; files: FilesState; @@ -49,7 +46,6 @@ export type GlobalState = { }; pending: Set; }; - schemes: SchemesState; gifs: any; groups: GroupsState; channelCategories: ChannelCategoriesState; @@ -64,7 +60,6 @@ export type GlobalState = { users: UsersRequestsStatuses; files: FilesRequestsStatuses; roles: RolesRequestsStatuses; - jobs: JobsRequestsStatuses; }; views: any; websocket: { diff --git a/app/mm-redux/types/users.ts b/app/mm-redux/types/users.ts index 5051548ee..c9620b785 100644 --- a/app/mm-redux/types/users.ts +++ b/app/mm-redux/types/users.ts @@ -47,7 +47,6 @@ export type UsersState = { currentUserId: string; isManualStatus: RelationOneToOne; mySessions: Array; - myAudits: Array; profiles: IDMappedObjects; profilesInTeam: RelationOneToMany; profilesNotInTeam: RelationOneToMany; diff --git a/app/mm-redux/utils/emoji_utils.ts b/app/mm-redux/utils/emoji_utils.ts index d48a219fc..ce2fd2949 100644 --- a/app/mm-redux/utils/emoji_utils.ts +++ b/app/mm-redux/utils/emoji_utils.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Emoji, SystemEmoji, CustomEmoji} from '@mm-redux/types/emojis'; export function isSystemEmoji(emoji: Emoji): emoji is SystemEmoji { diff --git a/app/mm-redux/utils/file_utils.test.js b/app/mm-redux/utils/file_utils.test.js index b68fa5127..717761294 100644 --- a/app/mm-redux/utils/file_utils.test.js +++ b/app/mm-redux/utils/file_utils.test.js @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import assert from 'assert'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import * as FileUtils from '@mm-redux/utils/file_utils'; diff --git a/app/mm-redux/utils/file_utils.ts b/app/mm-redux/utils/file_utils.ts index a6959a3a7..e8c8867db 100644 --- a/app/mm-redux/utils/file_utils.ts +++ b/app/mm-redux/utils/file_utils.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {Files, General} from '../constants'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {FileInfo} from '@mm-redux/types/files'; import {Dictionary} from '@mm-redux/types/utilities'; diff --git a/app/mm-redux/utils/mix.ts b/app/mm-redux/utils/mix.ts new file mode 100644 index 000000000..4d89a7f1b --- /dev/null +++ b/app/mm-redux/utils/mix.ts @@ -0,0 +1,17 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +class MixinBuilder { + superclass: any; + constructor(superclass: any) { + this.superclass = superclass; + } + + with(...mixins: any[]) { + return mixins.reduce((c, mixin) => mixin(c), this.superclass); + } +} + +const mix = (superclass: any) => new MixinBuilder(superclass); + +export default mix; diff --git a/app/mm-redux/utils/sentry.test.js b/app/mm-redux/utils/sentry.test.js index 663583b9f..98fc386d0 100644 --- a/app/mm-redux/utils/sentry.test.js +++ b/app/mm-redux/utils/sentry.test.js @@ -3,7 +3,7 @@ import assert from 'assert'; -import Client4 from '@mm-redux/client/client4'; +import {Client} from '@client/rest'; import {cleanUrlForLogging} from '@mm-redux/utils/sentry'; @@ -11,7 +11,7 @@ describe('utils/sentry', () => { describe('cleanUrlForLogging', () => { const baseUrl = 'https://mattermost.example.com/subpath'; - const client = new Client4(); + const client = new Client(); client.setUrl(baseUrl); const tests = [{ diff --git a/app/mm-redux/utils/sentry.ts b/app/mm-redux/utils/sentry.ts index c69a29da0..00e8bec12 100644 --- a/app/mm-redux/utils/sentry.ts +++ b/app/mm-redux/utils/sentry.ts @@ -24,7 +24,7 @@ export function cleanUrlForLogging(baseUrl: string, apiUrl: string): string { 'files', 'preferences', 'hooks', 'incoming', 'outgoing', 'oauth', 'apps', 'emoji', 'brand', 'image', 'data_retention', 'jobs', 'plugins', 'roles', 'system', 'timezones', 'schemes', 'redirect_location', 'patch', 'mfa', 'password', 'reset', 'send', 'active', 'verify', 'terms_of_service', 'login', 'logout', 'ids', - 'usernames', 'me', 'username', 'email', 'default', 'sessions', 'revoke', 'all', 'audits', 'device', 'status', + 'usernames', 'me', 'username', 'email', 'default', 'sessions', 'revoke', 'all', 'device', 'status', 'search', 'switch', 'authorized', 'authorize', 'deauthorize', 'tokens', 'disable', 'enable', 'exists', 'unread', 'invite', 'batch', 'stats', 'import', 'schemeRoles', 'direct', 'group', 'convert', 'view', 'search_autocomplete', 'thread', 'info', 'flagged', 'pinned', 'pin', 'unpin', 'opengraph', 'actions', 'thumbnail', 'preview', 'link', diff --git a/app/screens/channel/index.js b/app/screens/channel/index.js index 5701f7e80..2325c449c 100644 --- a/app/screens/channel/index.js +++ b/app/screens/channel/index.js @@ -9,7 +9,7 @@ import {recordLoadTime} from '@actions/views/root'; import {selectDefaultTeam} from '@actions/views/select_team'; import {ViewTypes} from '@constants'; import {getChannelStats} from '@mm-redux/actions/channels'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels'; import {getServerVersion} from '@mm-redux/selectors/entities/general'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; diff --git a/app/screens/edit_profile/edit_profile.js b/app/screens/edit_profile/edit_profile.js index 1ffbbffc2..c32051425 100644 --- a/app/screens/edit_profile/edit_profile.js +++ b/app/screens/edit_profile/edit_profile.js @@ -11,7 +11,7 @@ import DocumentPicker from 'react-native-document-picker'; import {Navigation} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getFormattedFileSize} from '@mm-redux/utils/file_utils'; import {buildFileUploadData, encodeHeaderURIStringToUTF8} from 'app/utils/file'; diff --git a/app/screens/gallery/footer/index.tsx b/app/screens/gallery/footer/index.tsx index f3db184f5..c8cf253d8 100644 --- a/app/screens/gallery/footer/index.tsx +++ b/app/screens/gallery/footer/index.tsx @@ -7,7 +7,7 @@ import {injectIntl} from 'react-intl'; import Clipboard from '@react-native-community/clipboard'; import {ATTACHMENT_DOWNLOAD} from '@constants/attachment'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import EventEmitter from '@mm-redux/utils/event_emitter'; import type {CallbackFunctionWithoutArguments, PrepareFileRef, FooterProps, FooterRef, ShowToast, ToastRef} from 'types/screens/gallery'; diff --git a/app/screens/gallery/footer/prepare_file/prepare_file.tsx b/app/screens/gallery/footer/prepare_file/prepare_file.tsx index 317bbbaab..bdda30dc6 100644 --- a/app/screens/gallery/footer/prepare_file/prepare_file.tsx +++ b/app/screens/gallery/footer/prepare_file/prepare_file.tsx @@ -11,7 +11,7 @@ import Share from 'react-native-share'; import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; import ProgressBar from '@components/progress_bar'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getLocalPath} from '@utils/file'; import mattermostBucket from 'app/mattermost_bucket'; diff --git a/app/screens/gallery/footer/summary/index.ts b/app/screens/gallery/footer/summary/index.ts index 97d74bb93..931199c53 100644 --- a/app/screens/gallery/footer/summary/index.ts +++ b/app/screens/gallery/footer/summary/index.ts @@ -3,7 +3,7 @@ import {connect} from 'react-redux'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {General} from '@mm-redux/constants'; import {getChannel, getCurrentChannel} from '@mm-redux/selectors/entities/channels'; import {getConfig} from '@mm-redux/selectors/entities/general'; diff --git a/app/screens/gallery/gallery_video.tsx b/app/screens/gallery/gallery_video.tsx index 66fc6ec36..cbb61a6b8 100644 --- a/app/screens/gallery/gallery_video.tsx +++ b/app/screens/gallery/gallery_video.tsx @@ -9,7 +9,7 @@ import {TapGestureHandler, State, TapGestureHandlerStateChangeEvent} from 'react import Video, {OnLoadData, OnProgressData} from 'react-native-video'; import {DeviceTypes} from '@constants'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getLocalPath} from '@utils/file'; import {GalleryItemProps} from 'types/screens/gallery'; diff --git a/app/screens/notification/notification_icon.tsx b/app/screens/notification/notification_icon.tsx index 73bfc88a1..e3b646fb6 100644 --- a/app/screens/notification/notification_icon.tsx +++ b/app/screens/notification/notification_icon.tsx @@ -8,7 +8,7 @@ import {useSelector} from 'react-redux'; import CompassIcon from '@components/compass_icon'; import ProfilePicture from '@components/profile_picture'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getConfig} from '@mm-redux/selectors/entities/general'; import {getUser} from '@mm-redux/selectors/entities/users'; import type {GlobalState} from '@mm-redux/types/store'; diff --git a/app/screens/select_server/select_server.js b/app/screens/select_server/select_server.js index 8ebd00f37..674d9c43a 100644 --- a/app/screens/select_server/select_server.js +++ b/app/screens/select_server/select_server.js @@ -33,7 +33,7 @@ import ErrorText from '@components/error_text'; import FormattedText from '@components/formatted_text'; import fetchConfig from '@init/fetch'; import globalEventHandler from '@init/global_event_handler'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; import {checkUpgradeType, isUpgradeAvailable} from '@utils/client_upgrade'; import {t} from '@utils/i18n'; diff --git a/app/screens/sso/index.tsx b/app/screens/sso/index.tsx index 99144d145..37148fb5e 100644 --- a/app/screens/sso/index.tsx +++ b/app/screens/sso/index.tsx @@ -13,7 +13,7 @@ import {scheduleExpiredNotification} from '@actions/views/session'; import {ssoLogin} from '@actions/views/user'; import emmProvider from '@init/emm_provider'; import {DispatchFunc} from '@mm-redux/types/actions'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {getConfig} from '@mm-redux/selectors/entities/general'; import {ErrorApi} from '@mm-redux/types/client4'; diff --git a/app/screens/sso/sso_with_webview.tsx b/app/screens/sso/sso_with_webview.tsx index 150db18de..0b8e5b702 100644 --- a/app/screens/sso/sso_with_webview.tsx +++ b/app/screens/sso/sso_with_webview.tsx @@ -10,7 +10,7 @@ import {WebView} from 'react-native-webview'; import {WebViewErrorEvent, WebViewMessageEvent, WebViewNavigation, WebViewNavigationEvent} from 'react-native-webview/lib/WebViewTypes'; import urlParse from 'url-parse'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import type {Theme} from '@mm-redux/types/preferences'; import Loading from 'app/components/loading'; diff --git a/app/store/initial_state.js b/app/store/initial_state.js index 00a716ccb..90ba4748b 100644 --- a/app/store/initial_state.js +++ b/app/store/initial_state.js @@ -21,7 +21,6 @@ const state = { users: { currentUserId: '', mySessions: [], - myAudits: [], profiles: {}, profilesInTeam: {}, profilesInChannel: {}, diff --git a/app/utils/error_handling.js b/app/utils/error_handling.js index dc441e219..7356fc0f1 100644 --- a/app/utils/error_handling.js +++ b/app/utils/error_handling.js @@ -8,7 +8,7 @@ import {dismissAllModals} from '@actions/navigation'; import {purgeOfflineStore} from '@actions/views/root'; import {close as closeWebSocket} from '@actions/websocket'; import {DEFAULT_LOCALE, getTranslations} from '@i18n'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {logError} from '@mm-redux/actions/errors'; import {t} from '@utils/i18n'; import { diff --git a/app/utils/image_cache_manager.js b/app/utils/image_cache_manager.js index 8974c0989..5cd1e6fc0 100644 --- a/app/utils/image_cache_manager.js +++ b/app/utils/image_cache_manager.js @@ -8,7 +8,7 @@ import RNFetchBlob from 'rn-fetch-blob'; import Url from 'url-parse'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {DeviceTypes} from 'app/constants'; import { diff --git a/app/utils/mix.ts b/app/utils/mix.ts new file mode 100644 index 000000000..4d89a7f1b --- /dev/null +++ b/app/utils/mix.ts @@ -0,0 +1,17 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +class MixinBuilder { + superclass: any; + constructor(superclass: any) { + this.superclass = superclass; + } + + with(...mixins: any[]) { + return mixins.reduce((c, mixin) => mixin(c), this.superclass); + } +} + +const mix = (superclass: any) => new MixinBuilder(superclass); + +export default mix; diff --git a/app/utils/network.js b/app/utils/network.js index 6c65e34a7..82c0ff5ff 100644 --- a/app/utils/network.js +++ b/app/utils/network.js @@ -5,7 +5,7 @@ import {Platform} from 'react-native'; import NetInfo from '@react-native-community/netinfo'; import RNFetchBlob from 'rn-fetch-blob'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import mattermostBucket from 'app/mattermost_bucket'; import mattermostManaged from 'app/mattermost_managed'; diff --git a/app/utils/security.js b/app/utils/security.js index e9b123357..ca541deed 100644 --- a/app/utils/security.js +++ b/app/utils/security.js @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import CookieManager from 'react-native-cookies'; export function setCSRFFromCookie(url) { diff --git a/app/utils/sentry/index.js b/app/utils/sentry/index.js index 645812dbc..de5967fd5 100644 --- a/app/utils/sentry/index.js +++ b/app/utils/sentry/index.js @@ -4,7 +4,7 @@ import {Platform} from 'react-native'; import Config from '@assets/config'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getConfig} from '@mm-redux/selectors/entities/general'; import {getCurrentUser} from '@mm-redux/selectors/entities/users'; import {getCurrentTeam, getCurrentTeamMembership} from '@mm-redux/selectors/entities/teams'; @@ -291,7 +291,7 @@ export function cleanUrlForLogging(original) { 'files', 'preferences', 'hooks', 'incoming', 'outgoing', 'oauth', 'apps', 'emoji', 'brand', 'image', 'data_retention', 'jobs', 'plugins', 'roles', 'system', 'timezones', 'schemes', 'redirect_location', 'patch', 'mfa', 'password', 'reset', 'send', 'active', 'verify', 'terms_of_service', 'login', 'logout', 'ids', - 'usernames', 'me', 'username', 'email', 'default', 'sessions', 'revoke', 'all', 'audits', 'device', 'status', + 'usernames', 'me', 'username', 'email', 'default', 'sessions', 'revoke', 'all', 'device', 'status', 'search', 'switch', 'authorized', 'authorize', 'deauthorize', 'tokens', 'disable', 'enable', 'exists', 'unread', 'invite', 'batch', 'stats', 'import', 'schemeRoles', 'direct', 'group', 'convert', 'view', 'search_autocomplete', 'thread', 'info', 'flagged', 'pinned', 'pin', 'unpin', 'opengraph', 'actions', 'thumbnail', 'preview', 'link', diff --git a/app/utils/sentry/index.test.js b/app/utils/sentry/index.test.js index fd99000b6..8bc99cd5d 100644 --- a/app/utils/sentry/index.test.js +++ b/app/utils/sentry/index.test.js @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {cleanUrlForLogging} from 'app/utils/sentry'; diff --git a/babel.config.js b/babel.config.js index 4eb38c17b..57d768854 100644 --- a/babel.config.js +++ b/babel.config.js @@ -14,6 +14,7 @@ module.exports = { alias: { '@assets': './dist/assets', '@actions': './app/actions', + '@client': './app/client', '@components': './app/components', '@constants': './app/constants', '@i18n': './app/i18n', diff --git a/share_extension/actions/index.ts b/share_extension/actions/index.ts index 5d9002c16..bc0a20f65 100644 --- a/share_extension/actions/index.ts +++ b/share_extension/actions/index.ts @@ -5,7 +5,7 @@ import {batchActions} from 'redux-batched-actions'; import {loadSidebar} from '@actions/views/channel'; import {ChannelTypes, RoleTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {getRedirectChannelNameForTeam, getChannelsNameMapInTeam} from '@mm-redux/selectors/entities/channels'; import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; import {DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; diff --git a/share_extension/screens/share.tsx b/share_extension/screens/share.tsx index 79b2b2371..9968a6cb9 100644 --- a/share_extension/screens/share.tsx +++ b/share_extension/screens/share.tsx @@ -8,7 +8,7 @@ import {Alert, BackHandler, NativeModules, StyleSheet, View} from 'react-native' import {useSelector} from 'react-redux'; import {MAX_FILE_COUNT, MAX_MESSAGE_LENGTH_FALLBACK} from '@constants/post_draft'; -import {Client4} from '@mm-redux/client'; +import {Client4} from '@client/rest'; import {Preferences} from '@mm-redux/constants'; import {getCurrentChannel} from '@mm-redux/selectors/entities/channels'; import {getConfig, canUploadFilesOnMobile} from '@mm-redux/selectors/entities/general'; diff --git a/test/test_helper.js b/test/test_helper.js index 32ec9ab4b..7ec4f4ff6 100644 --- a/test/test_helper.js +++ b/test/test_helper.js @@ -5,7 +5,7 @@ import assert from 'assert'; import nock from 'nock'; import Config from '@assets/config.json'; -import Client from '@mm-redux/client/client4'; +import {Client} from '@client/rest'; import {DEFAULT_LOCALE} from '@mm-redux/constants/general'; import {generateId} from '@mm-redux/utils/helpers'; diff --git a/tsconfig.json b/tsconfig.json index 835bda0a2..29588fe49 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,6 +34,7 @@ "paths": { "@actions/*": ["app/actions/*"], "@assets/*": ["dist/assets/*"], + "@client/*": ["app/client/*"], "@components/*": ["app/components/*"], "@constants/*": ["app/constants/*"], "@constants": ["app/constants/index"],