UNPKG

mattermost-redux

Version:

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

256 lines (220 loc) 8.67 kB
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {Client4} from 'client'; import {SearchTypes} from 'action_types'; import {getCurrentTeamId} from 'selectors/entities/teams'; import {getCurrentUserId, getCurrentUserMentionKeys} from 'selectors/entities/users'; import {getChannelAndMyMember, getChannelMembers} from './channels'; import {forceLogoutIfNecessary} from './helpers'; import {logError} from './errors'; import {getProfilesAndStatusesForPosts, receivedPosts} from './posts'; import {ActionResult, batchActions, DispatchFunc, GetStateFunc, ActionFunc} from 'types/actions'; import {Post} from 'types/posts'; import {SearchParameter} from 'types/search'; const WEBAPP_SEARCH_PER_PAGE = 20; export function getMissingChannelsFromPosts(posts: Map<string, Post>): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const { channels, membersInChannel, myMembers, } = getState().entities.channels; const promises: Array<Promise<ActionResult>> = []; Object.values(posts).forEach((post) => { const id = post.channel_id; if (!channels[id] || !myMembers[id]) { promises.push(dispatch(getChannelAndMyMember(id))); } if (!membersInChannel[id]) { promises.push(dispatch(getChannelMembers(id))); } }); return Promise.all(promises); }; } export function searchPostsWithParams(teamId: string, params: SearchParameter): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const isGettingMore = params.page > 0; dispatch({ type: SearchTypes.SEARCH_POSTS_REQUEST, isGettingMore, }); let posts; try { posts = await Client4.searchPostsWithParams(teamId, params); const profilesAndStatuses = getProfilesAndStatusesForPosts(posts.posts, dispatch, getState); const missingChannels = dispatch(getMissingChannelsFromPosts(posts.posts)); const arr: [Promise<any>, Promise<any>] = [profilesAndStatuses, missingChannels]; await Promise.all(arr); } catch (error) { forceLogoutIfNecessary(error, dispatch, getState); dispatch(logError(error)); return {error}; } dispatch(batchActions([ { type: SearchTypes.RECEIVED_SEARCH_POSTS, data: posts, isGettingMore, }, receivedPosts(posts), { type: SearchTypes.RECEIVED_SEARCH_TERM, data: { teamId, params, isEnd: posts.order.length === 0, }, }, { type: SearchTypes.SEARCH_POSTS_SUCCESS, }, ], 'SEARCH_POST_BATCH')); return {data: posts}; }; } export function searchPosts(teamId: string, terms: string, isOrSearch: boolean, includeDeletedChannels: boolean) { return searchPostsWithParams(teamId, {terms, is_or_search: isOrSearch, include_deleted_channels: includeDeletedChannels, page: 0, per_page: WEBAPP_SEARCH_PER_PAGE}); } export function getMorePostsForSearch(): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const teamId = getCurrentTeamId(getState()); const {params, isEnd} = getState().entities.search.current[teamId]; if (!isEnd) { const newParams = Object.assign({}, params); newParams.page += 1; return dispatch(searchPostsWithParams(teamId, newParams)); } return {data: true}; }; } export function clearSearch(): ActionFunc { return async (dispatch) => { dispatch({type: SearchTypes.REMOVE_SEARCH_POSTS}); return {data: true}; }; } export function getFlaggedPosts(): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); const userId = getCurrentUserId(state); const teamId = getCurrentTeamId(state); dispatch({type: SearchTypes.SEARCH_FLAGGED_POSTS_REQUEST}); let posts; try { posts = await Client4.getFlaggedPosts(userId, '', teamId); await Promise.all([getProfilesAndStatusesForPosts(posts.posts, dispatch, getState) as any, dispatch(getMissingChannelsFromPosts(posts.posts)) as any]); } catch (error) { forceLogoutIfNecessary(error, dispatch, getState); dispatch(batchActions([ {type: SearchTypes.SEARCH_FLAGGED_POSTS_FAILURE, error}, logError(error), ])); return {error}; } dispatch(batchActions([ { type: SearchTypes.RECEIVED_SEARCH_FLAGGED_POSTS, data: posts, }, receivedPosts(posts), { type: SearchTypes.SEARCH_FLAGGED_POSTS_SUCCESS, }, ], 'SEARCH_FLAGGED_POSTS_BATCH')); return {data: posts}; }; } export function getPinnedPosts(channelId: string): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { dispatch({type: SearchTypes.SEARCH_PINNED_POSTS_REQUEST}); let result; try { result = await Client4.getPinnedPosts(channelId); const profilesAndStatuses = getProfilesAndStatusesForPosts(result.posts, dispatch, getState); const missingChannels = dispatch(getMissingChannelsFromPosts(result.posts)); const arr: [Promise<any>, Promise<any>] = [profilesAndStatuses, missingChannels]; await Promise.all(arr); } catch (error) { forceLogoutIfNecessary(error, dispatch, getState); dispatch(batchActions([ {type: SearchTypes.SEARCH_PINNED_POSTS_FAILURE, error}, logError(error), ])); return {error}; } dispatch(batchActions([ { type: SearchTypes.RECEIVED_SEARCH_PINNED_POSTS, data: { pinned: result, channelId, }, }, receivedPosts(result), { type: SearchTypes.SEARCH_PINNED_POSTS_SUCCESS, }, ], 'SEARCH_PINNED_POSTS_BATCH')); return {data: result}; }; } export function clearPinnedPosts(channelId: string): ActionFunc { return async (dispatch) => { dispatch({ type: SearchTypes.REMOVE_SEARCH_PINNED_POSTS, data: { channelId, }, }); return {data: true}; }; } export function getRecentMentions(): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { const state = getState(); const teamId = getCurrentTeamId(state); let posts; try { const termKeys = getCurrentUserMentionKeys(state).filter(({key}) => { return key !== '@channel' && key !== '@all' && key !== '@here'; }); const terms = termKeys.map(({key}) => key).join(' ').trim() + ' '; Client4.trackEvent('api', 'api_posts_search_mention'); posts = await Client4.searchPosts(teamId, terms, true); const profilesAndStatuses = getProfilesAndStatusesForPosts(posts.posts, dispatch, getState); const missingChannels = dispatch(getMissingChannelsFromPosts(posts.posts)); const arr: [Promise<any>, Promise<any>] = [profilesAndStatuses, missingChannels]; await Promise.all(arr); } catch (error) { forceLogoutIfNecessary(error, dispatch, getState); dispatch(logError(error)); return {error}; } dispatch(batchActions([ { type: SearchTypes.RECEIVED_SEARCH_POSTS, data: posts, }, receivedPosts(posts), ], 'SEARCH_RECENT_MENTIONS_BATCH')); return {data: posts}; }; } export function removeSearchTerms(teamId: string, terms: string): ActionFunc { return async (dispatch) => { dispatch({ type: SearchTypes.REMOVE_SEARCH_TERM, data: { teamId, terms, }, }); return {data: true}; }; } export default { clearSearch, removeSearchTerms, searchPosts, };