UNPKG

mattermost-redux

Version:

Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client

279 lines (278 loc) 11.4 kB
"use strict"; // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. Object.defineProperty(exports, "__esModule", { value: true }); exports.WEBAPP_SEARCH_PER_PAGE = void 0; exports.getMissingChannelsFromPosts = getMissingChannelsFromPosts; exports.getMissingChannelsFromFiles = getMissingChannelsFromFiles; exports.searchPostsWithParams = searchPostsWithParams; exports.searchPosts = searchPosts; exports.getMorePostsForSearch = getMorePostsForSearch; exports.clearSearch = clearSearch; exports.searchFilesWithParams = searchFilesWithParams; exports.getMoreFilesForSearch = getMoreFilesForSearch; exports.getFlaggedPosts = getFlaggedPosts; exports.getPinnedPosts = getPinnedPosts; const redux_batched_actions_1 = require("redux-batched-actions"); const action_types_1 = require("mattermost-redux/action_types"); const client_1 = require("mattermost-redux/client"); const users_1 = require("mattermost-redux/selectors/entities/users"); const channels_1 = require("./channels"); const errors_1 = require("./errors"); const files_1 = require("./files"); const helpers_1 = require("./helpers"); const posts_1 = require("./posts"); exports.WEBAPP_SEARCH_PER_PAGE = 20; function getMissingChannelsFromPosts(posts) { return async (dispatch, getState) => { const { channels, membersInChannel, myMembers, } = getState().entities.channels; const promises = []; Object.values(posts).forEach((post) => { const id = post.channel_id; if (!channels[id]) { // Fetch channel data independently so a 403 on the membership request (e.g. for public channels // the user hasn't joined) doesn't prevent the channel from being loaded. promises.push(dispatch((0, channels_1.getChannel)(id))); } if (!myMembers[id]) { // Best-effort: will 403 for non-member public channels, which is fine. promises.push(dispatch((0, channels_1.getChannelAndMyMember)(id))); } if (!membersInChannel[id]) { promises.push(dispatch((0, channels_1.getChannelMembers)(id))); } }); return Promise.all(promises); }; } function getMissingChannelsFromFiles(files) { return async (dispatch, getState) => { const { channels, membersInChannel, myMembers, } = getState().entities.channels; const promises = []; Object.values(files).forEach((file) => { const id = file.channel_id; if (!channels[id]) { // Fetch channel data independently so a 403 on the membership request (e.g. for public channels // the user hasn't joined) doesn't prevent the channel from being loaded. promises.push(dispatch((0, channels_1.getChannel)(id))); } if (!myMembers[id]) { // Best-effort: will 403 for non-member public channels, which is fine. promises.push(dispatch((0, channels_1.getChannelAndMyMember)(id))); } if (!membersInChannel[id]) { promises.push(dispatch((0, channels_1.getChannelMembers)(id))); } }); return Promise.all(promises); }; } function searchPostsWithParams(teamId, params) { return async (dispatch, getState) => { const isGettingMore = params.page > 0; dispatch({ type: action_types_1.SearchTypes.SEARCH_POSTS_REQUEST, isGettingMore, }); // Reset truncation info for new searches (not pagination) if (!isGettingMore) { dispatch({ type: action_types_1.SearchTypes.RECEIVED_SEARCH_TRUNCATION_INFO, data: { firstInaccessiblePostTime: 0, searchType: 'posts', }, }); } let posts; try { posts = await client_1.Client4.searchPostsWithParams(teamId, params); const profilesAndStatuses = (0, posts_1.getMentionsAndStatusesForPosts)(posts.posts, dispatch, getState); const missingChannels = dispatch(getMissingChannelsFromPosts(posts.posts)); const arr = [profilesAndStatuses, missingChannels]; await Promise.all(arr); } catch (error) { (0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState); dispatch((0, errors_1.logError)(error)); return { error }; } dispatch((0, redux_batched_actions_1.batchActions)([ { type: action_types_1.SearchTypes.RECEIVED_SEARCH_POSTS, data: posts, isGettingMore, }, (0, posts_1.receivedPosts)(posts), { type: action_types_1.SearchTypes.RECEIVED_SEARCH_TERM, data: { teamId, params, isEnd: posts.order.length === 0, }, }, { type: action_types_1.SearchTypes.SEARCH_POSTS_SUCCESS, }, ], 'SEARCH_POST_BATCH')); // Dispatch truncation info separately to avoid typing conflicts const firstInaccessiblePostTime = posts.first_inaccessible_post_time || 0; if (firstInaccessiblePostTime > 0) { dispatch({ type: action_types_1.SearchTypes.RECEIVED_SEARCH_TRUNCATION_INFO, data: { firstInaccessiblePostTime, searchType: 'posts', }, }); } return { data: posts }; }; } function searchPosts(teamId, terms, isOrSearch, includeDeletedChannels) { return searchPostsWithParams(teamId, { terms, is_or_search: isOrSearch, include_deleted_channels: includeDeletedChannels, page: 0, per_page: exports.WEBAPP_SEARCH_PER_PAGE }); } function getMorePostsForSearch(teamId) { return async (dispatch, getState) => { const { params, isEnd } = getState().entities.search.current[teamId || 'ALL_TEAMS']; if (!isEnd) { const newParams = Object.assign({}, params); newParams.page += 1; return dispatch(searchPostsWithParams(teamId, newParams)); } return { data: true }; }; } function clearSearch() { return async (dispatch) => { dispatch({ type: action_types_1.SearchTypes.REMOVE_SEARCH_POSTS }); dispatch({ type: action_types_1.SearchTypes.REMOVE_SEARCH_FILES }); return { data: true }; }; } function searchFilesWithParams(teamId, params) { return async (dispatch, getState) => { const isGettingMore = params.page > 0; dispatch({ type: action_types_1.SearchTypes.SEARCH_FILES_REQUEST, isGettingMore, }); // Reset truncation info for new searches (not pagination) if (!isGettingMore) { dispatch({ type: action_types_1.SearchTypes.RECEIVED_SEARCH_TRUNCATION_INFO, data: { firstInaccessiblePostTime: 0, searchType: 'files', }, }); } let files; try { files = await client_1.Client4.searchFilesWithParams(teamId, params); await dispatch(getMissingChannelsFromFiles(files.file_infos)); } catch (error) { (0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState); dispatch((0, errors_1.logError)(error)); return { error }; } dispatch((0, redux_batched_actions_1.batchActions)([ { type: action_types_1.SearchTypes.RECEIVED_SEARCH_FILES, data: files, isGettingMore, }, (0, files_1.receivedFiles)(files.file_infos), { type: action_types_1.SearchTypes.RECEIVED_SEARCH_TERM, data: { teamId, params, isFilesEnd: files.order.length === 0, }, }, { type: action_types_1.SearchTypes.SEARCH_FILES_SUCCESS, }, ], 'SEARCH_FILE_BATCH')); return { data: files }; }; } function getMoreFilesForSearch(teamId) { return async (dispatch, getState) => { const { params, isFilesEnd } = getState().entities.search.current[teamId || 'ALL_TEAMS']; if (!isFilesEnd) { const newParams = Object.assign({}, params); newParams.page += 1; return dispatch(searchFilesWithParams(teamId, newParams)); } return { data: true }; }; } function getFlaggedPosts() { return async (dispatch, getState) => { const state = getState(); const userId = (0, users_1.getCurrentUserId)(state); dispatch({ type: action_types_1.SearchTypes.SEARCH_FLAGGED_POSTS_REQUEST }); let posts; try { posts = await client_1.Client4.getFlaggedPosts(userId); await Promise.all([(0, posts_1.getMentionsAndStatusesForPosts)(posts.posts, dispatch, getState), dispatch(getMissingChannelsFromPosts(posts.posts))]); } catch (error) { (0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState); dispatch({ type: action_types_1.SearchTypes.SEARCH_FLAGGED_POSTS_FAILURE, error }); dispatch((0, errors_1.logError)(error)); return { error }; } dispatch((0, redux_batched_actions_1.batchActions)([ { type: action_types_1.SearchTypes.RECEIVED_SEARCH_FLAGGED_POSTS, data: posts, }, (0, posts_1.receivedPosts)(posts), { type: action_types_1.SearchTypes.SEARCH_FLAGGED_POSTS_SUCCESS, }, ], 'SEARCH_FLAGGED_POSTS_BATCH')); return { data: posts }; }; } function getPinnedPosts(channelId) { return async (dispatch, getState) => { dispatch({ type: action_types_1.SearchTypes.SEARCH_PINNED_POSTS_REQUEST }); let result; try { result = await client_1.Client4.getPinnedPosts(channelId); const profilesAndStatuses = (0, posts_1.getMentionsAndStatusesForPosts)(result.posts, dispatch, getState); const missingChannels = dispatch(getMissingChannelsFromPosts(result.posts)); const arr = [profilesAndStatuses, missingChannels]; await Promise.all(arr); } catch (error) { (0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState); dispatch({ type: action_types_1.SearchTypes.SEARCH_PINNED_POSTS_FAILURE, error }); return { error }; } dispatch((0, redux_batched_actions_1.batchActions)([ { type: action_types_1.SearchTypes.RECEIVED_SEARCH_PINNED_POSTS, data: { pinned: result, channelId, }, }, (0, posts_1.receivedPosts)(result), { type: action_types_1.SearchTypes.SEARCH_PINNED_POSTS_SUCCESS, }, ], 'SEARCH_PINNED_POSTS_BATCH')); return { data: result }; }; } exports.default = { clearSearch, searchPosts, };