diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 67dd1ffe9..ed2d4f790 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ When filling in a section please remove the help text and the above text. #### Checklist [Place an '[x]' (no spaces) in all applicable fields. Please remove unrelated fields.] - [ ] Added or updated unit tests (required for all new features) -- [ ] All new/modified APIs include changes to the drivers +- [ ] All new/modified APIs include changes to [mattermost-redux](https://github.com/mattermost/mattermost-redux) (please link) - [ ] Has UI changes - [ ] Includes text changes and localization file updates diff --git a/app/actions/navigation/index.js b/app/actions/navigation/index.js index 7646a59b8..763513d67 100644 --- a/app/actions/navigation/index.js +++ b/app/actions/navigation/index.js @@ -3,8 +3,8 @@ import {NavigationTypes} from 'app/constants'; import Routes from 'app/navigation/routes'; -import {Constants} from 'service/constants'; -import {selectPost} from 'service/actions/posts'; +import {Constants} from 'mattermost-redux/constants'; +import {selectPost} from 'mattermost-redux/actions/posts'; export function goBack() { return async (dispatch, getState) => { diff --git a/app/actions/storage/index.js b/app/actions/storage/index.js index 2d5fee8c6..0bcb5fa46 100644 --- a/app/actions/storage/index.js +++ b/app/actions/storage/index.js @@ -3,9 +3,10 @@ import {AsyncStorage} from 'react-native'; import {batchActions} from 'redux-batched-actions'; + import {ViewTypes} from 'app/constants'; -import {logError, getLogErrorAction} from 'service/actions/errors'; -import {ChannelTypes, GeneralTypes, TeamsTypes, UsersTypes} from 'service/constants'; +import {logError, getLogErrorAction} from 'mattermost-redux/actions/errors'; +import {ChannelTypes, GeneralTypes, TeamsTypes, UsersTypes} from 'mattermost-redux/constants'; export function loadStorage() { return async (dispatch, getState) => { @@ -17,7 +18,6 @@ export function loadStorage() { const credentials = {token, url}; const currentChannelId = otherStorage[currentTeamId] ? otherStorage[currentTeamId].currentChannelId : ''; - const actions = []; if (credentials) { diff --git a/app/actions/views/account_notifications.js b/app/actions/views/account_notifications.js index 24f4e6ca0..33c9c388a 100644 --- a/app/actions/views/account_notifications.js +++ b/app/actions/views/account_notifications.js @@ -1,9 +1,9 @@ // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {updateUserNotifyProps} from 'service/actions/users'; -import {Preferences} from 'service/constants'; -import {savePreferences} from 'service/actions/preferences'; +import {updateUserNotifyProps} from 'mattermost-redux/actions/users'; +import {Preferences} from 'mattermost-redux/constants'; +import {savePreferences} from 'mattermost-redux/actions/preferences'; export function handleUpdateUserNotifyProps(notifyProps) { return async (dispatch, getState) => { diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index a49879b1a..e0ab54572 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -12,14 +12,14 @@ import { getMyChannelMembers, selectChannel, leaveChannel as serviceLeaveChannel -} from 'service/actions/channels'; -import {getPosts, getPostsSince} from 'service/actions/posts'; -import {getFilesForPost} from 'service/actions/files'; -import {savePreferences, deletePreferences} from 'service/actions/preferences'; -import {getTeamMembersByIds} from 'service/actions/teams'; -import {Constants, UsersTypes} from 'service/constants'; -import {getChannelByName, getDirectChannelName, isDirectChannelVisible} from 'service/utils/channel_utils'; -import {getPreferencesByCategory} from 'service/utils/preference_utils'; +} from 'mattermost-redux/actions/channels'; +import {getPosts, getPostsSince} from 'mattermost-redux/actions/posts'; +import {getFilesForPost} from 'mattermost-redux/actions/files'; +import {savePreferences, deletePreferences} from 'mattermost-redux/actions/preferences'; +import {getTeamMembersByIds} from 'mattermost-redux/actions/teams'; +import {Constants, UsersTypes} from 'mattermost-redux/constants'; +import {getChannelByName, getDirectChannelName, isDirectChannelVisible} from 'mattermost-redux/utils/channel_utils'; +import {getPreferencesByCategory} from 'mattermost-redux/utils/preference_utils'; export function loadChannelsIfNecessary(teamId) { return async (dispatch, getState) => { @@ -45,7 +45,7 @@ export function loadChannelsIfNecessary(teamId) { export function loadProfilesAndTeamMembersForDMSidebar(teamId) { return async (dispatch, getState) => { const state = getState(); - const currentUserId = state.entities.users.currentId; + const {currentUserId} = state.entities.users; const {channels} = state.entities.channels; const {myPreferences} = state.entities.preferences; const {membersInTeam} = state.entities.teams; @@ -92,7 +92,7 @@ export function loadPostsIfNecessary(channel) { const postsInChannel = state.entities.posts.postsByChannel[channel.id]; // Make sure we include a team id for DM channels - const teamId = channel.team_id || state.entities.teams.currentId; + const teamId = channel.team_id || state.entities.teams.currentTeamId; // Get the first page of posts if it appears we haven't gotten it yet, like the webapp if (!postsInChannel || postsInChannel.length < Constants.POST_CHUNK_SIZE) { @@ -111,8 +111,8 @@ export function loadFilesForPostIfNecessary(post) { const fileIdsForPost = files.fileIdsByPostId[post.id]; if (!fileIdsForPost) { - const teamId = teams.currentId; - await getFilesForPost(teamId, post.channel_id, post.id)(dispatch, getState); + const {currentTeamId} = teams; + await getFilesForPost(currentTeamId, post.channel_id, post.id)(dispatch, getState); } }; } @@ -120,9 +120,8 @@ export function loadFilesForPostIfNecessary(post) { export function selectInitialChannel(teamId) { return async (dispatch, getState) => { const state = getState(); - const {channels, myMembers} = state.entities.channels; - const currentChannelId = state.entities.channels.currentId; - const currentUserId = state.entities.users.currentId; + const {channels, currentChannelId, myMembers} = state.entities.channels; + const {currentUserId} = state.entities.users; const currentChannel = channels[currentChannelId]; const {myPreferences} = state.entities.preferences; @@ -148,7 +147,7 @@ export function selectInitialChannel(teamId) { export function handleSelectChannel(channelId) { return async (dispatch, getState) => { - const currentTeamId = getState().entities.teams.currentId; + const {currentTeamId} = getState().entities.teams; await updateStorage(currentTeamId, {currentChannelId: channelId}); await selectChannel(channelId)(dispatch, getState); @@ -169,10 +168,10 @@ export function handlePostDraftChanged(channelId, postDraft) { export function toggleDMChannel(otherUserId, visible) { return async (dispatch, getState) => { const state = getState(); - const userId = state.entities.users.currentId; + const {currentUserId} = state.entities.users; const dm = [{ - user_id: userId, + user_id: currentUserId, category: Constants.CATEGORY_DIRECT_CHANNEL_SHOW, name: otherUserId, value: visible @@ -192,7 +191,7 @@ export function closeDMChannel(channel) { toggleDMChannel(channel.teammate_id, 'false')(dispatch, getState).then(() => { if (channel.isCurrent) { - selectInitialChannel(state.entities.teams.currentId)(dispatch, getState); + selectInitialChannel(state.entities.teams.currentTeamId)(dispatch, getState); } }); }; @@ -200,9 +199,9 @@ export function closeDMChannel(channel) { export function markFavorite(channelId) { return async (dispatch, getState) => { - const userId = getState().entities.users.currentId; + const {currentUserId} = getState().entities.users; const fav = [{ - user_id: userId, + user_id: currentUserId, category: Constants.CATEGORY_FAVORITE_CHANNEL, name: channelId, value: 'true' @@ -213,9 +212,9 @@ export function markFavorite(channelId) { export function unmarkFavorite(channelId) { return async (dispatch, getState) => { - const userId = getState().entities.users.currentId; + const {currentUserId} = getState().entities.users; const fav = [{ - user_id: userId, + user_id: currentUserId, category: Constants.CATEGORY_FAVORITE_CHANNEL, name: channelId }]; @@ -225,10 +224,10 @@ export function unmarkFavorite(channelId) { export function leaveChannel(channel, reset = false) { return async (dispatch, getState) => { - const {currentId: teamId} = getState().entities.teams; - await serviceLeaveChannel(teamId, channel.id)(dispatch, getState); + const {currentTeamId} = getState().entities.teams; + await serviceLeaveChannel(currentTeamId, channel.id)(dispatch, getState); if (channel.isCurrent || reset) { - await selectInitialChannel(teamId)(dispatch, getState); + await selectInitialChannel(currentTeamId)(dispatch, getState); } }; } diff --git a/app/actions/views/channel_add_members.js b/app/actions/views/channel_add_members.js index 0718a4eda..4e81d6422 100644 --- a/app/actions/views/channel_add_members.js +++ b/app/actions/views/channel_add_members.js @@ -1,7 +1,7 @@ // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {addChannelMember} from 'service/actions/channels'; +import {addChannelMember} from 'mattermost-redux/actions/channels'; export function handleAddChannelMembers(teamId, channelId, members) { return async (dispatch, getState) => { diff --git a/app/actions/views/channel_members.js b/app/actions/views/channel_members.js index 74f2dad8d..bf81d3420 100644 --- a/app/actions/views/channel_members.js +++ b/app/actions/views/channel_members.js @@ -1,7 +1,7 @@ // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {removeChannelMember} from 'service/actions/channels'; +import {removeChannelMember} from 'mattermost-redux/actions/channels'; export function handleRemoveChannelMembers(teamId, channelId, members) { return async (dispatch, getState) => { diff --git a/app/actions/views/create_channel.js b/app/actions/views/create_channel.js index db465d82c..f4a421d19 100644 --- a/app/actions/views/create_channel.js +++ b/app/actions/views/create_channel.js @@ -2,10 +2,10 @@ // See License.txt for license information. import {handleSelectChannel} from './channel'; -import {createChannel} from 'service/actions/channels'; -import {getCurrentTeamId} from 'service/selectors/entities/teams'; -import {getCurrentUserId} from 'service/selectors/entities/users'; -import {cleanUpUrlable} from 'service/utils/channel_utils'; +import {createChannel} from 'mattermost-redux/actions/channels'; +import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; +import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; +import {cleanUpUrlable} from 'mattermost-redux/utils/channel_utils'; export function handleCreateChannel(displayName, purpose, header, type) { return async (dispatch, getState) => { diff --git a/app/actions/views/login.js b/app/actions/views/login.js index 78ce77192..e5be28d25 100644 --- a/app/actions/views/login.js +++ b/app/actions/views/login.js @@ -3,7 +3,7 @@ import {ViewTypes} from 'app/constants'; import {updateStorage} from 'app/actions/storage'; -import Client from 'service/client'; +import Client from 'mattermost-redux/client'; export function handleLoginIdChanged(loginId) { return async (dispatch, getState) => { diff --git a/app/actions/views/more_dms.js b/app/actions/views/more_dms.js index 8a218c1f4..753aa416d 100644 --- a/app/actions/views/more_dms.js +++ b/app/actions/views/more_dms.js @@ -1,27 +1,27 @@ // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {getDirectChannelName} from 'service/utils/channel_utils'; -import {createDirectChannel} from 'service/actions/channels'; -import {getTeamMember} from 'service/actions/teams'; +import {getDirectChannelName} from 'mattermost-redux/utils/channel_utils'; +import {createDirectChannel} from 'mattermost-redux/actions/channels'; +import {getTeamMember} from 'mattermost-redux/actions/teams'; import {handleSelectChannel, toggleDMChannel} from 'app/actions/views/channel'; export function makeDirectChannel(otherUserId) { return async (dispatch, getState) => { const state = getState(); - const {currentId} = state.entities.users; - const channelName = getDirectChannelName(currentId, otherUserId); + const {currentUserId} = state.entities.users; + const channelName = getDirectChannelName(currentUserId, otherUserId); const {channels, myMembers} = state.entities.channels; const channel = Object.values(channels).find((c) => c.name === channelName); - const teamId = state.entities.teams.currentId; + const {currentTeamId} = state.entities.teams; - await getTeamMember(teamId, otherUserId)(dispatch, getState); + await getTeamMember(currentTeamId, otherUserId)(dispatch, getState); if (channel && myMembers[channel.id]) { await toggleDMChannel(otherUserId, 'true')(dispatch, getState); handleSelectChannel(channel.id)(dispatch, getState); } else { - const created = await createDirectChannel(teamId, currentId, otherUserId)(dispatch, getState); + const created = await createDirectChannel(currentTeamId, currentUserId, otherUserId)(dispatch, getState); if (created) { await toggleDMChannel(otherUserId, 'true')(dispatch, getState); handleSelectChannel(created.id)(dispatch, getState); diff --git a/app/actions/views/root.js b/app/actions/views/root.js index cf0bad390..05c5edda0 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -12,10 +12,8 @@ import {goToChannelView} from 'app/actions/views/load_team'; import {handleTeamChange, selectFirstAvailableTeam} from 'app/actions/views/select_team'; import {updateStorage} from 'app/actions/storage'; -import Client from 'service/client'; -import {markChannelAsRead, viewChannel} from 'service/actions/channels'; -import {getClientConfig, getLicenseConfig, setServerVersion} from 'service/actions/general'; -import {loadMe} from 'service/actions/users'; +import {getClientConfig, getLicenseConfig, setServerVersion} from 'mattermost-redux/actions/general'; +import {markChannelAsRead, viewChannel} from 'mattermost-redux/actions/channels'; export function goToSelectServer() { return async (dispatch, getState) => { @@ -27,15 +25,6 @@ export function goToSelectServer() { }; } -export function setStoreFromLocalData(data) { - return async (dispatch, getState) => { - Client.setToken(data.token); - Client.setUrl(data.url); - - return loadMe()(dispatch, getState); - }; -} - export function loadConfigAndLicense(serverVersion) { return async (dispatch, getState) => { getClientConfig()(dispatch, getState); @@ -67,7 +56,7 @@ export function goToNotification(notification) { loadChannelsIfNecessary(teamId)(dispatch, getState); } else { await selectFirstAvailableTeam()(dispatch, getState); - teamId = getState().entities.teams.currentId; + teamId = getState().entities.teams.currentTeamId; } const channelId = data.channel_id; @@ -82,7 +71,6 @@ export function goToNotification(notification) { export default { goToSelectServer, loadConfigAndLicense, - setStoreFromLocalData, queueNotification, clearNotification, goToNotification diff --git a/app/actions/views/select_team.js b/app/actions/views/select_team.js index df908fc61..f8f324194 100644 --- a/app/actions/views/select_team.js +++ b/app/actions/views/select_team.js @@ -3,12 +3,12 @@ import {batchActions} from 'redux-batched-actions'; -import {ChannelTypes, TeamsTypes} from 'service/constants'; +import {ChannelTypes, TeamsTypes} from 'mattermost-redux/constants'; import {updateStorage} from 'app/actions/storage'; export function handleTeamChange(team) { return async (dispatch, getState) => { - const currentTeamId = getState().entities.teams.currentId; + const {currentTeamId} = getState().entities.teams; if (currentTeamId === team.id) { return; } diff --git a/app/components/action_button.js b/app/components/action_button.js index 38f6352b9..9aee66724 100644 --- a/app/components/action_button.js +++ b/app/components/action_button.js @@ -7,12 +7,11 @@ import { TouchableOpacity, View } from 'react-native'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; - -import {getTheme} from 'service/selectors/entities/preferences'; -import EventEmitter from 'service/utils/event_emitter'; +import {getTheme} from 'app/selectors/preferences'; import {changeOpacity} from 'app/utils/theme'; class ActionButton extends PureComponent { diff --git a/app/components/autocomplete/at_mention/at_mention.js b/app/components/autocomplete/at_mention/at_mention.js index 93f9a1469..c9db253f1 100644 --- a/app/components/autocomplete/at_mention/at_mention.js +++ b/app/components/autocomplete/at_mention/at_mention.js @@ -15,7 +15,7 @@ import FormattedText from 'app/components/formatted_text'; import ProfilePicture from 'app/components/profile_picture'; import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; -import {RequestStatus} from 'service/constants'; +import {RequestStatus} from 'mattermost-redux/constants'; const AT_MENTION_REGEX = /\B(@([^@\r\n\s]*))$/i; diff --git a/app/components/autocomplete/at_mention/index.js b/app/components/autocomplete/at_mention/index.js index 71495cedb..341e820a5 100644 --- a/app/components/autocomplete/at_mention/index.js +++ b/app/components/autocomplete/at_mention/index.js @@ -4,15 +4,15 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {autocompleteUsersInChannel} from 'service/actions/users'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getDefaultChannel} from 'service/selectors/entities/channels'; -import {getAutocompleteUsersInCurrentChannel} from 'service/selectors/entities/users'; +import {getTheme} from 'app/selectors/preferences'; +import {autocompleteUsersInChannel} from 'mattermost-redux/actions/users'; +import {getDefaultChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getAutocompleteUsersInCurrentChannel} from 'mattermost-redux/selectors/entities/users'; import AtMention from './at_mention'; function mapStateToProps(state, ownProps) { - const currentChannelId = state.entities.channels.currentId; + const {currentChannelId} = state.entities.channels; let postDraft; if (ownProps.rootId.length) { @@ -23,9 +23,9 @@ function mapStateToProps(state, ownProps) { return { ...ownProps, - currentUserId: state.entities.users.currentId, + currentUserId: state.entities.users.currentUserId, currentChannelId, - currentTeamId: state.entities.teams.currentId, + currentTeamId: state.entities.teams.currentTeamId, defaultChannel: getDefaultChannel(state), postDraft, autocompleteUsersInCurrentChannel: getAutocompleteUsersInCurrentChannel(state), diff --git a/app/components/autocomplete/channel_mention/channel_mention.js b/app/components/autocomplete/channel_mention/channel_mention.js index 340c02cce..6fe7ef41d 100644 --- a/app/components/autocomplete/channel_mention/channel_mention.js +++ b/app/components/autocomplete/channel_mention/channel_mention.js @@ -13,7 +13,7 @@ import { import FormattedText from 'app/components/formatted_text'; import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; -import {RequestStatus} from 'service/constants'; +import {RequestStatus} from 'mattermost-redux/constants'; const CHANNEL_MENTION_REGEX = /\B(~([^~\r\n]*))$/i; diff --git a/app/components/autocomplete/channel_mention/index.js b/app/components/autocomplete/channel_mention/index.js index 974d49ad7..a16055dd9 100644 --- a/app/components/autocomplete/channel_mention/index.js +++ b/app/components/autocomplete/channel_mention/index.js @@ -4,14 +4,14 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {autocompleteChannels} from 'service/actions/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getAutocompleteChannelWithSections} from 'service/selectors/entities/channels'; +import {autocompleteChannels} from 'mattermost-redux/actions/channels'; +import {getTheme} from 'app/selectors/preferences'; +import {getAutocompleteChannelWithSections} from 'mattermost-redux/selectors/entities/channels'; import ChannelMention from './channel_mention'; function mapStateToProps(state, ownProps) { - const currentChannelId = state.entities.channels.currentId; + const {currentChannelId} = state.entities.channels; let postDraft; if (ownProps.rootId.length) { @@ -23,7 +23,7 @@ function mapStateToProps(state, ownProps) { return { ...ownProps, currentChannelId, - currentTeamId: state.entities.teams.currentId, + currentTeamId: state.entities.teams.currentTeamId, postDraft, autocompleteChannels: getAutocompleteChannelWithSections(state), requestStatus: state.requests.channels.autocompleteChannels.status, diff --git a/app/components/channel_drawer_list/channel_drawer_item.js b/app/components/channel_drawer_list/channel_drawer_item.js index 24b15e970..a05e83c73 100644 --- a/app/components/channel_drawer_list/channel_drawer_item.js +++ b/app/components/channel_drawer_list/channel_drawer_item.js @@ -8,7 +8,7 @@ import Icon from 'react-native-vector-icons/FontAwesome'; import {OnlineStatus, AwayStatus, OfflineStatus} from 'app/components/status_icons'; import {changeOpacity} from 'app/utils/theme'; -import {Constants} from 'service/constants'; +import {Constants} from 'mattermost-redux/constants'; import Badge from 'app/components/badge'; diff --git a/app/components/channel_drawer_list/channel_drawer_list.js b/app/components/channel_drawer_list/channel_drawer_list.js index c6a540abf..60d20f306 100644 --- a/app/components/channel_drawer_list/channel_drawer_list.js +++ b/app/components/channel_drawer_list/channel_drawer_list.js @@ -13,7 +13,7 @@ import { View } from 'react-native'; import {injectIntl, intlShape} from 'react-intl'; -import {Constants} from 'service/constants'; +import {Constants} from 'mattermost-redux/constants'; import LineDivider from 'app/components/line_divider'; import ChannelDrawerItem from './channel_drawer_item'; import FormattedText from 'app/components/formatted_text'; diff --git a/app/components/error_list/error_list_container.js b/app/components/error_list/error_list_container.js index 4270d4abb..8209ca6b7 100644 --- a/app/components/error_list/error_list_container.js +++ b/app/components/error_list/error_list_container.js @@ -4,8 +4,8 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {getDisplayableErrors} from 'service/selectors/errors'; -import {dismissError, clearErrors} from 'service/actions/errors'; +import {getDisplayableErrors} from 'mattermost-redux/selectors/errors'; +import {dismissError, clearErrors} from 'mattermost-redux/actions/errors'; import ErrorList from './error_list'; diff --git a/app/components/file_attachment_list/file_attachment.js b/app/components/file_attachment_list/file_attachment.js index 725544b19..53bd146ac 100644 --- a/app/components/file_attachment_list/file_attachment.js +++ b/app/components/file_attachment_list/file_attachment.js @@ -15,7 +15,7 @@ import { import Icon from 'react-native-vector-icons/FontAwesome'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import * as Utils from 'service/utils/file_utils.js'; +import * as Utils from 'mattermost-redux/utils/file_utils.js'; import FileAttachmentIcon from './file_attachment_icon'; diff --git a/app/components/file_attachment_list/file_attachment_icon.js b/app/components/file_attachment_list/file_attachment_icon.js index 86d93f6db..314dcb547 100644 --- a/app/components/file_attachment_list/file_attachment_icon.js +++ b/app/components/file_attachment_list/file_attachment_icon.js @@ -12,7 +12,7 @@ import { StyleSheet } from 'react-native'; -import * as Utils from 'service/utils/file_utils'; +import * as Utils from 'mattermost-redux/utils/file_utils'; import audioIcon from 'assets/images/icons/audio.png'; import codeIcon from 'assets/images/icons/code.png'; diff --git a/app/components/file_attachment_list/file_attachment_list_container.js b/app/components/file_attachment_list/file_attachment_list_container.js index 1c20bb733..6848156a4 100644 --- a/app/components/file_attachment_list/file_attachment_list_container.js +++ b/app/components/file_attachment_list/file_attachment_list_container.js @@ -4,9 +4,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {makeGetFilesForPost} from 'service/selectors/entities/files'; +import {makeGetFilesForPost} from 'mattermost-redux/selectors/entities/files'; import {loadFilesForPostIfNecessary} from 'app/actions/views/channel'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import FileAttachmentList from './file_attachment_list'; diff --git a/app/components/logout/logout_container.js b/app/components/logout/logout_container.js index f9b03706c..264c881a2 100644 --- a/app/components/logout/logout_container.js +++ b/app/components/logout/logout_container.js @@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {logout} from 'service/actions/users'; +import {logout} from 'mattermost-redux/actions/users'; import Logout from './logout.js'; diff --git a/app/components/post/post.js b/app/components/post/post.js index 908bddded..87411074a 100644 --- a/app/components/post/post.js +++ b/app/components/post/post.js @@ -19,7 +19,7 @@ import ProfilePicture from 'app/components/profile_picture'; import FileAttachmentList from 'app/components/file_attachment_list/file_attachment_list_container'; import {makeStyleSheetFromTheme} from 'app/utils/theme'; -import {isSystemMessage} from 'service/utils/post_utils.js'; +import {isSystemMessage} from 'mattermost-redux/utils/post_utils.js'; export default class Post extends Component { static propTypes = { diff --git a/app/components/post/post_container.js b/app/components/post/post_container.js index f51fbd0e8..533d54803 100644 --- a/app/components/post/post_container.js +++ b/app/components/post/post_container.js @@ -4,10 +4,11 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences'; +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import {goToUserProfile} from 'app/actions/navigation'; -import {getUser} from 'service/selectors/entities/users'; -import {displayUsername} from 'service/utils/user_utils'; +import {getUser} from 'mattermost-redux/selectors/entities/users'; +import {displayUsername} from 'mattermost-redux/utils/user_utils'; import Post from './post'; diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js index 0c3ff99d3..25f76fe9f 100644 --- a/app/components/post_list/post_list.js +++ b/app/components/post_list/post_list.js @@ -12,8 +12,8 @@ import DateHeader from './date_header'; import LoadMorePosts from './load_more_posts'; import NewMessagesDivider from './new_messages_divider'; -import {Constants} from 'service/constants'; -import {addDatesToPostList} from 'service/utils/post_utils'; +import {Constants} from 'mattermost-redux/constants'; +import {addDatesToPostList} from 'mattermost-redux/utils/post_utils'; const style = StyleSheet.create({ container: { diff --git a/app/components/post_list/post_list_container.js b/app/components/post_list/post_list_container.js index 9557e384c..84b2f88c5 100644 --- a/app/components/post_list/post_list_container.js +++ b/app/components/post_list/post_list_container.js @@ -3,7 +3,7 @@ import {connect} from 'react-redux'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import PostList from './post_list'; diff --git a/app/components/post_textbox/post_textbox_container.js b/app/components/post_textbox/post_textbox_container.js index ef481346f..2b8805ceb 100644 --- a/app/components/post_textbox/post_textbox_container.js +++ b/app/components/post_textbox/post_textbox_container.js @@ -4,11 +4,11 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {createPost} from 'service/actions/posts'; -import {userTyping} from 'service/actions/websocket'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentUserId} from 'service/selectors/entities/users'; -import {getUsersTyping} from 'service/selectors/entities/typing'; +import {createPost} from 'mattermost-redux/actions/posts'; +import {userTyping} from 'mattermost-redux/actions/websocket'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; +import {getUsersTyping} from 'mattermost-redux/selectors/entities/typing'; import PostTextbox from './post_textbox'; diff --git a/app/components/profile_picture/profile_picture.js b/app/components/profile_picture/profile_picture.js index 85398d787..f0e749b58 100644 --- a/app/components/profile_picture/profile_picture.js +++ b/app/components/profile_picture/profile_picture.js @@ -9,7 +9,7 @@ import {makeStyleSheetFromTheme} from 'app/utils/theme'; import placeholder from 'assets/images/profile.jpg'; -import Client from 'service/client'; +import Client from 'mattermost-redux/client'; const statusToIcon = { online: 'check', diff --git a/app/components/profile_picture/profile_picture_container.js b/app/components/profile_picture/profile_picture_container.js index d0ec83bd9..faba0137d 100644 --- a/app/components/profile_picture/profile_picture_container.js +++ b/app/components/profile_picture/profile_picture_container.js @@ -4,9 +4,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getStatusesByIdsBatchedDebounced} from 'service/actions/users'; -import {getStatusForUserId} from 'service/selectors/entities/users'; +import {getTheme} from 'app/selectors/preferences'; +import {getStatusesByIdsBatchedDebounced} from 'mattermost-redux/actions/users'; +import {getStatusForUserId} from 'mattermost-redux/selectors/entities/users'; import ProfilePicture from './profile_picture'; diff --git a/app/components/push_notification/index.js b/app/components/push_notification/index.js index 6a44f3874..507018895 100644 --- a/app/components/push_notification/index.js +++ b/app/components/push_notification/index.js @@ -5,14 +5,14 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {goToNotification, queueNotification} from 'app/actions/views/root'; -import {setDeviceToken} from 'service/actions/general'; -import {getUnreads} from 'service/selectors/entities/channels'; +import {setDeviceToken} from 'mattermost-redux/actions/general'; +import {getUnreads} from 'mattermost-redux/selectors/entities/channels'; import PushNotification from './push_notification'; function mapStateToProps(state, ownProps) { - const {currentId: currentTeamId} = state.entities.teams; - const {currentId: currentChannelId} = state.entities.channels; + const {currentTeamId} = state.entities.teams; + const {currentChannelId} = state.entities.channels; return { ...ownProps, diff --git a/app/components/push_notification/push_notification.js b/app/components/push_notification/push_notification.js index 48489b1f2..05077a6d3 100644 --- a/app/components/push_notification/push_notification.js +++ b/app/components/push_notification/push_notification.js @@ -10,7 +10,7 @@ import {changeOpacity} from 'app/utils/theme'; import icon from 'assets/images/icon.png'; import {GooglePlaySenderId} from 'assets/config.json'; -import {Constants} from 'service/constants'; +import {Constants} from 'mattermost-redux/constants'; export default class PushNotification extends PureComponent { static propTypes = { diff --git a/app/components/root/root.js b/app/components/root/root.js index e8f57e32b..1e75e44a1 100644 --- a/app/components/root/root.js +++ b/app/components/root/root.js @@ -8,10 +8,10 @@ import DeviceInfo from 'react-native-device-info'; import PushNotification from 'app/components/push_notification'; -import Client from 'service/client'; -import {Constants} from 'service/constants'; -import {getTranslations} from 'service/i18n'; -import EventEmitter from 'service/utils/event_emitter'; +import Client from 'mattermost-redux/client'; +import {Constants} from 'mattermost-redux/constants'; +import {getTranslations} from 'app/i18n'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; export default class Root extends PureComponent { static propTypes = { diff --git a/app/components/root/root_container.js b/app/components/root/root_container.js index e9b08cbdb..2b5408665 100644 --- a/app/components/root/root_container.js +++ b/app/components/root/root_container.js @@ -8,15 +8,15 @@ import Config from 'assets/config.json'; import {flushToStorage} from 'app/actions/storage'; import {goToNotification, loadConfigAndLicense, queueNotification} from 'app/actions/views/root'; -import {setAppState, setDeviceToken} from 'service/actions/general'; +import {setAppState, setDeviceToken} from 'mattermost-redux/actions/general'; import Root from './root'; function mapStateToProps(state, ownProps) { const users = state.entities.users; - const currentUserId = users.currentId; - const {currentId: currentTeamId} = state.entities.teams; - const {currentId: currentChannelId} = state.entities.channels; + const {currentUserId} = users; + const {currentTeamId} = state.entities.teams; + const {currentChannelId} = state.entities.channels; let locale = Config.DefaultLocale; if (currentUserId && users.profiles[currentUserId]) { diff --git a/app/constants/navigation.js b/app/constants/navigation.js index 0d980e2ec..bcf5cb231 100644 --- a/app/constants/navigation.js +++ b/app/constants/navigation.js @@ -1,7 +1,7 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import keyMirror from 'service/utils/key_mirror'; +import keyMirror from 'mattermost-redux/utils/key_mirror'; const NavigationTypes = keyMirror({ NAVIGATION_PUSH: null, diff --git a/app/constants/storage.js b/app/constants/storage.js index 9bbececb6..530403eb2 100644 --- a/app/constants/storage.js +++ b/app/constants/storage.js @@ -1,7 +1,7 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import keyMirror from 'service/utils/key_mirror'; +import keyMirror from 'mattermost-redux/utils/key_mirror'; const StorageTypes = keyMirror({ SAVE_TO_STORAGE: null, diff --git a/app/constants/view.js b/app/constants/view.js index b302fb62b..4fab923ad 100644 --- a/app/constants/view.js +++ b/app/constants/view.js @@ -1,7 +1,7 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import keyMirror from 'service/utils/key_mirror'; +import keyMirror from 'mattermost-redux/utils/key_mirror'; const ViewTypes = keyMirror({ SERVER_URL_CHANGED: null, diff --git a/service/i18n/index.js b/app/i18n/index.js similarity index 100% rename from service/i18n/index.js rename to app/i18n/index.js diff --git a/app/initial_state.js b/app/initial_state.js index 8fc99245e..a2f7ff69f 100644 --- a/app/initial_state.js +++ b/app/initial_state.js @@ -11,11 +11,12 @@ const state = { appState: false, credentials: {}, config: {}, + deviceToken: '', license: {}, - deviceToken: '' + serverVersion: '' }, users: { - currentId: '', + currentUserId: '', mySessions: [], myAudits: [], profiles: {}, @@ -26,7 +27,7 @@ const state = { search: {} }, teams: { - currentId: '', + currentTeamId: '', teams: {}, myMembers: {}, membersInTeam: {}, @@ -34,7 +35,7 @@ const state = { openTeamIds: new Set() }, channels: { - currentId: '', + currentChannelId: '', channels: {}, myMembers: {}, stats: {} @@ -50,6 +51,7 @@ const state = { }, typing: {} }, + errors: [], requests: { channels: { getChannel: { diff --git a/app/navigation/router.js b/app/navigation/router.js index 84df0a307..98412a85e 100644 --- a/app/navigation/router.js +++ b/app/navigation/router.js @@ -15,8 +15,9 @@ import {closeDrawers, goBack} from 'app/actions/navigation'; import Drawer from 'app/components/drawer'; import FormattedText from 'app/components/formatted_text'; import {RouteTransitions} from 'app/navigation/routes'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import ErrorList from 'app/components/error_list'; + import NavigationModal from './navigation_modal'; const navigationPanResponder = NavigationExperimental.Card.CardStackPanResponder; diff --git a/app/navigation/routes.js b/app/navigation/routes.js index f96fda3d7..c52e530c6 100644 --- a/app/navigation/routes.js +++ b/app/navigation/routes.js @@ -27,7 +27,7 @@ import { UserProfile } from 'app/scenes'; -import keyMirror from 'service/utils/key_mirror'; +import keyMirror from 'mattermost-redux/utils/key_mirror'; export const RouteTransitions = keyMirror({ Horizontal: null diff --git a/app/reducers/navigation/index.js b/app/reducers/navigation/index.js index df2819e25..cb8e1a405 100644 --- a/app/reducers/navigation/index.js +++ b/app/reducers/navigation/index.js @@ -3,7 +3,7 @@ import {NavigationExperimental} from 'react-native'; -import {UsersTypes} from 'service/constants'; +import {UsersTypes} from 'mattermost-redux/constants'; import {NavigationTypes} from 'app/constants'; import Routes from 'app/navigation/routes'; diff --git a/app/reducers/views/channel.js b/app/reducers/views/channel.js index ab4b881ce..4f29ba1c8 100644 --- a/app/reducers/views/channel.js +++ b/app/reducers/views/channel.js @@ -5,7 +5,7 @@ import {combineReducers} from 'redux'; import {ViewTypes} from 'app/constants'; -import {ChannelTypes} from 'service/constants'; +import {ChannelTypes} from 'mattermost-redux/constants'; function drafts(state = {}, action) { switch (action.type) { diff --git a/app/reducers/views/i18n.js b/app/reducers/views/i18n.js index 96fb525fd..39025fce9 100644 --- a/app/reducers/views/i18n.js +++ b/app/reducers/views/i18n.js @@ -5,7 +5,7 @@ import {combineReducers} from 'redux'; import Config from 'assets/config.json'; -import {UsersTypes} from 'service/constants'; +import {UsersTypes} from 'mattermost-redux/constants'; function locale(state = Config.DefaultLocale, action) { switch (action.type) { diff --git a/app/reducers/views/login.js b/app/reducers/views/login.js index 7078c75b0..025443e51 100644 --- a/app/reducers/views/login.js +++ b/app/reducers/views/login.js @@ -2,7 +2,7 @@ // See License.txt for license information. import {combineReducers} from 'redux'; -import {UsersTypes} from 'service/constants'; +import {UsersTypes} from 'mattermost-redux/constants'; import {ViewTypes} from 'app/constants'; function loginId(state = '', action) { diff --git a/app/reducers/views/options_modal.js b/app/reducers/views/options_modal.js index 2ef212b09..7c04d6730 100644 --- a/app/reducers/views/options_modal.js +++ b/app/reducers/views/options_modal.js @@ -3,7 +3,7 @@ import {combineReducers} from 'redux'; -import {UsersTypes} from 'service/constants'; +import {UsersTypes} from 'mattermost-redux/constants'; import {ViewTypes} from 'app/constants'; function title(state = '', action) { diff --git a/app/scenes/account_notifications/account_notifications.js b/app/scenes/account_notifications/account_notifications.js index f03286a4a..d970304c6 100644 --- a/app/scenes/account_notifications/account_notifications.js +++ b/app/scenes/account_notifications/account_notifications.js @@ -10,9 +10,9 @@ import { import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import EventEmitter from 'service/utils/event_emitter'; -import {Preferences, RequestStatus} from 'service/constants'; -import {getPreferencesByCategory} from 'service/utils/preference_utils'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; +import {Preferences, RequestStatus} from 'mattermost-redux/constants'; +import {getPreferencesByCategory} from 'mattermost-redux/utils/preference_utils'; import Section from './section'; import SectionItem from './section_item'; diff --git a/app/scenes/account_notifications/index.js b/app/scenes/account_notifications/index.js index 5b7bd360d..7c079fea9 100644 --- a/app/scenes/account_notifications/index.js +++ b/app/scenes/account_notifications/index.js @@ -5,8 +5,8 @@ import {bindActionCreators} from 'redux'; import {goBack} from 'app/actions/navigation'; import {handleUpdateUserNotifyProps} from 'app/actions/views/account_notifications'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentUser} from 'service/selectors/entities/users'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentUser} from 'mattermost-redux/selectors/entities/users'; import navigationSceneConnect from '../navigationSceneConnect'; diff --git a/app/scenes/account_notifications/save_notifications_button.js b/app/scenes/account_notifications/save_notifications_button.js index c9cf77e1c..0603a864d 100644 --- a/app/scenes/account_notifications/save_notifications_button.js +++ b/app/scenes/account_notifications/save_notifications_button.js @@ -11,8 +11,8 @@ import { import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; -import {getTheme} from 'service/selectors/entities/preferences'; -import EventEmitter from 'service/utils/event_emitter'; +import {getTheme} from 'app/selectors/preferences'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; class AccountNotifcationsButton extends PureComponent { static propTypes = { diff --git a/app/scenes/account_settings/account_settings_container.js b/app/scenes/account_settings/account_settings_container.js index ef322cc59..caa11cf21 100644 --- a/app/scenes/account_settings/account_settings_container.js +++ b/app/scenes/account_settings/account_settings_container.js @@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'; import {goToAccountNotifications} from 'app/actions/navigation'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import navigationSceneConnect from '../navigationSceneConnect'; import AccountSettings from './account_settings'; diff --git a/app/scenes/channel/channel.js b/app/scenes/channel/channel.js index a75f78f07..d7f84a08a 100644 --- a/app/scenes/channel/channel.js +++ b/app/scenes/channel/channel.js @@ -12,8 +12,8 @@ import KeyboardLayout from 'app/components/layout/keyboard_layout'; import Loading from 'app/components/loading'; import PostTextbox from 'app/components/post_textbox'; -import {Constants} from 'service/constants'; -import EventEmitter from 'service/utils/event_emitter'; +import {Constants} from 'mattermost-redux/constants'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; import ChannelDrawerButton from './channel_drawer_button'; import ChannelMenuButton from './channel_menu_button'; diff --git a/app/scenes/channel/channel_container.js b/app/scenes/channel/channel_container.js index 2710decfc..8deac5c10 100644 --- a/app/scenes/channel/channel_container.js +++ b/app/scenes/channel/channel_container.js @@ -16,17 +16,17 @@ import { selectInitialChannel, handlePostDraftChanged } from 'app/actions/views/channel'; -import {startPeriodicStatusUpdates, stopPeriodicStatusUpdates} from 'service/actions/users'; +import {startPeriodicStatusUpdates, stopPeriodicStatusUpdates} from 'mattermost-redux/actions/users'; import {selectFirstAvailableTeam} from 'app/actions/views/select_team'; -import {getCurrentChannel} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentTeam} from 'service/selectors/entities/teams'; +import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import { init as initWebSocket, close as closeWebSocket -} from 'service/actions/websocket'; +} from 'mattermost-redux/actions/websocket'; import Channel from './channel'; diff --git a/app/scenes/channel/channel_drawer_button.js b/app/scenes/channel/channel_drawer_button.js index d24cadb18..39c95a25a 100644 --- a/app/scenes/channel/channel_drawer_button.js +++ b/app/scenes/channel/channel_drawer_button.js @@ -10,8 +10,8 @@ import { import Icon from 'react-native-vector-icons/FontAwesome'; import Badge from 'app/components/badge'; -import {getUnreads} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getUnreads} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; function ChannelDrawerButton(props) { let badge; diff --git a/app/scenes/channel/channel_menu_button.js b/app/scenes/channel/channel_menu_button.js index 91bde8fed..d3c80ea4e 100644 --- a/app/scenes/channel/channel_menu_button.js +++ b/app/scenes/channel/channel_menu_button.js @@ -9,7 +9,7 @@ import { } from 'react-native'; import Icon from 'react-native-vector-icons/FontAwesome'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; function ChannelMenuButton(props) { return ( diff --git a/app/scenes/channel/channel_post_list/channel_post_list.js b/app/scenes/channel/channel_post_list/channel_post_list.js index 48fea5353..991d074fb 100644 --- a/app/scenes/channel/channel_post_list/channel_post_list.js +++ b/app/scenes/channel/channel_post_list/channel_post_list.js @@ -3,7 +3,7 @@ import React, {PropTypes, PureComponent} from 'react'; -import {Constants, RequestStatus} from 'service/constants'; +import {Constants, RequestStatus} from 'mattermost-redux/constants'; import Loading from 'app/components/loading'; import PostList from 'app/components/post_list'; diff --git a/app/scenes/channel/channel_post_list/channel_post_list_container.js b/app/scenes/channel/channel_post_list/channel_post_list_container.js index b6371523e..845e2b0a2 100644 --- a/app/scenes/channel/channel_post_list/channel_post_list_container.js +++ b/app/scenes/channel/channel_post_list/channel_post_list_container.js @@ -7,10 +7,10 @@ import {createSelector} from 'reselect'; import {goToThread} from 'app/actions/navigation'; import {loadPostsIfNecessary} from 'app/actions/views/channel'; -import {getPostsBefore} from 'service/actions/posts'; +import {getPostsBefore} from 'mattermost-redux/actions/posts'; -import {getAllPosts, getPostsInCurrentChannel} from 'service/selectors/entities/posts'; -import {getCurrentChannelMembership} from 'service/selectors/entities/channels'; +import {getAllPosts, getPostsInCurrentChannel} from 'mattermost-redux/selectors/entities/posts'; +import {getCurrentChannelMembership} from 'mattermost-redux/selectors/entities/channels'; import ChannelPostList from './channel_post_list'; diff --git a/app/scenes/channel/channel_title.js b/app/scenes/channel/channel_title.js index 39b2e6320..1b600d84c 100644 --- a/app/scenes/channel/channel_title.js +++ b/app/scenes/channel/channel_title.js @@ -10,8 +10,8 @@ import { } from 'react-native'; import Icon from 'react-native-vector-icons/FontAwesome'; -import {getCurrentChannel} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; function ChannelTitle(props) { const channelName = props.currentChannel.display_name; diff --git a/app/scenes/channel_add_members/add_member_button.js b/app/scenes/channel_add_members/add_member_button.js index b8af71c10..6d6cf98de 100644 --- a/app/scenes/channel_add_members/add_member_button.js +++ b/app/scenes/channel_add_members/add_member_button.js @@ -10,7 +10,7 @@ import { import FormattedText from 'app/components/formatted_text'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; function AddMemberButton(props) { return ( diff --git a/app/scenes/channel_add_members/channel_add_members_container.js b/app/scenes/channel_add_members/channel_add_members_container.js index 8ccc712e7..2726cd5de 100644 --- a/app/scenes/channel_add_members/channel_add_members_container.js +++ b/app/scenes/channel_add_members/channel_add_members_container.js @@ -7,12 +7,13 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {handleAddChannelMembers} from 'app/actions/views/channel_add_members'; import {goBack} from 'app/actions/navigation'; -import {getCurrentChannel, getCurrentChannelStats} from 'service/selectors/entities/channels'; -import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentTeam, getCurrentTeamStats} from 'service/selectors/entities/teams'; -import {getProfilesNotInCurrentChannel} from 'service/selectors/entities/users'; -import {getTeamStats} from 'service/actions/teams'; -import {getProfilesNotInChannel} from 'service/actions/users'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentChannel, getCurrentChannelStats} from 'mattermost-redux/selectors/entities/channels'; +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {getCurrentTeam, getCurrentTeamStats} from 'mattermost-redux/selectors/entities/teams'; +import {getProfilesNotInCurrentChannel} from 'mattermost-redux/selectors/entities/users'; +import {getTeamStats} from 'mattermost-redux/actions/teams'; +import {getProfilesNotInChannel} from 'mattermost-redux/actions/users'; import ChannelAddMembers from './channel_add_members'; diff --git a/app/scenes/channel_drawer/channel_drawer_container.js b/app/scenes/channel_drawer/channel_drawer_container.js index 0d8410b6b..ca3106de0 100644 --- a/app/scenes/channel_drawer/channel_drawer_container.js +++ b/app/scenes/channel_drawer/channel_drawer_container.js @@ -7,11 +7,11 @@ import {connect} from 'react-redux'; import {closeDrawers} from 'app/actions/navigation'; import {handleSelectChannel} from 'app/actions/views/channel'; -import {getChannelsByCategory, getCurrentChannel} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentTeam} from 'service/selectors/entities/teams'; +import {getChannelsByCategory, getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; -import {viewChannel, markChannelAsRead} from 'service/actions/channels'; +import {viewChannel, markChannelAsRead} from 'mattermost-redux/actions/channels'; import ChannelDrawer from './channel_drawer.js'; diff --git a/app/scenes/channel_info/channel_info.js b/app/scenes/channel_info/channel_info.js index cdee15728..d75655293 100644 --- a/app/scenes/channel_info/channel_info.js +++ b/app/scenes/channel_info/channel_info.js @@ -11,7 +11,7 @@ import { } from 'react-native'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import {Constants} from 'service/constants'; +import {Constants} from 'mattermost-redux/constants'; import ChannelInfoHeader from './channel_info_header'; import ChannelInfoRow from './channel_info_row'; diff --git a/app/scenes/channel_info/channel_info_container.js b/app/scenes/channel_info/channel_info_container.js index 940d05267..bcedacda4 100644 --- a/app/scenes/channel_info/channel_info_container.js +++ b/app/scenes/channel_info/channel_info_container.js @@ -6,11 +6,11 @@ import {bindActionCreators} from 'redux'; import navigationSceneConnect from '../navigationSceneConnect'; import {goToChannelMembers, goToChannelAddMembers, goBack} from 'app/actions/navigation'; -import {getChannelStats, deleteChannel} from 'service/actions/channels'; +import {getChannelStats, deleteChannel} from 'mattermost-redux/actions/channels'; import {markFavorite, unmarkFavorite, leaveChannel} from 'app/actions/views/channel'; -import {getCurrentChannel, getCurrentChannelStats, getChannelsByCategory, canManageChannelMembers} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getUser} from 'service/selectors/entities/users'; +import {getCurrentChannel, getCurrentChannelStats, getChannelsByCategory, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; +import {getUser} from 'mattermost-redux/selectors/entities/users'; import ChannelInfo from './channel_info'; @@ -25,7 +25,7 @@ function mapStateToProps(state, ownProps) { return { ...ownProps, - currentTeamId: state.entities.teams.currentId, + currentTeamId: state.entities.teams.currentTeamId, currentChannel, currentChannelCreatorName, currentChannelMemberCount, diff --git a/app/scenes/channel_members/channel_members.js b/app/scenes/channel_members/channel_members.js index 94c9430d8..963a32993 100644 --- a/app/scenes/channel_members/channel_members.js +++ b/app/scenes/channel_members/channel_members.js @@ -13,7 +13,7 @@ import {injectIntl, intlShape} from 'react-intl'; import MemberList from 'app/components/custom_list'; import {createMembersSections, loadingText} from 'app/utils/member_list'; import MemberListRow from 'app/components/custom_list/member_list_row'; -import {displayUsername} from 'service/utils/user_utils'; +import {displayUsername} from 'mattermost-redux/utils/user_utils'; import {makeStyleSheetFromTheme} from 'app/utils/theme'; import ChannelMembersTitle from './channel_members_title'; diff --git a/app/scenes/channel_members/channel_members_container.js b/app/scenes/channel_members/channel_members_container.js index 1fad713ec..075fdf819 100644 --- a/app/scenes/channel_members/channel_members_container.js +++ b/app/scenes/channel_members/channel_members_container.js @@ -7,11 +7,12 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {goBack} from 'app/actions/navigation'; import {handleRemoveChannelMembers} from 'app/actions/views/channel_members'; -import {getCurrentChannel, getCurrentChannelStats, canManageChannelMembers} from 'service/selectors/entities/channels'; -import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentTeam} from 'service/selectors/entities/teams'; -import {getProfilesInCurrentChannel} from 'service/selectors/entities/users'; -import {getProfilesInChannel} from 'service/actions/users'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentChannel, getCurrentChannelStats, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels'; +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; +import {getProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users'; +import {getProfilesInChannel} from 'mattermost-redux/actions/users'; import ChannelMembers from './channel_members'; @@ -23,7 +24,7 @@ function mapStateToProps(state) { currentChannel: getCurrentChannel(state), currentChannelMembers: getProfilesInCurrentChannel(state), currentChannelMemberCount, - currentUserId: state.entities.users.currentId, + currentUserId: state.entities.users.currentUserId, currentTeam: getCurrentTeam(state), preferences: getMyPreferences(state), requestStatus: state.requests.users.getProfilesInChannel.status, diff --git a/app/scenes/channel_members/channel_members_title.js b/app/scenes/channel_members/channel_members_title.js index f74384e98..2c3d4fef8 100644 --- a/app/scenes/channel_members/channel_members_title.js +++ b/app/scenes/channel_members/channel_members_title.js @@ -5,8 +5,8 @@ import React, {PropTypes} from 'react'; import {connect} from 'react-redux'; import {View} from 'react-native'; -import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getCurrentChannel, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; import FormattedText from 'app/components/formatted_text'; diff --git a/app/scenes/channel_members/remove_member_button.js b/app/scenes/channel_members/remove_member_button.js index bc6bbe169..399fd6cf1 100644 --- a/app/scenes/channel_members/remove_member_button.js +++ b/app/scenes/channel_members/remove_member_button.js @@ -10,8 +10,8 @@ import { import FormattedText from 'app/components/formatted_text'; -import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getCurrentChannel, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; function RemoveMemberButton(props) { const {canManageUsers} = props; diff --git a/app/scenes/create_channel/create_channel.js b/app/scenes/create_channel/create_channel.js index 88c1f6164..1dde287a4 100644 --- a/app/scenes/create_channel/create_channel.js +++ b/app/scenes/create_channel/create_channel.js @@ -20,8 +20,8 @@ import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_lo import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import {Constants, RequestStatus} from 'service/constants'; -import EventEmitter from 'service/utils/event_emitter'; +import {Constants, RequestStatus} from 'mattermost-redux/constants'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; import ActionButton from 'app/components/action_button'; diff --git a/app/scenes/create_channel/index.js b/app/scenes/create_channel/index.js index 5ca450970..e8ce28e72 100644 --- a/app/scenes/create_channel/index.js +++ b/app/scenes/create_channel/index.js @@ -8,7 +8,7 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {goBack, closeModal} from 'app/actions/navigation'; import {handleCreateChannel} from 'app/actions/views/create_channel'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import CreateChannel from './create_channel'; diff --git a/app/scenes/load_team/load_team.js b/app/scenes/load_team/load_team.js index 5570278db..c95b2ca46 100644 --- a/app/scenes/load_team/load_team.js +++ b/app/scenes/load_team/load_team.js @@ -3,7 +3,7 @@ import {PropTypes, PureComponent} from 'react'; -import {RequestStatus} from 'service/constants'; +import {RequestStatus} from 'mattermost-redux/constants'; export default class LoadTeam extends PureComponent { static propTypes = { diff --git a/app/scenes/load_team/load_team_container.js b/app/scenes/load_team/load_team_container.js index 583ddd1d8..8600a65b4 100644 --- a/app/scenes/load_team/load_team_container.js +++ b/app/scenes/load_team/load_team_container.js @@ -7,7 +7,7 @@ import {connect} from 'react-redux'; import {goToChannelView} from 'app/actions/views/load_team'; import {clearNotification, goToNotification} from 'app/actions/views/root'; import {handleTeamChange} from 'app/actions/views/select_team'; -import {getCurrentTeam} from 'service/selectors/entities/teams'; +import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import LoadTeam from './load_team.js'; diff --git a/app/scenes/login/login.js b/app/scenes/login/login.js index 0d4e565f4..372cf8c93 100644 --- a/app/scenes/login/login.js +++ b/app/scenes/login/login.js @@ -20,7 +20,7 @@ import {GlobalStyles} from 'app/styles'; import logo from 'assets/images/logo.png'; -import {RequestStatus} from 'service/constants'; +import {RequestStatus} from 'mattermost-redux/constants'; class Login extends Component { static propTypes = { diff --git a/app/scenes/login/login_container.js b/app/scenes/login/login_container.js index 3d210e1ab..cf514adef 100644 --- a/app/scenes/login/login_container.js +++ b/app/scenes/login/login_container.js @@ -7,7 +7,7 @@ import navigationSceneConnect from '../navigationSceneConnect'; import LoginActions from 'app/actions/views/login'; import {goToMfa, goToLoadTeam} from 'app/actions/navigation'; -import {checkMfa, login} from 'service/actions/users'; +import {checkMfa, login} from 'mattermost-redux/actions/users'; import Login from './login.js'; diff --git a/app/scenes/mfa/mfa.js b/app/scenes/mfa/mfa.js index 151e6ede3..e4f3ec522 100644 --- a/app/scenes/mfa/mfa.js +++ b/app/scenes/mfa/mfa.js @@ -18,7 +18,7 @@ import {GlobalStyles} from 'app/styles'; import logo from 'assets/images/logo.png'; -import RequestStatus from 'service/constants/request_status'; +import RequestStatus from 'mattermost-redux/constants/request_status'; export default class Mfa extends Component { static propTypes = { diff --git a/app/scenes/mfa/mfa_container.js b/app/scenes/mfa/mfa_container.js index 220a011ab..e015ca19b 100644 --- a/app/scenes/mfa/mfa_container.js +++ b/app/scenes/mfa/mfa_container.js @@ -6,7 +6,7 @@ import {bindActionCreators} from 'redux'; import navigationSceneConnect from '../navigationSceneConnect'; import {goBack} from 'app/actions/navigation'; -import {login} from 'service/actions/users'; +import {login} from 'mattermost-redux/actions/users'; import Mfa from './mfa'; diff --git a/app/scenes/more_channels/create_button.js b/app/scenes/more_channels/create_button.js index 579ae90cd..f8c701be6 100644 --- a/app/scenes/more_channels/create_button.js +++ b/app/scenes/more_channels/create_button.js @@ -10,7 +10,7 @@ import { import FormattedText from 'app/components/formatted_text'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; function CreateButton(props) { return ( diff --git a/app/scenes/more_channels/index.js b/app/scenes/more_channels/index.js index 9850c9e93..c45adfbad 100644 --- a/app/scenes/more_channels/index.js +++ b/app/scenes/more_channels/index.js @@ -6,16 +6,16 @@ import {bindActionCreators} from 'redux'; import navigationSceneConnect from '../navigationSceneConnect'; import {goBack, goToCreateChannel} from 'app/actions/navigation'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getMoreChannels as getMoreChannelsSelector} from 'service/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; +import {getMoreChannels as getMoreChannelsSelector} from 'mattermost-redux/selectors/entities/channels'; import {handleSelectChannel} from 'app/actions/views/channel'; -import {getMoreChannels, joinChannel, searchMoreChannels} from 'service/actions/channels'; +import {getMoreChannels, joinChannel, searchMoreChannels} from 'mattermost-redux/actions/channels'; import MoreChannels from './more_channels'; function mapStateToProps(state) { - const {currentId: currentUserId} = state.entities.users; - const {currentId: currentTeamId} = state.entities.teams; + const {currentUserId} = state.entities.users; + const {currentTeamId} = state.entities.teams; const {getMoreChannels: requestStatus} = state.requests.channels; return { diff --git a/app/scenes/more_channels/more_channels.js b/app/scenes/more_channels/more_channels.js index 12b594558..61de31764 100644 --- a/app/scenes/more_channels/more_channels.js +++ b/app/scenes/more_channels/more_channels.js @@ -16,7 +16,7 @@ import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; import SearchBar from 'app/components/search_bar'; -import {Constants, RequestStatus} from 'service/constants'; +import {Constants, RequestStatus} from 'mattermost-redux/constants'; import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; import CreateButton from './create_button'; diff --git a/app/scenes/more_dms/index.js b/app/scenes/more_dms/index.js index 2f9d01f71..466ff4dc2 100644 --- a/app/scenes/more_dms/index.js +++ b/app/scenes/more_dms/index.js @@ -7,9 +7,10 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {goBack} from 'app/actions/navigation'; import {makeDirectChannel} from 'app/actions/views/more_dms'; -import {getProfiles, searchProfiles} from 'service/actions/users'; -import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences'; -import {searchProfiles as searchSelector} from 'service/selectors/entities/users'; +import {getTheme} from 'app/selectors/preferences'; +import {getProfiles, searchProfiles} from 'mattermost-redux/actions/users'; +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {searchProfiles as searchSelector} from 'mattermost-redux/selectors/entities/users'; import MoreDirectMessages from './more_dms'; @@ -17,9 +18,9 @@ function mapStateToProps(state, ownProps) { const {getProfiles: requestStatus, searchProfiles: searchRequest} = state.requests.users; function getUsers() { - const {profiles, currentId} = state.entities.users; + const {profiles, currentUserId} = state.entities.users; const users = {...profiles}; - Reflect.deleteProperty(users, currentId); + Reflect.deleteProperty(users, currentUserId); return Object.values(users).sort((a, b) => { const nameA = a.username; const nameB = b.username; diff --git a/app/scenes/more_dms/more_dms.js b/app/scenes/more_dms/more_dms.js index 6fe634dfd..baa771cb6 100644 --- a/app/scenes/more_dms/more_dms.js +++ b/app/scenes/more_dms/more_dms.js @@ -15,7 +15,7 @@ import Loading from 'app/components/loading'; import MemberList from 'app/components/custom_list'; import SearchBar from 'app/components/search_bar'; import {createMembersSections, loadingText, renderMemberRow} from 'app/utils/member_list'; -import {Constants, RequestStatus} from 'service/constants'; +import {Constants, RequestStatus} from 'mattermost-redux/constants'; import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; class MoreDirectMessages extends PureComponent { diff --git a/app/scenes/right_menu_drawer/right_menu_drawer_container.js b/app/scenes/right_menu_drawer/right_menu_drawer_container.js index 739b67ee2..1ec01f5da 100644 --- a/app/scenes/right_menu_drawer/right_menu_drawer_container.js +++ b/app/scenes/right_menu_drawer/right_menu_drawer_container.js @@ -5,10 +5,10 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {goToModalAccountSettings, goBack, goToModalSelectTeam} from 'app/actions/navigation'; -import {clearErrors} from 'service/actions/errors'; +import {clearErrors} from 'mattermost-redux/actions/errors'; -import {logout} from 'service/actions/users'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {logout} from 'mattermost-redux/actions/users'; +import {getTheme} from 'app/selectors/preferences'; import RightMenuDrawer from './right_menu_drawer'; @@ -17,8 +17,8 @@ function mapStateToProps(state, ownProps) { ...ownProps, theme: getTheme(state), errors: state.errors, - currentUserId: state.entities.users.currentId, - currentTeamId: state.entities.teams.currentId + currentUserId: state.entities.users.currentUserId, + currentTeamId: state.entities.teams.currentTeamId }; } diff --git a/app/scenes/root/root.js b/app/scenes/root/root.js index 054d7c546..30504263e 100644 --- a/app/scenes/root/root.js +++ b/app/scenes/root/root.js @@ -5,7 +5,7 @@ import React, {PropTypes, PureComponent} from 'react'; import {AsyncStorage} from 'react-native'; import Loading from 'app/components/loading'; -import {RequestStatus} from 'service/constants'; +import {RequestStatus} from 'mattermost-redux/constants'; export default class Root extends PureComponent { static propTypes = { diff --git a/app/scenes/root/root_container.js b/app/scenes/root/root_container.js index 25cb07ece..02a135457 100644 --- a/app/scenes/root/root_container.js +++ b/app/scenes/root/root_container.js @@ -6,10 +6,12 @@ import {bindActionCreators} from 'redux'; import navigationSceneConnect from '../navigationSceneConnect'; import {loadStorage, removeStorage} from 'app/actions/storage'; -import {goToSelectServer, setStoreFromLocalData} from 'app/actions/views/root'; +import {goToSelectServer} from 'app/actions/views/root'; import {handleServerUrlChanged} from 'app/actions/views/select_server'; import {goToLoadTeam} from 'app/actions/navigation'; +import {setStoreFromLocalData} from 'mattermost-redux/actions/general'; + import Root from './root'; function mapStateToProps(state, ownProps) { diff --git a/app/scenes/saml/index.js b/app/scenes/saml/index.js index 10ca6c3ae..1fe7a90da 100644 --- a/app/scenes/saml/index.js +++ b/app/scenes/saml/index.js @@ -7,7 +7,7 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {handleSuccessfulLogin} from 'app/actions/views/login'; import {goToLoadTeam} from 'app/actions/navigation'; -import {setStoreFromLocalData} from 'app/actions/views/root'; +import {setStoreFromLocalData} from 'mattermost-redux/actions/general'; import Saml from './saml'; diff --git a/app/scenes/select_server/select_server.js b/app/scenes/select_server/select_server.js index 9bc521288..5ec209803 100644 --- a/app/scenes/select_server/select_server.js +++ b/app/scenes/select_server/select_server.js @@ -20,8 +20,8 @@ import {isValidUrl, stripTrailingSlashes} from 'app/utils/url'; import logo from 'assets/images/logo.png'; -import {RequestStatus} from 'service/constants'; -import Client from 'service/client'; +import {RequestStatus} from 'mattermost-redux/constants'; +import Client from 'mattermost-redux/client'; export default class SelectServer extends PureComponent { static propTypes = { diff --git a/app/scenes/select_server/select_server_container.js b/app/scenes/select_server/select_server_container.js index a9dcbad31..d7e421950 100644 --- a/app/scenes/select_server/select_server_container.js +++ b/app/scenes/select_server/select_server_container.js @@ -5,8 +5,8 @@ import {bindActionCreators} from 'redux'; import navigationSceneConnect from '../navigationSceneConnect'; -import {getPing, resetPing} from 'service/actions/general'; -import {RequestStatus} from 'service/constants'; +import {getPing, resetPing} from 'mattermost-redux/actions/general'; +import {RequestStatus} from 'mattermost-redux/constants'; import * as SelectServerActions from 'app/actions/views/select_server'; import SelectServer from './select_server'; diff --git a/app/scenes/select_team/select_team_container.js b/app/scenes/select_team/select_team_container.js index 06f10e629..19f20cc6c 100644 --- a/app/scenes/select_team/select_team_container.js +++ b/app/scenes/select_team/select_team_container.js @@ -8,7 +8,7 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {goBack} from 'app/actions/navigation'; import {handleTeamChange} from 'app/actions/views/select_team'; -import {getCurrentTeam} from 'service/selectors/entities/teams'; +import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import SelectTeam from './select_team.js'; diff --git a/app/scenes/thread/thread_container.js b/app/scenes/thread/thread_container.js index 0e3593067..70d71e16f 100644 --- a/app/scenes/thread/thread_container.js +++ b/app/scenes/thread/thread_container.js @@ -4,11 +4,11 @@ import {bindActionCreators} from 'redux'; import {handleCommentDraftChanged} from 'app/actions/views/thread'; -import {selectPost} from 'service/actions/posts'; +import {selectPost} from 'mattermost-redux/actions/posts'; -import {makeGetPostsForThread} from 'service/selectors/entities/posts'; -import {getTheme} from 'service/selectors/entities/preferences'; -import {getCurrentTeamId} from 'service/selectors/entities/teams'; +import {makeGetPostsForThread} from 'mattermost-redux/selectors/entities/posts'; +import {getTheme} from 'app/selectors/preferences'; +import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import navigationSceneConnect from '../navigationSceneConnect'; import Thread from './thread'; diff --git a/app/scenes/thread/thread_title.js b/app/scenes/thread/thread_title.js index 1c08fae1c..56da04e29 100644 --- a/app/scenes/thread/thread_title.js +++ b/app/scenes/thread/thread_title.js @@ -7,9 +7,9 @@ import { View } from 'react-native'; -import {Constants} from 'service/constants'; -import {getCurrentChannel} from 'service/selectors/entities/channels'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {Constants} from 'mattermost-redux/constants'; +import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getTheme} from 'app/selectors/preferences'; import FormattedText from 'app/components/formatted_text'; diff --git a/app/scenes/user_profile/user_profile.js b/app/scenes/user_profile/user_profile.js index e5feff113..5120698f2 100644 --- a/app/scenes/user_profile/user_profile.js +++ b/app/scenes/user_profile/user_profile.js @@ -11,7 +11,7 @@ import { import ProfilePicture from 'app/components/profile_picture'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import {getFullName} from 'service/utils/user_utils'; +import {getFullName} from 'mattermost-redux/utils/user_utils'; import UserProfileRow from './user_profile_row'; diff --git a/app/scenes/user_profile/user_profile_container.js b/app/scenes/user_profile/user_profile_container.js index 52b0a799c..903bd1de5 100644 --- a/app/scenes/user_profile/user_profile_container.js +++ b/app/scenes/user_profile/user_profile_container.js @@ -4,7 +4,7 @@ import {bindActionCreators} from 'redux'; import {handleSendMessage} from 'app/actions/views/user_profile'; -import {getTheme} from 'service/selectors/entities/preferences'; +import {getTheme} from 'app/selectors/preferences'; import UserProfile from './user_profile'; @@ -12,7 +12,7 @@ import navigationSceneConnect from '../navigationSceneConnect'; function mapStateToProps(state, ownProps) { return { - currentUserId: state.entities.users.currentId, + currentUserId: state.entities.users.currentUserId, user: state.entities.users.profiles[ownProps.userId], theme: getTheme(state) }; diff --git a/service/selectors/entities/preferences.js b/app/selectors/preferences.js similarity index 83% rename from service/selectors/entities/preferences.js rename to app/selectors/preferences.js index 47a342e40..d7d08bd88 100644 --- a/service/selectors/entities/preferences.js +++ b/app/selectors/preferences.js @@ -6,14 +6,11 @@ import {createSelector} from 'reselect'; import Config from 'assets/config.json'; import Themes from 'assets/themes.json'; -import {Preferences} from 'service/constants'; -import {getPreferenceKey} from 'service/utils/preference_utils'; +import {Preferences} from 'mattermost-redux/constants'; +import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils'; -import {getCurrentTeamId} from './teams'; - -export function getMyPreferences(state) { - return state.entities.preferences.myPreferences; -} +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; export const getTheme = createSelector( getMyPreferences, diff --git a/app/store/index.js b/app/store/index.js index 6f30b551d..5b945e8da 100644 --- a/app/store/index.js +++ b/app/store/index.js @@ -2,7 +2,7 @@ // See License.txt for license information. import appReducer from 'app/reducers'; -import configureServiceStore from 'service/store'; +import configureServiceStore from 'mattermost-redux/store'; function getAppReducer() { return require('../../app/reducers'); // eslint-disable-line global-require diff --git a/app/utils/member_list.js b/app/utils/member_list.js index 005f99afa..5f617f29b 100644 --- a/app/utils/member_list.js +++ b/app/utils/member_list.js @@ -3,7 +3,7 @@ import React from 'react'; import MemberListRow from 'app/components/custom_list/member_list_row'; -import {displayUsername} from 'service/utils/user_utils'; +import {displayUsername} from 'mattermost-redux/utils/user_utils'; export const loadingText = { id: 'mobile.loading_members', diff --git a/package.json b/package.json index 1fd9d3075..494a6f7dd 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "harmony-reflect": "1.5.1", "intl": "1.2.5", "isomorphic-fetch": "2.2.1", + "mattermost-redux": "mattermost/mattermost-redux#release-3.7", "react": "15.4.1", "react-addons-pure-render-mixin": "15.4.1", "react-intl": "2.2.2", @@ -29,6 +30,7 @@ "reselect": "2.5.4" }, "devDependencies": { + "babel-cli": "6.23.0", "babel-eslint": "7.1.1", "babel-plugin-module-resolver": "2.4.0", "babel-preset-es2015": "6.18.0", @@ -51,8 +53,7 @@ "react-test-renderer": "15.4.1", "redux-logger": "2.7.4", "remote-redux-devtools": "0.5.7", - "remote-redux-devtools-on-debugger": "0.7.0", - "ws": "1.1.1" + "remote-redux-devtools-on-debugger": "0.7.0" }, "scripts": { "check": "node_modules/.bin/eslint --ext \".js\" --ignore-pattern node_modules --quiet .", diff --git a/service/actions/channels.js b/service/actions/channels.js deleted file mode 100644 index bf56913af..000000000 --- a/service/actions/channels.js +++ /dev/null @@ -1,753 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import { - Constants, - ChannelTypes, - Preferences, - PreferencesTypes, - UsersTypes -} from 'service/constants'; -import {batchActions} from 'redux-batched-actions'; - -import Client from 'service/client'; - -import {logError, getLogErrorAction} from './errors'; -import {forceLogoutIfNecessary} from './helpers'; - -export function selectChannel(channelId) { - return async (dispatch, getState) => { - try { - dispatch({ - type: ChannelTypes.SELECT_CHANNEL, - data: channelId - }, getState); - } catch (error) { - logError(error)(dispatch); - } - }; -} - -export function createChannel(channel, userId) { - return async (dispatch, getState) => { - dispatch(batchActions([ - { - type: ChannelTypes.CREATE_CHANNEL_REQUEST - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_REQUEST - } - ]), getState); - - let created; - try { - created = await Client.createChannel(channel); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - { - type: ChannelTypes.CREATE_CHANNEL_FAILURE, - error - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_FAILURE, - error - }, - getLogErrorAction(error) - ]), getState); - return null; - } - - const member = { - channel_id: created.id, - user_id: userId, - roles: `${Constants.CHANNEL_USER_ROLE} ${Constants.CHANNEL_ADMIN_ROLE}`, - last_viewed_at: 0, - msg_count: 0, - mention_count: 0, - notify_props: {desktop: 'default', mark_unread: 'all'}, - last_update_at: created.create_at - }; - - const actions = []; - const {channels, myMembers} = getState().entities.channels; - - if (!channels[created.id]) { - actions.push({type: ChannelTypes.RECEIVED_CHANNEL, data: created}); - } - - if (!myMembers[created.id]) { - actions.push({type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, data: member}); - } - - dispatch(batchActions([ - ...actions, - { - type: ChannelTypes.CREATE_CHANNEL_SUCCESS - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_SUCCESS - } - ]), getState); - - return created; - }; -} - -export function createDirectChannel(teamId, userId, otherUserId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.CREATE_CHANNEL_REQUEST}, getState); - - let created; - try { - created = await Client.createDirectChannel(teamId, otherUserId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.CREATE_CHANNEL_FAILURE, error}, - {type: ChannelTypes.CHANNEL_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - const member = { - channel_id: created.id, - user_id: userId, - roles: `${Constants.CHANNEL_USER_ROLE} ${Constants.CHANNEL_ADMIN_ROLE}`, - last_viewed_at: 0, - msg_count: 0, - mention_count: 0, - notify_props: {desktop: 'default', mark_unread: 'all'}, - last_update_at: created.create_at - }; - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL, - data: created - }, - { - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, - data: member - }, - { - type: PreferencesTypes.RECEIVED_PREFERENCES, - data: [{category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, name: otherUserId, value: 'true'}] - }, - { - type: ChannelTypes.CREATE_CHANNEL_SUCCESS - } - ]), getState); - - return created; - }; -} - -export function updateChannel(channel) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.UPDATE_CHANNEL_REQUEST}, getState); - - let updated; - try { - updated = await Client.updateChannel(channel); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - - dispatch(batchActions([ - {type: ChannelTypes.UPDATE_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL, - data: updated - }, - { - type: ChannelTypes.UPDATE_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function updateChannelNotifyProps(userId, teamId, channelId, props) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.NOTIFY_PROPS_REQUEST}, getState); - - const data = { - user_id: userId, - channel_id: channelId, - ...props - }; - - let notifyProps; - try { - notifyProps = await Client.updateChannelNotifyProps(teamId, data); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - - dispatch(batchActions([ - {type: ChannelTypes.NOTIFY_PROPS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL_PROPS, - data: { - channel_id: channelId, - notifyProps - } - }, - { - type: ChannelTypes.NOTIFY_PROPS_SUCCESS - } - ]), getState); - }; -} - -export function getChannel(teamId, channelId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.CHANNEL_REQUEST}, getState); - - let data; - try { - data = await Client.getChannel(teamId, channelId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.CHANNELS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL, - data: data.channel - }, - { - type: ChannelTypes.CHANNEL_SUCCESS - }, - { - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, - data: data.member - } - ]), getState); - }; -} - -export function fetchMyChannelsAndMembers(teamId) { - return async (dispatch, getState) => { - dispatch(batchActions([ - { - type: ChannelTypes.CHANNELS_REQUEST - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_REQUEST - } - ]), getState); - - let channels; - let channelMembers; - try { - const channelsRequest = Client.getChannels(teamId); - const channelMembersRequest = Client.getMyChannelMembers(teamId); - - channels = await channelsRequest; - channelMembers = await channelMembersRequest; - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.CHANNELS_FAILURE, error}, - {type: ChannelTypes.CHANNEL_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNELS, - data: channels - }, - { - type: ChannelTypes.CHANNELS_SUCCESS - }, - { - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS, - data: channelMembers - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_SUCCESS - } - ]), getState); - }; -} - -export function getMyChannelMembers(teamId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.CHANNEL_MEMBERS_REQUEST}, getState); - - let channelMembers; - try { - const channelMembersRequest = Client.getMyChannelMembers(teamId); - - channelMembers = await channelMembersRequest; - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.CHANNEL_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS, - data: channelMembers - }, - { - type: ChannelTypes.CHANNEL_MEMBERS_SUCCESS - } - ]), getState); - }; -} - -export function leaveChannel(teamId, channelId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.LEAVE_CHANNEL_REQUEST}, getState); - - try { - await Client.leaveChannel(teamId, channelId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.LEAVE_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.LEAVE_CHANNEL, - data: channelId - }, - { - type: ChannelTypes.LEAVE_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function joinChannel(userId, teamId, channelId, channelName) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.JOIN_CHANNEL_REQUEST}, getState); - - let channel; - try { - if (channelId) { - channel = await Client.joinChannel(teamId, channelId); - } else if (channelName) { - channel = await Client.joinChannelByName(teamId, channelName); - } - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.JOIN_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - const channelMember = { - channel_id: channel.id, - user_id: userId, - roles: `${Constants.CHANNEL_USER_ROLE}`, - last_viewed_at: 0, - msg_count: 0, - mention_count: 0, - notify_props: {desktop: 'default', mark_unread: 'all'}, - last_update_at: new Date().getTime() - }; - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL, - data: channel - }, - { - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, - data: channelMember - }, - { - type: ChannelTypes.JOIN_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function deleteChannel(teamId, channelId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.DELETE_CHANNEL_REQUEST}, getState); - - try { - await Client.deleteChannel(teamId, channelId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.DELETE_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - const entities = getState().entities; - const {channels, currentId} = entities.channels; - if (channelId === currentId) { - const channel = Object.keys(channels).filter((key) => channels[key].name === Constants.DEFAULT_CHANNEL); - let defaultChannelId = ''; - if (channel.length) { - defaultChannelId = channel[0]; - } - - dispatch({type: ChannelTypes.SELECT_CHANNEL, data: defaultChannelId}, getState); - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL_DELETED, - data: channelId - }, - { - type: ChannelTypes.DELETE_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function viewChannel(teamId, channelId) { - return async (dispatch, getState) => { - const state = getState(); - const {currentId} = state.entities.channels; - let prevChannelId = ''; - - if (channelId !== currentId) { - prevChannelId = currentId; - } - - dispatch({type: ChannelTypes.UPDATE_LAST_VIEWED_REQUEST}, getState); - - try { - // this API should return the timestamp that was set - await Client.viewChannel(teamId, channelId, prevChannelId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.UPDATE_LAST_VIEWED_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch({type: ChannelTypes.UPDATE_LAST_VIEWED_SUCCESS}, getState); - }; -} - -export function getMoreChannels(teamId, offset, limit = Constants.CHANNELS_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.MORE_CHANNELS_REQUEST}, getState); - - let channels; - try { - channels = await Client.getMoreChannels(teamId, offset, limit); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.MORE_CHANNELS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_MORE_CHANNELS, - data: await channels - }, - { - type: ChannelTypes.MORE_CHANNELS_SUCCESS - } - ]), getState); - - return channels; - }; -} - -export function searchMoreChannels(teamId, term) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.MORE_CHANNELS_REQUEST}, getState); - - let channels; - try { - channels = await Client.searchMoreChannels(teamId, term); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.MORE_CHANNELS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_MORE_CHANNELS, - data: await channels - }, - { - type: ChannelTypes.MORE_CHANNELS_SUCCESS - } - ]), getState); - }; -} - -export function getChannelStats(teamId, channelId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.CHANNEL_STATS_REQUEST}, getState); - - let stat; - try { - stat = await Client.getChannelStats(teamId, channelId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.CHANNEL_STATS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_CHANNEL_STATS, - data: stat - }, - { - type: ChannelTypes.CHANNEL_STATS_SUCCESS - } - ]), getState); - }; -} - -export function addChannelMember(teamId, channelId, userId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.ADD_CHANNEL_MEMBER_REQUEST}, getState); - - try { - await Client.addChannelMember(teamId, channelId, userId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.ADD_CHANNEL_MEMBER_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILE_IN_CHANNEL, - data: {user_id: userId}, - id: channelId - }, - { - type: ChannelTypes.ADD_CHANNEL_MEMBER_SUCCESS - } - ]), getState); - }; -} - -export function removeChannelMember(teamId, channelId, userId) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.REMOVE_CHANNEL_MEMBER_REQUEST}, getState); - - try { - await Client.removeChannelMember(teamId, channelId, userId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.REMOVE_CHANNEL_MEMBER_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL, - data: {user_id: userId}, - id: channelId - }, - { - type: ChannelTypes.REMOVE_CHANNEL_MEMBER_SUCCESS - } - ]), getState); - }; -} - -export function updateChannelHeader(channelId, header) { - return async (dispatch, getState) => { - dispatch({ - type: ChannelTypes.UPDATE_CHANNEL_HEADER, - data: { - channelId, - header - } - }, getState); - }; -} - -export function updateChannelPurpose(channelId, purpose) { - return async (dispatch, getState) => { - dispatch({ - type: ChannelTypes.UPDATE_CHANNEL_PURPOSE, - data: { - channelId, - purpose - } - }, getState); - }; -} - -export function markChannelAsRead(channelId, prevChannelId) { - return async (dispatch, getState) => { - const state = getState(); - - const {channels} = state.entities.channels; - let totalMsgCount = 0; - if (channels[channelId]) { - totalMsgCount = channels[channelId].total_msg_count; - } - const actions = [{ - type: ChannelTypes.RECEIVED_LAST_VIEWED, - data: { - channel_id: channelId, - last_viewed_at: new Date().getTime(), - total_msg_count: totalMsgCount - } - }]; - - if (prevChannelId) { - let prevTotalMsgCount = 0; - if (channels[prevChannelId]) { - prevTotalMsgCount = channels[prevChannelId].total_msg_count; - } - actions.push({ - type: ChannelTypes.RECEIVED_LAST_VIEWED, - data: { - channel_id: prevChannelId, - last_viewed_at: new Date().getTime(), - total_msg_count: prevTotalMsgCount - } - }); - } - - dispatch(batchActions([...actions]), getState); - }; -} - -export function markChannelAsUnread(channelId, mentionsArray) { - return async (dispatch, getState) => { - const state = getState(); - const {channels, myMembers} = state.entities.channels; - const currentUserId = state.entities.users.currentId; - const channel = {...channels[channelId]}; - const member = {...myMembers[channelId]}; - - if (channel && member) { - channel.total_msg_count++; - if (member.notify_props && member.notify_props.mark_unread === Constants.MENTION) { - member.msg_count++; - } - - let mentions = []; - if (mentionsArray) { - mentions = JSON.parse(mentionsArray); - if (mentions.indexOf(currentUserId) !== -1) { - member.mention_count++; - } - } - - dispatch(batchActions([{ - type: ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, - data: member - }, { - type: ChannelTypes.RECEIVED_CHANNEL, - data: channel - }]), getState); - } - }; -} - -export function autocompleteChannels(teamId, term) { - return async (dispatch, getState) => { - dispatch({type: ChannelTypes.AUTOCOMPLETE_CHANNELS_REQUEST}, getState); - - let data; - try { - data = await Client.autocompleteChannels(teamId, term); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: ChannelTypes.AUTOCOMPLETE_CHANNELS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: ChannelTypes.RECEIVED_AUTOCOMPLETE_CHANNELS, - data, - teamId - }, - { - type: ChannelTypes.AUTOCOMPLETE_CHANNELS_SUCCESS - } - ]), getState); - }; -} - -export default { - selectChannel, - createChannel, - createDirectChannel, - updateChannel, - updateChannelNotifyProps, - getChannel, - fetchMyChannelsAndMembers, - getMyChannelMembers, - leaveChannel, - joinChannel, - deleteChannel, - viewChannel, - getMoreChannels, - searchMoreChannels, - getChannelStats, - addChannelMember, - removeChannelMember, - updateChannelHeader, - updateChannelPurpose, - markChannelAsRead, - markChannelAsUnread, - autocompleteChannels -}; diff --git a/service/actions/errors.js b/service/actions/errors.js deleted file mode 100644 index 8d8e068b6..000000000 --- a/service/actions/errors.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {ErrorTypes} from 'service/constants'; - -export function dismissErrorObject(index) { - return { - type: ErrorTypes.DISMISS_ERROR, - index - }; -} - -export function dismissError(index) { - return async (dispatch) => { - dispatch(dismissErrorObject(index)); - }; -} - -export function getLogErrorAction(error, displayable = true) { - return { - type: ErrorTypes.LOG_ERROR, - displayable, - error - }; -} - -export function logError(error, displayable = true) { - return async (dispatch) => { - // do something with the incoming error - // like sending it to analytics - - dispatch(getLogErrorAction(error, displayable)); - }; -} - -export function clearErrors() { - return async (dispatch) => { - dispatch({type: ErrorTypes.CLEAR_ERRORS}); - }; -} diff --git a/service/actions/files.js b/service/actions/files.js deleted file mode 100644 index 8eebc1659..000000000 --- a/service/actions/files.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; - -import Client from 'service/client'; -import {FilesTypes} from 'service/constants'; -import {getLogErrorAction} from 'service/actions/errors'; -import {forceLogoutIfNecessary} from './helpers'; - -export function getFilesForPost(teamId, channelId, postId) { - return async (dispatch, getState) => { - dispatch({type: FilesTypes.FETCH_FILES_FOR_POST_REQUEST}, getState); - let files; - - try { - files = await Client.getFileInfosForPost(teamId, channelId, postId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: FilesTypes.FETCH_FILES_FOR_POST_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: FilesTypes.RECEIVED_FILES_FOR_POST, - data: files, - postId - }, - { - type: FilesTypes.FETCH_FILES_FOR_POST_SUCCESS - } - ]), getState); - }; -} diff --git a/service/actions/general.js b/service/actions/general.js deleted file mode 100644 index 0b980e6d4..000000000 --- a/service/actions/general.js +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; - -import Client from 'service/client'; -import {bindClientFunc, FormattedError} from './helpers.js'; -import {GeneralTypes} from 'service/constants'; -import {getMyChannelMembers} from './channels'; -import {getLogErrorAction} from 'service/actions/errors'; - -export function getPing() { - return async (dispatch, getState) => { - dispatch({type: GeneralTypes.PING_REQUEST}, getState); - - let data; - const pingError = new FormattedError( - 'mobile.server_ping_failed', - 'Cannot connect to the server. Please check your server URL and internet connection.' - ); - try { - data = await Client.getPing(); - if (!data.version) { - // successful ping but not the right return data - dispatch(batchActions([ - {type: GeneralTypes.PING_FAILURE, error: pingError}, - getLogErrorAction(pingError) - ]), getState); - return; - } - } catch (error) { - dispatch(batchActions([ - {type: GeneralTypes.PING_FAILURE, error: pingError}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch({type: GeneralTypes.PING_SUCCESS, data}, getState); - }; -} - -export function resetPing() { - return async (dispatch, getState) => { - dispatch({type: GeneralTypes.PING_RESET}, getState); - }; -} - -export function getClientConfig() { - return bindClientFunc( - Client.getClientConfig, - GeneralTypes.CLIENT_CONFIG_REQUEST, - [GeneralTypes.CLIENT_CONFIG_RECEIVED, GeneralTypes.CLIENT_CONFIG_SUCCESS], - GeneralTypes.CLIENT_CONFIG_FAILURE - ); -} - -export function getLicenseConfig() { - return bindClientFunc( - Client.getLicenseConfig, - GeneralTypes.CLIENT_LICENSE_REQUEST, - [GeneralTypes.CLIENT_LICENSE_RECEIVED, GeneralTypes.CLIENT_LICENSE_SUCCESS], - GeneralTypes.CLIENT_LICENSE_FAILURE - ); -} - -export function logClientError(message, level = 'ERROR') { - return bindClientFunc( - Client.logClientError, - GeneralTypes.LOG_CLIENT_ERROR_REQUEST, - GeneralTypes.LOG_CLIENT_ERROR_SUCCESS, - GeneralTypes.LOG_CLIENT_ERROR_FAILURE, - message, - level - ); -} - -export function setAppState(state) { - return async (dispatch, getState) => { - dispatch({type: GeneralTypes.RECEIVED_APP_STATE, data: state}, getState); - - if (state) { - const teamId = getState().entities.teams.currentId; - if (teamId) { - getMyChannelMembers(teamId)(dispatch, getState); - } - } - }; -} - -export function setServerVersion(serverVersion) { - return async (dispatch, getState) => { - dispatch({type: GeneralTypes.RECEIVED_SERVER_VERSION, data: serverVersion}, getState); - }; -} - -export function setDeviceToken(token) { - return async (dispatch, getState) => { - dispatch({type: GeneralTypes.RECEIVED_APP_DEVICE_TOKEN, data: token}, getState); - }; -} - -export default { - getPing, - getClientConfig, - getLicenseConfig, - logClientError, - setAppState, - setServerVersion, - setDeviceToken -}; diff --git a/service/actions/helpers.js b/service/actions/helpers.js deleted file mode 100644 index c97d9d0d8..000000000 --- a/service/actions/helpers.js +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; -import Client from 'service/client'; -import {UsersTypes} from 'service/constants'; -import {getLogErrorAction} from './errors'; -const HTTP_UNAUTHORIZED = 401; - -export async function forceLogoutIfNecessary(err, dispatch) { - if (err.status_code === HTTP_UNAUTHORIZED && err.url.indexOf('/login') === -1) { - dispatch({type: UsersTypes.LOGOUT_REQUEST}); - await Client.logout(); - dispatch({type: UsersTypes.LOGOUT_SUCCESS}); - } -} - -function dispatcher(type, data, dispatch, getState) { - if (type.indexOf('SUCCESS') === -1) { // we don't want to pass the data for the request types - dispatch(requestSuccess(type, data), getState); - } else { - dispatch(requestData(type), getState); - } -} - -export function requestData(type) { - return { - type - }; -} - -export function requestSuccess(type, data) { - return { - type, - data - }; -} - -export function requestFailure(type, error) { - return { - type, - error - }; -} - -export function bindClientFunc(clientFunc, request, success, failure, ...args) { - return async (dispatch, getState) => { - dispatch(requestData(request), getState); - - let data = null; - try { - data = await clientFunc(...args); - } catch (err) { - forceLogoutIfNecessary(err, dispatch); - dispatch(batchActions([ - requestFailure(failure, err), - getLogErrorAction(err) - ]), getState); - return; - } - - if (Array.isArray(success)) { - success.forEach((s) => { - dispatcher(s, data, dispatch, getState); - }); - } else { - dispatcher(success, data, dispatch, getState); - } - }; -} - -// Debounce function based on underscores modified to use es6 and a cb -export function debounce(func, wait, immediate, cb) { - let timeout; - return function fx(...args) { - const runLater = () => { - timeout = null; - if (!immediate) { - Reflect.apply(func, this, args); - if (cb) { - cb(); - } - } - }; - const callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(runLater, wait); - if (callNow) { - Reflect.apply(func, this, args); - if (cb) { - cb(); - } - } - }; -} - -export class FormattedError extends Error { - constructor(id, defaultMessage, values = {}) { - super(defaultMessage); - this.intl = { - id, - defaultMessage, - values - }; - } -} diff --git a/service/actions/posts.js b/service/actions/posts.js deleted file mode 100644 index 7e4fe873f..000000000 --- a/service/actions/posts.js +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import Client from 'service/client'; -import {batchActions} from 'redux-batched-actions'; -import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; -import {Constants, PostsTypes} from 'service/constants'; -import {getLogErrorAction} from './errors'; -import {getProfilesByIds, getStatusesByIds} from './users'; - -async function getProfilesAndStatusesForPosts(list, dispatch, getState) { - const {profiles, statuses} = getState().entities.users; - const posts = list.posts; - const profilesToLoad = []; - const statusesToLoad = []; - - Object.keys(posts).forEach((key) => { - const post = posts[key]; - const userId = post.user_id; - - if (!profiles[userId]) { - profilesToLoad.push(userId); - } - - if (!statuses[userId]) { - statusesToLoad.push(userId); - } - }); - - if (profilesToLoad.length) { - await getProfilesByIds(profilesToLoad)(dispatch, getState); - } - - if (statusesToLoad.length) { - await getStatusesByIds(statusesToLoad)(dispatch, getState); - } -} - -export function createPost(teamId, post) { - return bindClientFunc( - Client.createPost, - PostsTypes.CREATE_POST_REQUEST, - [PostsTypes.RECEIVED_POST, PostsTypes.CREATE_POST_SUCCESS], - PostsTypes.CREATE_POST_FAILURE, - teamId, - post - ); -} - -export function editPost(teamId, post) { - return bindClientFunc( - Client.editPost, - PostsTypes.EDIT_POST_REQUEST, - [PostsTypes.RECEIVED_POST, PostsTypes.EDIT_POST_SUCCESS], - PostsTypes.EDIT_POST_FAILURE, - teamId, - post - ); -} - -export function deletePost(teamId, post) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.DELETE_POST_REQUEST}, getState); - - try { - await Client.deletePost(teamId, post.channel_id, post.id); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.DELETE_POST_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: PostsTypes.POST_DELETED, - data: {...post} - }, - { - type: PostsTypes.DELETE_POST_SUCCESS - } - ]), getState); - }; -} - -export function removePost(post) { - return async (dispatch, getState) => { - dispatch({ - type: PostsTypes.REMOVE_POST, - data: {...post} - }, getState); - }; -} - -export function getPost(teamId, channelId, postId) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.GET_POST_REQUEST}, getState); - - let post; - try { - post = await Client.getPost(teamId, channelId, postId); - getProfilesAndStatusesForPosts(post, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.GET_POST_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: {...post}, - channelId - }, - { - type: PostsTypes.GET_POST_SUCCESS - } - ]), getState); - }; -} - -export function getPosts(teamId, channelId, offset = 0, limit = Constants.POST_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.GET_POSTS_REQUEST}, getState); - let posts; - - try { - posts = await Client.getPosts(teamId, channelId, offset, limit); - getProfilesAndStatusesForPosts(posts, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.GET_POSTS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: posts, - channelId - }, - { - type: PostsTypes.GET_POSTS_SUCCESS - } - ]), getState); - - return posts; - }; -} - -export function getPostsSince(teamId, channelId, since) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.GET_POSTS_SINCE_REQUEST}, getState); - - let posts; - try { - posts = await Client.getPostsSince(teamId, channelId, since); - getProfilesAndStatusesForPosts(posts, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.GET_POSTS_SINCE_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: posts, - channelId - }, - { - type: PostsTypes.GET_POSTS_SINCE_SUCCESS - } - ]), getState); - - return posts; - }; -} - -export function getPostsBefore(teamId, channelId, postId, offset = 0, limit = Constants.POST_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.GET_POSTS_BEFORE_REQUEST}, getState); - - let posts; - try { - posts = await Client.getPostsBefore(teamId, channelId, postId, offset, limit); - getProfilesAndStatusesForPosts(posts, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.GET_POSTS_BEFORE_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: posts, - channelId - }, - { - type: PostsTypes.GET_POSTS_BEFORE_SUCCESS - } - ]), getState); - - return posts; - }; -} - -export function getPostsAfter(teamId, channelId, postId, offset = 0, limit = Constants.POST_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: PostsTypes.GET_POSTS_AFTER_REQUEST}, getState); - - let posts; - try { - posts = await Client.getPostsAfter(teamId, channelId, postId, offset, limit); - getProfilesAndStatusesForPosts(posts, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PostsTypes.GET_POSTS_AFTER_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: posts, - channelId - }, - { - type: PostsTypes.GET_POSTS_AFTER_SUCCESS - } - ]), getState); - - return posts; - }; -} - -export function selectPost(postId) { - return async (dispatch, getState) => { - dispatch({ - type: PostsTypes.RECEIVED_POST_SELECTED, - data: postId - }, getState); - }; -} - -export default { - createPost, - editPost, - deletePost, - removePost, - getPost, - getPosts, - getPostsSince, - getPostsBefore, - getPostsAfter, - selectPost -}; diff --git a/service/actions/preferences.js b/service/actions/preferences.js deleted file mode 100644 index 54db35372..000000000 --- a/service/actions/preferences.js +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; - -import Client from 'service/client'; -import {Preferences, PreferencesTypes} from 'service/constants'; -import {getMyPreferences as getMyPreferencesSelector} from 'service/selectors/entities/preferences'; -import {getCurrentUserId} from 'service/selectors/entities/users'; -import {getPreferenceKey} from 'service/utils/preference_utils'; - -import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; - -import {getLogErrorAction} from './errors'; -export function getMyPreferences() { - return bindClientFunc( - Client.getMyPreferences, - PreferencesTypes.MY_PREFERENCES_REQUEST, - [PreferencesTypes.RECEIVED_PREFERENCES, PreferencesTypes.MY_PREFERENCES_SUCCESS], - PreferencesTypes.MY_PREFERENCES_FAILURE - ); -} - -export function savePreferences(preferences) { - return async (dispatch, getState) => { - dispatch({type: PreferencesTypes.SAVE_PREFERENCES_REQUEST}, getState); - - try { - await Client.savePreferences(preferences); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PreferencesTypes.SAVE_PREFERENCES_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: PreferencesTypes.RECEIVED_PREFERENCES, - data: preferences - }, - { - type: PreferencesTypes.SAVE_PREFERENCES_SUCCESS - } - ]), getState); - }; -} - -export function deletePreferences(preferences) { - return async (dispatch, getState) => { - dispatch({type: PreferencesTypes.DELETE_PREFERENCES_REQUEST}, getState); - - try { - await Client.deletePreferences(preferences); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PreferencesTypes.DELETE_PREFERENCES_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: PreferencesTypes.DELETED_PREFERENCES, - data: preferences - }, - { - type: PreferencesTypes.DELETE_PREFERENCES_SUCCESS - } - ]), getState); - }; -} - -export function makeDirectChannelVisibleIfNecessary(otherUserId) { - return async (dispatch, getState) => { - const state = getState(); - const myPreferences = getMyPreferencesSelector(state); - const currentUserId = getCurrentUserId(state); - - let preference = myPreferences[getPreferenceKey(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, otherUserId)]; - - if (!preference || preference.value === 'false') { - preference = { - user_id: currentUserId, - category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, - name: otherUserId, - value: 'true' - }; - - await savePreferences([preference])(dispatch, getState); - } - }; -} diff --git a/service/actions/teams.js b/service/actions/teams.js deleted file mode 100644 index 3c3c6dae1..000000000 --- a/service/actions/teams.js +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import Client from 'service/client'; -import {batchActions} from 'redux-batched-actions'; -import {Constants, TeamsTypes} from 'service/constants'; -import {getLogErrorAction} from './errors'; -import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; -import {getProfilesByIds, getStatusesByIds} from './users'; - -async function getProfilesAndStatusesForMembers(userIds, dispatch, getState) { - const {profiles, statuses} = getState().entities.users; - const profilesToLoad = []; - const statusesToLoad = []; - - userIds.forEach((userId) => { - if (!profiles[userId]) { - profilesToLoad.push(userId); - } - - if (!statuses[userId]) { - statusesToLoad.push(userId); - } - }); - - if (profilesToLoad.length) { - await getProfilesByIds(profilesToLoad)(dispatch, getState); - } - - if (statusesToLoad.length) { - await getStatusesByIds(statusesToLoad)(dispatch, getState); - } -} - -export function selectTeam(team) { - return async (dispatch, getState) => dispatch({ - type: TeamsTypes.SELECT_TEAM, - data: team.id - }, getState); -} - -export function fetchTeams() { - return bindClientFunc( - Client.getAllTeams, - TeamsTypes.FETCH_TEAMS_REQUEST, - [TeamsTypes.RECEIVED_ALL_TEAMS, TeamsTypes.FETCH_TEAMS_SUCCESS], - TeamsTypes.FETCH_TEAMS_FAILURE - ); -} - -export function getAllTeamListings() { - return bindClientFunc( - Client.getAllTeamListings, - TeamsTypes.TEAM_LISTINGS_REQUEST, - [TeamsTypes.RECEIVED_TEAM_LISTINGS, TeamsTypes.TEAM_LISTINGS_SUCCESS], - TeamsTypes.TEAM_LISTINGS_FAILURE - ); -} - -export function createTeam(userId, team) { - return async (dispatch, getState) => { - dispatch({type: TeamsTypes.CREATE_TEAM_REQUEST}, getState); - - let created; - try { - created = await Client.createTeam(team); - } catch (err) { - forceLogoutIfNecessary(err, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.CREATE_TEAM_FAILURE, error: err}, - getLogErrorAction(err) - ]), getState); - return; - } - - const member = { - team_id: created.id, - user_id: userId, - roles: `${Constants.TEAM_ADMIN_ROLE} ${Constants.TEAM_USER_ROLE}`, - delete_at: 0, - msg_count: 0, - mention_count: 0 - }; - - dispatch(batchActions([ - { - type: TeamsTypes.CREATED_TEAM, - data: created - }, - { - type: TeamsTypes.RECEIVED_MY_TEAM_MEMBERS, - data: [member] - }, - { - type: TeamsTypes.SELECT_TEAM, - data: created.id - }, - { - type: TeamsTypes.CREATE_TEAM_SUCCESS - } - ]), getState); - }; -} - -export function updateTeam(team) { - return bindClientFunc( - Client.updateTeam, - TeamsTypes.UPDATE_TEAM_REQUEST, - [TeamsTypes.UPDATED_TEAM, TeamsTypes.UPDATE_TEAM_SUCCESS], - TeamsTypes.UPDATE_TEAM_FAILURE, - team - ); -} - -export function getMyTeamMembers() { - return bindClientFunc( - Client.getMyTeamMembers, - TeamsTypes.MY_TEAM_MEMBERS_REQUEST, - [TeamsTypes.RECEIVED_MY_TEAM_MEMBERS, TeamsTypes.MY_TEAM_MEMBERS_SUCCESS], - TeamsTypes.MY_TEAM_MEMBERS_FAILURE - ); -} - -export function getTeamMember(teamId, userId) { - return async (dispatch, getState) => { - dispatch({type: TeamsTypes.TEAM_MEMBERS_REQUEST}, getState); - - let member; - try { - member = await Client.getTeamMember(teamId, userId); - getProfilesAndStatusesForMembers([userId], dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.TEAM_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: TeamsTypes.RECEIVED_MEMBERS_IN_TEAM, - data: [member] - }, - { - type: TeamsTypes.TEAM_MEMBERS_SUCCESS - } - ]), getState); - }; -} - -export function getTeamMembersByIds(teamId, userIds) { - return async (dispatch, getState) => { - dispatch({type: TeamsTypes.TEAM_MEMBERS_REQUEST}, getState); - - let members; - try { - members = await Client.getTeamMemberByIds(teamId, userIds); - getProfilesAndStatusesForMembers(userIds, dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.TEAM_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - } - - dispatch(batchActions([ - { - type: TeamsTypes.RECEIVED_MEMBERS_IN_TEAM, - data: members - }, - { - type: TeamsTypes.TEAM_MEMBERS_SUCCESS - } - ]), getState); - }; -} - -export function getTeamStats(teamId) { - return bindClientFunc( - Client.getTeamStats, - TeamsTypes.TEAM_STATS_REQUEST, - [TeamsTypes.RECEIVED_TEAM_STATS, TeamsTypes.TEAM_STATS_SUCCESS], - TeamsTypes.TEAM_STATS_FAILURE, - teamId - ); -} - -export function addUserToTeam(teamId, userId) { - return async (dispatch, getState) => { - dispatch({type: TeamsTypes.ADD_TEAM_MEMBER_REQUEST}, getState); - - try { - await Client.addUserToTeam(teamId, userId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.ADD_TEAM_MEMBER_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - const member = { - team_id: teamId, - user_id: userId - }; - - dispatch(batchActions([ - { - type: TeamsTypes.RECEIVED_MEMBER_IN_TEAM, - data: member - }, - { - type: TeamsTypes.ADD_TEAM_MEMBER_SUCCESS - } - ]), getState); - }; -} - -export function removeUserFromTeam(teamId, userId) { - return async (dispatch, getState) => { - dispatch({type: TeamsTypes.REMOVE_TEAM_MEMBER_REQUEST}, getState); - - try { - await Client.removeUserFromTeam(teamId, userId); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.REMOVE_TEAM_MEMBER_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - const member = { - team_id: teamId, - user_id: userId - }; - - dispatch(batchActions([ - { - type: TeamsTypes.REMOVE_MEMBER_FROM_TEAM, - data: member - }, - { - type: TeamsTypes.REMOVE_TEAM_MEMBER_SUCCESS - } - ]), getState); - }; -} diff --git a/service/actions/users.js b/service/actions/users.js deleted file mode 100644 index 544dbf3a7..000000000 --- a/service/actions/users.js +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; -import Client from 'service/client'; -import {Constants, PreferencesTypes, UsersTypes, TeamsTypes} from 'service/constants'; -import {fetchTeams} from 'service/actions/teams'; -import {getLogErrorAction} from 'service/actions/errors'; -import {bindClientFunc, forceLogoutIfNecessary, debounce} from './helpers'; - -export function checkMfa(loginId) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.CHECK_MFA_REQUEST}, getState); - try { - const mfa = await Client.checkMfa(loginId); - dispatch({type: UsersTypes.CHECK_MFA_SUCCESS}, getState); - return mfa; - } catch (error) { - dispatch(batchActions([ - {type: UsersTypes.CHECK_MFA_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - }; -} - -export function login(loginId, password, mfaToken = '') { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.LOGIN_REQUEST}, getState); - - const deviceId = getState().entities.general.deviceToken; - - return Client.login(loginId, password, mfaToken, deviceId). - then(async (data) => { - let teamMembers; - let preferences; - try { - const teamMembersRequest = Client.getMyTeamMembers(); - const preferencesRequest = Client.getMyPreferences(); - - teamMembers = await teamMembersRequest; - preferences = await preferencesRequest; - } catch (error) { - dispatch(batchActions([ - {type: UsersTypes.LOGIN_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - try { - await fetchTeams()(dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.LOGIN_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_ME, - data - }, - { - type: PreferencesTypes.RECEIVED_PREFERENCES, - data: await preferences - }, - { - type: TeamsTypes.RECEIVED_MY_TEAM_MEMBERS, - data: await teamMembers - }, - { - type: UsersTypes.LOGIN_SUCCESS - } - ]), getState); - }). - catch((error) => { - dispatch(batchActions([ - {type: UsersTypes.LOGIN_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - }); - }; -} - -export function loadMe() { - return async (dispatch, getState) => { - let user; - dispatch({type: UsersTypes.LOGIN_REQUEST}, getState); - try { - user = await Client.getMe(); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.LOGIN_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - const deviceId = getState().entities.general.deviceToken; - if (deviceId) { - Client.attachDevice(deviceId); - } - - let preferences; - dispatch({type: PreferencesTypes.MY_PREFERENCES_REQUEST}, getState); - try { - preferences = await Client.getMyPreferences(); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: PreferencesTypes.MY_PREFERENCES_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - try { - await fetchTeams()(dispatch, getState); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.FETCH_TEAMS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - let teamMembers; - dispatch({type: TeamsTypes.MY_TEAM_MEMBERS_REQUEST}, getState); - try { - teamMembers = await Client.getMyTeamMembers(); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: TeamsTypes.MY_TEAM_MEMBERS_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_ME, - data: user - }, - { - type: UsersTypes.LOGIN_SUCCESS - }, - { - type: PreferencesTypes.RECEIVED_PREFERENCES, - data: preferences - }, - { - type: PreferencesTypes.MY_PREFERENCES_SUCCESS - }, - { - type: TeamsTypes.RECEIVED_MY_TEAM_MEMBERS, - data: teamMembers - }, - { - type: TeamsTypes.MY_TEAM_MEMBERS_SUCCESS - } - ]), getState); - }; -} - -export function logout() { - return bindClientFunc( - Client.logout, - UsersTypes.LOGOUT_REQUEST, - UsersTypes.LOGOUT_SUCCESS, - UsersTypes.LOGOUT_FAILURE, - ); -} - -export function getProfiles(offset, limit = Constants.PROFILE_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.PROFILES_REQUEST}, getState); - - let profiles; - try { - profiles = await Client.getProfiles(offset, limit); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.PROFILES_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return null; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILES, - data: profiles - }, - { - type: UsersTypes.PROFILES_SUCCESS - } - ]), getState); - - return profiles; - }; -} - -export function getProfilesByIds(userIds) { - return bindClientFunc( - Client.getProfilesByIds, - UsersTypes.PROFILES_REQUEST, - [UsersTypes.RECEIVED_PROFILES, UsersTypes.PROFILES_SUCCESS], - UsersTypes.PROFILES_FAILURE, - userIds - ); -} - -export function getProfilesInTeam(teamId, offset, limit = Constants.PROFILE_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.PROFILES_IN_TEAM_REQUEST}, getState); - - let profiles; - try { - profiles = await Client.getProfilesInTeam(teamId, offset, limit); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.PROFILES_IN_TEAM_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILES_IN_TEAM, - data: profiles, - id: teamId - }, - { - type: UsersTypes.RECEIVED_PROFILES, - data: profiles - }, - { - type: UsersTypes.PROFILES_IN_TEAM_SUCCESS - } - ]), getState); - }; -} - -export function getProfilesInChannel(teamId, channelId, offset, limit = Constants.PROFILE_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.PROFILES_IN_CHANNEL_REQUEST}, getState); - - let profiles; - try { - profiles = await Client.getProfilesInChannel(teamId, channelId, offset, limit); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.PROFILES_IN_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILES_IN_CHANNEL, - data: profiles, - id: channelId - }, - { - type: UsersTypes.RECEIVED_PROFILES, - data: profiles - }, - { - type: UsersTypes.PROFILES_IN_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function getProfilesNotInChannel(teamId, channelId, offset, limit = Constants.PROFILE_CHUNK_SIZE) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.PROFILES_NOT_IN_CHANNEL_REQUEST}, getState); - - let profiles; - try { - profiles = await Client.getProfilesNotInChannel(teamId, channelId, offset, limit); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.PROFILES_NOT_IN_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_PROFILES_NOT_IN_CHANNEL, - data: profiles, - id: channelId - }, - { - type: UsersTypes.RECEIVED_PROFILES, - data: profiles - }, - { - type: UsersTypes.PROFILES_NOT_IN_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -// We create an array to hold the id's that we want to get a status for. We build our -// debounced function that will get called after a set period of idle time in which -// the array of id's will be passed to the getStatusesByIds with a cb that clears out -// the array. Helps with performance because instead of making 75 different calls for -// 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 = []; -const debouncedGetStatusesByIds = debounce(async (dispatch, getState) => { - getStatusesByIds([...new Set(ids)])(dispatch, getState); -}, 20, false, () => { - ids = []; -}); -export function getStatusesByIdsBatchedDebounced(id) { - ids = [...ids, id]; - return debouncedGetStatusesByIds; -} - -export function getStatusesByIds(userIds) { - return bindClientFunc( - Client.getStatusesByIds, - UsersTypes.PROFILES_STATUSES_REQUEST, - [UsersTypes.RECEIVED_STATUSES, UsersTypes.PROFILES_STATUSES_SUCCESS], - UsersTypes.PROFILES_STATUSES_FAILURE, - userIds - ); -} - -export function getSessions(userId) { - return bindClientFunc( - Client.getSessions, - UsersTypes.SESSIONS_REQUEST, - [UsersTypes.RECEIVED_SESSIONS, UsersTypes.SESSIONS_SUCCESS], - UsersTypes.SESSIONS_FAILURE, - userId - ); -} - -export function revokeSession(id) { - return bindClientFunc( - Client.revokeSession, - UsersTypes.REVOKE_SESSION_REQUEST, - [UsersTypes.RECEIVED_REVOKED_SESSION, UsersTypes.REVOKE_SESSION_SUCCESS], - UsersTypes.REVOKE_SESSION_FAILURE, - id - ); -} - -export function getAudits(userId) { - return bindClientFunc( - Client.getAudits, - UsersTypes.AUDITS_REQUEST, - [UsersTypes.RECEIVED_AUDITS, UsersTypes.AUDITS_SUCCESS], - UsersTypes.AUDITS_FAILURE, - userId - ); -} - -export function autocompleteUsersInChannel(teamId, channelId, term) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.AUTOCOMPLETE_IN_CHANNEL_REQUEST}, getState); - - let data; - try { - data = await Client.autocompleteUsersInChannel(teamId, channelId, term); - } catch (error) { - forceLogoutIfNecessary(error, dispatch); - dispatch(batchActions([ - {type: UsersTypes.AUTOCOMPLETE_IN_CHANNEL_FAILURE, error}, - getLogErrorAction(error) - ]), getState); - return; - } - - dispatch(batchActions([ - { - type: UsersTypes.RECEIVED_AUTOCOMPLETE_IN_CHANNEL, - data, - channelId - }, - { - type: UsersTypes.AUTOCOMPLETE_IN_CHANNEL_SUCCESS - } - ]), getState); - }; -} - -export function searchProfiles(term, options) { - return bindClientFunc( - Client.searchProfiles, - UsersTypes.SEARCH_PROFILES_REQUEST, - [UsersTypes.RECEIVED_SEARCH_PROFILES, UsersTypes.SEARCH_PROFILES_SUCCESS], - UsersTypes.SEARCH_PROFILES_FAILURE, - term, - options - ); -} - -let statusIntervalId = ''; -export function startPeriodicStatusUpdates() { - return async (dispatch, getState) => { - clearInterval(statusIntervalId); - - statusIntervalId = setInterval( - () => { - const {statuses} = getState().entities.users; - - if (!statuses) { - return; - } - - const userIds = Object.keys(statuses); - if (!userIds.length) { - return; - } - - getStatusesByIds(userIds)(dispatch, getState); - }, - Constants.STATUS_INTERVAL - ); - }; -} - -export function stopPeriodicStatusUpdates() { - return async () => { - if (statusIntervalId) { - clearInterval(statusIntervalId); - } - }; -} - -export function updateUserNotifyProps(notifyProps) { - return async (dispatch, getState) => { - dispatch({type: UsersTypes.UPDATE_NOTIFY_PROPS_REQUEST}, getState); - - let data; - try { - data = await Client.updateUserNotifyProps(notifyProps); - } catch (error) { - dispatch({type: UsersTypes.UPDATE_NOTIFY_PROPS_FAILURE, error}, getState); - return; - } - - dispatch(batchActions([ - {type: UsersTypes.RECEIVED_ME, data}, - {type: UsersTypes.UPDATE_NOTIFY_PROPS_SUCCESS} - ]), getState); - }; -} - -export default { - checkMfa, - login, - logout, - getProfiles, - getProfilesByIds, - getProfilesInTeam, - getProfilesInChannel, - getProfilesNotInChannel, - getStatusesByIds, - getSessions, - revokeSession, - getAudits, - searchProfiles, - startPeriodicStatusUpdates, - stopPeriodicStatusUpdates, - updateUserNotifyProps -}; diff --git a/service/actions/websocket.js b/service/actions/websocket.js deleted file mode 100644 index 08c172c52..000000000 --- a/service/actions/websocket.js +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {batchActions} from 'redux-batched-actions'; -import Client from 'service/client'; -import websocketClient from 'service/client/websocket_client'; -import {getProfilesByIds, getStatusesByIds} from 'service/actions/users'; -import { - fetchMyChannelsAndMembers, - getChannel, - getChannelStats, - updateChannelHeader, - updateChannelPurpose, - markChannelAsUnread, - markChannelAsRead -} from 'service/actions/channels'; -import { - getPosts, - getPostsSince -} from 'service/actions/posts'; -import {makeDirectChannelVisibleIfNecessary} from 'service/actions/preferences'; -import { - Constants, - ChannelTypes, - GeneralTypes, - PostsTypes, - PreferencesTypes, - TeamsTypes, - UsersTypes, - WebsocketEvents -} from 'service/constants'; -import {getCurrentChannelStats} from 'service/selectors/entities/channels'; -import {getUserIdFromChannelName} from 'service/utils/channel_utils'; -import {isSystemMessage, shouldIgnorePost} from 'service/utils/post_utils'; -import EventEmitter from 'service/utils/event_emitter'; - -export function init(platform, siteUrl, token, optionalWebSocket) { - return async (dispatch, getState) => { - const config = getState().entities.general.config; - let connUrl = siteUrl || Client.getUrl(); - const authToken = token || Client.getToken(); - - // replace the protocol with a websocket one - if (connUrl.startsWith('https:')) { - connUrl = connUrl.replace(/^https:/, 'wss:'); - } else { - connUrl = connUrl.replace(/^http:/, 'ws:'); - } - - // append a port number if one isn't already specified - if (!(/:\d+$/).test(connUrl)) { - if (connUrl.startsWith('wss:')) { - connUrl += ':' + (config.WebsocketSecurePort || 443); - } else { - connUrl += ':' + (config.WebsocketPort || 80); - } - } - - connUrl += `${Client.getUrlVersion()}/users/websocket`; - websocketClient.setFirstConnectCallback(handleFirstConnect); - websocketClient.setEventCallback(handleEvent); - websocketClient.setReconnectCallback(handleReconnect); - websocketClient.setCloseCallback(handleClose); - websocketClient.setConnectingCallback(handleConnecting); - - const websocketOpts = { - connectionUrl: connUrl, - platform - }; - - if (optionalWebSocket) { - websocketOpts.webSocketConnector = optionalWebSocket; - } - - return websocketClient.initialize(authToken, dispatch, getState, websocketOpts); - }; -} - -export function close() { - return async (dispatch, getState) => { - websocketClient.close(true); - if (dispatch) { - dispatch({type: GeneralTypes.WEBSOCKET_FAILURE, error: 'Closed'}, getState); - } - }; -} - -function handleConnecting(dispatch, getState) { - dispatch({type: GeneralTypes.WEBSOCKET_REQUEST}, getState); -} - -function handleFirstConnect(dispatch, getState) { - dispatch({type: GeneralTypes.WEBSOCKET_SUCCESS}, getState); -} - -function handleReconnect(dispatch, getState) { - const entities = getState().entities; - const currentTeamId = entities.teams.currentId; - const currentChannelId = entities.channels.currentId; - - if (currentTeamId) { - fetchMyChannelsAndMembers(currentTeamId)(dispatch, getState); - - if (currentChannelId) { - loadPostsHelper(currentTeamId, currentChannelId, dispatch, getState); - } - } - - dispatch({type: GeneralTypes.WEBSOCKET_SUCCESS}, getState); -} - -function handleClose(connectFailCount, dispatch, getState) { - dispatch({type: GeneralTypes.WEBSOCKET_FAILURE, error: connectFailCount}, getState); -} - -function handleEvent(msg, dispatch, getState) { - switch (msg.event) { - case WebsocketEvents.POSTED: - case WebsocketEvents.EPHEMERAL_MESSAGE: - handleNewPostEvent(msg, dispatch, getState); - break; - case WebsocketEvents.POST_EDITED: - handlePostEdited(msg, dispatch, getState); - break; - case WebsocketEvents.POST_DELETED: - handlePostDeleted(msg, dispatch, getState); - break; - case WebsocketEvents.LEAVE_TEAM: - handleLeaveTeamEvent(msg, dispatch, getState); - break; - case WebsocketEvents.USER_ADDED: - handleUserAddedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.USER_REMOVED: - handleUserRemovedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.USER_UPDATED: - handleUserUpdatedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.CHANNEL_CREATED: - handleChannelCreatedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.CHANNEL_DELETED: - handleChannelDeletedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.DIRECT_ADDED: - handleDirectAddedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.PREFERENCE_CHANGED: - handlePreferenceChangedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.STATUS_CHANGED: - handleStatusChangedEvent(msg, dispatch, getState); - break; - case WebsocketEvents.TYPING: - handleUserTypingEvent(msg, dispatch, getState); - break; - case WebsocketEvents.HELLO: - handleHelloEvent(msg); - break; - } -} - -async function handleNewPostEvent(msg, dispatch, getState) { - const state = getState(); - const currentChannelId = state.entities.channels.currentId; - const users = state.entities.users; - const {posts} = state.entities.posts; - const post = JSON.parse(msg.data.post); - const userId = post.user_id; - const teamId = msg.data.team_id; - const status = users.statuses[userId]; - - if (!users.profiles[userId]) { - getProfilesByIds([userId])(dispatch, getState); - } - - if (status !== Constants.ONLINE) { - getStatusesByIds([userId])(dispatch, getState); - } - - switch (post.type) { - case Constants.POST_HEADER_CHANGE: - updateChannelHeader(post.channel_id, post.props.new_header)(dispatch, getState); - break; - case Constants.POST_PURPOSE_CHANGE: - updateChannelPurpose(post.channel_id, post.props.new_purpose)(dispatch, getState); - break; - } - - if (msg.data.channel_type === Constants.DM_CHANNEL) { - const otherUserId = getUserIdFromChannelName(users.currentId, msg.data.channel_name); - - makeDirectChannelVisibleIfNecessary(otherUserId)(dispatch, getState); - } - - if (post.root_id && !posts[post.root_id]) { - await Client.getPost(teamId, post.channel_id, post.root_id).then((data) => { - const rootUserId = data.posts[post.root_id].user_id; - const rootStatus = users.statuses[rootUserId]; - if (!users.profiles[rootUserId]) { - getProfilesByIds([rootUserId])(dispatch, getState); - } - - if (rootStatus !== Constants.ONLINE) { - getStatusesByIds([rootUserId])(dispatch, getState); - } - - dispatch({ - type: PostsTypes.RECEIVED_POSTS, - data, - channelId: post.channel_id - }, getState); - }); - } - - dispatch(batchActions([ - { - type: PostsTypes.RECEIVED_POSTS, - data: { - order: [], - posts: { - [post.id]: post - } - }, - channelId: post.channel_id - }, - { - type: WebsocketEvents.STOP_TYPING, - data: { - id: post.channel_id + post.root_id, - userId: post.user_id - } - } - ]), getState); - - if (shouldIgnorePost(post)) { - // if the post type is in the ignore list we'll do nothing with the read state - return; - } - - let markAsRead = false; - if (userId === users.currentId && !isSystemMessage(post)) { - // In case the current user posted the message and that message wasn't triggered by a system message - markAsRead = true; - } else if (post.channel_id === currentChannelId) { - // if the post is for the channel that the user is currently viewing we'll mark the channel as read - markAsRead = true; - } - - if (markAsRead) { - markChannelAsRead(post.channel_id)(dispatch, getState); - } else { - markChannelAsUnread(post.channel_id, msg.data.mentions)(dispatch, getState); - } -} - -function handlePostEdited(msg, dispatch, getState) { - const data = JSON.parse(msg.data.post); - - dispatch({type: PostsTypes.RECEIVED_POST, data}, getState); -} - -function handlePostDeleted(msg, dispatch, getState) { - const data = JSON.parse(msg.data.post); - dispatch({type: PostsTypes.POST_DELETED, data}, getState); -} - -function handleLeaveTeamEvent(msg, dispatch, getState) { - const entities = getState().entities; - const teams = entities.teams; - const users = entities.users; - - if (users.currentId === msg.data.user_id) { - dispatch({type: TeamsTypes.LEAVE_TEAM, data: teams.teams[msg.data.team_id]}, getState); - - // if they are on the team being removed deselect the current team and channel - if (teams.currentId === msg.data.team_id) { - EventEmitter.emit('leave_team'); - } - } -} - -function handleUserAddedEvent(msg, dispatch, getState) { - const state = getState(); - const channels = state.entities.channels; - const teams = state.entities.teams; - const users = state.entities.users; - const teamId = msg.data.team_id; - - if (msg.broadcast.channel_id === channels.currentId) { - getChannelStats(teamId, channels.currentId)(dispatch, getState); - } - - if (teamId === teams.currentId && msg.data.user_id === users.currentId) { - getChannel(teamId, msg.broadcast.channel_id)(dispatch, getState); - } -} - -function handleUserRemovedEvent(msg, dispatch, getState) { - const state = getState(); - const channels = state.entities.channels; - const teams = state.entities.teams; - const users = state.entities.users; - const teamId = teams.currentId; - - if (msg.broadcast.user_id === users.currentId && teamId) { - fetchMyChannelsAndMembers(teamId)(dispatch, getState); - dispatch({ - type: ChannelTypes.LEAVE_CHANNEL, - data: msg.data.channel_id - }, getState); - } else if (msg.broadcast.channel_id === channels.currentId) { - getChannelStats(teamId, channels.currentId)(dispatch, getState); - } -} - -function handleUserUpdatedEvent(msg, dispatch, getState) { - const entities = getState().entities; - const users = entities.users; - const user = msg.data.user; - - if (user.id !== users.currentId) { - dispatch({ - type: UsersTypes.RECEIVED_PROFILES, - data: { - [user.id]: user - } - }, getState); - } -} - -function handleChannelCreatedEvent(msg, dispatch, getState) { - const {channel_id: channelId, team_id: teamId} = msg.data; - const state = getState(); - const {channels} = state.entities.channels; - const {currentId: currentTeamId} = state.entities.teams; - - if (teamId === currentTeamId && !channels[channelId]) { - getChannel(teamId, channelId)(dispatch, getState); - } -} - -function handleChannelDeletedEvent(msg, dispatch, getState) { - const entities = getState().entities; - const {channels, currentId} = entities.channels; - const teams = entities.teams; - - if (msg.broadcast.team_id === teams.currentId) { - if (msg.data.channel_id === currentId) { - let channelId = ''; - const channel = Object.keys(channels).filter((key) => channels[key].name === Constants.DEFAULT_CHANNEL); - - if (channel.length) { - channelId = channel[0]; - } - - dispatch({type: ChannelTypes.SELECT_CHANNEL, data: channelId}, getState); - } - dispatch({type: ChannelTypes.RECEIVED_CHANNEL_DELETED, data: msg.data.channel_id}, getState); - - fetchMyChannelsAndMembers(teams.currentId)(dispatch, getState); - } -} - -function handleDirectAddedEvent(msg, dispatch, getState) { - const state = getState(); - const teams = state.entities.teams; - - getChannel(teams.currentId, msg.broadcast.channel_id)(dispatch, getState); -} - -function handlePreferenceChangedEvent(msg, dispatch, getState) { - const preference = JSON.parse(msg.data.preference); - dispatch({type: PreferencesTypes.RECEIVED_PREFERENCES, data: [preference]}, getState); - - if (preference.category === Constants.CATEGORY_DIRECT_CHANNEL_SHOW) { - const state = getState(); - const users = state.entities.users; - const userId = preference.name; - const status = users.statuses[userId]; - - if (!users.profiles[userId]) { - getProfilesByIds([userId])(dispatch, getState); - } - - if (status !== Constants.ONLINE) { - getStatusesByIds([userId])(dispatch, getState); - } - } -} - -function handleStatusChangedEvent(msg, dispatch, getState) { - dispatch({ - type: UsersTypes.RECEIVED_STATUSES, - data: { - [msg.data.user_id]: msg.data.status - } - }, getState); -} - -function handleHelloEvent(msg) { - const serverVersion = msg.data.server_version; - if (serverVersion && Client.serverVersion !== serverVersion) { - Client.serverVersion = serverVersion; - EventEmitter.emit(Constants.CONFIG_CHANGED, serverVersion); - } -} - -const typingUsers = {}; -function handleUserTypingEvent(msg, dispatch, getState) { - const state = getState(); - const {profiles, statuses} = state.entities.users; - const {config} = state.entities.general; - const userId = msg.data.user_id; - const id = msg.broadcast.channel_id + msg.data.parent_id; - const data = {id, userId}; - - // Create entry - if (!typingUsers[id]) { - typingUsers[id] = {}; - } - - // If we already have this user, clear it's timeout to be deleted - if (typingUsers[id][userId]) { - clearTimeout(typingUsers[id][userId].timeout); - } - - // Set the user and a timeout to remove it - typingUsers[id][userId] = setTimeout(() => { - Reflect.deleteProperty(typingUsers[id], userId); - if (typingUsers[id] === {}) { - Reflect.deleteProperty(typingUsers, id); - } - dispatch({ - type: WebsocketEvents.STOP_TYPING, - data - }, getState); - }, parseInt(config.TimeBetweenUserTypingUpdatesMilliseconds, 10)); - - dispatch({ - type: WebsocketEvents.TYPING, - data - }, getState); - - if (!profiles[userId]) { - getProfilesByIds([userId])(dispatch, getState); - } - - const status = statuses[userId]; - if (status !== Constants.ONLINE) { - getStatusesByIds([userId])(dispatch, getState); - } -} - -// Helpers - -function loadPostsHelper(teamId, channelId, dispatch, getState) { - const {posts, postsByChannel} = getState().entities.posts; - const postsArray = postsByChannel[channelId]; - const latestPostId = postsArray[postsArray.length - 1]; - - let latestPostTime = 0; - if (latestPostId) { - latestPostTime = posts[latestPostId].create_at || 0; - } - - if (Object.keys(posts).length === 0 || postsArray.length < Constants.POST_CHUNK_SIZE || latestPostTime === 0) { - getPosts(teamId, channelId)(dispatch, getState); - } else { - getPostsSince(teamId, channelId, latestPostTime)(dispatch, getState); - } -} - -let lastTimeTypingSent = 0; -export function userTyping(channelId, parentPostId) { - return async (dispatch, getState) => { - const state = getState(); - const config = state.entities.general.config; - const t = Date.now(); - const membersInChannel = getCurrentChannelStats(state).member_count; - - if (((t - lastTimeTypingSent) > config.TimeBetweenUserTypingUpdatesMilliseconds) && - (membersInChannel < config.MaxNotificationsPerChannel) && (config.EnableUserTypingMessages === 'true')) { - websocketClient.userTyping(channelId, parentPostId); - lastTimeTypingSent = t; - } - }; -} diff --git a/service/client/client.js b/service/client/client.js deleted file mode 100644 index 9095fc73b..000000000 --- a/service/client/client.js +++ /dev/null @@ -1,790 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import fetch from './fetch_etag'; - -import EventEmitter from 'service/utils/event_emitter'; -import {Constants} from 'service/constants'; - -const HEADER_AUTH = 'Authorization'; -const HEADER_BEARER = 'BEARER'; -const HEADER_REQUESTED_WITH = 'X-Requested-With'; -const HEADER_TOKEN = 'Token'; -const HEADER_X_VERSION_ID = 'X-Version-Id'; -const HEADER_USER_AGENT = 'User-Agent'; - -export default class Client { - constructor() { - this.logToConsole = false; - this.token = ''; - this.url = ''; - this.urlVersion = '/api/v3'; - this.serverVersion = ''; - this.userAgent = null; - - this.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; - } - - setUrl(url) { - this.url = url; - } - - setUserAgent(userAgent) { - this.userAgent = userAgent; - } - - getToken() { - return this.token; - } - - setToken(token) { - this.token = token; - } - - getServerVersion() { - return this.serverVersion; - } - - getUrlVersion() { - return this.urlVersion; - } - - getBaseRoute() { - return `${this.url}${this.urlVersion}`; - } - - getAdminRoute() { - return `${this.url}${this.urlVersion}/admin`; - } - - getGeneralRoute() { - return `${this.url}${this.urlVersion}/general`; - } - - getLicenseRoute() { - return `${this.url}${this.urlVersion}/license`; - } - - getTeamsRoute() { - return `${this.url}${this.urlVersion}/teams`; - } - - getPreferencesRoute() { - return `${this.url}${this.urlVersion}/preferences`; - } - - getTeamNeededRoute(teamId) { - return `${this.url}${this.urlVersion}/teams/${teamId}`; - } - - getChannelsRoute(teamId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/channels`; - } - - getChannelNameRoute(teamId, channelName) { - return `${this.url}${this.urlVersion}/teams/${teamId}/channels/name/${channelName}`; - } - - getChannelNeededRoute(teamId, channelId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/channels/${channelId}`; - } - - getCommandsRoute(teamId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/commands`; - } - - getEmojiRoute() { - return `${this.url}${this.urlVersion}/emoji`; - } - - getHooksRoute(teamId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/hooks`; - } - - getPostsRoute(teamId, channelId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/channels/${channelId}/posts`; - } - - getUsersRoute() { - return `${this.url}${this.urlVersion}/users`; - } - - getFilesRoute(teamId) { - return `${this.url}${this.urlVersion}/teams/${teamId}/files`; - } - - getOAuthRoute() { - return `${this.url}${this.urlVersion}/oauth`; - } - - getUserNeededRoute(userId) { - return `${this.url}${this.urlVersion}/users/${userId}`; - } - - enableLogErrorsToConsole(enabled) { - this.logToConsole = enabled; - } - - getOptions(options) { - const headers = { - [HEADER_REQUESTED_WITH]: 'XMLHttpRequest' - }; - - if (this.token) { - headers[HEADER_AUTH] = `${HEADER_BEARER} ${this.token}`; - } - - if (this.userAgent) { - headers[HEADER_USER_AGENT] = this.userAgent; - } - - if (options.headers) { - Object.assign(headers, options.headers); - } - - return { - ...options, - headers - }; - } - - // General routes - - getClientConfig = async () => { - return this.doFetch( - `${this.getGeneralRoute()}/client_props`, - {method: 'get'} - ); - }; - - getLicenseConfig = async () => { - return this.doFetch( - `${this.getLicenseRoute()}/client_config`, - {method: 'get'} - ); - }; - - getPing = async () => { - return this.doFetch( - `${this.getGeneralRoute()}/ping`, - {method: 'get'} - ); - }; - - logClientError = async (message, level = 'ERROR') => { - const body = { - message, - level - }; - - return this.doFetch( - `${this.getGeneralRoute()}/log_client`, - {method: 'post', body} - ); - }; - - // User routes - createUser = async (user) => { - return this.createUserWithInvite(user); - }; - - // TODO: add deep linking to emails so we can create accounts from within - // the mobile app - createUserWithInvite = async(user, data, emailHash, inviteId) => { - let url = `${this.getUsersRoute()}/create`; - - url += '?d=' + encodeURIComponent(data); - - if (emailHash) { - url += '&h=' + encodeURIComponent(emailHash); - } - - if (inviteId) { - url += '&iid=' + encodeURIComponent(inviteId); - } - - return this.doFetch( - url, - {method: 'post', body: JSON.stringify(user)} - ); - }; - - checkMfa = async (loginId) => { - return this.doFetch( - `${this.getUsersRoute()}/mfa`, - {method: 'post', body: JSON.stringify({login_id: loginId})} - ); - }; - - login = async (loginId, password, token = '', deviceId = '') => { - const body = { - login_id: loginId, - password, - token, - device_id: deviceId - }; - - const {headers, data} = await this.doFetchWithResponse( - `${this.getUsersRoute()}/login`, - {method: 'post', body: JSON.stringify(body)} - ); - - if (headers.has(HEADER_TOKEN)) { - this.token = headers.get(HEADER_TOKEN); - } - - return data; - }; - - logout = async () => { - const {response} = await this.doFetchWithResponse( - `${this.getUsersRoute()}/logout`, - {method: 'post'} - ); - if (response.ok) { - this.token = ''; - } - this.serverVersion = ''; - return response; - }; - - attachDevice = async (deviceId) => { - return this.doFetch( - `${this.getUsersRoute()}/attach_device`, - {method: 'post', body: JSON.stringify({device_id: deviceId})} - ); - }; - - updateUser = async (user) => { - return this.doFetch( - `${this.getUsersRoute()}/update`, - {method: 'post', body: JSON.stringify(user)} - ); - }; - - updatePassword = async (userId, currentPassword, newPassword) => { - const data = { - user_id: userId, - current_password: currentPassword, - new_password: newPassword - }; - - return this.doFetch( - `${this.getUsersRoute()}/newpassword`, - {method: 'post', body: JSON.stringify(data)} - ); - }; - - updateUserNotifyProps = async (notifyProps) => { - return this.doFetch( - `${this.getUsersRoute()}/update_notify`, - {method: 'post', body: JSON.stringify(notifyProps)} - ); - }; - - updateUserRoles = async (userId, newRoles) => { - return this.doFetch( - `${this.getUserNeededRoute(userId)}/update_roles`, - {method: 'post', body: JSON.stringify({new_roles: newRoles})} - ); - }; - - getMe = async () => { - return this.doFetch( - `${this.getUsersRoute()}/me`, - {method: 'get'} - ); - }; - - getProfiles = async (offset, limit) => { - return this.doFetch( - `${this.getUsersRoute()}/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getProfilesByIds = async (userIds) => { - return this.doFetch( - `${this.getUsersRoute()}/ids`, - {method: 'post', body: JSON.stringify(userIds)} - ); - }; - - getProfilesInTeam = async (teamId, offset, limit) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/users/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getProfilesInChannel = async (teamId, channelId, offset, limit) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/users/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getProfilesNotInChannel = async (teamId, channelId, offset, limit) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/users/not_in_channel/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getUser = async (userId) => { - return this.doFetch( - `${this.getUserNeededRoute(userId)}/get`, - {method: 'get'} - ); - }; - - getStatusesByIds = async (userIds) => { - return this.doFetch( - `${this.getUsersRoute()}/status/ids`, - {method: 'post', body: JSON.stringify(userIds)} - ); - }; - - getSessions = async (userId) => { - return this.doFetch( - `${this.getUserNeededRoute(userId)}/sessions`, - {method: 'get'} - ); - }; - - revokeSession = async (id) => { - return this.doFetch( - `${this.getUsersRoute()}/revoke_session`, - {method: 'post', body: JSON.stringify({id})} - ); - }; - - getAudits = async (userId) => { - return this.doFetch( - `${this.getUserNeededRoute(userId)}/audits`, - {method: 'get'} - ); - }; - - getProfilePictureUrl = (userId, lastPictureUpdate) => { - let params = ''; - if (lastPictureUpdate) { - params = `?time=${lastPictureUpdate}`; - } - - return `${this.getUsersRoute()}/${userId}/image${params}`; - }; - - autocompleteUsersInChannel = (teamId, channelId, term) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/users/autocomplete?term=${encodeURIComponent(term)}`, - {method: 'get'} - ); - }; - - searchProfiles = (term, options) => { - return this.doFetch( - `${this.getUsersRoute()}/search`, - {method: 'post', body: JSON.stringify({term, ...options})} - ); - }; - - // Team routes - - createTeam = async (team) => { - return this.doFetch( - `${this.getTeamsRoute()}/create`, - {method: 'post', body: JSON.stringify(team)} - ); - }; - - updateTeam = async (team) => { - return this.doFetch( - `${this.getTeamNeededRoute(team.id)}/update`, - {method: 'post', body: JSON.stringify(team)} - ); - }; - - getAllTeams = async () => { - return this.doFetch( - `${this.getTeamsRoute()}/all`, - {method: 'get'} - ); - }; - - getMyTeamMembers = async () => { - return this.doFetch( - `${this.getTeamsRoute()}/members`, - {method: 'get'} - ); - }; - - getAllTeamListings = async () => { - return this.doFetch( - `${this.getTeamsRoute()}/all_team_listings`, - {method: 'get'} - ); - }; - - getTeamMember = async (teamId, userId) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/members/${userId}`, - {method: 'get'} - ); - }; - - getTeamMemberByIds = async (teamId, userIds) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/members/ids`, - {method: 'post', body: JSON.stringify(userIds)} - ); - }; - - getTeamStats = async (teamId) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/stats`, - {method: 'get'} - ); - }; - - addUserToTeam = async (teamId, userId) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/add_user_to_team`, - {method: 'post', body: JSON.stringify({user_id: userId})} - ); - }; - - removeUserFromTeam = async (teamId, userId) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/remove_user_from_team`, - {method: 'post', body: JSON.stringify({user_id: userId})} - ); - }; - - // Channel routes - - createChannel = async (channel) => { - return this.doFetch( - `${this.getChannelsRoute(channel.team_id)}/create`, - {method: 'post', body: JSON.stringify(channel)} - ); - }; - - createDirectChannel = async (teamId, userId) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/create_direct`, - {method: 'post', body: JSON.stringify({user_id: userId})} - ); - }; - - getChannel = async (teamId, channelId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/`, - {method: 'get'} - ); - }; - - getChannels = async (teamId) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/`, - {method: 'get'} - ); - }; - - getMyChannelMembers = async (teamId) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/members`, - {method: 'get'} - ); - }; - - updateChannel = async (channel) => { - return this.doFetch( - `${this.getChannelsRoute(channel.team_id)}/update`, - {method: 'post', body: JSON.stringify(channel)} - ); - }; - - updateChannelNotifyProps = async (teamId, data) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/update_notify_props`, - {method: 'post', body: JSON.stringify(data)} - ); - }; - - leaveChannel = async (teamId, channelId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/leave`, - {method: 'post'} - ); - }; - - joinChannel = async (teamId, channelId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/join`, - {method: 'post'} - ); - }; - - joinChannelByName = async (teamId, channelName) => { - return this.doFetch( - `${this.getChannelNameRoute(teamId, channelName)}/join`, - {method: 'post'} - ); - }; - - deleteChannel = async (teamId, channelId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/delete`, - {method: 'post'} - ); - }; - - viewChannel = async (teamId, channelId, prevChannelId = '') => { - const data = { - channel_id: channelId, - prev_channel_id: prevChannelId - }; - - return this.doFetch( - `${this.getChannelsRoute(teamId)}/view`, - {method: 'post', body: JSON.stringify(data)} - ); - }; - - getMoreChannels = async (teamId, offset, limit) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/more/${offset}/${limit}`, - {method: 'get'} - ); - }; - - searchMoreChannels = async (teamId, term) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/more/search`, - {method: 'post', body: JSON.stringify({term})} - ); - }; - - getChannelStats = async (teamId, channelId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/stats`, - {method: 'get'} - ); - }; - - addChannelMember = async (teamId, channelId, userId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/add`, - {method: 'post', body: JSON.stringify({user_id: userId})} - ); - }; - - removeChannelMember = async (teamId, channelId, userId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/remove`, - {method: 'post', body: JSON.stringify({user_id: userId})} - ); - }; - - autocompleteChannels = async (teamId, term) => { - return this.doFetch( - `${this.getChannelsRoute(teamId)}/autocomplete?term=${encodeURIComponent(term)}`, - {method: 'get'} - ); - } - - // Post routes - createPost = async (teamId, post) => { - return this.doFetch( - `${this.getPostsRoute(teamId, post.channel_id)}/create`, - {method: 'post', body: JSON.stringify(post)} - ); - }; - - editPost = async (teamId, post) => { - return this.doFetch( - `${this.getPostsRoute(teamId, post.channel_id)}/update`, - {method: 'post', body: JSON.stringify(post)} - ); - }; - - deletePost = async (teamId, channelId, postId) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/${postId}/delete`, - {method: 'post'} - ); - }; - - getPost = async (teamId, channelId, postId) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/${postId}/get`, - {method: 'get'} - ); - }; - - getPosts = async (teamId, channelId, offset, limit) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/page/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getPostsSince = async (teamId, channelId, since) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/since/${since}`, - {method: 'get'} - ); - }; - - getPostsBefore = async (teamId, channelId, postId, offset, limit) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/${postId}/before/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getPostsAfter = async (teamId, channelId, postId, offset, limit) => { - return this.doFetch( - `${this.getPostsRoute(teamId, channelId)}/${postId}/after/${offset}/${limit}`, - {method: 'get'} - ); - }; - - getFileInfosForPost = async (teamId, channelId, postId) => { - return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/posts/${postId}/get_file_infos`, - {method: 'get'} - ); - }; - - uploadFile = async (teamId, channelId, clientId, fileFormData, formBoundary) => { - return this.doFetch( - `${this.getTeamNeededRoute(teamId)}/files/upload`, - { - method: 'post', - headers: { - 'Content-Type': `multipart/form-data; boundary=${formBoundary}` - }, - body: fileFormData - } - ); - }; - - // Preferences routes - getMyPreferences = async () => { - return this.doFetch( - `${this.getPreferencesRoute()}/`, - {method: 'get'} - ); - }; - - savePreferences = async (preferences) => { - return this.doFetch( - `${this.getPreferencesRoute()}/save`, - {method: 'post', body: JSON.stringify(preferences)} - ); - }; - - deletePreferences = async (preferences) => { - return this.doFetch( - `${this.getPreferencesRoute()}/delete`, - {method: 'post', body: JSON.stringify(preferences)} - ); - }; - - getPreferenceCategory = async (category) => { - return this.doFetch( - `${this.getPreferencesRoute()}/${category}`, - {method: 'get'} - ); - }; - - getPreference = async (category, name) => { - return this.doFetch( - `${this.getPreferencesRoute()}/${category}/${name}`, - {method: 'get'} - ); - }; - - // Client helpers - doFetch = async (url, options) => { - const {data} = await this.doFetchWithResponse(url, options); - - return data; - }; - - doFetchWithResponse = async (url, options) => { - const response = await fetch(url, this.getOptions(options)); - const headers = parseAndMergeNestedHeaders(response.headers); - - let data; - try { - data = await response.json(); - } catch (err) { - throw { - intl: { - id: 'mobile.request.invalid_response', - defaultMessage: 'Received invalid response from the server.' - } - }; - } - - if (headers.has(HEADER_X_VERSION_ID)) { - const serverVersion = headers.get(HEADER_X_VERSION_ID); - if (serverVersion && this.serverVersion !== serverVersion) { - this.serverVersion = serverVersion; - EventEmitter.emit(Constants.CONFIG_CHANGED, serverVersion); - } - } - - if (response.ok) { - return { - response, - headers, - data - }; - } - - const msg = data.message || ''; - - if (this.logToConsole) { - console.error(msg); // eslint-disable-line no-console - } - - throw { - message: msg, - server_error_id: data.id, - status_code: data.status_code, - url - }; - }; -} - -function parseAndMergeNestedHeaders(originalHeaders) { - // TODO: This is a workaround for https://github.com/matthew-andrews/isomorphic-fetch/issues/97 - // The real solution is to set Access-Control-Expose-Headers on the server - const headers = new Map(); - let nestedHeaders = new Map(); - originalHeaders.forEach((val, key) => { - 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(); - const moreNestedHeaders = new Map( - nestedHeaderStrings.map((h) => h.split(/:\s/)) - ); - nestedHeaders = new Map([...nestedHeaders, ...moreNestedHeaders]); - } - headers.set(capitalizedKey, realVal); - }); - return new Map([...headers, ...nestedHeaders]); -} diff --git a/service/client/fetch_etag.js b/service/client/fetch_etag.js deleted file mode 100644 index 81e67f655..000000000 --- a/service/client/fetch_etag.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -const data = {}; -const etags = {}; - -export default (url = null, 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]); //eslint-disable-line no-undefined -}; diff --git a/service/client/index.js b/service/client/index.js deleted file mode 100644 index 8f550c485..000000000 --- a/service/client/index.js +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import Client from './client.js'; - -export default new Client(); \ No newline at end of file diff --git a/service/client/websocket_client.js b/service/client/websocket_client.js deleted file mode 100644 index 1eb5057fa..000000000 --- a/service/client/websocket_client.js +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -const MAX_WEBSOCKET_FAILS = 7; -const MIN_WEBSOCKET_RETRY_TIME = 3000; // 3 sec -const MAX_WEBSOCKET_RETRY_TIME = 300000; // 5 mins - -let Socket; - -class WebSocketClient { - constructor() { - this.conn = null; - this.connectionUrl = null; - this.token = null; - this.sequence = 1; - this.connectFailCount = 0; - this.eventCallback = null; - this.firstConnectCallback = null; - this.reconnectCallback = null; - this.errorCallback = null; - this.closeCallback = null; - this.connectingCallback = null; - this.dispatch = null; - this.getState = null; - this.stop = false; - this.platform = ''; - } - - initialize(token, dispatch, getState, opts) { - const defaults = { - forceConnection: true, - connectionUrl: this.connectionUrl, - webSocketConnector: WebSocket - }; - - const {connectionUrl, forceConnection, webSocketConnector, platform} = Object.assign({}, defaults, opts); - - if (platform) { - this.platform = platform; - } - - if (forceConnection) { - this.stop = false; - } - - return new Promise((resolve, reject) => { - if (this.conn) { - resolve(); - return; - } - - if (connectionUrl == null) { - console.log('websocket must have connection url'); //eslint-disable-line no-console - reject('websocket must have connection url'); - return; - } - - if (!dispatch) { - console.log('websocket must have a dispatch'); //eslint-disable-line no-console - reject('websocket must have a dispatch'); - return; - } - - if (this.connectFailCount === 0) { - console.log('websocket connecting to ' + connectionUrl); //eslint-disable-line no-console - } - - Socket = webSocketConnector; - if (this.connectingCallback) { - this.connectingCallback(dispatch, getState); - } - - const regex = platform === 'android' ? /^(?:https?|wss?):\/\/[^/][^*:]*/ : /^(?:https?|wss?):\/\/[^/]*/; - const captured = (regex).exec(connectionUrl); - const origin = captured ? captured[0] : null; - - this.conn = new Socket(connectionUrl, null, {origin}); - this.connectionUrl = connectionUrl; - this.token = token; - this.dispatch = dispatch; - this.getState = getState; - - this.conn.onopen = () => { - if (token) { - this.sendMessage('authentication_challenge', {token}); - } - - if (this.connectFailCount > 0) { - console.log('websocket re-established connection'); //eslint-disable-line no-console - if (this.reconnectCallback) { - this.reconnectCallback(this.dispatch, this.getState); - } - } else if (this.firstConnectCallback) { - this.firstConnectCallback(this.dispatch, this.getState); - resolve(); - } - - this.connectFailCount = 0; - }; - - this.conn.onclose = () => { - this.conn = null; - this.sequence = 1; - - if (this.connectFailCount === 0) { - console.log('websocket closed'); //eslint-disable-line no-console - } - - this.connectFailCount++; - - if (this.closeCallback) { - this.closeCallback(this.connectFailCount, this.dispatch, this.getState); - } - - let retryTime = MIN_WEBSOCKET_RETRY_TIME; - - // If we've failed a bunch of connections then start backing off - if (this.connectFailCount > MAX_WEBSOCKET_FAILS) { - retryTime = MIN_WEBSOCKET_RETRY_TIME * this.connectFailCount; - if (retryTime > MAX_WEBSOCKET_RETRY_TIME) { - retryTime = MAX_WEBSOCKET_RETRY_TIME; - } - } - - setTimeout( - () => { - if (this.stop) { - return; - } - this.initialize(token, dispatch, getState, Object.assign({}, opts, {forceConnection: true})); - }, - retryTime - ); - }; - - this.conn.onerror = (evt) => { - if (this.connectFailCount <= 1) { - console.log('websocket error'); //eslint-disable-line no-console - console.log(evt); //eslint-disable-line no-console - } - - if (this.errorCallback) { - this.errorCallback(evt, this.dispatch, this.getState); - } - }; - - this.conn.onmessage = (evt) => { - const msg = JSON.parse(evt.data); - if (msg.seq_reply) { - if (msg.error) { - console.log(msg); //eslint-disable-line no-console - } - } else if (this.eventCallback) { - this.eventCallback(msg, this.dispatch, this.getState); - } - }; - }); - } - - setConnectingCallback(callback) { - this.connectingCallback = callback; - } - - setEventCallback(callback) { - this.eventCallback = callback; - } - - setFirstConnectCallback(callback) { - this.firstConnectCallback = callback; - } - - setReconnectCallback(callback) { - this.reconnectCallback = callback; - } - - setErrorCallback(callback) { - this.errorCallback = callback; - } - - setCloseCallback(callback) { - this.closeCallback = callback; - } - - close(stop = false) { - this.stop = stop; - this.connectFailCount = 0; - this.sequence = 1; - if (this.conn && this.conn.readyState === Socket.OPEN) { - this.conn.onclose = () => {}; //eslint-disable-line no-empty-function - this.conn.close(); - this.conn = null; - console.log('websocket closed'); //eslint-disable-line no-console - } - } - - sendMessage(action, data) { - const msg = { - action, - seq: this.sequence++, - data - }; - - if (this.conn && this.conn.readyState === Socket.OPEN) { - this.conn.send(JSON.stringify(msg)); - } else if (!this.conn || this.conn.readyState === Socket.CLOSED) { - this.conn = null; - this.initialize(this.token, this.dispatch, this.getState, {forceConnection: true, platform: this.platform}); - } - } - - userTyping(channelId, parentId) { - this.sendMessage('user_typing', { - channel_id: channelId, - parent_id: parentId - }); - } - - getStatuses() { - this.sendMessage('get_statuses', null); - } - - getStatusesByIds(userIds) { - this.sendMessage('get_statuses_by_ids', { - user_ids: userIds - }); - } -} - -export default new WebSocketClient(); diff --git a/service/constants/channels.js b/service/constants/channels.js deleted file mode 100644 index a9edefa64..000000000 --- a/service/constants/channels.js +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const ChannelTypes = keyMirror({ - CHANNEL_REQUEST: null, - CHANNEL_SUCCESS: null, - CHANNEL_FAILURE: null, - - CHANNELS_REQUEST: null, - CHANNELS_SUCCESS: null, - CHANNELS_FAILURE: null, - - CHANNEL_MEMBERS_REQUEST: null, - CHANNEL_MEMBERS_SUCCESS: null, - CHANNEL_MEMBERS_FAILURE: null, - - CREATE_CHANNEL_REQUEST: null, - CREATE_CHANNEL_SUCCESS: null, - CREATE_CHANNEL_FAILURE: null, - - UPDATE_CHANNEL_REQUEST: null, - UPDATE_CHANNEL_SUCCESS: null, - UPDATE_CHANNEL_FAILURE: null, - - NOTIFY_PROPS_REQUEST: null, - NOTIFY_PROPS_SUCCESS: null, - NOTIFY_PROPS_FAILURE: null, - - LEAVE_CHANNEL_REQUEST: null, - LEAVE_CHANNEL_SUCCESS: null, - LEAVE_CHANNEL_FAILURE: null, - - JOIN_CHANNEL_REQUEST: null, - JOIN_CHANNEL_SUCCESS: null, - JOIN_CHANNEL_FAILURE: null, - - DELETE_CHANNEL_REQUEST: null, - DELETE_CHANNEL_SUCCESS: null, - DELETE_CHANNEL_FAILURE: null, - - UPDATE_LAST_VIEWED_REQUEST: null, - UPDATE_LAST_VIEWED_SUCCESS: null, - UPDATE_LAST_VIEWED_FAILURE: null, - - MORE_CHANNELS_REQUEST: null, - MORE_CHANNELS_SUCCESS: null, - MORE_CHANNELS_FAILURE: null, - - CHANNEL_STATS_REQUEST: null, - CHANNEL_STATS_SUCCESS: null, - CHANNEL_STATS_FAILURE: null, - - ADD_CHANNEL_MEMBER_REQUEST: null, - ADD_CHANNEL_MEMBER_SUCCESS: null, - ADD_CHANNEL_MEMBER_FAILURE: null, - - REMOVE_CHANNEL_MEMBER_REQUEST: null, - REMOVE_CHANNEL_MEMBER_SUCCESS: null, - REMOVE_CHANNEL_MEMBER_FAILURE: null, - - AUTOCOMPLETE_CHANNELS_REQUEST: null, - AUTOCOMPLETE_CHANNELS_SUCCESS: null, - AUTOCOMPLETE_CHANNELS_FAILURE: null, - - SELECT_CHANNEL: null, - LEAVE_CHANNEL: null, - RECEIVED_CHANNEL: null, - RECEIVED_CHANNELS: null, - RECEIVED_MY_CHANNEL_MEMBERS: null, - RECEIVED_MY_CHANNEL_MEMBER: null, - RECEIVED_MORE_CHANNELS: null, - RECEIVED_CHANNEL_STATS: null, - RECEIVED_CHANNEL_PROPS: null, - RECEIVED_CHANNEL_DELETED: null, - RECEIVED_LAST_VIEWED: null, - RECEIVED_AUTOCOMPLETE_CHANNELS: null, - UPDATE_CHANNEL_HEADER: null, - UPDATE_CHANNEL_PURPOSE: null -}); - -export default ChannelTypes; diff --git a/service/constants/constants.js b/service/constants/constants.js deleted file mode 100644 index 677611f87..000000000 --- a/service/constants/constants.js +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -const Constants = { - CONFIG_CHANGED: 'config_changed', - - POST_CHUNK_SIZE: 60, - PROFILE_CHUNK_SIZE: 100, - CHANNELS_CHUNK_SIZE: 50, - SEARCH_TIMEOUT_MILLISECONDS: 100, - STATUS_INTERVAL: 60000, - - MENTION: 'mention', - - OFFLINE: 'offline', - AWAY: 'away', - ONLINE: 'online', - - TEAM_USER_ROLE: 'team_user', - TEAM_ADMIN_ROLE: 'team_admin', - - CHANNEL_USER_ROLE: 'channel_user', - CHANNEL_ADMIN_ROLE: 'channel_admin', - - DEFAULT_CHANNEL: 'town-square', - DM_CHANNEL: 'D', - OPEN_CHANNEL: 'O', - PRIVATE_CHANNEL: 'P', - - POST_DELETED: 'DELETED', - SYSTEM_MESSAGE_PREFIX: 'system_', - - CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show', - CATEGORY_DISPLAY_SETTINGS: 'display_settings', - CATEGORY_FAVORITE_CHANNEL: 'favorite_channel', - DISPLAY_PREFER_NICKNAME: 'nickname_full_name', - DISPLAY_PREFER_FULL_NAME: 'full_name', - - START_OF_NEW_MESSAGES: 'start-of-new-messages', - - POST_HEADER_CHANGE: 'system_header_change', - POST_PURPOSE_CHANGE: 'system_purpose_change', - - PUSH_NOTIFY_APPLE_REACT_NATIVE: 'apple_rn', - PUSH_NOTIFY_ANDROID_REACT_NATIVE: 'android_rn' -}; - -const FileConstants = { - AUDIO_TYPES: ['mp3', 'wav', 'wma', 'm4a', 'flac', 'aac', 'ogg'], - CODE_TYPES: ['as', 'applescript', 'osascript', 'scpt', 'bash', 'sh', 'zsh', 'clj', 'boot', 'cl2', 'cljc', 'cljs', 'cljs.hl', 'cljscm', 'cljx', 'hic', 'coffee', '_coffee', 'cake', 'cjsx', 'cson', 'iced', 'cpp', 'c', 'cc', 'h', 'c++', 'h++', 'hpp', 'cs', 'csharp', 'css', 'd', 'di', 'dart', 'delphi', 'dpr', 'dfm', 'pas', 'pascal', 'freepascal', 'lazarus', 'lpr', 'lfm', 'diff', 'django', 'jinja', 'dockerfile', 'docker', 'erl', 'f90', 'f95', 'fsharp', 'fs', 'gcode', 'nc', 'go', 'groovy', 'handlebars', 'hbs', 'html.hbs', 'html.handlebars', 'hs', 'hx', 'java', 'jsp', 'js', 'jsx', 'json', 'jl', 'kt', 'ktm', 'kts', 'less', 'lisp', 'lua', 'mk', 'mak', 'md', 'mkdown', 'mkd', 'matlab', 'm', 'mm', 'objc', 'obj-c', 'ml', 'perl', 'pl', 'php', 'php3', 'php4', 'php5', 'php6', 'ps', 'ps1', 'pp', 'py', 'gyp', 'r', 'ruby', 'rb', 'gemspec', 'podspec', 'thor', 'irb', 'rs', 'scala', 'scm', 'sld', 'scss', 'st', 'sql', 'swift', 'tex', 'txt', 'vbnet', 'vb', 'bas', 'vbs', 'v', 'veo', 'xml', 'html', 'xhtml', 'rss', 'atom', 'xsl', 'plist', 'yaml'], - IMAGE_TYPES: ['jpg', 'gif', 'bmp', 'png', 'jpeg'], - PATCH_TYPES: ['patch'], - PDF_TYPES: ['pdf'], - PRESENTATION_TYPES: ['ppt', 'pptx'], - SPREADSHEET_TYPES: ['xlsx', 'csv'], - VIDEO_TYPES: ['mp4', 'avi', 'webm', 'mkv', 'wmv', 'mpg', 'mov', 'flv'], - WORD_TYPES: ['doc', 'docx'] -}; - -const PostsTypes = { - ADD_REMOVE: 'system_add_remove', - ADD_TO_CHANNEL: 'system_add_to_channel', - CHANNEL_DELETED: 'system_channel_deleted', - DISPLAYNAME_CHANGE: 'system_displayname_change', - EPHEMERAL: 'system_ephemeral', - HEADER_CHANGE: 'system_header_change', - JOIN_CHANNEL: 'system_join_channel', - JOIN_LEAVE: 'system_join_leave', - LEAVE_CHANNEL: 'system_leave_channel', - PURPOSE_CHANGE: 'system_purpose_change', - REMOVE_FROM_CHANNEL: 'system_remove_from_channel' -}; - -export default { - ...Constants, - ...FileConstants, - ...PostsTypes, - IGNORE_POST_TYPES: [ - PostsTypes.ADD_REMOVE, - PostsTypes.ADD_TO_CHANNEL, - PostsTypes.CHANNEL_DELETED, - PostsTypes.JOIN_LEAVE, - PostsTypes.JOIN_CHANNEL, - PostsTypes.LEAVE_CHANNEL, - PostsTypes.REMOVE_FROM_CHANNEL - ] -}; diff --git a/service/constants/errors.js b/service/constants/errors.js deleted file mode 100644 index 5f070f968..000000000 --- a/service/constants/errors.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const ErrorTypes = keyMirror({ - DISMISS_ERROR: null, - LOG_ERROR: null, - CLEAR_ERRORS: null -}); - -export default ErrorTypes; diff --git a/service/constants/files.js b/service/constants/files.js deleted file mode 100644 index 81c9f4c56..000000000 --- a/service/constants/files.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const FilesTypes = keyMirror({ - FETCH_FILES_FOR_POST_REQUEST: null, - FETCH_FILES_FOR_POST_SUCCESS: null, - FETCH_FILES_FOR_POST_FAILURE: null, - - RECEIVED_FILES_FOR_POST: null -}); - -export default FilesTypes; diff --git a/service/constants/general.js b/service/constants/general.js deleted file mode 100644 index be814a2f2..000000000 --- a/service/constants/general.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const GeneralTypes = keyMirror({ - RECEIVED_APP_STATE: null, - RECEIVED_APP_CREDENTIALS: null, - REMOVED_APP_CREDENTIALS: null, - RECEIVED_APP_DEVICE_TOKEN: null, - - PING_REQUEST: null, - PING_SUCCESS: null, - PING_FAILURE: null, - PING_RESET: null, - - RECEIVED_SERVER_VERSION: null, - - CLIENT_CONFIG_REQUEST: null, - CLIENT_CONFIG_SUCCESS: null, - CLIENT_CONFIG_FAILURE: null, - CLIENT_CONFIG_RECEIVED: null, - - CLIENT_LICENSE_REQUEST: null, - CLIENT_LICENSE_SUCCESS: null, - CLIENT_LICENSE_FAILURE: null, - CLIENT_LICENSE_RECEIVED: null, - - LOG_CLIENT_ERROR_REQUEST: null, - LOG_CLIENT_ERROR_SUCCESS: null, - LOG_CLIENT_ERROR_FAILURE: null, - - WEBSOCKET_REQUEST: null, - WEBSOCKET_SUCCESS: null, - WEBSOCKET_FAILURE: null -}); - -export default GeneralTypes; diff --git a/service/constants/index.js b/service/constants/index.js deleted file mode 100644 index fe55967ce..000000000 --- a/service/constants/index.js +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import Constants from './constants'; -import ChannelTypes from './channels'; -import ErrorTypes from './errors'; -import GeneralTypes from './general'; -import UsersTypes from './users'; -import TeamsTypes from './teams'; -import PostsTypes from './posts'; -import FilesTypes from './files'; -import PreferencesTypes from './preferences'; -import RequestStatus from './request_status'; -import WebsocketEvents from './websocket'; - -const Preferences = { - CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show', - CATEGORY_NOTIFICATIONS: 'notifications', - CATEGORY_THEME: 'theme', - EMAIL_INTERVAL: 'email_interval', - INTERVAL_FIFTEEN_MINUTES: 15 * 60, - INTERVAL_HOUR: 60 * 60, - INTERVAL_IMMEDIATE: 30 // "immediate" is a 30 second interval -}; - -export { - Constants, - ErrorTypes, - GeneralTypes, - UsersTypes, - TeamsTypes, - ChannelTypes, - PostsTypes, - FilesTypes, - PreferencesTypes, - Preferences, - RequestStatus, - WebsocketEvents -}; diff --git a/service/constants/posts.js b/service/constants/posts.js deleted file mode 100644 index e8dcc832c..000000000 --- a/service/constants/posts.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const PostsTypes = keyMirror({ - CREATE_POST_REQUEST: null, - CREATE_POST_SUCCESS: null, - CREATE_POST_FAILURE: null, - - EDIT_POST_REQUEST: null, - EDIT_POST_SUCCESS: null, - EDIT_POST_FAILURE: null, - - DELETE_POST_REQUEST: null, - DELETE_POST_SUCCESS: null, - DELETE_POST_FAILURE: null, - - GET_POST_REQUEST: null, - GET_POST_SUCCESS: null, - GET_POST_FAILURE: null, - - GET_POSTS_REQUEST: null, - GET_POSTS_SUCCESS: null, - GET_POSTS_FAILURE: null, - - GET_POSTS_SINCE_REQUEST: null, - GET_POSTS_SINCE_SUCCESS: null, - GET_POSTS_SINCE_FAILURE: null, - - GET_POSTS_BEFORE_REQUEST: null, - GET_POSTS_BEFORE_SUCCESS: null, - GET_POSTS_BEFORE_FAILURE: null, - - GET_POSTS_AFTER_REQUEST: null, - GET_POSTS_AFTER_SUCCESS: null, - GET_POSTS_AFTER_FAILURE: null, - - RECEIVED_POST: null, - RECEIVED_POSTS: null, - RECEIVED_FOCUSED_POST: null, - RECEIVED_POST_SELECTED: null, - RECEIVED_EDIT_POST: null, - POST_DELETED: null, - REMOVE_POST: null -}); - -export default PostsTypes; diff --git a/service/constants/preferences.js b/service/constants/preferences.js deleted file mode 100644 index f99594597..000000000 --- a/service/constants/preferences.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -export default keyMirror({ - MY_PREFERENCES_REQUEST: null, - MY_PREFERENCES_SUCCESS: null, - MY_PREFERENCES_FAILURE: null, - - SAVE_PREFERENCES_REQUEST: null, - SAVE_PREFERENCES_SUCCESS: null, - SAVE_PREFERENCES_FAILURE: null, - - DELETE_PREFERENCES_REQUEST: null, - DELETE_PREFERENCES_SUCCESS: null, - DELETE_PREFERENCES_FAILURE: null, - - RECEIVED_PREFERENCES: null, - DELETED_PREFERENCES: null -}); diff --git a/service/constants/request_status.js b/service/constants/request_status.js deleted file mode 100644 index 1ff6116e0..000000000 --- a/service/constants/request_status.js +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -export default { - NOT_STARTED: 'not_started', - STARTED: 'started', - SUCCESS: 'success', - FAILURE: 'failure' -}; diff --git a/service/constants/teams.js b/service/constants/teams.js deleted file mode 100644 index f9b0ca5ab..000000000 --- a/service/constants/teams.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const TeamTypes = keyMirror({ - FETCH_TEAMS_REQUEST: null, - FETCH_TEAMS_SUCCESS: null, - FETCH_TEAMS_FAILURE: null, - - CREATE_TEAM_REQUEST: null, - CREATE_TEAM_SUCCESS: null, - CREATE_TEAM_FAILURE: null, - - UPDATE_TEAM_REQUEST: null, - UPDATE_TEAM_SUCCESS: null, - UPDATE_TEAM_FAILURE: null, - - MY_TEAM_MEMBERS_REQUEST: null, - MY_TEAM_MEMBERS_SUCCESS: null, - MY_TEAM_MEMBERS_FAILURE: null, - - TEAM_LISTINGS_REQUEST: null, - TEAM_LISTINGS_SUCCESS: null, - TEAM_LISTINGS_FAILURE: null, - - TEAM_MEMBERS_REQUEST: null, - TEAM_MEMBERS_SUCCESS: null, - TEAM_MEMBERS_FAILURE: null, - - TEAM_STATS_REQUEST: null, - TEAM_STATS_SUCCESS: null, - TEAM_STATS_FAILURE: null, - - ADD_TEAM_MEMBER_REQUEST: null, - ADD_TEAM_MEMBER_SUCCESS: null, - ADD_TEAM_MEMBER_FAILURE: null, - - REMOVE_TEAM_MEMBER_REQUEST: null, - REMOVE_TEAM_MEMBER_SUCCESS: null, - REMOVE_TEAM_MEMBER_FAILURE: null, - - CREATED_TEAM: null, - SELECT_TEAM: null, - UPDATED_TEAM: null, - RECEIVED_ALL_TEAMS: null, - RECEIVED_MY_TEAM_MEMBERS: null, - RECEIVED_TEAM_LISTINGS: null, - RECEIVED_MEMBERS_IN_TEAM: null, - RECEIVED_MEMBER_IN_TEAM: null, - REMOVE_MEMBER_FROM_TEAM: null, - RECEIVED_TEAM_STATS: null, - LEAVE_TEAM: null -}); - -export default TeamTypes; diff --git a/service/constants/users.js b/service/constants/users.js deleted file mode 100644 index 18c4035a1..000000000 --- a/service/constants/users.js +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import keyMirror from 'service/utils/key_mirror'; - -const UserTypes = keyMirror({ - LOGIN_REQUEST: null, - LOGIN_SUCCESS: null, - LOGIN_FAILURE: null, - - LOGOUT_REQUEST: null, - LOGOUT_SUCCESS: null, - LOGOUT_FAILURE: null, - - PROFILES_REQUEST: null, - PROFILES_SUCCESS: null, - PROFILES_FAILURE: null, - - PROFILES_IN_TEAM_REQUEST: null, - PROFILES_IN_TEAM_SUCCESS: null, - PROFILES_IN_TEAM_FAILURE: null, - - PROFILES_IN_CHANNEL_REQUEST: null, - PROFILES_IN_CHANNEL_SUCCESS: null, - PROFILES_IN_CHANNEL_FAILURE: null, - - PROFILES_NOT_IN_CHANNEL_REQUEST: null, - PROFILES_NOT_IN_CHANNEL_SUCCESS: null, - PROFILES_NOT_IN_CHANNEL_FAILURE: null, - - PROFILES_STATUSES_REQUEST: null, - PROFILES_STATUSES_SUCCESS: null, - PROFILES_STATUSES_FAILURE: null, - - SESSIONS_REQUEST: null, - SESSIONS_SUCCESS: null, - SESSIONS_FAILURE: null, - - REVOKE_SESSION_REQUEST: null, - REVOKE_SESSION_SUCCESS: null, - REVOKE_SESSION_FAILURE: null, - - AUDITS_REQUEST: null, - AUDITS_SUCCESS: null, - AUDITS_FAILURE: null, - - CHECK_MFA_REQUEST: null, - CHECK_MFA_SUCCESS: null, - CHECK_MFA_FAILURE: null, - - AUTOCOMPLETE_IN_CHANNEL_REQUEST: null, - AUTOCOMPLETE_IN_CHANNEL_SUCCESS: null, - AUTOCOMPLETE_IN_CHANNEL_FAILURE: null, - - SEARCH_PROFILES_REQUEST: null, - SEARCH_PROFILES_SUCCESS: null, - SEARCH_PROFILES_FAILURE: null, - - UPDATE_NOTIFY_PROPS_REQUEST: null, - UPDATE_NOTIFY_PROPS_SUCCESS: null, - UPDATE_NOTIFY_PROPS_FAILURE: null, - - RECEIVED_ME: null, - RECEIVED_PROFILES: null, - RECEIVED_SEARCH_PROFILES: null, - RECEIVED_PROFILES_IN_TEAM: null, - RECEIVED_PROFILES_IN_CHANNEL: null, - RECEIVED_PROFILE_IN_CHANNEL: null, - RECEIVED_PROFILES_NOT_IN_CHANNEL: null, - RECEIVED_PROFILE_NOT_IN_CHANNEL: null, - RECEIVED_SESSIONS: null, - RECEIVED_REVOKED_SESSION: null, - RECEIVED_AUDITS: null, - RECEIVED_STATUSES: null, - RECEIVED_AUTOCOMPLETE_IN_CHANNEL: null, - RESET_LOGOUT_STATE: null -}); - -export default UserTypes; diff --git a/service/constants/websocket.js b/service/constants/websocket.js deleted file mode 100644 index 3e2be84e4..000000000 --- a/service/constants/websocket.js +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -const WebsocketEvents = { - POSTED: 'posted', - POST_EDITED: 'post_edited', - POST_DELETED: 'post_deleted', - CHANNEL_CREATED: 'channel_created', - CHANNEL_DELETED: 'channel_deleted', - DIRECT_ADDED: 'direct_added', - LEAVE_TEAM: 'leave_team', - USER_ADDED: 'user_added', - USER_REMOVED: 'user_removed', - USER_UPDATED: 'user_updated', - TYPING: 'typing', - STOP_TYPING: 'stop_typing', - PREFERENCE_CHANGED: 'preference_changed', - EPHEMERAL_MESSAGE: 'ephemeral_message', - STATUS_CHANGED: 'status_change', - HELLO: 'hello', - WEBRTC: 'webrtc', - REACTION_ADDED: 'reaction_added', - REACTION_REMOVED: 'reaction_removed' -}; - -export default WebsocketEvents; diff --git a/service/reducers/entities/channels.js b/service/reducers/entities/channels.js deleted file mode 100644 index 6d9cd76f0..000000000 --- a/service/reducers/entities/channels.js +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {ChannelTypes, TeamsTypes, UsersTypes} from 'service/constants'; -import {combineReducers} from 'redux'; - -function currentId(state = '', action) { - switch (action.type) { - case ChannelTypes.SELECT_CHANNEL: - return action.data; - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -function channels(state = {}, action) { - const nextState = {...state}; - - switch (action.type) { - case ChannelTypes.RECEIVED_CHANNEL: - return { - ...state, - [action.data.id]: action.data - }; - - case ChannelTypes.RECEIVED_CHANNELS: - case ChannelTypes.RECEIVED_MORE_CHANNELS: { - for (const channel of action.data) { - nextState[channel.id] = channel; - } - return nextState; - } - case ChannelTypes.RECEIVED_CHANNEL_DELETED: - Reflect.deleteProperty(nextState, action.data); - return nextState; - case ChannelTypes.RECEIVED_LAST_VIEWED: { - const channelId = action.data.channel_id; - const lastUpdatedAt = action.data.last_viewed_at; - const channel = state[channelId]; - if (!channel) { - return state; - } - return { - ...state, - [channelId]: { - ...channel, - extra_update_at: lastUpdatedAt - } - }; - } - case ChannelTypes.UPDATE_CHANNEL_HEADER: { - const {channelId, header} = action.data; - return { - ...state, - [channelId]: { - ...state[channelId], - header - } - }; - } - case ChannelTypes.UPDATE_CHANNEL_PURPOSE: { - const {channelId, purpose} = action.data; - return { - ...state, - [channelId]: { - ...state[channelId], - purpose - } - }; - } - case UsersTypes.LOGOUT_SUCCESS: - case TeamsTypes.SELECT_TEAM: - return {}; - - default: - return state; - } -} - -function myMembers(state = {}, action) { - const nextState = {...state}; - - switch (action.type) { - case ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER: { - const channelMember = action.data; - return { - ...state, - [channelMember.channel_id]: channelMember - }; - } - case ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS: { - for (const cm of action.data) { - nextState[cm.channel_id] = cm; - } - return nextState; - } - case ChannelTypes.RECEIVED_CHANNEL_PROPS: { - const member = {...state[action.data.channel_id]}; - member.notify_props = action.data.notifyProps; - - return { - ...state, - [action.data.channel_id]: member - }; - } - case ChannelTypes.RECEIVED_LAST_VIEWED: { - let member = state[action.data.channel_id]; - if (!member) { - return state; - } - member = {...member, - last_viewed_at: action.data.last_viewed_at, - msg_count: action.data.total_msg_count, - mention_count: 0 - }; - - return { - ...state, - [action.data.channel_id]: member - }; - } - case ChannelTypes.LEAVE_CHANNEL: - case ChannelTypes.RECEIVED_CHANNEL_DELETED: - Reflect.deleteProperty(nextState, action.data); - return nextState; - - case UsersTypes.LOGOUT_SUCCESS: - case TeamsTypes.SELECT_TEAM: - return {}; - default: - return state; - } -} - -function stats(state = {}, action) { - switch (action.type) { - case ChannelTypes.RECEIVED_CHANNEL_STATS: { - const nextState = {...state}; - const stat = action.data; - nextState[stat.channel_id] = stat; - - return nextState; - } - case UsersTypes.LOGOUT_SUCCESS: - case TeamsTypes.SELECT_TEAM: - return {}; - default: - return state; - } -} - -function autocompleteChannels(state = [], action) { - switch (action.type) { - case ChannelTypes.RECEIVED_AUTOCOMPLETE_CHANNELS: - return action.data; - default: - return state; - } -} - -export default combineReducers({ - - // the current selected channel - currentId, - - // object where every key is the channel id and has and object with the channel detail - channels, - - //object where every key is the channel id and has and object with the channel members detail - myMembers, - - // object where every key is the channel id and has an object with the channel stats - stats, - - // array containing channel objects that have been matched to the current channel mention term - autocompleteChannels -}); diff --git a/service/reducers/entities/files.js b/service/reducers/entities/files.js deleted file mode 100644 index bc9a3bad8..000000000 --- a/service/reducers/entities/files.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {FilesTypes, UsersTypes} from 'service/constants'; - -function files(state = {}, action) { - switch (action.type) { - case FilesTypes.RECEIVED_FILES_FOR_POST: { - const filesById = action.data.reduce((filesMap, file) => { - return {...filesMap, - [file.id]: file - }; - }, {}); - return {...state, - ...filesById - }; - } - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function fileIdsByPostId(state = {}, action) { - switch (action.type) { - case FilesTypes.RECEIVED_FILES_FOR_POST: { - const {data, postId} = action; - const filesIdsForPost = data.map((file) => file.id); - return {...state, - [postId]: filesIdsForPost - }; - } - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -export default combineReducers({ - files, - fileIdsByPostId -}); diff --git a/service/reducers/entities/general.js b/service/reducers/entities/general.js deleted file mode 100644 index 1c34dd62f..000000000 --- a/service/reducers/entities/general.js +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {GeneralTypes, UsersTypes} from 'service/constants'; - -function config(state = {}, action) { - switch (action.type) { - case GeneralTypes.CLIENT_CONFIG_RECEIVED: - return Object.assign({}, state, action.data); - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function license(state = {}, action) { - switch (action.type) { - case GeneralTypes.CLIENT_LICENSE_RECEIVED: - return Object.assign({}, state, action.data); - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function appState(state = false, action) { - switch (action.type) { - case GeneralTypes.RECEIVED_APP_STATE: - return action.data; - - default: - return state; - } -} - -function credentials(state = {}, action) { - switch (action.type) { - case GeneralTypes.RECEIVED_APP_CREDENTIALS: - return Object.assign({}, state, action.data); - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function serverVersion(state = '', action) { - switch (action.type) { - case GeneralTypes.RECEIVED_SERVER_VERSION: - return action.data; - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -function deviceToken(state = '', action) { - switch (action.type) { - case GeneralTypes.RECEIVED_APP_DEVICE_TOKEN: - return action.data; - - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -export default combineReducers({ - appState, - credentials, - config, - license, - serverVersion, - deviceToken -}); diff --git a/service/reducers/entities/index.js b/service/reducers/entities/index.js deleted file mode 100644 index 7eeb40763..000000000 --- a/service/reducers/entities/index.js +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; - -import channels from './channels'; -import general from './general'; -import users from './users'; -import teams from './teams'; -import posts from './posts'; -import files from './files'; -import preferences from './preferences'; -import typing from './typing'; - -export default combineReducers({ - general, - users, - teams, - channels, - posts, - files, - preferences, - typing -}); diff --git a/service/reducers/entities/posts.js b/service/reducers/entities/posts.js deleted file mode 100644 index d34e4e5b2..000000000 --- a/service/reducers/entities/posts.js +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {Constants, PostsTypes, UsersTypes} from 'service/constants'; - -function handleReceivedPost(posts = {}, postsByChannel = {}, action) { - const post = action.data; - const channelId = post.channel_id; - - const nextPosts = { - ...posts, - [post.id]: post - }; - - let nextPostsByChannel = postsByChannel; - - // Only change postsByChannel if the order of the posts needs to change - if (!postsByChannel[channelId] || postsByChannel[channelId].indexOf(post.id) === -1) { - // If we don't already have the post, assume it's the most recent one - const postsInChannel = postsByChannel[channelId] || []; - - nextPostsByChannel = {...postsByChannel}; - nextPostsByChannel[channelId] = [ - post.id, - ...postsInChannel - ]; - } - - return {posts: nextPosts, postsByChannel: nextPostsByChannel}; -} - -function handleReceivedPosts(posts = {}, postsByChannel = {}, action) { - const newPosts = action.data.posts; - const channelId = action.channelId; - - const nextPosts = {...posts}; - const nextPostsByChannel = {...postsByChannel}; - const postsInChannel = postsByChannel[channelId] ? [...postsByChannel[channelId]] : []; - - for (const newPost of Object.values(newPosts)) { - // Only change the stored post if it's changed since we last received it - if (!nextPosts[newPost.id] || nextPosts[newPost.id].update_at > newPost.update_at) { - nextPosts[newPost.id] = newPost; - } - - if (postsInChannel.indexOf(newPost.id) === -1) { - // Just add the post id to the end of the order and we'll sort it out later - postsInChannel.push(newPost.id); - } - } - - // Sort to ensure that the most recent posts are first - postsInChannel.sort((a, b) => { - if (nextPosts[a].create_at > nextPosts[b].create_at) { - return -1; - } else if (nextPosts[a].create_at < nextPosts[b].create_at) { - return 1; - } - - return 0; - }); - - nextPostsByChannel[channelId] = postsInChannel; - - return {posts: nextPosts, postsByChannel: nextPostsByChannel}; -} - -function handlePostDeleted(posts = {}, postsByChannel = {}, action) { - const post = action.data; - - let nextPosts = posts; - - // We only need to do something if already have the post - if (posts[post.id]) { - nextPosts = {...posts}; - - nextPosts[post.id] = { - ...posts[post.id], - state: Constants.POST_DELETED, - file_ids: [], - has_reactions: false - }; - - // No changes to the order until the user actually removes the post - } - - return {posts: nextPosts, postsByChannel}; -} - -function handleRemovePost(posts = {}, postsByChannel = {}, action) { - const post = action.data; - const channelId = post.channel_id; - - let nextPosts = posts; - let nextPostsByChannel = postsByChannel; - - // We only need to do something if already have the post - if (nextPosts[post.id]) { - nextPosts = {...posts}; - nextPostsByChannel = {...postsByChannel}; - const postsInChannel = postsByChannel[channelId] ? [...postsByChannel[channelId]] : []; - - // Remove the post itself - Reflect.deleteProperty(nextPosts, post.id); - - const index = postsInChannel.indexOf(post.id); - if (index !== -1) { - postsInChannel.splice(index, 1); - } - - // Remove any of its comments - for (const id of postsInChannel) { - if (nextPosts[id].root_id === post.id) { - Reflect.deleteProperty(nextPosts, id); - - const commentIndex = postsInChannel.indexOf(id); - if (commentIndex !== -1) { - postsInChannel.splice(commentIndex, 1); - } - } - } - - nextPostsByChannel[channelId] = postsInChannel; - } - - return {posts: nextPosts, postsByChannel: nextPostsByChannel}; -} - -function handlePosts(posts = {}, postsByChannel = {}, action) { - switch (action.type) { - case PostsTypes.RECEIVED_POST: - return handleReceivedPost(posts, postsByChannel, action); - case PostsTypes.RECEIVED_POSTS: - return handleReceivedPosts(posts, postsByChannel, action); - case PostsTypes.POST_DELETED: - return handlePostDeleted(posts, postsByChannel, action); - case PostsTypes.REMOVE_POST: - return handleRemovePost(posts, postsByChannel, action); - - case UsersTypes.LOGOUT_SUCCESS: - return { - posts: {}, - postsByChannel: {} - }; - default: - return { - posts, - postsByChannel - }; - } -} - -function selectedPostId(state = '', action) { - switch (action.type) { - case PostsTypes.RECEIVED_POST_SELECTED: - return action.data; - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -function currentFocusedPostId(state = '', action) { - switch (action.type) { - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -export default function(state = {}, action) { - const {posts, postsByChannel} = handlePosts(state.posts, state.postsByChannel, action); - - const nextState = { - - // Object mapping post ids to post objects - posts, - - // Object mapping channel ids to an list of posts ids in that channel with the most recent post first - postsByChannel, - - // The current selected post - selectedPostId: selectedPostId(state.selectedPostId, action), - - // The current selected focused post (permalink view) - currentFocusedPostId: currentFocusedPostId(state.currentFocusedPostId, action) - }; - - if (state.posts === nextState.posts && state.postsByChannel === nextState.postsByChannel && - state.selectedPostId === nextState.selectedPostId && - state.currentFocusedPostId === nextState.currentFocusedPostId) { - // None of the children have changed so don't even let the parent object change - return state; - } - - return nextState; -} diff --git a/service/reducers/entities/preferences.js b/service/reducers/entities/preferences.js deleted file mode 100644 index 22cf9b686..000000000 --- a/service/reducers/entities/preferences.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {PreferencesTypes, UsersTypes} from 'service/constants'; - -function getKey(preference) { - return `${preference.category}--${preference.name}`; -} - -function myPreferences(state = {}, action) { - switch (action.type) { - case PreferencesTypes.RECEIVED_PREFERENCES: { - const nextState = {...state}; - - for (const preference of action.data) { - nextState[getKey(preference)] = preference; - } - - return nextState; - } - case PreferencesTypes.DELETED_PREFERENCES: { - const nextState = {...state}; - - for (const preference of action.data) { - Reflect.deleteProperty(nextState, getKey(preference)); - } - - return nextState; - } - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -export default combineReducers({ - - // object where the key is the category-name and has the corresponding value - myPreferences -}); diff --git a/service/reducers/entities/teams.js b/service/reducers/entities/teams.js deleted file mode 100644 index c37a40695..000000000 --- a/service/reducers/entities/teams.js +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {TeamsTypes, UsersTypes} from 'service/constants'; - -function currentId(state = '', action) { - switch (action.type) { - case TeamsTypes.SELECT_TEAM: - return action.data; - - case UsersTypes.LOGOUT_SUCCESS: - return ''; - default: - return state; - } -} - -function teams(state = {}, action) { - switch (action.type) { - case TeamsTypes.RECEIVED_ALL_TEAMS: - case TeamsTypes.RECEIVED_TEAM_LISTINGS: - return Object.assign({}, state, action.data); - - case TeamsTypes.CREATED_TEAM: - case TeamsTypes.UPDATED_TEAM: - return { - ...state, - [action.data.id]: action.data - }; - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function myMembers(state = {}, action) { - switch (action.type) { - case TeamsTypes.RECEIVED_MY_TEAM_MEMBERS: { - const nextState = {}; - const members = action.data; - for (const m of members) { - nextState[m.team_id] = m; - } - return nextState; - } - - case TeamsTypes.LEAVE_TEAM: { - const nextState = {...state}; - const data = action.data; - Reflect.deleteProperty(nextState, data.id); - return nextState; - } - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function membersInTeam(state = {}, action) { - switch (action.type) { - case TeamsTypes.RECEIVED_MEMBER_IN_TEAM: { - const data = action.data; - const members = new Set(state[data.team_id]); - members.add(data.user_id); - return { - ...state, - [data.team_id]: members - }; - } - case TeamsTypes.RECEIVED_MEMBERS_IN_TEAM: { - const data = action.data; - if (data.length) { - const teamId = data[0].team_id; - const members = new Set(state[teamId]); - for (const member of data) { - members.add(member.user_id); - } - - return { - ...state, - [teamId]: members - }; - } - - return state; - } - case TeamsTypes.REMOVE_MEMBER_FROM_TEAM: { - const data = action.data; - const members = state[data.team_id]; - if (members) { - const set = new Set(members); - set.delete(data.user_id); - return { - ...state, - [data.team_id]: set - }; - } - - return state; - } - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function stats(state = {}, action) { - switch (action.type) { - case TeamsTypes.RECEIVED_TEAM_STATS: { - const stat = action.data; - return { - ...state, - [stat.team_id]: stat - }; - } - case UsersTypes.LOGOUT_SUCCESS: - return {}; - default: - return state; - } -} - -function openTeamIds(state = new Set(), action) { - switch (action.type) { - case TeamsTypes.RECEIVED_TEAM_LISTINGS: { - const teamsData = action.data; - const newState = new Set(); - for (const teamId in teamsData) { - if (teamsData.hasOwnProperty(teamId)) { - newState.add(teamId); - } - } - return newState; - } - default: - return state; - } -} - -export default combineReducers({ - - // the current selected team - currentId, - - // object where every key is the team id and has and object with the team detail - teams, - - //object where every key is the team id and has and object with the team members detail - myMembers, - - // object where every key is the team id and has a Set of user ids that are members in the team - membersInTeam, - - // object where every key is the team id and has an object with the team stats - stats, - - // Set with the team ids the user is not a member of - openTeamIds -}); diff --git a/service/reducers/entities/typing.js b/service/reducers/entities/typing.js deleted file mode 100644 index 290c018ac..000000000 --- a/service/reducers/entities/typing.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {WebsocketEvents} from 'service/constants'; - -export default function typing(state = {}, action) { - const {data, type} = action; - switch (type) { - case WebsocketEvents.TYPING: { - const {id, userId} = data; - - return { - ...state, - [id]: { - ...state[id], - [userId]: true - } - }; - } - case WebsocketEvents.STOP_TYPING: { - const nextState = {...state}; - const {id, userId} = data; - const users = {...nextState[id]}; - if (users) { - Reflect.deleteProperty(users, userId); - } - - nextState[id] = users; - if (!Object.keys(nextState[id]).length) { - Reflect.deleteProperty(nextState, id); - } - - return nextState; - } - default: - return state; - } -} diff --git a/service/reducers/entities/users.js b/service/reducers/entities/users.js deleted file mode 100644 index 59f9f50b6..000000000 --- a/service/reducers/entities/users.js +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {UsersTypes} from 'service/constants'; - -function profilesToSet(state, action) { - const id = action.id; - const nextSet = new Set(state[id]); - Object.keys(action.data).forEach((key) => { - nextSet.add(key); - }); - - return { - ...state, - [id]: nextSet - }; -} - -function addProfileToSet(state, action) { - const id = action.id; - const nextSet = new Set(state[id]); - nextSet.add(action.data.user_id); - return { - ...state, - [id]: nextSet - }; -} - -function removeProfileFromSet(state, action) { - const id = action.id; - const nextSet = new Set(state[id]); - nextSet.delete(action.data.user_id); - return { - ...state, - [id]: nextSet - }; -} - -function currentId(state = '', action) { - switch (action.type) { - case UsersTypes.RECEIVED_ME: - return action.data.id; - - case UsersTypes.LOGOUT_SUCCESS: - return ''; - - } - - return state; -} - -function mySessions(state = [], action) { - switch (action.type) { - case UsersTypes.RECEIVED_SESSIONS: - return [...action.data]; - - case UsersTypes.RECEIVED_REVOKED_SESSION: { - let index = -1; - const length = state.length; - for (let i = 0; i < length; i++) { - if (state[i].id === action.data.id) { - index = i; - break; - } - } - if (index > -1) { - return state.slice(0, index).concat(state.slice(index + 1)); - } - - return state; - } - case UsersTypes.LOGOUT_SUCCESS: - return []; - - default: - return state; - } -} - -function myAudits(state = [], action) { - switch (action.type) { - case UsersTypes.RECEIVED_AUDITS: - return [...action.data]; - - case UsersTypes.LOGOUT_SUCCESS: - return []; - - default: - return state; - } -} - -function profiles(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_ME: { - return { - ...state, - [action.data.id]: {...action.data} - }; - } - case UsersTypes.RECEIVED_PROFILES: - return Object.assign({}, state, action.data); - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function profilesInTeam(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_PROFILES_IN_TEAM: - return profilesToSet(state, action); - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function profilesInChannel(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_PROFILE_IN_CHANNEL: - return addProfileToSet(state, action); - - case UsersTypes.RECEIVED_PROFILES_IN_CHANNEL: - return profilesToSet(state, action); - - case UsersTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL: - return removeProfileFromSet(state, action); - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function profilesNotInChannel(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL: - return addProfileToSet(state, action); - - case UsersTypes.RECEIVED_PROFILES_NOT_IN_CHANNEL: - return profilesToSet(state, action); - - case UsersTypes.RECEIVED_PROFILE_IN_CHANNEL: - return removeProfileFromSet(state, action); - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function statuses(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_STATUSES: { - return Object.assign({}, state, action.data); - } - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -function autocompleteUsersInChannel(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_AUTOCOMPLETE_IN_CHANNEL: - return Object.assign({}, state, {[action.channelId]: action.data}); - default: - return state; - } -} - -function search(state = {}, action) { - switch (action.type) { - case UsersTypes.RECEIVED_SEARCH_PROFILES: - return action.data; - - case UsersTypes.LOGOUT_SUCCESS: - return {}; - - default: - return state; - } -} - -export default combineReducers({ - - // the current selected user - currentId, - - // array with the user's sessions - mySessions, - - // array with the user's audits - myAudits, - - // object where every key is a user id and has an object with the users details - profiles, - - // object where every key is a team id and has a Set with the users id that are members of the team - profilesInTeam, - - // object where every key is a channel id and has a Set with the users id that are members of the channel - profilesInChannel, - - // object where every key is a channel id and has a Set with the users id that are members of the channel - profilesNotInChannel, - - // object where every key is the user id and has a value with the current status of each user - statuses, - - // object where every key is a channel id and has a [channelId] object that contains members that are in and out of the current channel - autocompleteUsersInChannel, - - // object where every key is a user id and has an object with the users details - search -}); diff --git a/service/reducers/errors/index.js b/service/reducers/errors/index.js deleted file mode 100644 index 6ceeaa08b..000000000 --- a/service/reducers/errors/index.js +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {ErrorTypes} from 'service/constants'; - -export default (state = [], action) => { - switch (action.type) { - case ErrorTypes.DISMISS_ERROR: { - const nextState = [...state]; - nextState.splice(action.index, 1); - - return nextState; - } - case ErrorTypes.LOG_ERROR: { - const nextState = [...state]; - const {displayable, error} = action; - nextState.push({displayable, error}); - - return nextState; - } - case ErrorTypes.CLEAR_ERRORS: { - return []; - } - default: - return state; - } -}; diff --git a/service/reducers/index.js b/service/reducers/index.js deleted file mode 100644 index 77b028cb4..000000000 --- a/service/reducers/index.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import entities from './entities'; -import errors from './errors'; -import requests from './requests'; - -export default { - entities, - errors, - requests -}; diff --git a/service/reducers/requests/channels.js b/service/reducers/requests/channels.js deleted file mode 100644 index 0bb9110fb..000000000 --- a/service/reducers/requests/channels.js +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {handleRequest, initialRequestState} from './helpers'; -import {ChannelTypes} from 'service/constants'; - -import {combineReducers} from 'redux'; - -function getChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.CHANNEL_REQUEST, - ChannelTypes.CHANNEL_SUCCESS, - ChannelTypes.CHANNEL_FAILURE, - state, - action - ); -} - -function getChannels(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.CHANNELS_REQUEST, - ChannelTypes.CHANNELS_SUCCESS, - ChannelTypes.CHANNELS_FAILURE, - state, - action - ); -} - -function myMembers(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.CHANNEL_MEMBERS_REQUEST, - ChannelTypes.CHANNEL_MEMBERS_SUCCESS, - ChannelTypes.CHANNEL_MEMBERS_FAILURE, - state, - action - ); -} - -function createChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.CREATE_CHANNEL_REQUEST, - ChannelTypes.CREATE_CHANNEL_SUCCESS, - ChannelTypes.CREATE_CHANNEL_FAILURE, - state, - action - ); -} - -function updateChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.UPDATE_CHANNEL_REQUEST, - ChannelTypes.UPDATE_CHANNEL_SUCCESS, - ChannelTypes.UPDATE_CHANNEL_FAILURE, - state, - action - ); -} - -function updateChannelNotifyProps(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.NOTIFY_PROPS_REQUEST, - ChannelTypes.NOTIFY_PROPS_SUCCESS, - ChannelTypes.NOTIFY_PROPS_FAILURE, - state, - action - ); -} - -function leaveChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.LEAVE_CHANNEL_REQUEST, - ChannelTypes.LEAVE_CHANNEL_SUCCESS, - ChannelTypes.LEAVE_CHANNEL_FAILURE, - state, - action - ); -} - -function joinChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.JOIN_CHANNEL_REQUEST, - ChannelTypes.JOIN_CHANNEL_SUCCESS, - ChannelTypes.JOIN_CHANNEL_FAILURE, - state, - action - ); -} - -function deleteChannel(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.DELETE_CHANNEL_REQUEST, - ChannelTypes.DELETE_CHANNEL_SUCCESS, - ChannelTypes.DELETE_CHANNEL_FAILURE, - state, - action - ); -} - -function updateLastViewedAt(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.UPDATE_LAST_VIEWED_REQUEST, - ChannelTypes.UPDATE_LAST_VIEWED_SUCCESS, - ChannelTypes.UPDATE_LAST_VIEWED_FAILURE, - state, - action - ); -} - -function getMoreChannels(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.MORE_CHANNELS_REQUEST, - ChannelTypes.MORE_CHANNELS_SUCCESS, - ChannelTypes.MORE_CHANNELS_FAILURE, - state, - action - ); -} - -function getChannelStats(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.CHANNEL_STATS_REQUEST, - ChannelTypes.CHANNEL_STATS_SUCCESS, - ChannelTypes.CHANNEL_STATS_FAILURE, - state, - action - ); -} - -function addChannelMember(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.ADD_CHANNEL_MEMBER_REQUEST, - ChannelTypes.ADD_CHANNEL_MEMBER_SUCCESS, - ChannelTypes.ADD_CHANNEL_MEMBER_FAILURE, - state, - action - ); -} - -function removeChannelMember(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.REMOVE_CHANNEL_MEMBER_REQUEST, - ChannelTypes.REMOVE_CHANNEL_MEMBER_SUCCESS, - ChannelTypes.REMOVE_CHANNEL_MEMBER_FAILURE, - state, - action - ); -} - -function autocompleteChannels(state = initialRequestState(), action) { - return handleRequest( - ChannelTypes.AUTOCOMPLETE_CHANNELS_REQUEST, - ChannelTypes.AUTOCOMPLETE_CHANNELS_SUCCESS, - ChannelTypes.AUTOCOMPLETE_CHANNELS_FAILURE, - state, - action - ); -} - -export default combineReducers({ - getChannel, - getChannels, - myMembers, - createChannel, - updateChannel, - updateChannelNotifyProps, - leaveChannel, - joinChannel, - deleteChannel, - updateLastViewedAt, - getMoreChannels, - getChannelStats, - addChannelMember, - removeChannelMember, - autocompleteChannels -}); diff --git a/service/reducers/requests/files.js b/service/reducers/requests/files.js deleted file mode 100644 index 044dd7b94..000000000 --- a/service/reducers/requests/files.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; - -import {handleRequest, initialRequestState} from './helpers'; -import {FilesTypes} from 'service/constants'; - -function getFilesForPost(state = initialRequestState(), action) { - return handleRequest( - FilesTypes.FETCH_FILES_FOR_POST_REQUEST, - FilesTypes.FETCH_FILES_FOR_POST_SUCCESS, - FilesTypes.FETCH_FILES_FOR_POST_FAILURE, - state, - action - ); -} - -export default combineReducers({ - getFilesForPost -}); diff --git a/service/reducers/requests/general.js b/service/reducers/requests/general.js deleted file mode 100644 index 03b289db5..000000000 --- a/service/reducers/requests/general.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; -import {GeneralTypes} from 'service/constants'; -import {handleRequest, initialRequestState} from './helpers'; - -function server(state = initialRequestState(), action) { - if (action.type === GeneralTypes.PING_RESET) { - return initialRequestState(); - } - - return handleRequest( - GeneralTypes.PING_REQUEST, - GeneralTypes.PING_SUCCESS, - GeneralTypes.PING_FAILURE, - state, - action - ); -} - -function config(state = initialRequestState(), action) { - return handleRequest( - GeneralTypes.CLIENT_CONFIG_REQUEST, - GeneralTypes.CLIENT_CONFIG_SUCCESS, - GeneralTypes.CLIENT_CONFIG_FAILURE, - state, - action - ); -} - -function license(state = initialRequestState(), action) { - return handleRequest( - GeneralTypes.CLIENT_LICENSE_REQUEST, - GeneralTypes.CLIENT_LICENSE_SUCCESS, - GeneralTypes.CLIENT_LICENSE_FAILURE, - state, - action - ); -} - -function websocket(state = initialRequestState(), action) { - return handleRequest( - GeneralTypes.WEBSOCKET_REQUEST, - GeneralTypes.WEBSOCKET_SUCCESS, - GeneralTypes.WEBSOCKET_FAILURE, - state, - action - ); -} - -export default combineReducers({ - server, - config, - license, - websocket -}); diff --git a/service/reducers/requests/helpers.js b/service/reducers/requests/helpers.js deleted file mode 100644 index 05d086528..000000000 --- a/service/reducers/requests/helpers.js +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {RequestStatus} from 'service/constants'; - -export function initialRequestState() { - return { - status: RequestStatus.NOT_STARTED, - error: null - }; -} - -export function handleRequest(REQUEST, SUCCESS, FAILURE, state, action) { - switch (action.type) { - case REQUEST: - return { - ...state, - status: RequestStatus.STARTED - }; - case SUCCESS: - return { - ...state, - status: RequestStatus.SUCCESS, - error: null - }; - case FAILURE: { - let error = action.error; - - if (error instanceof Error) { - error = error.hasOwnProperty('intl') ? {...error} : error.toString(); - } - - return { - ...state, - status: RequestStatus.FAILURE, - error - }; - } - default: - return state; - } -} diff --git a/service/reducers/requests/index.js b/service/reducers/requests/index.js deleted file mode 100644 index b65caeda9..000000000 --- a/service/reducers/requests/index.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {combineReducers} from 'redux'; - -import channels from './channels'; -import files from './files'; -import general from './general'; -import posts from './posts'; -import teams from './teams'; -import users from './users'; -import preferences from './preferences'; - -export default combineReducers({ - channels, - files, - general, - posts, - teams, - users, - preferences -}); diff --git a/service/reducers/requests/posts.js b/service/reducers/requests/posts.js deleted file mode 100644 index 62cc9bd4e..000000000 --- a/service/reducers/requests/posts.js +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {handleRequest, initialRequestState} from './helpers'; -import {PostsTypes} from 'service/constants'; - -import {combineReducers} from 'redux'; - -function createPost(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.CREATE_POST_REQUEST, - PostsTypes.CREATE_POST_SUCCESS, - PostsTypes.CREATE_POST_FAILURE, - state, - action - ); -} - -function editPost(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.EDIT_POST_REQUEST, - PostsTypes.EDIT_POST_SUCCESS, - PostsTypes.EDIT_POST_FAILURE, - state, - action - ); -} - -function deletePost(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.DELETE_POST_REQUEST, - PostsTypes.DELETE_POST_SUCCESS, - PostsTypes.DELETE_POST_FAILURE, - state, - action - ); -} - -function getPost(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.GET_POST_REQUEST, - PostsTypes.GET_POST_SUCCESS, - PostsTypes.GET_POST_FAILURE, - state, - action - ); -} - -function getPosts(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.GET_POSTS_REQUEST, - PostsTypes.GET_POSTS_SUCCESS, - PostsTypes.GET_POSTS_FAILURE, - state, - action - ); -} - -function getPostsSince(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.GET_POSTS_SINCE_REQUEST, - PostsTypes.GET_POSTS_SINCE_SUCCESS, - PostsTypes.GET_POSTS_SINCE_FAILURE, - state, - action - ); -} - -function getPostsBefore(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.GET_POSTS_BEFORE_REQUEST, - PostsTypes.GET_POSTS_BEFORE_SUCCESS, - PostsTypes.GET_POSTS_BEFORE_FAILURE, - state, - action - ); -} - -function getPostsAfter(state = initialRequestState(), action) { - return handleRequest( - PostsTypes.GET_POSTS_AFTER_REQUEST, - PostsTypes.GET_POSTS_AFTER_SUCCESS, - PostsTypes.GET_POSTS_AFTER_FAILURE, - state, - action - ); -} - -export default combineReducers({ - createPost, - editPost, - deletePost, - getPost, - getPosts, - getPostsSince, - getPostsBefore, - getPostsAfter -}); diff --git a/service/reducers/requests/preferences.js b/service/reducers/requests/preferences.js deleted file mode 100644 index 72f83482e..000000000 --- a/service/reducers/requests/preferences.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {handleRequest, initialRequestState} from './helpers'; -import {PreferencesTypes} from 'service/constants'; - -import {combineReducers} from 'redux'; - -function getMyPreferences(state = initialRequestState(), action) { - return handleRequest( - PreferencesTypes.MY_PREFERENCES_REQUEST, - PreferencesTypes.MY_PREFERENCES_SUCCESS, - PreferencesTypes.MY_PREFERENCES_FAILURE, - state, - action - ); -} - -function savePreferences(state = initialRequestState(), action) { - return handleRequest( - PreferencesTypes.SAVE_PREFERENCES_REQUEST, - PreferencesTypes.SAVE_PREFERENCES_SUCCESS, - PreferencesTypes.SAVE_PREFERENCES_FAILURE, - state, - action - ); -} - -function deletePreferences(state = initialRequestState(), action) { - return handleRequest( - PreferencesTypes.DELETE_PREFERENCES_REQUEST, - PreferencesTypes.DELETE_PREFERENCES_SUCCESS, - PreferencesTypes.DELETE_PREFERENCES_FAILURE, - state, - action - ); -} - -export default combineReducers({ - getMyPreferences, - savePreferences, - deletePreferences -}); diff --git a/service/reducers/requests/teams.js b/service/reducers/requests/teams.js deleted file mode 100644 index 9635522a7..000000000 --- a/service/reducers/requests/teams.js +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {handleRequest, initialRequestState} from './helpers'; -import {TeamsTypes} from 'service/constants'; - -import {combineReducers} from 'redux'; - -function allTeams(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.FETCH_TEAMS_REQUEST, - TeamsTypes.FETCH_TEAMS_SUCCESS, - TeamsTypes.FETCH_TEAMS_FAILURE, - state, - action - ); -} - -function getAllTeamListings(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.TEAM_LISTINGS_REQUEST, - TeamsTypes.TEAM_LISTINGS_SUCCESS, - TeamsTypes.TEAM_LISTINGS_FAILURE, - state, - action - ); -} - -function createTeam(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.CREATE_TEAM_REQUEST, - TeamsTypes.CREATE_TEAM_SUCCESS, - TeamsTypes.CREATE_TEAM_FAILURE, - state, - action - ); -} - -function updateTeam(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.UPDATE_TEAM_REQUEST, - TeamsTypes.UPDATE_TEAM_SUCCESS, - TeamsTypes.UPDATE_TEAM_FAILURE, - state, - action - ); -} - -function getMyTeamMembers(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.MY_TEAM_MEMBERS_REQUEST, - TeamsTypes.MY_TEAM_MEMBERS_SUCCESS, - TeamsTypes.MY_TEAM_MEMBERS_FAILURE, - state, - action - ); -} - -function getTeamMembers(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.TEAM_MEMBERS_REQUEST, - TeamsTypes.TEAM_MEMBERS_SUCCESS, - TeamsTypes.TEAM_MEMBERS_FAILURE, - state, - action - ); -} - -function getTeamStats(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.TEAM_STATS_REQUEST, - TeamsTypes.TEAM_STATS_SUCCESS, - TeamsTypes.TEAM_STATS_FAILURE, - state, - action - ); -} - -function addUserToTeam(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.ADD_TEAM_MEMBER_REQUEST, - TeamsTypes.ADD_TEAM_MEMBER_SUCCESS, - TeamsTypes.ADD_TEAM_MEMBER_FAILURE, - state, - action - ); -} - -function removeUserFromTeam(state = initialRequestState(), action) { - return handleRequest( - TeamsTypes.REMOVE_TEAM_MEMBER_REQUEST, - TeamsTypes.REMOVE_TEAM_MEMBER_SUCCESS, - TeamsTypes.REMOVE_TEAM_MEMBER_FAILURE, - state, - action - ); -} - -export default combineReducers({ - allTeams, - getAllTeamListings, - createTeam, - updateTeam, - getMyTeamMembers, - getTeamMembers, - getTeamStats, - addUserToTeam, - removeUserFromTeam -}); diff --git a/service/reducers/requests/users.js b/service/reducers/requests/users.js deleted file mode 100644 index a95dbf865..000000000 --- a/service/reducers/requests/users.js +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {handleRequest, initialRequestState} from './helpers'; -import {UsersTypes, RequestStatus} from 'service/constants'; - -import {combineReducers} from 'redux'; - -function checkMfa(state = initialRequestState(), action) { - switch (action.type) { - case UsersTypes.CHECK_MFA_REQUEST: - return {...state, status: RequestStatus.STARTED}; - - case UsersTypes.CHECK_MFA_SUCCESS: - return {...state, status: RequestStatus.SUCCESS, error: null}; - - case UsersTypes.CHECK_MFA_FAILURE: - return {...state, status: RequestStatus.FAILURE, error: action.error}; - - case UsersTypes.LOGOUT_SUCCESS: - return {...state, status: RequestStatus.NOT_STARTED, error: null}; - - default: - return state; - } -} - -function login(state = initialRequestState(), action) { - switch (action.type) { - case UsersTypes.LOGIN_REQUEST: - return {...state, status: RequestStatus.STARTED}; - - case UsersTypes.LOGIN_SUCCESS: - return {...state, status: RequestStatus.SUCCESS, error: null}; - - case UsersTypes.LOGIN_FAILURE: - return {...state, status: RequestStatus.FAILURE, error: action.error}; - - case UsersTypes.LOGOUT_SUCCESS: - return {...state, status: RequestStatus.NOT_STARTED, error: null}; - - default: - return state; - } -} - -function logout(state = initialRequestState(), action) { - switch (action.type) { - case UsersTypes.LOGOUT_REQUEST: - return {...state, status: RequestStatus.STARTED}; - - case UsersTypes.LOGOUT_SUCCESS: - return {...state, status: RequestStatus.SUCCESS, error: null}; - - case UsersTypes.LOGOUT_FAILURE: - return {...state, status: RequestStatus.FAILURE, error: action.error}; - - case UsersTypes.RESET_LOGOUT_STATE: - return initialRequestState(); - - default: - return state; - } -} - -function getProfiles(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.PROFILES_REQUEST, - UsersTypes.PROFILES_SUCCESS, - UsersTypes.PROFILES_FAILURE, - state, - action - ); -} - -function getProfilesInTeam(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.PROFILES_IN_TEAM_REQUEST, - UsersTypes.PROFILES_IN_TEAM_SUCCESS, - UsersTypes.PROFILES_IN_TEAM_FAILURE, - state, - action - ); -} - -function getProfilesInChannel(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.PROFILES_IN_CHANNEL_REQUEST, - UsersTypes.PROFILES_IN_CHANNEL_SUCCESS, - UsersTypes.PROFILES_IN_CHANNEL_FAILURE, - state, - action - ); -} - -function getProfilesNotInChannel(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.PROFILES_NOT_IN_CHANNEL_REQUEST, - UsersTypes.PROFILES_NOT_IN_CHANNEL_SUCCESS, - UsersTypes.PROFILES_NOT_IN_CHANNEL_FAILURE, - state, - action - ); -} - -function getStatusesByIds(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.PROFILES_STATUSES_REQUEST, - UsersTypes.PROFILES_STATUSES_SUCCESS, - UsersTypes.PROFILES_STATUSES_FAILURE, - state, - action - ); -} - -function getSessions(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.SESSIONS_REQUEST, - UsersTypes.SESSIONS_SUCCESS, - UsersTypes.SESSIONS_FAILURE, - state, - action - ); -} - -function revokeSession(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.REVOKE_SESSION_REQUEST, - UsersTypes.REVOKE_SESSION_SUCCESS, - UsersTypes.REVOKE_SESSION_FAILURE, - state, - action - ); -} - -function getAudits(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.AUDITS_REQUEST, - UsersTypes.AUDITS_SUCCESS, - UsersTypes.AUDITS_FAILURE, - state, - action - ); -} - -function autocompleteUsersInChannel(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.AUTOCOMPLETE_IN_CHANNEL_REQUEST, - UsersTypes.AUTOCOMPLETE_IN_CHANNEL_SUCCESS, - UsersTypes.AUTOCOMPLETE_IN_CHANNEL_FAILURE, - state, - action - ); -} - -function searchProfiles(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.SEARCH_PROFILES_REQUEST, - UsersTypes.SEARCH_PROFILES_SUCCESS, - UsersTypes.SEARCH_PROFILES_FAILURE, - state, - action - ); -} - -function updateUserNotifyProps(state = initialRequestState(), action) { - return handleRequest( - UsersTypes.UPDATE_NOTIFY_PROPS_REQUEST, - UsersTypes.UPDATE_NOTIFY_PROPS_SUCCESS, - UsersTypes.UPDATE_NOTIFY_PROPS_FAILURE, - state, - action - ); -} - -export default combineReducers({ - checkMfa, - login, - logout, - getProfiles, - getProfilesInTeam, - getProfilesInChannel, - getProfilesNotInChannel, - getStatusesByIds, - getSessions, - revokeSession, - getAudits, - autocompleteUsersInChannel, - searchProfiles, - updateUserNotifyProps -}); diff --git a/service/selectors/entities/channels.js b/service/selectors/entities/channels.js deleted file mode 100644 index d6d4c5ee3..000000000 --- a/service/selectors/entities/channels.js +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; -import {getCurrentTeamId, getCurrentTeamMembership} from 'service/selectors/entities/teams'; -import {getCurrentUserId, getUsers} from 'service/selectors/entities/users'; -import {buildDisplayableChannelList, getNotMemberChannels, completeDirectChannelInfo} from 'service/utils/channel_utils'; -import {Constants} from 'service/constants'; - -function getAllChannels(state) { - return state.entities.channels.channels; -} - -function getAllChannelStats(state) { - return state.entities.channels.stats; -} - -export function getCurrentChannelId(state) { - return state.entities.channels.currentId; -} - -export function getChannelMemberships(state) { - return state.entities.channels.myMembers; -} - -export function getAutocompleteChannels(state) { - return state.entities.channels.autocompleteChannels; -} - -export const getCurrentChannel = createSelector( - getAllChannels, - getCurrentChannelId, - (state) => state.entities.users, - (state) => state.entities.preferences.myPreferences, - (allChannels, currentChannelId, users, myPreferences) => { - const channel = allChannels[currentChannelId]; - if (channel) { - return completeDirectChannelInfo(users, myPreferences, channel); - } - return channel; - } -); - -export const getCurrentChannelMembership = createSelector( - getCurrentChannelId, - getChannelMemberships, - (currentChannelId, channelMemberships) => { - return channelMemberships[currentChannelId] || {}; - } -); - -export const getCurrentChannelStats = createSelector( - getAllChannelStats, - getCurrentChannelId, - (allChannelStats, currentChannelId) => { - return allChannelStats[currentChannelId]; - } -); - -export const getChannelsOnCurrentTeam = createSelector( - getAllChannels, - getCurrentTeamId, - (allChannels, currentTeamId) => { - const channels = []; - - for (const channel of Object.values(allChannels)) { - if (channel.team_id === currentTeamId || channel.team_id === '') { - channels.push(channel); - } - } - - return channels; - } -); - -export const getChannelsByCategory = createSelector( - getCurrentChannelId, - getChannelsOnCurrentTeam, - (state) => state.entities.channels.myMembers, - (state) => state.entities.users, - (state) => state.entities.preferences.myPreferences, - (state) => state.entities.teams, - (currentChannelId, channels, myMembers, usersState, myPreferences, teamsState) => { - const allChannels = channels.map((c) => { - const channel = {...c}; - channel.isCurrent = c.id === currentChannelId; - return channel; - }).filter((c) => myMembers.hasOwnProperty(c.id)); - - return buildDisplayableChannelList(usersState, teamsState, allChannels, myPreferences); - } -); - -export const getDefaultChannel = createSelector( - getAllChannels, - getCurrentTeamId, - (channels, teamId) => { - return Object.values(channels).find((c) => c.team_id === teamId && c.name === Constants.DEFAULT_CHANNEL); - } -); - -export const getMoreChannels = createSelector( - getAllChannels, - getChannelMemberships, - (allChannels, myMembers) => { - return getNotMemberChannels(Object.values(allChannels), myMembers); - } -); - -export const getUnreads = createSelector( - getAllChannels, - getChannelMemberships, - (channels, myMembers) => { - let messageCount = 0; - let mentionCount = 0; - Object.keys(myMembers).forEach((channelId) => { - const channel = channels[channelId]; - const m = myMembers[channelId]; - if (channel && m) { - if (channel.type === 'D') { - mentionCount += channel.total_msg_count - m.msg_count; - } else if (m.mention_count > 0) { - mentionCount += m.mention_count; - } - if (m.notify_props && m.notify_props.mark_unread !== 'mention' && channel.total_msg_count - m.msg_count > 0) { - messageCount += 1; - } - } - }); - - return {messageCount, mentionCount}; - } -); - -export const getAutocompleteChannelWithSections = createSelector( - getChannelMemberships, - getAutocompleteChannels, - (myMembers, autocompleteChannels) => { - const channels = { - myChannels: [], - otherChannels: [] - }; - autocompleteChannels.forEach((c) => { - if (myMembers[c.id]) { - channels.myChannels.push(c); - } else { - channels.otherChannels.push(c); - } - }); - - return channels; - } -); - -export const canManageChannelMembers = createSelector( - getCurrentChannel, - getCurrentChannelMembership, - getCurrentTeamMembership, - getUsers, - getCurrentUserId, - (channel, channelMembership, teamMembership, allUsers, currentUserId) => { - const user = allUsers[currentUserId]; - const roles = `${channelMembership.roles} ${teamMembership.roles} ${user.roles}`; - if (channel.type === Constants.DM_CHANNEL || channel.name === Constants.DEFAULT_CHANNEL) { - return false; - } - if (channel.type === Constants.OPEN_CHANNEL) { - return true; - } - return roles.includes('_admin'); - } -); diff --git a/service/selectors/entities/files.js b/service/selectors/entities/files.js deleted file mode 100644 index f0e6f448e..000000000 --- a/service/selectors/entities/files.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; - -function getAllFiles(state) { - return state.entities.files.files; -} - -function getFilesIdsForPost(state, props) { - return state.entities.files.fileIdsByPostId[props.post.id] || []; -} - -export function makeGetFilesForPost() { - return createSelector( - [getAllFiles, getFilesIdsForPost], - (allFiles, fileIdsForPost) => { - return fileIdsForPost.map((id) => allFiles[id]); - } - ); -} diff --git a/service/selectors/entities/general.js b/service/selectors/entities/general.js deleted file mode 100644 index e1342d66e..000000000 --- a/service/selectors/entities/general.js +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -export function getCurrentUrl(state) { - return state.entities.general.credentials.url; -} diff --git a/service/selectors/entities/posts.js b/service/selectors/entities/posts.js deleted file mode 100644 index 8fb4f9631..000000000 --- a/service/selectors/entities/posts.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; - -export function getAllPosts(state) { - return state.entities.posts.posts; -} - -function getPostIdsInCurrentChannel(state) { - return state.entities.posts.postsByChannel[state.entities.channels.currentId] || []; -} - -export const getPostsInCurrentChannel = createSelector( - getAllPosts, - getPostIdsInCurrentChannel, - (posts, postIds) => { - return postIds.map((id) => posts[id]); - } -); - -// Returns a function that creates a creates a selector that will get the posts for a given thread. -// That selector will take a props object (containing a channelId field and a rootId field) as its -// only argument and will be memoized based on that argument. -export function makeGetPostsForThread() { - return createSelector( - getAllPosts, - (state, props) => state.entities.posts.postsByChannel[props.channelId], - (state, props) => props, - (posts, postIds, {rootId}) => { - const thread = []; - - for (const id of postIds) { - const post = posts[id]; - - if (id === rootId || post.root_id === rootId) { - thread.push(post); - } - } - - return thread; - } - ); -} diff --git a/service/selectors/entities/teams.js b/service/selectors/entities/teams.js deleted file mode 100644 index 039898053..000000000 --- a/service/selectors/entities/teams.js +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; - -import {getCurrentUrl} from './general'; - -export function getCurrentTeamId(state) { - return state.entities.teams.currentId; -} - -export function getTeams(state) { - return state.entities.teams.teams; -} - -export function getTeamStats(state) { - return state.entities.teams.stats; -} - -export function getTeamMemberships(state) { - return state.entities.teams.myMembers; -} - -export const getCurrentTeam = createSelector( - getTeams, - getCurrentTeamId, - (teams, currentTeamId) => { - return teams[currentTeamId]; - } -); - -export const getCurrentTeamMembership = createSelector( - getCurrentTeamId, - getTeamMemberships, - (currentTeamId, teamMemberships) => { - return teamMemberships[currentTeamId]; - } -); - -export const getCurrentTeamUrl = createSelector( - getCurrentUrl, - getCurrentTeam, - (currentUrl, currentTeam) => { - return `${currentUrl}/${currentTeam.name}`; - } -); - -export const getCurrentTeamStats = createSelector( - getCurrentTeamId, - getTeamStats, - (currentTeamId, teamStats) => { - return teamStats[currentTeamId]; - } -); diff --git a/service/selectors/entities/typing.js b/service/selectors/entities/typing.js deleted file mode 100644 index f072482d7..000000000 --- a/service/selectors/entities/typing.js +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; -import {getCurrentChannelId} from './channels'; -import {getMyPreferences} from './preferences'; -import {getUsers} from './users'; -import {displayUsername} from 'service/utils/user_utils'; - -export const getUsersTyping = createSelector( - getUsers, - getMyPreferences, - getCurrentChannelId, - (state) => state.entities.posts.selectedPostId, - (state) => state.entities.typing, - (profiles, preferences, channelId, parentPostId, typing) => { - const id = channelId + parentPostId; - - if (typing[id]) { - const users = Object.keys(typing[id]); - - if (users.length) { - return users.map((userId) => { - return displayUsername(profiles[userId], preferences); - }); - } - } - - return []; - } -); diff --git a/service/selectors/entities/users.js b/service/selectors/entities/users.js deleted file mode 100644 index 3c679601b..000000000 --- a/service/selectors/entities/users.js +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {createSelector} from 'reselect'; - -import {getCurrentChannelId, getCurrentChannelMembership} from './channels'; -import {getCurrentTeamMembership} from './teams'; - -export function getCurrentUserId(state) { - return state.entities.users.currentId; -} - -export function getProfilesInChannel(state) { - return state.entities.users.profilesInChannel; -} - -export function getProfilesNotInChannel(state) { - return state.entities.users.profilesNotInChannel; -} - -export function getUserStatuses(state) { - return state.entities.users.statuses; -} - -export function getUser(state, id) { - return state.entities.users.profiles[id]; -} - -export function getUsers(state) { - return state.entities.users.profiles; -} - -export function getAutocompleteUsersInChannel(state) { - return state.entities.users.autocompleteUsersInChannel; -} - -export const getCurrentUser = createSelector( - getUsers, - getCurrentUserId, - (profiles, currentUserId) => { - return profiles[currentUserId]; - } -); - -export const getCurrentUserRoles = createSelector( - getCurrentChannelMembership, - getCurrentTeamMembership, - getCurrentUser, - (currentChannelMembership, currentTeamMembership, currentUser) => { - return `${currentTeamMembership.roles} ${currentChannelMembership.roles} ${currentUser.roles}`; - } -); - -export const getProfileSetInCurrentChannel = createSelector( - getCurrentChannelId, - getProfilesInChannel, - (currentChannel, channelProfiles) => { - return channelProfiles[currentChannel]; - } -); - -export const getProfileSetNotInCurrentChannel = createSelector( - getCurrentChannelId, - getProfilesNotInChannel, - (currentChannel, channelProfiles) => { - return channelProfiles[currentChannel]; - } -); - -function sortAndInjectProfiles(profiles, profileSet) { - const currentProfiles = []; - if (typeof profileSet === 'undefined') { - return currentProfiles; - } - - profileSet.forEach((p) => { - currentProfiles.push(profiles[p]); - }); - - const sortedCurrentProfiles = currentProfiles.sort((a, b) => { - const nameA = a.username; - const nameB = b.username; - - return nameA.localeCompare(nameB); - }); - - return sortedCurrentProfiles; -} - -export const getProfilesInCurrentChannel = createSelector( - getUsers, - getProfileSetInCurrentChannel, - (profiles, currentChannelProfileSet) => sortAndInjectProfiles(profiles, currentChannelProfileSet) -); - -export const getProfilesNotInCurrentChannel = createSelector( - getUsers, - getProfileSetNotInCurrentChannel, - (profiles, notInCurrentChannelProfileSet) => sortAndInjectProfiles(profiles, notInCurrentChannelProfileSet) -); - -export function getStatusForUserId(state, userId) { - return getUserStatuses(state)[userId]; -} - -export const getAutocompleteUsersInCurrentChannel = createSelector( - getCurrentChannelId, - getAutocompleteUsersInChannel, - (currentChannelId, autocompleteUsersInChannel) => { - return autocompleteUsersInChannel[currentChannelId] || {}; - } -); - -export const searchProfiles = createSelector( - (state) => state.entities.users.search, - getCurrentUserId, - (users, currentId) => { - const profiles = {...users}; - return Object.values(profiles).sort((a, b) => { - const nameA = a.username; - const nameB = b.username; - - return nameA.localeCompare(nameB); - }).filter((p) => p.id !== currentId); - } -); diff --git a/service/selectors/errors.js b/service/selectors/errors.js deleted file mode 100644 index 89d61787c..000000000 --- a/service/selectors/errors.js +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -export function getDisplayableErrors(state) { - return state.errors.filter((error) => error.displayable); -} diff --git a/service/store/configureStore.dev.js b/service/store/configureStore.dev.js deleted file mode 100644 index 0df064ac4..000000000 --- a/service/store/configureStore.dev.js +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {applyMiddleware, compose, createStore, combineReducers} from 'redux'; -import {enableBatching} from 'redux-batched-actions'; -import devTools from 'remote-redux-devtools'; -import thunk from 'redux-thunk'; - -import serviceReducer from 'service/reducers'; -import deepFreezeAndThrowOnMutation from 'service/utils/deep_freeze'; - -export default function configureServiceStore(preloadedState, appReducer, getAppReducer) { - const store = createStore( - createReducer(serviceReducer, appReducer), - preloadedState, - compose( - applyMiddleware(thunk), - devTools({ - name: 'Mattermost', - hostname: 'localhost', - port: 5678 - }) - ) - ); - - if (module.hot) { - // Enable Webpack hot module replacement for reducers - module.hot.accept(() => { - const nextServiceReducer = require('../reducers').default; // eslint-disable-line global-require - let nextAppReducer; - if (getAppReducer) { - nextAppReducer = getAppReducer(); // eslint-disable-line global-require - } - store.replaceReducer(createReducer(nextServiceReducer, nextAppReducer)); - }); - } - - return store; -} - -function createReducer(...reducers) { - const baseReducer = combineReducers(Object.assign({}, ...reducers)); - - return enableFreezing(enableBatching(baseReducer)); -} - -function enableFreezing(reducer) { - return (state, action) => { - const nextState = reducer(state, action); - - if (nextState !== state) { - deepFreezeAndThrowOnMutation(nextState); - } - - return nextState; - }; -} diff --git a/service/store/configureStore.prod.js b/service/store/configureStore.prod.js deleted file mode 100644 index daaee3704..000000000 --- a/service/store/configureStore.prod.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {applyMiddleware, createStore, combineReducers} from 'redux'; -import {enableBatching} from 'redux-batched-actions'; -import serviceReducer from 'service/reducers'; -import thunk from 'redux-thunk'; - -export default function configureServiceStore(preloadedState, appReducer) { - const baseReducer = combineReducers(Object.assign({}, serviceReducer, appReducer)); - return createStore( - enableBatching(baseReducer), - preloadedState, - applyMiddleware(thunk) - ); -} diff --git a/service/store/index.js b/service/store/index.js deleted file mode 100644 index 05ec67267..000000000 --- a/service/store/index.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -/* eslint-disable global-require, no-process-env */ - -if (process.env.NODE_ENV === 'production') { - module.exports = require('./configureStore.prod.js'); -} else { - module.exports = require('./configureStore.dev.js'); -} - -/* eslint-enable global-require, no-process-env */ \ No newline at end of file diff --git a/service/utils/channel_utils.js b/service/utils/channel_utils.js deleted file mode 100644 index 56fe69dd2..000000000 --- a/service/utils/channel_utils.js +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {Constants} from 'service/constants'; -import {displayUsername} from './user_utils'; -import {getPreferencesByCategory} from './preference_utils'; - -const defaultPrefix = 'D'; // fallback for future types -const typeToPrefixMap = {[Constants.OPEN_CHANNEL]: 'A', [Constants.PRIVATE_CHANNEL]: 'B', [Constants.DM_CHANNEL]: 'C'}; - -export function buildDisplayableChannelList(usersState, teamsState, allChannels, myPreferences) { - const missingDMChannels = createMissingDirectChannels(usersState.currentId, allChannels, myPreferences); - const channels = allChannels. - concat(missingDMChannels). - map(completeDirectChannelInfo.bind(null, usersState, myPreferences)); - - channels.sort((a, b) => { - const locale = usersState.profiles[usersState.currentId].locale; - - return buildDisplayNameAndTypeComparable(a). - localeCompare(buildDisplayNameAndTypeComparable(b), locale, {numeric: true}); - }); - - const favoriteChannels = channels.filter(isFavoriteChannel.bind(null, myPreferences)); - const notFavoriteChannels = channels.filter(not(isFavoriteChannel.bind(null, myPreferences))); - const directChannels = notFavoriteChannels. - filter( - andX( - isDirectChannel, - isDirectChannelVisible.bind(null, usersState.currentId, myPreferences) - ) - ); - - return { - favoriteChannels, - publicChannels: notFavoriteChannels.filter(isOpenChannel), - privateChannels: notFavoriteChannels.filter(isPrivateChannel), - directChannels: directChannels.filter( - isConnectedToTeamMember.bind(null, teamsState.membersInTeam[teamsState.currentId]) - ), - directNonTeamChannels: directChannels.filter( - isNotConnectedToTeamMember.bind(null, teamsState.membersInTeam[teamsState.currentId]) - ) - }; -} - -export function getNotMemberChannels(allChannels, myMembers) { - return allChannels.filter(not(isNotMemberOf.bind(this, myMembers))); -} - -export function getDirectChannelName(id, otherId) { - let handle; - - if (otherId > id) { - handle = id + '__' + otherId; - } else { - handle = otherId + '__' + id; - } - - return handle; -} - -export function getChannelByName(channels, name) { - const channelIds = Object.keys(channels); - for (let i = 0; i < channelIds.length; i++) { - const id = channelIds[i]; - if (channels[id].name === name) { - return channels[id]; - } - } - return null; -} - -function isOpenChannel(channel) { - return channel.type === Constants.OPEN_CHANNEL; -} - -function isPrivateChannel(channel) { - return channel.type === Constants.PRIVATE_CHANNEL; -} - -function isConnectedToTeamMember(members, channel) { - return members && members.has(channel.teammate_id); -} - -function isNotConnectedToTeamMember(members, channel) { - if (!members) { - return true; - } - return !members.has(channel.teammate_id); -} - -function isDirectChannel(channel) { - return channel.type === Constants.DM_CHANNEL; -} - -export function isDirectChannelVisible(userId, myPreferences, channel) { - const channelId = getUserIdFromChannelName(userId, channel.name); - const dm = myPreferences[`${Constants.CATEGORY_DIRECT_CHANNEL_SHOW}--${channelId}`]; - return dm && dm.value === 'true'; -} - -function isFavoriteChannel(myPreferences, channel) { - const fav = myPreferences[`${Constants.CATEGORY_FAVORITE_CHANNEL}--${channel.id}`]; - channel.isFavorite = fav && fav.value === 'true'; - return channel.isFavorite; -} - -function createMissingDirectChannels(currentUserId, allChannels, myPreferences) { - const preferences = getPreferencesByCategory(myPreferences, Constants.CATEGORY_DIRECT_CHANNEL_SHOW); - - return Array. - from(preferences). - filter((entry) => entry[1] === 'true'). - map((entry) => entry[0]). - filter((teammateId) => !allChannels.some(isDirectChannelForUser.bind(null, currentUserId, teammateId))). - map(createFakeChannelCurried(currentUserId)); -} - -function isDirectChannelForUser(userId, otherUserId, channel) { - return channel.type === Constants.DM_CHANNEL && getUserIdFromChannelName(userId, channel.name) === otherUserId; -} - -function isNotMemberOf(myMembers, channel) { - return myMembers[channel.id]; -} - -export function getUserIdFromChannelName(userId, channelName) { - const ids = channelName.split('__'); - let otherUserId = ''; - if (ids[0] === userId) { - otherUserId = ids[1]; - } else { - otherUserId = ids[0]; - } - - return otherUserId; -} - -function createFakeChannel(userId, otherUserId) { - return { - name: getDirectChannelName(userId, otherUserId), - last_post_at: 0, - total_msg_count: 0, - type: Constants.DM_CHANNEL, - fake: true - }; -} - -function createFakeChannelCurried(userId) { - return (otherUserId) => createFakeChannel(userId, otherUserId); -} - -export function completeDirectChannelInfo(usersState, myPreferences, channel) { - if (!isDirectChannel(channel)) { - return channel; - } - - const dmChannelClone = {...channel}; - const teammateId = getUserIdFromChannelName(usersState.currentId, channel.name); - - return Object.assign(dmChannelClone, { - display_name: displayUsername(usersState.profiles[teammateId], myPreferences), - teammate_id: teammateId, - status: usersState.statuses[teammateId] || 'offline' - }); -} - -export function buildDisplayNameAndTypeComparable(channel) { - return (typeToPrefixMap[channel.type] || defaultPrefix) + channel.display_name.toLocaleLowerCase() + channel.name.toLocaleLowerCase(); -} - -function not(f) { - return (...args) => !f(...args); -} - -function andX(...fns) { - return (...args) => fns.every((f) => f(...args)); -} - -export function cleanUpUrlable(input) { - let cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-'); - cleaned = cleaned.replace(/-{2,}/, '-'); - cleaned = cleaned.replace(/^-+/, ''); - cleaned = cleaned.replace(/-+$/, ''); - return cleaned; -} diff --git a/service/utils/deep_freeze.js b/service/utils/deep_freeze.js deleted file mode 100644 index caaa16b10..000000000 --- a/service/utils/deep_freeze.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -/** - * If your application is accepting different values for the same field over - * time and is doing a diff on them, you can either (1) create a copy or - * (2) ensure that those values are not mutated behind two passes. - * This function helps you with (2) by freezing the object and throwing if - * the user subsequently modifies the value. - * - * There are two caveats with this function: - * - If the call site is not in strict mode, it will only throw when - * mutating existing fields, adding a new one - * will unfortunately fail silently :( - * - If the object is already frozen or sealed, it will not continue the - * deep traversal and will leave leaf nodes unfrozen. - * - * Freezing the object and adding the throw mechanism is expensive and will - * only be used in DEV. - */ -export default function deepFreezeAndThrowOnMutation(object) { - if (typeof object !== 'object' || object === null || Object.isFrozen(object) || Object.isSealed(object)) { - return object; - } - - for (const key in object) { - if (object.hasOwnProperty(key)) { - object.__defineGetter__(key, identity.bind(null, object[key])); // eslint-disable-line no-underscore-dangle - object.__defineSetter__(key, throwOnImmutableMutation.bind(null, key)); // eslint-disable-line no-underscore-dangle - } - } - - Object.freeze(object); - Object.seal(object); - - for (const key in object) { - if (object.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutation(object[key]); - } - } - - return object; -} - -function throwOnImmutableMutation(key, value) { - throw Error( - 'You attempted to set the key `' + key + '` with the value `' + - JSON.stringify(value) + '` on an object that is meant to be immutable ' + - 'and has been frozen.' - ); -} - -function identity(value) { - return value; -} diff --git a/service/utils/event_emitter.js b/service/utils/event_emitter.js deleted file mode 100644 index 93d69d02a..000000000 --- a/service/utils/event_emitter.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -function isFunction(obj) { - return typeof obj === 'function'; -} - -class EventEmitter { - constructor() { - this.listeners = new Map(); - } - - addListener(label, callback) { - if (!this.listeners.has(label)) { - this.listeners.set(label, []); - } - this.listeners.get(label).push(callback); - } - - on(label, callback) { - this.addListener(label, callback); - } - - removeListener(label, callback) { - const listeners = this.listeners.get(label); - let index; - - if (listeners && listeners.length) { - index = listeners.reduce((i, listener, idx) => { - return (isFunction(listener) && listener === callback) ? idx : i; - }, -1); - - if (index > -1) { - listeners.splice(index, 1); - this.listeners.set(label, listeners); - return true; - } - } - return false; - } - - off(label, callback) { - this.removeListener(label, callback); - } - - emit(label, ...args) { - const listeners = this.listeners.get(label); - - if (listeners && listeners.length) { - listeners.forEach((listener) => { - listener(...args); - }); - return true; - } - return false; - } -} - -export default new EventEmitter(); diff --git a/service/utils/file_utils.js b/service/utils/file_utils.js deleted file mode 100644 index 55b73f7a7..000000000 --- a/service/utils/file_utils.js +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {Constants} from 'service/constants'; - -export function getFormattedFileSize(file) { - const bytes = file.size; - const fileSizes = [ - ['TB', 1024 * 1024 * 1024 * 1024], - ['GB', 1024 * 1024 * 1024], - ['MB', 1024 * 1024], - ['KB', 1024] - ]; - const size = fileSizes.find((unitAndMinBytes) => { - const minBytes = unitAndMinBytes[1]; - return bytes > minBytes; - }); - if (size) { - return `${Math.floor(bytes / size[1])} ${size[0]}`; - } - return `${bytes} B`; -} - -export function getFileType(file) { - const fileExt = file.extension.toLowerCase(); - const fileTypes = [ - 'image', - 'code', - 'pdf', - 'video', - 'audio', - 'spreadsheet', - 'word', - 'presentation', - 'patch' - ]; - return fileTypes.find((fileType) => { - const constForFileTypeExtList = `${fileType}_types`.toUpperCase(); - const fileTypeExts = Constants[constForFileTypeExtList]; - return fileTypeExts.indexOf(fileExt) > -1; - }) || 'other'; -} diff --git a/service/utils/key_mirror.js b/service/utils/key_mirror.js deleted file mode 100644 index 4e3c1f9c9..000000000 --- a/service/utils/key_mirror.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -/** - * Constructs an enumeration with keys equal to their value. - * - * For example: - * - * var COLORS = keyMirror({blue: null, red: null}); - * var myColor = COLORS.blue; - * var isColorValid = !!COLORS[myColor]; - * - * The last line could not be performed if the values of the generated enum were - * not equal to their keys. - * - * Input: {key1: val1, key2: val2} - * Output: {key1: key1, key2: key2} - * - * @param {object} obj - * @return {object} - */ -export default function keyMirror(obj) { - if (!(obj instanceof Object && !Array.isArray(obj))) { - throw new Error('keyMirror(...): Argument must be an object.'); - } - - const ret = {}; - for (const key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; - } - - ret[key] = key; - } - - return ret; -} diff --git a/service/utils/post_utils.js b/service/utils/post_utils.js deleted file mode 100644 index fb67d90a2..000000000 --- a/service/utils/post_utils.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {Constants} from 'service/constants'; - -export function isSystemMessage(post) { - return post.type && post.type.startsWith(Constants.SYSTEM_MESSAGE_PREFIX); -} - -export function shouldIgnorePost(post) { - return Constants.IGNORE_POST_TYPES.includes(post.type); -} - -export function addDatesToPostList(posts, options = {}) { - const {indicateNewMessages, currentUserId, lastViewedAt} = options; - - const out = []; - - let lastDate = null; - let subsequentPostIsUnread = false; - let subsequentPostUserId; - let postIsUnread; - for (const post of posts) { - postIsUnread = post.create_at > lastViewedAt; - if (indicateNewMessages && subsequentPostIsUnread && !postIsUnread && subsequentPostUserId !== currentUserId) { - out.push(Constants.START_OF_NEW_MESSAGES); - } - subsequentPostIsUnread = postIsUnread; - subsequentPostUserId = post.user_id; - - const postDate = new Date(post.create_at); - - // Push on a date header if the last post was on a different day than the current one - if (lastDate && lastDate.toDateString() !== postDate.toDateString()) { - out.push(lastDate); - } - - lastDate = postDate; - out.push(post); - } - - // Push on the date header for the oldest post - if (lastDate) { - out.push(lastDate); - } - - return out; -} diff --git a/service/utils/preference_utils.js b/service/utils/preference_utils.js deleted file mode 100644 index 14e2618a4..000000000 --- a/service/utils/preference_utils.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -export function getPreferenceKey(category, name) { - return `${category}--${name}`; -} - -export function getPreferencesByCategory(myPreferences, category) { - const prefix = `${category}--`; - const preferences = new Map(); - Object.keys(myPreferences).forEach((key) => { - if (key.startsWith(prefix)) { - preferences.set(key.substring(prefix.length), myPreferences[key]); - } - }); - - return preferences; -} diff --git a/service/utils/user_utils.js b/service/utils/user_utils.js deleted file mode 100644 index cf9abd2e9..000000000 --- a/service/utils/user_utils.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import {Constants} from 'service/constants'; - -export function getFullName(user) { - if (user.first_name && user.last_name) { - return user.first_name + ' ' + user.last_name; - } else if (user.first_name) { - return user.first_name; - } else if (user.last_name) { - return user.last_name; - } - - return ''; -} - -export function displayUsername(user, myPreferences) { - let nameFormat = 'false'; - const pref = myPreferences[`${Constants.CATEGORY_DISPLAY_SETTINGS}--name_format`]; - if (pref && pref.value) { - nameFormat = pref.value; - } - let username = ''; - - if (user) { - if (nameFormat === Constants.DISPLAY_PREFER_NICKNAME) { - username = user.nickname || getFullName(user); - } else if (nameFormat === Constants.DISPLAY_PREFER_FULL_NAME) { - username = getFullName(user); - } - - if (!username.trim().length) { - username = user.username; - } - } - return username; -} diff --git a/test/service/actions/channels.test.js b/test/service/actions/channels.test.js deleted file mode 100644 index 11405a076..000000000 --- a/test/service/actions/channels.test.js +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import * as Actions from 'service/actions/channels'; -import {getProfilesByIds} from 'service/actions/users'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {RequestStatus} from 'service/constants'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Channels', () => { - let store; - let secondChannel; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('selectChannel', async () => { - const channelId = TestHelper.generateId(); - - await Actions.selectChannel(channelId)(store.dispatch, store.getState); - - const state = store.getState(); - assert.equal(state.entities.channels.currentId, channelId); - }); - - it('createChannel', async () => { - const channel = { - team_id: TestHelper.basicTeam.id, - name: 'redux-test', - display_name: 'Redux Test', - purpose: 'This is to test redux', - header: 'MM with Redux', - type: 'O' - }; - - await Actions.createChannel(channel, TestHelper.basicUser.id)(store.dispatch, store.getState); - const createRequest = store.getState().requests.channels.createChannel; - const membersRequest = store.getState().requests.channels.myMembers; - if (createRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(createRequest.error)); - } else if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - const {channels, myMembers} = store.getState().entities.channels; - const channelsCount = Object.keys(channels).length; - const membersCount = Object.keys(myMembers).length; - assert.ok(channels); - assert.ok(myMembers); - assert.ok(channels[Object.keys(myMembers)[0]]); - assert.ok(myMembers[Object.keys(channels)[0]]); - assert.equal(myMembers[Object.keys(channels)[0]].user_id, TestHelper.basicUser.id); - assert.equal(channelsCount, membersCount); - assert.equal(channelsCount, 1); - assert.equal(membersCount, 1); - }); - - it('createDirectChannel', async () => { - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await getProfilesByIds([user.id])(store.dispatch, store.getState); - await Actions.createDirectChannel(TestHelper.basicTeam.id, TestHelper.basicUser.id, user.id)(store.dispatch, store.getState); - - const createRequest = store.getState().requests.channels.createChannel; - if (createRequest.status === RequestStatus.FAILURE) { - throw new Error(createRequest.error); - } - - const state = store.getState(); - const {channels, myMembers} = state.entities.channels; - const profiles = state.entities.users.profiles; - const preferences = state.entities.preferences.myPreferences; - const channelsCount = Object.keys(channels).length; - const membersCount = Object.keys(myMembers).length; - - assert.ok(channels, 'channels is empty'); - assert.ok(myMembers, 'members is empty'); - assert.ok(profiles[user.id], 'profiles does not have userId'); - assert.ok(Object.keys(preferences).length, 'preferences is empty'); - assert.ok(channels[Object.keys(myMembers)[0]], 'channels should have the member'); - assert.ok(myMembers[Object.keys(channels)[0]], 'members should belong to channel'); - assert.equal(myMembers[Object.keys(channels)[0]].user_id, TestHelper.basicUser.id); - assert.equal(channelsCount, membersCount); - assert.equal(channels[Object.keys(channels)[0]].type, 'D'); - assert.equal(channelsCount, 1); - assert.equal(membersCount, 1); - }); - - it('updateChannel', async () => { - const channel = { - ...TestHelper.basicChannel, - purpose: 'This is to test redux', - header: 'MM with Redux' - }; - - await Actions.updateChannel(channel)(store.dispatch, store.getState); - - const updateRequest = store.getState().requests.channels.updateChannel; - if (updateRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(updateRequest.error)); - } - - const {channels} = store.getState().entities.channels; - const channelId = Object.keys(channels)[0]; - assert.ok(channelId); - assert.ok(channels[channelId]); - assert.strictEqual(channels[channelId].header, 'MM with Redux'); - }); - - it('getChannel', async () => { - await Actions.getChannel(TestHelper.basicTeam.id, TestHelper.basicChannel.id)(store.dispatch, store.getState); - - const channelRequest = store.getState().requests.channels.getChannel; - if (channelRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(channelRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ok(channels[TestHelper.basicChannel.id]); - assert.ok(myMembers[TestHelper.basicChannel.id]); - }); - - it('fetchMyChannelsAndMembers', async () => { - await Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); - - const channelsRequest = store.getState().requests.channels.getChannels; - const membersRequest = store.getState().requests.channels.myMembers; - if (channelsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(channelsRequest.error)); - } else if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ok(channels); - assert.ok(myMembers); - assert.ok(channels[Object.keys(myMembers)[0]]); - assert.ok(myMembers[Object.keys(channels)[0]]); - assert.equal(Object.keys(channels).length, Object.keys(myMembers).length); - }); - - it('updateChannelNotifyProps', async () => { - const notifyProps = { - mark_unread: 'mention', - desktop: 'none' - }; - - await Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); - await Actions.updateChannelNotifyProps( - TestHelper.basicUser.id, - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - notifyProps)(store.dispatch, store.getState); - - const updateRequest = store.getState().requests.channels.updateChannelNotifyProps; - if (updateRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(updateRequest.error)); - } - - const members = store.getState().entities.channels.myMembers; - const member = members[TestHelper.basicChannel.id]; - assert.ok(member); - assert.equal(member.notify_props.mark_unread, 'mention'); - assert.equal(member.notify_props.desktop, 'none'); - }); - - it('leaveChannel', async () => { - await Actions.leaveChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id - )(store.dispatch, store.getState); - - const leaveRequest = store.getState().requests.channels.leaveChannel; - if (leaveRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(leaveRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ifError(channels[TestHelper.basicChannel.id]); - assert.ifError(myMembers[TestHelper.basicChannel.id]); - }); - - it('joinChannel', async () => { - await Actions.joinChannel( - TestHelper.basicUser.id, - TestHelper.basicTeam.id, - TestHelper.basicChannel.id - )(store.dispatch, store.getState); - - const joinRequest = store.getState().requests.channels.joinChannel; - if (joinRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(joinRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ok(channels[TestHelper.basicChannel.id]); - assert.ok(myMembers[TestHelper.basicChannel.id]); - }); - - it('joinChannelByName', async () => { - const secondClient = TestHelper.createClient(); - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - await secondClient.login(user.email, 'password1'); - - secondChannel = await secondClient.createChannel( - TestHelper.fakeChannel(TestHelper.basicTeam.id)); - - await Actions.joinChannel( - TestHelper.basicUser.id, - TestHelper.basicTeam.id, - null, - secondChannel.name - )(store.dispatch, store.getState); - - const joinRequest = store.getState().requests.channels.joinChannel; - if (joinRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(joinRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ok(channels[secondChannel.id]); - assert.ok(myMembers[secondChannel.id]); - }); - - it('deleteChannel', async () => { - await Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); - await Actions.deleteChannel( - TestHelper.basicTeam.id, - secondChannel.id - )(store.dispatch, store.getState); - - const deleteRequest = store.getState().requests.channels.deleteChannel; - if (deleteRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(deleteRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - assert.ifError(channels[secondChannel.id]); - assert.ifError(myMembers[secondChannel.id]); - }); - - it('viewChannel', async () => { - const userChannel = await Client.createChannel( - TestHelper.fakeChannel(TestHelper.basicTeam.id) - ); - await Actions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); - const members = store.getState().entities.channels.myMembers; - const member = members[TestHelper.basicChannel.id]; - const otherMember = members[userChannel.id]; - assert.ok(member); - assert.ok(otherMember); - - await Actions.viewChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - userChannel.id - )(store.dispatch, store.getState); - - const updateRequest = store.getState().requests.channels.updateLastViewedAt; - if (updateRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(updateRequest.error)); - } - }); - - it('getMoreChannels', async () => { - const userClient = TestHelper.createClient(); - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - await userClient.login(user.email, 'password1'); - - const userChannel = await userClient.createChannel( - TestHelper.fakeChannel(TestHelper.basicTeam.id) - ); - - await Actions.getMoreChannels(TestHelper.basicTeam.id, 0)(store.dispatch, store.getState); - - const moreRequest = store.getState().requests.channels.getMoreChannels; - if (moreRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(moreRequest.error)); - } - - const {channels, myMembers} = store.getState().entities.channels; - const channel = channels[userChannel.id]; - - assert.ok(channel); - assert.ifError(myMembers[channel.id]); - }); - - it('getChannelStats', async () => { - await Actions.getChannelStats( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id - )(store.dispatch, store.getState); - - const statsRequest = store.getState().requests.channels.getChannelStats; - if (statsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(statsRequest.error)); - } - - const {stats} = store.getState().entities.channels; - const stat = stats[TestHelper.basicChannel.id]; - assert.ok(stat); - assert.equal(stat.member_count, 1); - }); - - it('addChannelMember', async () => { - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Actions.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - const addRequest = store.getState().requests.channels.addChannelMember; - if (addRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(addRequest.error)); - } - - const {profilesInChannel, profilesNotInChannel} = store.getState().entities.users; - const channel = profilesInChannel[TestHelper.basicChannel.id]; - const notChannel = profilesNotInChannel[TestHelper.basicChannel.id]; - assert.ok(channel); - assert.ok(notChannel); - assert.ok(channel.has(user.id)); - assert.ifError(notChannel.has(user.id)); - }); - - it('removeChannelMember', async () => { - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Actions.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - await Actions.removeChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - const removeRequest = store.getState().requests.channels.removeChannelMember; - if (removeRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(removeRequest.error)); - } - - const {profilesInChannel, profilesNotInChannel} = store.getState().entities.users; - const channel = profilesInChannel[TestHelper.basicChannel.id]; - const notChannel = profilesNotInChannel[TestHelper.basicChannel.id]; - assert.ok(channel); - assert.ok(notChannel); - assert.ok(notChannel.has(user.id)); - assert.ifError(channel.has(user.id)); - }); - - it('updateChannelHeader', async () => { - await Actions.getChannel(TestHelper.basicTeam.id, TestHelper.basicChannel.id)(store.dispatch, store.getState); - - const channelRequest = store.getState().requests.channels.getChannel; - if (channelRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(channelRequest.error)); - } - - const header = 'this is an updated test header'; - await Actions.updateChannelHeader( - TestHelper.basicChannel.id, - header - )(store.dispatch, store.getState); - const {channels} = store.getState().entities.channels; - const channel = channels[TestHelper.basicChannel.id]; - assert.ok(channel); - assert.deepEqual(channel.header, header); - }); - - it('updateChannelPurpose', async () => { - await Actions.getChannel(TestHelper.basicTeam.id, TestHelper.basicChannel.id)(store.dispatch, store.getState); - - const channelRequest = store.getState().requests.channels.getChannel; - if (channelRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(channelRequest.error)); - } - - const purpose = 'this is an updated test purpose'; - await Actions.updateChannelPurpose( - TestHelper.basicChannel.id, - purpose - )(store.dispatch, store.getState); - const {channels} = store.getState().entities.channels; - const channel = channels[TestHelper.basicChannel.id]; - assert.ok(channel); - assert.deepEqual(channel.purpose, purpose); - }); - - it('autocompleteChannels', async () => { - await Actions.autocompleteChannels( - TestHelper.basicTeam.id, - '' - )(store.dispatch, store.getState); - - const autocompleteRequest = store.getState().requests.channels.autocompleteChannels; - const data = store.getState().entities.channels.autocompleteChannels; - - if (autocompleteRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(autocompleteRequest.error)); - } - - assert.ok(data.length); - - const channel = data.find((c) => c.id === TestHelper.basicChannel.id); - - assert.ok(channel); - }); -}); diff --git a/test/service/actions/files.test.js b/test/service/actions/files.test.js deleted file mode 100644 index 3c44b7ecc..000000000 --- a/test/service/actions/files.test.js +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import fs from 'fs'; -import assert from 'assert'; - -const FormData = require('form-data'); - -import * as Actions from 'service/actions/files'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {RequestStatus} from 'service/constants'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Files', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('getFilesForPost', async () => { - const {basicClient, basicTeam, 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(); - - const fileUploadResp = await basicClient. - uploadFile(basicTeam.id, basicChannel.id, clientId, imageFormData, formBoundary); - const fileId = fileUploadResp.file_infos[0].id; - - const fakePostForFile = TestHelper.fakePost(basicChannel.id); - fakePostForFile.file_ids = [fileId]; - const postForFile = await basicClient.createPost(basicTeam.id, fakePostForFile); - - await Actions.getFilesForPost( - basicTeam.id, basicChannel.id, postForFile.id - )(store.dispatch, store.getState); - - const filesRequest = store.getState().requests.files.getFilesForPost; - const {files: allFiles, fileIdsByPostId} = store.getState().entities.files; - - if (filesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(filesRequest.error)); - } - - 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); - }); -}); diff --git a/test/service/actions/general.test.js b/test/service/actions/general.test.js deleted file mode 100644 index 4ebf26d4b..000000000 --- a/test/service/actions/general.test.js +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import configureStore from 'app/store'; - -import Config from 'assets/config.json'; - -import * as Actions from 'service/actions/general'; -import Client from 'service/client'; -import {RequestStatus} from 'service/constants'; - -import TestHelper from 'test/test_helper'; - -describe('Actions.General', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('getPing - Invalid URL', async () => { - Client.setUrl('https://google.com/fake/url'); - await Actions.getPing()(store.dispatch, store.getState); - - const {server} = store.getState().requests.general; - assert.ok(server.status === RequestStatus.FAILURE && server.error); - }); - - it('getPing', async () => { - TestHelper.basicClient.setUrl(Config.DefaultServerUrl); - await Actions.getPing()(store.dispatch, store.getState); - - const {server} = store.getState().requests.general; - if (server.status === RequestStatus.FAILED) { - throw new Error(JSON.stringify(server.error)); - } - }); - - it('getClientConfig', async () => { - await Actions.getClientConfig()(store.dispatch, store.getState); - - const configRequest = store.getState().requests.general.config; - if (configRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(configRequest.error)); - } - - const clientConfig = store.getState().entities.general.config; - - // Check a few basic fields since they may change over time - assert.ok(clientConfig.Version); - assert.ok(clientConfig.BuildNumber); - assert.ok(clientConfig.BuildDate); - assert.ok(clientConfig.BuildHash); - }); - - it('getLicenseConfig', async () => { - await Actions.getLicenseConfig()(store.dispatch, store.getState); - - const licenseRequest = store.getState().requests.general.license; - if (licenseRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(licenseRequest.error)); - } - - const licenseConfig = store.getState().entities.general.license; - - // Check a few basic fields since they may change over time - assert.notStrictEqual(licenseConfig.IsLicensed, undefined); - }); - - it('setServerVersion', async () => { - const version = '3.7.0'; - await Actions.setServerVersion(version)(store.dispatch, store.getState); - - const {serverVersion} = store.getState().entities.general; - assert.deepEqual(serverVersion, version); - }); -}); diff --git a/test/service/actions/posts.test.js b/test/service/actions/posts.test.js deleted file mode 100644 index 8d9b239b1..000000000 --- a/test/service/actions/posts.test.js +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import * as Actions from 'service/actions/posts'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {Constants, RequestStatus} from 'service/constants'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Posts', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('createPost', async () => { - const channelId = TestHelper.basicChannel.id; - const post = TestHelper.fakePost(channelId); - - await Actions.createPost( - TestHelper.basicTeam.id, - post - )(store.dispatch, store.getState); - - const state = store.getState(); - const createRequest = state.requests.posts.createPost; - if (createRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(createRequest.error)); - } - - const {posts, postsByChannel} = state.entities.posts; - assert.ok(posts); - assert.ok(postsByChannel); - assert.ok(postsByChannel[channelId]); - - let found = false; - for (const storedPost of Object.values(posts)) { - if (storedPost.message === post.message) { - found = true; - break; - } - } - assert.ok(found, 'failed to find new post in posts'); - - found = false; - for (const postIdInChannel of postsByChannel[channelId]) { - if (posts[postIdInChannel].message === post.message) { - found = true; - break; - } - } - assert.ok(found, 'failed to find new post in postsByChannel'); - }); - - it('editPost', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const message = post.message; - - post.message = `${message} (edited)`; - await Actions.editPost( - teamId, - post - )(store.dispatch, store.getState); - - const state = store.getState(); - const editRequest = state.requests.posts.editPost; - const {posts} = state.entities.posts; - - if (editRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(editRequest.error)); - } - - assert.ok(posts); - assert.ok(posts[post.id]); - - assert.strictEqual( - posts[post.id].message, - `${message} (edited)` - ); - }); - - it('deletePost', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - await Actions.createPost( - teamId, - TestHelper.fakePost(channelId) - )(store.dispatch, store.getState); - - const initialPosts = store.getState().entities.posts; - const created = initialPosts.posts[initialPosts.postsByChannel[channelId][0]]; - - await Actions.deletePost(teamId, created)(store.dispatch, store.getState); - - const state = store.getState(); - const deleteRequest = state.requests.posts.deletePost; - const {posts} = state.entities.posts; - - if (deleteRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(deleteRequest.error)); - } - - assert.ok(posts); - assert.ok(posts[created.id]); - - assert.strictEqual( - posts[created.id].state, - Constants.POST_DELETED - ); - }); - - it('removePost', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - const postId = TestHelper.basicPost.id; - - const post1a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: postId} - ); - - await Actions.getPosts( - teamId, - channelId - )(store.dispatch, store.getState); - - const postsCount = store.getState().entities.posts.postsByChannel[channelId].length; - - await Actions.removePost( - TestHelper.basicPost - )(store.dispatch, store.getState); - - const {posts, postsByChannel} = store.getState().entities.posts; - - assert.ok(posts); - assert.ok(postsByChannel); - assert.ok(postsByChannel[channelId]); - - // this should count that the basic post and post1a were removed - assert.equal(postsByChannel[channelId].length, postsCount - 2); - assert.ok(!posts[postId]); - assert.ok(!posts[post1a.id]); - }); - - it('getPost', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - - await Actions.getPost( - teamId, - channelId, - post.id - )(store.dispatch, store.getState); - - const state = store.getState(); - const getRequest = state.requests.posts.getPost; - const {posts, postsByChannel} = state.entities.posts; - - if (getRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(getRequest.error)); - } - - assert.ok(posts); - assert.ok(postsByChannel); - assert.ok(postsByChannel[channelId]); - - assert.ok(posts[post.id]); - - let found = false; - for (const postIdInChannel of postsByChannel[channelId]) { - if (postIdInChannel === post.id) { - found = true; - break; - } - } - assert.ok(found, 'failed to find post in postsByChannel'); - }); - - it('getPosts', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post1 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post1a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post1.id} - ); - const post2 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post3.id} - ); - - await Actions.getPosts( - teamId, - channelId - )(store.dispatch, store.getState); - - const state = store.getState(); - const getRequest = state.requests.posts.getPosts; - const {posts, postsByChannel} = state.entities.posts; - - if (getRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(getRequest.error)); - } - - assert.ok(posts); - assert.ok(postsByChannel); - - const postsInChannel = postsByChannel[channelId]; - assert.ok(postsInChannel); - assert.equal(postsInChannel[0], post3a.id, 'wrong order for post3a'); - assert.equal(postsInChannel[1], post3.id, 'wrong order for post3'); - assert.equal(postsInChannel[3], post1a.id, 'wrong order for post1a'); - - assert.ok(posts[post1.id]); - assert.ok(posts[post1a.id]); - assert.ok(posts[post2.id]); - assert.ok(posts[post3.id]); - assert.ok(posts[post3a.id]); - }); - - it('getPostsSince', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post1 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post1.id} - ); - const post2 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post3.id} - ); - - await Actions.getPostsSince( - teamId, - channelId, - post2.create_at - )(store.dispatch, store.getState); - - const state = store.getState(); - const getRequest = state.requests.posts.getPostsSince; - const {posts, postsByChannel} = state.entities.posts; - - if (getRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(getRequest.error)); - } - - assert.ok(posts); - assert.ok(postsByChannel); - - const postsInChannel = postsByChannel[channelId]; - assert.ok(postsInChannel); - assert.equal(postsInChannel[0], post3a.id, 'wrong order for post3a'); - assert.equal(postsInChannel[1], post3.id, 'wrong order for post3'); - assert.equal(postsInChannel.length, 2, 'wrong size'); - }); - - it('getPostsBefore', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post1 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post1a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post1.id} - ); - const post2 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post3.id} - ); - - await Actions.getPostsBefore( - teamId, - channelId, - post2.id, - 0, - 10 - )(store.dispatch, store.getState); - - const state = store.getState(); - const getRequest = state.requests.posts.getPostsBefore; - const {posts, postsByChannel} = state.entities.posts; - - if (getRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(getRequest.error)); - } - - assert.ok(posts); - assert.ok(postsByChannel); - - const postsInChannel = postsByChannel[channelId]; - assert.ok(postsInChannel); - assert.equal(postsInChannel[0], post1a.id, 'wrong order for post1a'); - assert.equal(postsInChannel[1], post1.id, 'wrong order for post1'); - assert.equal(postsInChannel.length, 10, 'wrong size'); - }); - - it('getPostsAfter', async () => { - const teamId = TestHelper.basicTeam.id; - const channelId = TestHelper.basicChannel.id; - - const post1 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post1.id} - ); - const post2 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3 = await Client.createPost( - teamId, - TestHelper.fakePost(channelId) - ); - const post3a = await Client.createPost( - teamId, - {...TestHelper.fakePost(channelId), root_id: post3.id} - ); - - await Actions.getPostsAfter( - teamId, - channelId, - post2.id, - 0, - 10 - )(store.dispatch, store.getState); - - const state = store.getState(); - const getRequest = state.requests.posts.getPostsAfter; - const {posts, postsByChannel} = state.entities.posts; - - if (getRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(getRequest.error)); - } - - assert.ok(posts); - assert.ok(postsByChannel); - - const postsInChannel = postsByChannel[channelId]; - assert.ok(postsInChannel); - assert.equal(postsInChannel[0], post3a.id, 'wrong order for post3a'); - assert.equal(postsInChannel[1], post3.id, 'wrong order for post3'); - assert.equal(postsInChannel.length, 2, 'wrong size'); - }); -}); diff --git a/test/service/actions/preferences.test.js b/test/service/actions/preferences.test.js deleted file mode 100644 index 95f3556b4..000000000 --- a/test/service/actions/preferences.test.js +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import configureStore from 'app/store'; - -import * as Actions from 'service/actions/preferences'; -import {login} from 'service/actions/users'; -import Client from 'service/client'; -import {Preferences, RequestStatus} from 'service/constants'; - -import TestHelper from 'test/test_helper'; - -describe('Actions.Preferences', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('getMyPreferences', async () => { - const user = TestHelper.basicUser; - const existingPreferences = [ - { - user_id: user.id, - category: 'test', - name: 'test1', - value: 'test' - }, - { - user_id: user.id, - category: 'test', - name: 'test2', - value: 'test' - } - ]; - - await Client.savePreferences(existingPreferences); - await Actions.getMyPreferences('1234')(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.preferences.getMyPreferences; - const {myPreferences} = state.entities.preferences; - - if (request.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(request.error)); - } - - assert.ok(myPreferences['test--test1'], 'first preference doesn\'t exist'); - assert.deepEqual(existingPreferences[0], myPreferences['test--test1']); - assert.ok(myPreferences['test--test2'], 'second preference doesn\'t exist'); - assert.deepEqual(existingPreferences[1], myPreferences['test--test2']); - }); - - it('savePrefrences', async () => { - const user = TestHelper.basicUser; - const existingPreferences = [ - { - user_id: user.id, - category: 'test', - name: 'test1', - value: 'test' - } - ]; - - await Client.savePreferences(existingPreferences); - await Actions.getMyPreferences()(store.dispatch, store.getState); - - const preferences = [ - { - user_id: user.id, - category: 'test', - name: 'test2', - value: 'test' - }, - { - user_id: user.id, - category: 'test', - name: 'test3', - value: 'test' - } - ]; - - await Actions.savePreferences(preferences)(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.preferences.savePreferences; - const {myPreferences} = state.entities.preferences; - - if (request.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(request.error)); - } - - assert.ok(myPreferences['test--test1'], 'first preference doesn\'t exist'); - assert.deepEqual(existingPreferences[0], myPreferences['test--test1']); - assert.ok(myPreferences['test--test2'], 'second preference doesn\'t exist'); - assert.deepEqual(preferences[0], myPreferences['test--test2']); - assert.ok(myPreferences['test--test3'], 'third preference doesn\'t exist'); - assert.deepEqual(preferences[1], myPreferences['test--test3']); - }); - - it('deletePreferences', async () => { - const user = TestHelper.basicUser; - const existingPreferences = [ - { - user_id: user.id, - category: 'test', - name: 'test1', - value: 'test' - }, - { - user_id: user.id, - category: 'test', - name: 'test2', - value: 'test' - }, - { - user_id: user.id, - category: 'test', - name: 'test3', - value: 'test' - } - ]; - - await Client.savePreferences(existingPreferences); - await Actions.getMyPreferences()(store.dispatch, store.getState); - await Actions.deletePreferences([ - existingPreferences[0], - existingPreferences[2] - ])(store.dispatch, store.getState); - - const state = store.getState(); - const request = state.requests.preferences.deletePreferences; - const {myPreferences} = state.entities.preferences; - - if (request.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(request.error)); - } - - assert.ok(!myPreferences['test--test1'], 'deleted preference still exists'); - assert.ok(myPreferences['test--test2'], 'second preference doesn\'t exist'); - assert.deepEqual(existingPreferences[1], myPreferences['test--test2']); - assert.ok(!myPreferences['test--test3'], 'third preference doesn\'t exist'); - }); - - it('makeDirectChannelVisibleIfNecessary', async () => { - const user = TestHelper.basicUser; - const user2 = await TestHelper.createClient().createUser(TestHelper.fakeUser()); - - await login(user.email, 'password1')(store.dispatch, store.getState); - - // Test that a new preference is created if non exists - await Actions.makeDirectChannelVisibleIfNecessary(user2.id)(store.dispatch, store.getState); - - let state = store.getState(); - let myPreferences = state.entities.preferences.myPreferences; - let preference = myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user2.id}`]; - assert.ok(preference, 'preference for showing direct channel doesn\'t exist'); - assert.equal(preference.value, 'true', 'preference for showing direct channel is not true'); - - // Test that nothing changes if the preference already exists and is true - await Actions.makeDirectChannelVisibleIfNecessary(user2.id)(store.dispatch, store.getState); - - const state2 = store.getState(); - assert.equal(state, state2, 'store should not change since direct channel is already visible'); - - // Test that the preference is updated if it already exists and is false - await Actions.savePreferences([{ - ...preference, - value: 'false' - }])(store.dispatch, store.getState); - - await Actions.makeDirectChannelVisibleIfNecessary(user2.id)(store.dispatch, store.getState); - - state = store.getState(); - myPreferences = state.entities.preferences.myPreferences; - preference = myPreferences[`${Preferences.CATEGORY_DIRECT_CHANNEL_SHOW}--${user2.id}`]; - assert.ok(preference, 'preference for showing direct channel doesn\'t exist'); - assert.equal(preference.value, 'true', 'preference for showing direct channel is not true'); - }).timeout(2000); -}); diff --git a/test/service/actions/teams.test.js b/test/service/actions/teams.test.js deleted file mode 100644 index 1a7982ef4..000000000 --- a/test/service/actions/teams.test.js +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import * as Actions from 'service/actions/teams'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {RequestStatus} from 'service/constants'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Teams', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('selectTeam', async () => { - await Actions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - const {currentId} = store.getState().entities.teams; - - assert.ok(currentId); - assert.equal(currentId, TestHelper.basicTeam.id); - }); - - it('fetchTeams', async () => { - await Actions.fetchTeams()(store.dispatch, store.getState); - - const teamsRequest = store.getState().requests.teams.allTeams; - const {teams} = store.getState().entities.teams; - - if (teamsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(teamsRequest.error)); - } - - assert.ok(teams); - assert.ok(teams[TestHelper.basicTeam.id]); - }); - - it('getAllTeamListings', async () => { - const team = {...TestHelper.fakeTeam(), allow_open_invite: true}; - - await Client.createTeam(team); - await Actions.getAllTeamListings()(store.dispatch, store.getState); - - const teamsRequest = store.getState().requests.teams.getAllTeamListings; - const {teams, openTeamIds} = store.getState().entities.teams; - - if (teamsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(teamsRequest.error)); - } - - assert.ok(Object.keys(teams).length > 0); - for (const teamId in teams) { - if (teams.hasOwnProperty(teamId)) { - assert.ok(openTeamIds.has(teamId)); - } - } - }); - - it('createTeam', async () => { - await Actions.createTeam( - TestHelper.basicUser.id, - TestHelper.fakeTeam() - )(store.dispatch, store.getState); - - const createRequest = store.getState().requests.teams.createTeam; - const {teams, myMembers, currentId} = store.getState().entities.teams; - - if (createRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(createRequest.error)); - } - - const teamId = Object.keys(teams)[0]; - assert.strictEqual(Object.keys(teams).length, 1); - assert.strictEqual(currentId, teamId); - assert.ok(myMembers[teamId]); - }); - - it('updateTeam', async () => { - const displayName = 'The Updated Team'; - const description = 'This is a team created by unit tests'; - const team = { - ...TestHelper.basicTeam, - display_name: displayName, - description - }; - - await Actions.updateTeam(team)(store.dispatch, store.getState); - - const updateRequest = store.getState().requests.teams.updateTeam; - const {teams} = store.getState().entities.teams; - - if (updateRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(updateRequest.error)); - } - - const updated = teams[TestHelper.basicTeam.id]; - assert.ok(updated); - assert.strictEqual(updated.display_name, displayName); - assert.strictEqual(updated.description, description); - }); - - it('getMyTeamMembers', async () => { - await Actions.getMyTeamMembers()(store.dispatch, store.getState); - - const membersRequest = store.getState().requests.teams.getMyTeamMembers; - const members = store.getState().entities.teams.myMembers; - - if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - - assert.ok(members); - assert.ok(members[TestHelper.basicTeam.id]); - }); - - it('getTeamMember', async () => { - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Actions.getTeamMember(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); - - const membersRequest = store.getState().requests.teams.getTeamMembers; - const members = store.getState().entities.teams.membersInTeam; - - if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id].has(user.id)); - }); - - it('getTeamMembersByIds', async () => { - const user1 = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - const user2 = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Actions.getTeamMembersByIds( - TestHelper.basicTeam.id, - [user1.id, user2.id] - )(store.dispatch, store.getState); - - const membersRequest = store.getState().requests.teams.getTeamMembers; - const members = store.getState().entities.teams.membersInTeam; - - if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id].has(user1.id)); - assert.ok(members[TestHelper.basicTeam.id].has(user2.id)); - }); - - it('getTeamStats', async () => { - await Actions.getTeamStats(TestHelper.basicTeam.id)(store.dispatch, store.getState); - - const {stats} = store.getState().entities.teams; - const statsRequest = store.getState().requests.teams.getTeamStats; - - if (statsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(statsRequest.error)); - } - - const stat = stats[TestHelper.basicTeam.id]; - assert.ok(stat); - - // we need to take into account the members of the tests above - assert.equal(stat.total_member_count, 4); - assert.equal(stat.active_member_count, 4); - }); - - it('addUserToTeam', async () => { - const user = await TestHelper.basicClient.createUser(TestHelper.fakeUser()); - - await Actions.addUserToTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); - - const membersRequest = store.getState().requests.teams.addUserToTeam; - const members = store.getState().entities.teams.membersInTeam; - - if (membersRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(membersRequest.error)); - } - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id].has(user.id)); - }); - - it('removeUserFromTeam', async () => { - const user = await TestHelper.basicClient.createUser(TestHelper.fakeUser()); - - await Actions.addUserToTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); - - let state = store.getState(); - let members = state.entities.teams.membersInTeam; - const addRequest = state.requests.teams.addUserToTeam; - - if (addRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(addRequest.error)); - } - - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(members[TestHelper.basicTeam.id].has(user.id)); - await Actions.removeUserFromTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); - state = store.getState(); - - const removeRequest = state.requests.teams.removeUserFromTeam; - - if (removeRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(removeRequest.error)); - } - - members = state.entities.teams.membersInTeam; - assert.ok(members[TestHelper.basicTeam.id]); - assert.ok(!members[TestHelper.basicTeam.id].has(user.id)); - }); -}); diff --git a/test/service/actions/users.test.js b/test/service/actions/users.test.js deleted file mode 100644 index a88032800..000000000 --- a/test/service/actions/users.test.js +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import * as Actions from 'service/actions/users'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {RequestStatus} from 'service/constants'; -import Routes from 'app/navigation/routes'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Users', () => { - let store; - before(async () => { - await TestHelper.initBasic(Client); - }); - - beforeEach(() => { - store = configureStore(); - }); - - after(async () => { - await TestHelper.basicClient.logout(); - }); - - it('login', async () => { - const user = TestHelper.basicUser; - await TestHelper.basicClient.logout(); - await Actions.login(user.email, 'password1')(store.dispatch, store.getState); - - const state = store.getState(); - const loginRequest = state.requests.users.login; - const {currentId, profiles} = state.entities.users; - const preferences = state.entities.preferences.myPreferences; - const teamMembers = state.entities.teams.myMembers; - - if (loginRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(loginRequest.error)); - } - - assert.ok(currentId); - assert.ok(profiles); - assert.ok(profiles[currentId]); - assert.ok(Object.keys(preferences).length); - - Object.keys(teamMembers).forEach((id) => { - assert.ok(teamMembers[id].team_id); - assert.equal(teamMembers[id].user_id, currentId); - }); - }); - - it('logout', async () => { - await Actions.logout()(store.dispatch, store.getState); - - const state = store.getState(); - const logoutRequest = state.requests.users.logout; - const general = state.entities.general; - const users = state.entities.users; - const loginView = state.views.login; - const teams = state.entities.teams; - const channels = state.entities.channels; - const posts = state.entities.posts; - const preferences = state.entities.preferences; - const navigation = state.navigation; - - if (logoutRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(logoutRequest.error)); - } - - assert.deepStrictEqual(general.config, {}, 'config not empty'); - assert.deepStrictEqual(general.license, {}, 'license not empty'); - assert.strictEqual(users.currentId, '', 'current user id not empty'); - assert.deepStrictEqual(users.mySessions, [], 'user sessions not empty'); - assert.deepStrictEqual(users.myAudits, [], 'user audits not empty'); - assert.deepStrictEqual(users.profiles, {}, 'user profiles not empty'); - assert.deepStrictEqual(users.profilesInTeam, {}, 'users profiles in team not empty'); - assert.deepStrictEqual(users.profilesInChannel, {}, 'users profiles in channel not empty'); - assert.deepStrictEqual(users.profilesNotInChannel, {}, 'users profiles NOT in channel not empty'); - assert.deepStrictEqual(users.statuses, {}, 'users statuses not empty'); - assert.strictEqual(loginView.loginId, '', 'login id not empty'); - assert.strictEqual(loginView.password, '', 'password not empty'); - assert.strictEqual(teams.currentId, '', 'current team id is not empty'); - assert.deepStrictEqual(teams.teams, {}, 'teams is not empty'); - assert.deepStrictEqual(teams.myMembers, {}, 'team members is not empty'); - assert.deepStrictEqual(teams.membersInTeam, {}, 'members in team is not empty'); - assert.deepStrictEqual(teams.stats, {}, 'team stats is not empty'); - assert.deepStrictEqual(teams.openTeamIds, new Set(), 'team open ids is not empty'); - assert.strictEqual(channels.currentId, '', 'current channel id is not empty'); - assert.deepStrictEqual(channels.channels, {}, 'channels is not empty'); - assert.deepStrictEqual(channels.myMembers, {}, 'channel members is not empty'); - assert.deepStrictEqual(channels.stats, {}, 'channel stats is not empty'); - assert.strictEqual(posts.selectedPostId, '', 'selected post id is not empty'); - assert.strictEqual(posts.currentFocusedPostId, '', 'current focused post id is not empty'); - assert.deepStrictEqual(posts.posts, {}, 'posts is not empty'); - assert.deepStrictEqual(posts.postsByChannel, {}, 'posts by channel is not empty'); - assert.deepStrictEqual(preferences.myPreferences, {}, 'user preferences not empty'); - assert.strictEqual(navigation.index, 0, 'navigation not reset to first element of stack'); - assert.deepStrictEqual(navigation.routes, [Routes.Root], 'navigation not reset to root route'); - }); - - it('getProfiles', async () => { - await TestHelper.basicClient.login(TestHelper.basicUser.email, 'password1'); - await TestHelper.basicClient.createUser(TestHelper.fakeUser()); - await Actions.getProfiles(0)(store.dispatch, store.getState); - - const profilesRequest = store.getState().requests.users.getProfiles; - const {profiles} = store.getState().entities.users; - - if (profilesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(profilesRequest.error)); - } - - assert.ok(Object.keys(profiles).length); - }); - - it('getProfilesInTeam', async () => { - await Actions.getProfilesInTeam(TestHelper.basicTeam.id, 0)(store.dispatch, store.getState); - - const profilesRequest = store.getState().requests.users.getProfilesInTeam; - const {profilesInTeam, profiles} = store.getState().entities.users; - - if (profilesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(profilesRequest.error)); - } - - const team = profilesInTeam[TestHelper.basicTeam.id]; - assert.ok(team); - assert.ok(team.has(TestHelper.basicUser.id)); - assert.equal(Object.keys(profiles).length, team.size, 'profiles != profiles in team'); - }); - - it('getProfilesInChannel', async () => { - await Actions.getProfilesInChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - 0 - )(store.dispatch, store.getState); - - const profilesRequest = store.getState().requests.users.getProfilesInChannel; - const {profiles, profilesInChannel} = store.getState().entities.users; - - if (profilesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(profilesRequest.error)); - } - - const channel = profilesInChannel[TestHelper.basicChannel.id]; - assert.ok(channel.has(TestHelper.basicUser.id)); - assert.equal(Object.keys(profiles).length, channel.size, 'profiles != profiles in channel'); - }); - - it('getProfilesNotInChannel', async () => { - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Actions.getProfilesNotInChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - 0 - )(store.dispatch, store.getState); - - const profilesRequest = store.getState().requests.users.getProfilesNotInChannel; - const {profiles, profilesNotInChannel} = store.getState().entities.users; - - if (profilesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(profilesRequest.error)); - } - - const channel = profilesNotInChannel[TestHelper.basicChannel.id]; - assert.ok(channel.has(user.id)); - assert.equal(Object.keys(profiles).length, channel.size, 'profiles != profiles in channel'); - }); - - it('getStatusesByIds', async () => { - const user = await TestHelper.basicClient.createUser(TestHelper.fakeUser()); - - await Actions.getStatusesByIds( - [TestHelper.basicUser.id, user.id] - )(store.dispatch, store.getState); - - const statusesRequest = store.getState().requests.users.getStatusesByIds; - const statuses = store.getState().entities.users.statuses; - - if (statusesRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(statusesRequest.error)); - } - - assert.ok(statuses[TestHelper.basicUser.id]); - assert.ok(statuses[user.id]); - assert.equal(Object.keys(statuses).length, 2); - }); - - it('getSessions', async () => { - await Actions.getSessions(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const sessionsRequest = store.getState().requests.users.getSessions; - const sessions = store.getState().entities.users.mySessions; - - if (sessionsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(sessionsRequest.error)); - } - - assert.ok(sessions.length); - assert.equal(sessions[0].user_id, TestHelper.basicUser.id); - }); - - it('revokeSession', async () => { - await Actions.getSessions(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const sessionsRequest = store.getState().requests.users.getSessions; - let sessions = store.getState().entities.users.mySessions; - if (sessionsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(sessionsRequest.error)); - } - - await Actions.revokeSession(sessions[0].id)(store.dispatch, store.getState); - - const revokeRequest = store.getState().requests.users.revokeSession; - if (revokeRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(revokeRequest.error)); - } - - sessions = store.getState().entities.users.mySessions; - assert.ok(sessions.length === 0); - }); - - it('revokeSession and logout', async () => { - await TestHelper.basicClient.login(TestHelper.basicUser.email, 'password1'); - await Actions.getSessions(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const sessionsRequest = store.getState().requests.users.getSessions; - const sessions = store.getState().entities.users.mySessions; - - if (sessionsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(sessionsRequest.error)); - } - - await Actions.revokeSession(sessions[0].id)(store.dispatch, store.getState); - - const revokeRequest = store.getState().requests.users.revokeSession; - if (revokeRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(revokeRequest.error)); - } - - await Actions.getProfiles(0)(store.dispatch, store.getState); - - const logoutRequest = store.getState().requests.users.logout; - if (logoutRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(logoutRequest.error)); - } - }); - - it('getAudits', async () => { - await TestHelper.basicClient.login(TestHelper.basicUser.email, 'password1'); - await Actions.getAudits(TestHelper.basicUser.id)(store.dispatch, store.getState); - - const auditsRequest = store.getState().requests.users.getAudits; - const audits = store.getState().entities.users.myAudits; - - if (auditsRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(auditsRequest.error)); - } - - assert.ok(audits.length); - assert.equal(audits[0].user_id, TestHelper.basicUser.id); - }); - - it('autocompleteUsersInChannel', async () => { - await Actions.autocompleteUsersInChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - '' - )(store.dispatch, store.getState); - - const autocompleteRequest = store.getState().requests.users.autocompleteUsersInChannel; - const data = store.getState().entities.users.autocompleteUsersInChannel; - - if (autocompleteRequest.status === RequestStatus.FAILURE) { - throw new Error(JSON.stringify(autocompleteRequest.error)); - } - - assert.ok(data[TestHelper.basicChannel.id]); - assert.ok(data[TestHelper.basicChannel.id].in_channel); - assert.ok(data[TestHelper.basicChannel.id].out_of_channel); - }); - - it('updateUserNotifyProps', async () => { - await Actions.login(TestHelper.basicUser.email, 'password1')(store.dispatch, store.getState); - - const state = store.getState(); - const currentUser = state.entities.users.profiles[state.entities.users.currentId]; - const notifyProps = currentUser.notify_props; - - await Actions.updateUserNotifyProps({ - ...notifyProps, - comments: 'any', - email: 'false', - first_name: 'false', - mention_keys: '', - user_id: currentUser.id - })(store.dispatch, store.getState); - - setTimeout(() => { - const updatedState = store.getState(); - const updatedCurrentUser = updatedState.entities.users.profiles[state.entities.users.currentId]; - const updateNotifyProps = updatedCurrentUser.notify_props; - - assert.equal(updateNotifyProps.comments, 'any'); - assert.equal(updateNotifyProps.email, 'false'); - assert.equal(updateNotifyProps.first_name, 'false'); - assert.equal(updateNotifyProps.mention_keys, ''); - }, 1000); - }); -}); diff --git a/test/service/actions/websocket.test.js b/test/service/actions/websocket.test.js deleted file mode 100644 index 974923624..000000000 --- a/test/service/actions/websocket.test.js +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; -import * as Actions from 'service/actions/websocket'; -import * as ChannelActions from 'service/actions/channels'; -import * as TeamActions from 'service/actions/teams'; -import * as RootActions from 'app/actions/views/root'; -import Client from 'service/client'; -import configureStore from 'app/store'; -import {Constants, RequestStatus} from 'service/constants'; -import TestHelper from 'test/test_helper'; - -describe('Actions.Websocket', () => { - let store; - before(async () => { - store = configureStore(); - await TestHelper.initBasic(Client); - const webSocketConnector = require('ws'); - return await Actions.init( - 'ios', - null, - null, - webSocketConnector - )(store.dispatch, store.getState); - }); - - after(async () => { - Actions.close()(); - await TestHelper.basicClient.logout(); - }); - - it('WebSocket Connect', () => { - const ws = store.getState().requests.general.websocket; - assert.ok(ws.status === RequestStatus.SUCCESS); - }); - - it('Websocket Handle New Post', async () => { - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - await client.login(user.email, 'password1'); - - await Client.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id); - - const post = {...TestHelper.fakePost(), channel_id: TestHelper.basicChannel.id}; - await client.createPost(TestHelper.basicTeam.id, post); - - const entities = store.getState().entities; - const {posts, postsByChannel} = entities.posts; - const channelId = TestHelper.basicChannel.id; - const postId = postsByChannel[channelId][0]; - - assert.ok(posts[postId].message.indexOf('Unit Test') > -1); - }); - - it('Websocket Handle Post Edited', async () => { - let post = {...TestHelper.fakePost(), channel_id: TestHelper.basicChannel.id}; - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Client.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id); - - await client.login(user.email, 'password1'); - - post = await client.createPost(TestHelper.basicTeam.id, post); - post.message += ' (edited)'; - - await client.editPost(TestHelper.basicTeam.id, post); - - store.subscribe(async () => { - const entities = store.getState().entities; - const {posts} = entities.posts; - assert.ok(posts[post.id].message.indexOf('(edited)') > -1); - }); - }); - - it('Websocket Handle Post Deleted', async () => { - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await Client.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id); - - await client.login(user.email, 'password1'); - let post = TestHelper.fakePost(); - post.channel_id = TestHelper.basicChannel.id; - post = await client.createPost(TestHelper.basicTeam.id, post); - - await client.deletePost(TestHelper.basicTeam.id, post.channel_id, post.id); - - store.subscribe(async () => { - const entities = store.getState().entities; - const {posts} = entities.posts; - assert.strictEqual(posts[post.id].state, Constants.POST_DELETED); - }); - }); - - it('WebSocket Leave Team', async () => { - const client = TestHelper.createClient(); - const user = await client.createUser(TestHelper.fakeUser()); - await client.login(user.email, 'password1'); - const team = await client.createTeam(TestHelper.fakeTeam()); - const channel = await client.createChannel(TestHelper.fakeChannel(team.id)); - await client.addUserToTeam(team.id, TestHelper.basicUser.id); - await client.addChannelMember(team.id, channel.id, TestHelper.basicUser.id); - - await RootActions.setStoreFromLocalData({ - url: Client.getUrl(), - token: Client.getToken() - })(store.dispatch, store.getState); - await TeamActions.selectTeam(team)(store.dispatch, store.getState); - await ChannelActions.selectChannel(channel.id)(store.dispatch, store.getState); - await client.removeUserFromTeam(team.id, TestHelper.basicUser.id); - - const {myMembers} = store.getState().entities.teams; - assert.ifError(myMembers[team.id]); - }); - - it('Websocket Handle User Added', async () => { - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await TeamActions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - - await ChannelActions.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - const entities = store.getState().entities; - const profilesInChannel = entities.users.profilesInChannel; - assert.ok(profilesInChannel[TestHelper.basicChannel.id].has(user.id)); - }); - - it('Websocket Handle User Removed', async () => { - await TeamActions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - - const user = await TestHelper.basicClient.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await ChannelActions.addChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - await ChannelActions.removeChannelMember( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id, - user.id - )(store.dispatch, store.getState); - - const state = store.getState(); - const entities = state.entities; - const profilesNotInChannel = entities.users.profilesNotInChannel; - - assert.ok(profilesNotInChannel[TestHelper.basicChannel.id].has(user.id)); - }); - - it('Websocket Handle User Updated', async () => { - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await client.login(user.email, 'password1'); - await client.updateUser({...user, first_name: 'tester4'}); - - store.subscribe(() => { - const state = store.getState(); - const entities = state.entities; - const profiles = entities.users.profiles; - - assert.strictEqual(profiles[user.id].first_name, 'tester4'); - }); - }); - - it('Websocket Handle Channel Created', (done) => { - async function test() { - await TeamActions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - const channel = await Client.createChannel(TestHelper.fakeChannel(TestHelper.basicTeam.id)); - - setTimeout(() => { - const state = store.getState(); - const entities = state.entities; - const {channels, myMembers} = entities.channels; - - assert.ok(channels[channel.id]); - assert.ok(myMembers[channel.id]); - done(); - }, 1000); - } - - test(); - }); - - it('Websocket Handle Channel Deleted', (done) => { - async function test() { - await TeamActions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - await ChannelActions.fetchMyChannelsAndMembers(TestHelper.basicTeam.id)(store.dispatch, store.getState); - await ChannelActions.selectChannel(TestHelper.basicChannel.id)(store.dispatch, store.getState); - await Client.deleteChannel( - TestHelper.basicTeam.id, - TestHelper.basicChannel.id - ); - - setTimeout(() => { - const state = store.getState(); - const entities = state.entities; - const {channels, currentId} = entities.channels; - - assert.ok(channels[currentId].name === Constants.DEFAULT_CHANNEL); - done(); - }, 500); - } - - test(); - }); - - it('Websocket Handle Direct Channel', (done) => { - async function test() { - const client = TestHelper.createClient(); - const user = await client.createUserWithInvite( - TestHelper.fakeUser(), - null, - null, - TestHelper.basicTeam.invite_id - ); - - await client.login(user.email, 'password1'); - await TeamActions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); - - setTimeout(() => { - const entities = store.getState().entities; - const {channels} = entities.channels; - assert.ok(Object.keys(channels).length); - done(); - }, 500); - - await client.createDirectChannel(TestHelper.basicTeam.id, TestHelper.basicUser.id); - } - - test(); - }); -}); diff --git a/test/service/selectors/posts.test.js b/test/service/selectors/posts.test.js deleted file mode 100644 index 62819b9da..000000000 --- a/test/service/selectors/posts.test.js +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import {makeGetPostsForThread} from 'service/selectors/entities/posts'; -import deepFreezeAndThrowOnMutation from 'service/utils/deep_freeze'; - -describe('Selectors.Posts', () => { - describe('makeGetPostsForThread', () => { - const posts = { - a: {id: 'a', channel_id: '1'}, - b: {id: 'b', channel_id: '1'}, - c: {id: 'c', root_id: 'a', channel_id: '1'}, - d: {id: 'd', root_id: 'b', channel_id: '1'}, - e: {id: 'e', root_id: 'a', channel_id: '1'}, - f: {id: 'f', channel_id: 'f'} - }; - const testState = deepFreezeAndThrowOnMutation({ - entities: { - posts: { - posts, - postsByChannel: { - 1: ['a', 'b', 'c', 'd', 'e', 'f'] - } - } - } - }); - - it('should return single post with no children', () => { - const getPostsForThread = makeGetPostsForThread(); - - assert.deepEqual(getPostsForThread(testState, {channelId: '1', rootId: 'f'}), [posts.f]); - }); - - it('should return post with children', () => { - const getPostsForThread = makeGetPostsForThread(); - - assert.deepEqual(getPostsForThread(testState, {channelId: '1', rootId: 'a'}), [posts.a, posts.c, posts.e]); - }); - - it('should return memoized result for identical props', () => { - const getPostsForThread = makeGetPostsForThread(); - - const props = {channelId: '1', rootId: 'a'}; - const result = getPostsForThread(testState, props); - - assert.equal(result, getPostsForThread(testState, props)); - }); - - it('should return different result for different props', () => { - const getPostsForThread = makeGetPostsForThread(); - - const result = getPostsForThread(testState, {channelId: '1', rootId: 'a'}); - - assert.notEqual(result, getPostsForThread(testState, {channelId: '1', rootId: 'a'})); - assert.deepEqual(result, getPostsForThread(testState, {channelId: '1', rootId: 'a'})); - }); - - it('should return memoized result for multiple selectors with different props', () => { - const getPostsForThread1 = makeGetPostsForThread(); - const getPostsForThread2 = makeGetPostsForThread(); - - const props1 = {channelId: '1', rootId: 'a'}; - const result1 = getPostsForThread1(testState, props1); - - const props2 = {channelId: '1', rootId: 'b'}; - const result2 = getPostsForThread2(testState, props2); - - assert.equal(result1, getPostsForThread1(testState, props1)); - assert.equal(result2, getPostsForThread2(testState, props2)); - }); - }); -}); diff --git a/test/service/selectors/preferences.test.js b/test/service/selectors/preferences.test.js deleted file mode 100644 index 5ed66c2cb..000000000 --- a/test/service/selectors/preferences.test.js +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import Config from 'assets/config.json'; -import Themes from 'assets/themes.json'; - -import {Preferences} from 'service/constants'; -import {getTheme} from 'service/selectors/entities/preferences'; - -describe('Selectors.Preferences', () => { - it('getTheme', () => { - it('should return default theme', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '' - }, - preferences: { - myPreferences: {} - } - } - }), - typeof Config.DefaultTheme === 'string' ? Themes[Config.DefaultTheme] : Config.DefaultTheme - ); - }); - - it('should return global theme by name', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: 'mattermost'} - } - } - } - }), - Themes.mattermost - ); - }); - - it('should return global custom theme', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: '{"sidebarBg": "#ff0000"}'} - } - } - } - }), - {sidebarBg: '#ff0000'} - ); - }); - - it('should return global theme by name when on team', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '1234' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: 'mattermost'} - } - } - } - }), - Themes.mattermost - ); - }); - - it('should return global custom theme when on team', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '1234' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: '{"sidebarBg": "#ff0000"}'} - } - } - } - }), - {sidebarBg: '#ff0000'} - ); - }); - - it('should return team-specific theme by name when on team', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '1234' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: 'mattermost'}, - [`${Preferences.CATEGORY_THEME}--1234`]: {value: 'mattermostDark'} - } - } - } - }), - Themes.mattermostDark - ); - }); - - it('should return team-specific custom theme when on team', () => { - assert.deepEqual( - getTheme({ - entities: { - teams: { - currentId: '1234' - }, - preferences: { - myPreferences: { - [`${Preferences.CATEGORY_THEME}--`]: {value: '{"sidebarBg": "#ff0000"}'}, - [`${Preferences.CATEGORY_THEME}--1234`]: {value: '{"sidebarBg": "#00ff00"}'} - } - } - } - }), - {sidebarBg: '#00ff00'} - ); - }); - }); -}); diff --git a/test/test_helper.js b/test/test_helper.js index 6057b24e2..c25fe3a45 100644 --- a/test/test_helper.js +++ b/test/test_helper.js @@ -5,7 +5,7 @@ import assert from 'assert'; import Config from 'assets/config.json'; -import Client from 'service/client/client'; +import Client from 'mattermost-redux/client/client'; const PASSWORD = 'password1'; diff --git a/test/utils/post_utils.test.js b/test/utils/post_utils.test.js deleted file mode 100644 index 4f0a8f5bd..000000000 --- a/test/utils/post_utils.test.js +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import assert from 'assert'; - -import {addDatesToPostList} from 'service/utils/post_utils'; - -describe('addDatesToPostList', () => { - it('single post', () => { - const input = [{create_at: 1486533600000}]; - - const output = addDatesToPostList(input); - - assert.notEqual(input, output); - assert.deepEqual(output, [ - input[0], - new Date(input[0].create_at) - ]); - }); - - it('two posts on same day', () => { - const input = [ - {create_at: 1486533600000}, - {create_at: 1486533601000} - ]; - - const output = addDatesToPostList(input); - - assert.notEqual(input, output); - assert.deepEqual(output, [ - input[0], - input[1], - new Date(input[1].create_at) - ]); - }); - - it('two posts on different days', () => { - const input = [ - {create_at: 1486533600000}, - {create_at: 1486620000000} - ]; - - const output = addDatesToPostList(input); - - assert.notEqual(input, output); - assert.deepEqual(output, [ - input[0], - new Date(input[0].create_at), - input[1], - new Date(input[1].create_at) - ]); - }); - - it('multiple posts', () => { - const input = [ - {create_at: 1486533600000}, - {create_at: 1486533601000}, - {create_at: 1486620000000}, - {create_at: 1486706400000}, - {create_at: 1486706401000} - ]; - - const output = addDatesToPostList(input); - - assert.notEqual(input, output); - assert.deepEqual(output, [ - input[0], - input[1], - new Date(input[1].create_at), - input[2], - new Date(input[2].create_at), - input[3], - input[4], - new Date(input[4].create_at) - ]); - }); -});