diff options
Diffstat (limited to 'webapp/actions')
-rw-r--r-- | webapp/actions/channel_actions.jsx | 137 | ||||
-rw-r--r-- | webapp/actions/emoji_actions.jsx | 46 | ||||
-rw-r--r-- | webapp/actions/global_actions.jsx | 23 | ||||
-rw-r--r-- | webapp/actions/integration_actions.jsx | 114 | ||||
-rw-r--r-- | webapp/actions/post_actions.jsx | 153 | ||||
-rw-r--r-- | webapp/actions/status_actions.jsx | 133 | ||||
-rw-r--r-- | webapp/actions/team_actions.jsx | 25 | ||||
-rw-r--r-- | webapp/actions/user_actions.jsx | 244 | ||||
-rw-r--r-- | webapp/actions/websocket_actions.jsx | 62 |
9 files changed, 884 insertions, 53 deletions
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx index ed8e00db6..8364fe9b6 100644 --- a/webapp/actions/channel_actions.jsx +++ b/webapp/actions/channel_actions.jsx @@ -1,18 +1,26 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {browserHistory} from 'react-router/es6'; -import * as Utils from 'utils/utils.jsx'; +import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; + import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; import ChannelStore from 'stores/channel_store.jsx'; +import PreferenceStore from 'stores/preference_store.jsx'; + +import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; + +import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import * as UserAgent from 'utils/user_agent.jsx'; -import Client from 'client/web_client.jsx'; +import * as Utils from 'utils/utils.jsx'; +import {Preferences, ActionTypes} from 'utils/constants.jsx'; + +import {browserHistory} from 'react-router/es6'; export function goToChannel(channel) { if (channel.fake) { - Utils.openDirectChannelToUser( + openDirectChannelToUser( UserStore.getProfileByUsername(channel.display_name), () => { browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name); @@ -53,3 +61,124 @@ export function setChannelAsRead(channelIdParam) { ChannelStore.emitLastViewed(Number.MAX_VALUE, false); } } + +export function addUserToChannel(channelId, userId, success, error) { + Client.addChannelMember( + channelId, + userId, + (data) => { + UserStore.removeProfileNotInChannel(channelId, userId); + const profile = UserStore.getProfile(userId); + if (profile) { + UserStore.saveProfileInChannel(channelId, profile); + UserStore.emitInChannelChange(); + } + UserStore.emitNotInChannelChange(); + + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'addChannelMember'); + + if (error) { + error(err); + } + } + ); +} + +export function removeUserFromChannel(channelId, userId, success, error) { + Client.removeChannelMember( + channelId, + userId, + (data) => { + UserStore.removeProfileInChannel(channelId, userId); + const profile = UserStore.getProfile(userId); + if (profile) { + UserStore.saveProfileNotInChannel(channelId, profile); + UserStore.emitNotInChannelChange(); + } + UserStore.emitInChannelChange(); + + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'removeChannelMember'); + + if (error) { + error(err); + } + } + ); +} + +export function openDirectChannelToUser(user, success, error) { + const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), user.id); + let channel = ChannelStore.getByName(channelName); + + if (channel) { + PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true'); + loadProfilesAndTeamMembersForDMSidebar(); + + AsyncClient.savePreference( + Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, + user.id, + 'true' + ); + + if (success) { + success(channel, true); + } + + return; + } + + channel = { + name: channelName, + last_post_at: 0, + total_msg_count: 0, + type: 'D', + display_name: user.username, + teammate_id: user.id, + status: UserStore.getStatus(user.id) + }; + + Client.createDirectChannel( + user.id, + (data) => { + Client.getChannel( + data.id, + (data2) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_CHANNEL, + channel: data2.channel, + member: data2.member + }); + + PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true'); + loadProfilesAndTeamMembersForDMSidebar(); + + AsyncClient.savePreference( + Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, + user.id, + 'true' + ); + + if (success) { + success(data2.channel, false); + } + } + ); + }, + () => { + browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/' + channelName); + if (error) { + error(); + } + } + ); +} diff --git a/webapp/actions/emoji_actions.jsx b/webapp/actions/emoji_actions.jsx new file mode 100644 index 000000000..128a9325a --- /dev/null +++ b/webapp/actions/emoji_actions.jsx @@ -0,0 +1,46 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; + +import UserStore from 'stores/user_store.jsx'; + +import * as AsyncClient from 'utils/async_client.jsx'; +import Client from 'client/web_client.jsx'; + +import {ActionTypes} from 'utils/constants.jsx'; + +export function loadEmoji(getProfiles = true) { + Client.listEmoji( + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_CUSTOM_EMOJIS, + emojis: data + }); + + if (getProfiles) { + loadProfilesForEmoji(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'listEmoji'); + } + ); +} + +function loadProfilesForEmoji(emojiList) { + const profilesToLoad = {}; + for (let i = 0; i < emojiList.length; i++) { + const emoji = emojiList[i]; + if (!UserStore.hasProfile(emoji.creator_id)) { + profilesToLoad[emoji.creator_id] = true; + } + } + + const list = Object.keys(profilesToLoad); + if (list.length === 0) { + return; + } + + AsyncClient.getProfilesByIds(list); +} diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index 941aa34f4..23ff5a295 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -12,7 +12,8 @@ import TeamStore from 'stores/team_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import SearchStore from 'stores/search_store.jsx'; -import {handleNewPost} from 'actions/post_actions.jsx'; +import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.jsx'; +import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; import Constants from 'utils/constants.jsx'; const ActionTypes = Constants.ActionTypes; @@ -43,9 +44,9 @@ export function emitChannelClickEvent(channel) { function switchToChannel(chan) { AsyncClient.getChannels(true); AsyncClient.getMoreChannels(true); - AsyncClient.getChannelExtraInfo(chan.id); + AsyncClient.getChannelStats(chan.id); AsyncClient.updateLastViewedAt(chan.id); - AsyncClient.getPosts(chan.id); + loadPosts(chan.id); trackPage(); AppDispatcher.handleViewAction({ @@ -108,7 +109,7 @@ export function emitInitialLoad(callback) { if (data.team_members) { AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_TEAM_MEMBERS, + type: ActionTypes.RECEIVED_MY_TEAM_MEMBERS, team_members: data.team_members }); } @@ -143,9 +144,9 @@ export function doFocusPost(channelId, postId, data) { }); AsyncClient.getChannels(true); AsyncClient.getMoreChannels(true); - AsyncClient.getChannelExtraInfo(channelId); - AsyncClient.getPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true); - AsyncClient.getPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true); + AsyncClient.getChannelStats(channelId); + loadPostsBefore(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true); + loadPostsAfter(postId, 0, Constants.POST_FOCUS_CONTEXT_RADIUS, true); } export function emitPostFocusEvent(postId, onSuccess) { @@ -246,14 +247,14 @@ export function emitLoadMorePostsFocusedTopEvent() { export function loadMorePostsTop(id, isFocusPost) { const earliestPostId = PostStore.getEarliestPost(id).id; if (PostStore.requestVisibilityIncrease(id, Constants.POST_CHUNK_SIZE)) { - AsyncClient.getPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost); + loadPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost); } } export function emitLoadMorePostsFocusedBottomEvent() { const id = PostStore.getFocusedPostId(); const latestPostId = PostStore.getLatestPost(id).id; - AsyncClient.getPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, Boolean(id)); + loadPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, Boolean(id)); } export function emitUserPostedEvent(post) { @@ -362,7 +363,7 @@ export function emitClearSuggestions(suggestionId) { export function emitPreferenceChangedEvent(preference) { if (preference.category === Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW) { - AsyncClient.getDirectProfiles(); + loadProfilesAndTeamMembersForDMSidebar(); } AppDispatcher.handleServerAction({ @@ -437,7 +438,7 @@ export function loadDefaultLocale() { export function viewLoggedIn() { AsyncClient.getChannels(); AsyncClient.getMoreChannels(); - AsyncClient.getChannelExtraInfo(); + AsyncClient.getChannelStats(); // Clear pending posts (shouldn't have pending posts if we are loading) PostStore.clearPendingPosts(); diff --git a/webapp/actions/integration_actions.jsx b/webapp/actions/integration_actions.jsx new file mode 100644 index 000000000..5fd2b024d --- /dev/null +++ b/webapp/actions/integration_actions.jsx @@ -0,0 +1,114 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; + +import TeamStore from 'stores/team_store.jsx'; +import UserStore from 'stores/user_store.jsx'; + +import * as AsyncClient from 'utils/async_client.jsx'; +import Client from 'client/web_client.jsx'; + +import {ActionTypes} from 'utils/constants.jsx'; + +export function loadIncomingHooks() { + Client.listIncomingHooks( + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_INCOMING_WEBHOOKS, + teamId: TeamStore.getCurrentId(), + incomingWebhooks: data + }); + + loadProfilesForIncomingHooks(data); + }, + (err) => { + AsyncClient.dispatchError(err, 'listIncomingHooks'); + } + ); +} + +function loadProfilesForIncomingHooks(hooks) { + const profilesToLoad = {}; + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + if (!UserStore.hasProfile(hook.user_id)) { + profilesToLoad[hook.user_id] = true; + } + } + + const list = Object.keys(profilesToLoad); + if (list.length === 0) { + return; + } + + AsyncClient.getProfilesByIds(list); +} + +export function loadOutgoingHooks() { + Client.listOutgoingHooks( + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_OUTGOING_WEBHOOKS, + teamId: TeamStore.getCurrentId(), + outgoingWebhooks: data + }); + + loadProfilesForOutgoingHooks(data); + }, + (err) => { + AsyncClient.dispatchError(err, 'listOutgoingHooks'); + } + ); +} + +function loadProfilesForOutgoingHooks(hooks) { + const profilesToLoad = {}; + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + if (!UserStore.hasProfile(hook.creator_id)) { + profilesToLoad[hook.creator_id] = true; + } + } + + const list = Object.keys(profilesToLoad); + if (list.length === 0) { + return; + } + + AsyncClient.getProfilesByIds(list); +} + +export function loadTeamCommands() { + Client.listTeamCommands( + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_COMMANDS, + teamId: Client.teamId, + commands: data + }); + + loadProfilesForCommands(data); + }, + (err) => { + AsyncClient.dispatchError(err, 'loadTeamCommands'); + } + ); +} + +function loadProfilesForCommands(commands) { + const profilesToLoad = {}; + for (let i = 0; i < commands.length; i++) { + const command = commands[i]; + if (!UserStore.hasProfile(command.creator_id)) { + profilesToLoad[command.creator_id] = true; + } + } + + const list = Object.keys(profilesToLoad); + if (list.length === 0) { + return; + } + + AsyncClient.getProfilesByIds(list); +} diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx index 63e3feec5..462576021 100644 --- a/webapp/actions/post_actions.jsx +++ b/webapp/actions/post_actions.jsx @@ -8,6 +8,8 @@ import PostStore from 'stores/post_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; +import {loadStatusesForChannel} from 'actions/status_actions.jsx'; + import * as PostUtils from 'utils/post_utils.jsx'; import Client from 'client/web_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; @@ -52,6 +54,8 @@ export function handleNewPost(post, msg) { post, websocketMessageProps }); + + loadProfilesForPosts(data.posts); }, (err) => { AsyncClient.dispatchError(err, 'getPost'); @@ -115,7 +119,7 @@ export function setUnreadPost(channelId, postId) { member.last_viewed_at = lastViewed; member.msg_count = channel.total_msg_count - unreadPosts; member.mention_count = 0; - ChannelStore.setChannelMember(member); + ChannelStore.storeMyChannelMember(member); ChannelStore.setUnreadCount(channelId); AsyncClient.setLastViewedAt(lastViewed, channelId); } @@ -153,9 +157,156 @@ export function getFlaggedPosts() { results: data, is_flagged_posts: true }); + + loadProfilesForPosts(data.posts); }, (err) => { AsyncClient.dispatchError(err, 'getFlaggedPosts'); } ); } + +export function loadPosts(channelId = ChannelStore.getCurrentId()) { + const postList = PostStore.getAllPosts(channelId); + const latestPostTime = PostStore.getLatestPostFromPageTime(channelId); + + if (!postList || Object.keys(postList).length === 0 || postList.order.length < Constants.POST_CHUNK_SIZE || latestPostTime === 0) { + loadPostsPage(channelId, Constants.POST_CHUNK_SIZE); + return; + } + + Client.getPosts( + channelId, + latestPostTime, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_POSTS, + id: channelId, + before: true, + numRequested: 0, + post_list: data + }); + + loadProfilesForPosts(data.posts); + loadStatusesForChannel(channelId); + }, + (err) => { + AsyncClient.dispatchError(err, 'loadPosts'); + } + ); +} + +export function loadPostsPage(channelId = ChannelStore.getCurrentId(), max = Constants.POST_CHUNK_SIZE) { + const postList = PostStore.getAllPosts(channelId); + + // if we already have more than POST_CHUNK_SIZE posts, + // let's get the amount we have but rounded up to next multiple of POST_CHUNK_SIZE, + // with a max + let numPosts = Math.min(max, Constants.POST_CHUNK_SIZE); + if (postList && postList.order.length > 0) { + numPosts = Math.min(max, Constants.POST_CHUNK_SIZE * Math.ceil(postList.order.length / Constants.POST_CHUNK_SIZE)); + } + + Client.getPostsPage( + channelId, + 0, + numPosts, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_POSTS, + id: channelId, + before: true, + numRequested: numPosts, + checkLatest: true, + post_list: data + }); + + loadProfilesForPosts(data.posts); + loadStatusesForChannel(channelId); + }, + (err) => { + AsyncClient.dispatchError(err, 'loadPostsPage'); + } + ); +} + +export function loadPostsBefore(postId, offset, numPost, isPost) { + const channelId = ChannelStore.getCurrentId(); + if (channelId == null) { + return; + } + + Client.getPostsBefore( + channelId, + postId, + offset, + numPost, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_POSTS, + id: channelId, + before: true, + numRequested: numPost, + post_list: data, + isPost + }); + + loadProfilesForPosts(data.posts); + loadStatusesForChannel(channelId); + }, + (err) => { + AsyncClient.dispatchError(err, 'loadPostsBefore'); + } + ); +} + +export function loadPostsAfter(postId, offset, numPost, isPost) { + const channelId = ChannelStore.getCurrentId(); + if (channelId == null) { + return; + } + + Client.getPostsAfter( + channelId, + postId, + offset, + numPost, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_POSTS, + id: channelId, + before: false, + numRequested: numPost, + post_list: data, + isPost + }); + + loadProfilesForPosts(data.posts); + loadStatusesForChannel(channelId); + }, + (err) => { + AsyncClient.dispatchError(err, 'loadPostsAfter'); + } + ); +} + +function loadProfilesForPosts(posts) { + const profilesToLoad = {}; + for (const pid in posts) { + if (!posts.hasOwnProperty(pid)) { + continue; + } + + const post = posts[pid]; + if (!UserStore.hasProfile(post.user_id)) { + profilesToLoad[post.user_id] = true; + } + } + + const list = Object.keys(profilesToLoad); + if (list.length === 0) { + return; + } + + AsyncClient.getProfilesByIds(list); +} diff --git a/webapp/actions/status_actions.jsx b/webapp/actions/status_actions.jsx new file mode 100644 index 000000000..c198c52ac --- /dev/null +++ b/webapp/actions/status_actions.jsx @@ -0,0 +1,133 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; + +import ChannelStore from 'stores/channel_store.jsx'; +import PostStore from 'stores/post_store.jsx'; +import PreferenceStore from 'stores/preference_store.jsx'; + +import Client from 'client/web_client.jsx'; + +import {ActionTypes, Preferences, Constants} from 'utils/constants.jsx'; + +export function loadStatusesForChannel(channelId = ChannelStore.getCurrentId()) { + const postList = PostStore.getVisiblePosts(channelId); + if (!postList || !postList.posts) { + return; + } + + const statusesToLoad = {}; + for (const pid in postList.posts) { + if (!postList.posts.hasOwnProperty(pid)) { + continue; + } + + const post = postList.posts[pid]; + statusesToLoad[post.user_id] = true; + } + + loadStatusesByIds(Object.keys(statusesToLoad)); +} + +export function loadStatusesForDMSidebar() { + const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW); + const statusesToLoad = []; + + for (const [key, value] of dmPrefs) { + if (value === 'true') { + statusesToLoad.push(key); + } + } + + loadStatusesByIds(statusesToLoad); +} + +export function loadStatusesForChannelAndSidebar() { + const statusesToLoad = {}; + + const channelId = ChannelStore.getCurrentId(); + const postList = PostStore.getVisiblePosts(channelId); + if (postList && postList.posts) { + for (const pid in postList.posts) { + if (!postList.posts.hasOwnProperty(pid)) { + continue; + } + + const post = postList.posts[pid]; + statusesToLoad[post.user_id] = true; + } + } + + const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW); + + for (const [key, value] of dmPrefs) { + if (value === 'true') { + statusesToLoad[key] = true; + } + } + + loadStatusesByIds(Object.keys(statusesToLoad)); +} + +export function loadStatusesForProfilesList(users) { + if (users == null) { + return; + } + + const statusesToLoad = []; + for (let i = 0; i < users.length; i++) { + statusesToLoad.push(users[i].id); + } + + loadStatusesByIds(statusesToLoad); +} + +export function loadStatusesForProfilesMap(users) { + if (users == null) { + return; + } + + const statusesToLoad = []; + for (const userId in users) { + if (!users.hasOwnProperty(userId)) { + return; + } + statusesToLoad.push(userId); + } + + loadStatusesByIds(statusesToLoad); +} + +export function loadStatusesByIds(userIds) { + if (userIds.length === 0) { + return; + } + + Client.getStatusesByIds( + userIds, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_STATUSES, + statuses: data + }); + } + ); +} + +let intervalId = ''; + +export function startPeriodicStatusUpdates() { + clearInterval(intervalId); + + intervalId = setInterval( + () => { + loadStatusesForChannelAndSidebar(); + }, + Constants.STATUS_INTERVAL + ); +} + +export function stopPeriodicStatusUpdates() { + clearInterval(intervalId); +} diff --git a/webapp/actions/team_actions.jsx b/webapp/actions/team_actions.jsx index 3bf25c193..e0403529e 100644 --- a/webapp/actions/team_actions.jsx +++ b/webapp/actions/team_actions.jsx @@ -2,6 +2,7 @@ // See License.txt for license information. import UserStore from 'stores/user_store.jsx'; +import TeamStore from 'stores/team_store.jsx'; import Constants from 'utils/constants.jsx'; const ActionTypes = Constants.ActionTypes; @@ -19,8 +20,6 @@ export function checkIfTeamExists(teamName, onSuccess, onError) { export function createTeam(team, onSuccess, onError) { Client.createTeam(team, (rteam) => { - AsyncClient.getDirectProfiles(); - AppDispatcher.handleServerAction({ type: ActionTypes.CREATED_TEAM, team: rteam, @@ -36,3 +35,25 @@ export function createTeam(team, onSuccess, onError) { onError ); } + +export function removeUserFromTeam(teamId, userId, success, error) { + Client.removeUserFromTeam( + teamId, + userId, + () => { + TeamStore.removeMemberInTeam(teamId, userId); + AsyncClient.getUser(userId); + + if (success) { + success(); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'removeUserFromTeam'); + + if (error) { + error(err); + } + } + ); +} diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx index 2d5fd805c..900353701 100644 --- a/webapp/actions/user_actions.jsx +++ b/webapp/actions/user_actions.jsx @@ -2,12 +2,17 @@ // See License.txt for license information. import AppDispatcher from 'dispatcher/app_dispatcher.jsx'; -import * as AsyncClient from 'utils/async_client.jsx'; -import Client from 'client/web_client.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import UserStore from 'stores/user_store.jsx'; +import ChannelStore from 'stores/channel_store.jsx'; + +import {loadStatusesForProfilesList, loadStatusesForProfilesMap} from 'actions/status_actions.jsx'; + +import {getDirectChannelName} from 'utils/utils.jsx'; +import * as AsyncClient from 'utils/async_client.jsx'; +import Client from 'client/web_client.jsx'; import {ActionTypes, Preferences} from 'utils/constants.jsx'; @@ -29,9 +34,179 @@ export function switchFromLdapToEmail(email, password, ldapPassword, onSuccess, ); } -export function getMoreDmList() { - AsyncClient.getTeamMembers(TeamStore.getCurrentId()); - AsyncClient.getProfilesForDirectMessageList(); +export function loadProfilesAndTeamMembers(offset, limit, teamId = TeamStore.getCurrentId(), success, error) { + Client.getProfilesInTeam( + teamId, + offset, + limit, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_PROFILES_IN_TEAM, + profiles: data, + team_id: teamId, + offset, + count: Object.keys(data).length + }); + + loadTeamMembersForProfilesMap(data, teamId, success, error); + loadStatusesForProfilesMap(data); + }, + (err) => { + AsyncClient.dispatchError(err, 'getProfilesInTeam'); + } + ); +} + +export function loadTeamMembersForProfilesMap(profiles, teamId = TeamStore.getCurrentId(), success, error) { + const membersToLoad = {}; + for (const pid in profiles) { + if (!profiles.hasOwnProperty(pid)) { + continue; + } + + if (!TeamStore.hasActiveMemberInTeam(teamId, pid)) { + membersToLoad[pid] = true; + } + } + + const list = Object.keys(membersToLoad); + if (list.length === 0) { + if (success) { + success({}); + } + return; + } + + loadTeamMembersForProfiles(list, teamId, success, error); +} + +export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getCurrentId(), success, error) { + const membersToLoad = {}; + for (let i = 0; i < profiles.length; i++) { + const pid = profiles[i].id; + + if (!TeamStore.hasActiveMemberInTeam(teamId, pid)) { + membersToLoad[pid] = true; + } + } + + const list = Object.keys(membersToLoad); + if (list.length === 0) { + if (success) { + success({}); + } + return; + } + + loadTeamMembersForProfiles(list, teamId, success, error); +} + +function loadTeamMembersForProfiles(userIds, teamId, success, error) { + Client.getTeamMembersByIds( + teamId, + userIds, + (data) => { + const memberMap = {}; + for (let i = 0; i < data.length; i++) { + memberMap[data[i].user_id] = data[i]; + } + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM, + team_id: teamId, + team_members: memberMap + }); + + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'getTeamMembersByIds'); + + if (error) { + error(err); + } + } + ); +} + +function populateDMChannelsWithProfiles(userIds) { + const currentUserId = UserStore.getCurrentId(); + + for (let i = 0; i < userIds.length; i++) { + const channelName = getDirectChannelName(currentUserId, userIds[i]); + const channel = ChannelStore.getByName(channelName); + if (channel) { + UserStore.saveUserIdInChannel(channel.id, userIds[i]); + } + } +} + +export function loadProfilesAndTeamMembersForDMSidebar() { + const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW); + const teamId = TeamStore.getCurrentId(); + const profilesToLoad = []; + const membersToLoad = []; + + for (const [key, value] of dmPrefs) { + if (value === 'true') { + if (!UserStore.hasProfile(key)) { + profilesToLoad.push(key); + } + membersToLoad.push(key); + } + } + + if (profilesToLoad.length > 0) { + Client.getProfilesByIds( + profilesToLoad, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_PROFILES, + profiles: data + }); + + // Use membersToLoad so we get all the DM profiles even if they were already loaded + populateDMChannelsWithProfiles(membersToLoad); + }, + (err) => { + AsyncClient.dispatchError(err, 'getProfilesByIds'); + } + ); + } else { + populateDMChannelsWithProfiles(membersToLoad); + } + + if (membersToLoad.length > 0) { + Client.getTeamMembersByIds( + teamId, + membersToLoad, + (data) => { + const memberMap = {}; + for (let i = 0; i < data.length; i++) { + memberMap[data[i].user_id] = data[i]; + } + + const nonMembersMap = {}; + for (let i = 0; i < membersToLoad.length; i++) { + if (!memberMap[membersToLoad[i]]) { + nonMembersMap[membersToLoad[i]] = true; + } + } + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM, + team_id: teamId, + team_members: memberMap, + non_team_members: nonMembersMap + }); + }, + (err) => { + AsyncClient.dispatchError(err, 'getTeamMembersByIds'); + } + ); + } } export function saveTheme(teamId, theme, onSuccess, onError) { @@ -82,3 +257,62 @@ function onThemeSaved(teamId, theme, onSuccess) { onSuccess(); } + +export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) { + Client.searchUsers( + term, + teamId, + options, + (data) => { + loadStatusesForProfilesList(data); + + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'searchUsers'); + + if (error) { + error(err); + } + } + ); +} + +export function autocompleteUsersInChannel(username, channelId, success, error) { + Client.autocompleteUsersInChannel( + username, + channelId, + (data) => { + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'autocompleteUsersInChannel'); + + if (error) { + error(err); + } + } + ); +} + +export function autocompleteUsersInTeam(username, success, error) { + Client.autocompleteUsersInTeam( + username, + (data) => { + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'autocompleteUsersInTeam'); + + if (error) { + error(err); + } + } + ); +} diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index 08449b87e..14a150692 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -3,8 +3,6 @@ import $ from 'jquery'; -import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; - import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; import PostStore from 'stores/post_store.jsx'; @@ -20,10 +18,11 @@ import * as Utils from 'utils/utils.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; -import * as UserActions from 'actions/user_actions.jsx'; -import {handleNewPost} from 'actions/post_actions.jsx'; +import {handleNewPost, loadPosts} from 'actions/post_actions.jsx'; +import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; +import * as StatusActions from 'actions/status_actions.jsx'; -import {Constants, SocketEvents, ActionTypes} from 'utils/constants.jsx'; +import {Constants, SocketEvents, UserStatuses} from 'utils/constants.jsx'; import {browserHistory} from 'react-router/es6'; @@ -53,6 +52,7 @@ export function initialize() { connUrl += Client.getUsersRoute() + '/websocket'; WebSocketClient.setEventCallback(handleEvent); + WebSocketClient.setFirstConnectCallback(handleFirstConnect); WebSocketClient.setReconnectCallback(handleReconnect); WebSocketClient.setCloseCallback(handleClose); WebSocketClient.initialize(connUrl); @@ -64,22 +64,19 @@ export function close() { } export function getStatuses() { - WebSocketClient.getStatuses( - (resp) => { - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_STATUSES, - statuses: resp.data - }); - } - ); + StatusActions.loadStatusesForChannelAndSidebar(); +} + +function handleFirstConnect() { + getStatuses(); + ErrorStore.clearLastError(); + ErrorStore.emitChange(); } function handleReconnect() { if (Client.teamId) { AsyncClient.getChannels(); - AsyncClient.getPosts(ChannelStore.getCurrentId()); - AsyncClient.getTeamMembers(TeamStore.getCurrentId()); - AsyncClient.getProfiles(); + loadPosts(ChannelStore.getCurrentId()); } getStatuses(); @@ -112,7 +109,7 @@ function handleEvent(msg) { break; case SocketEvents.NEW_USER: - handleNewUserEvent(); + handleNewUserEvent(msg); break; case SocketEvents.LEAVE_TEAM: @@ -170,6 +167,10 @@ function handleEvent(msg) { function handleNewPostEvent(msg) { const post = JSON.parse(msg.data.post); handleNewPost(post, msg); + + if (UserStore.getStatus(post.user_id) !== UserStatuses.ONLINE) { + StatusActions.loadStatusesByIds([post.user_id]); + } } function handlePostEditEvent(msg) { @@ -196,36 +197,33 @@ function handlePostDeleteEvent(msg) { } } -function handleNewUserEvent() { - AsyncClient.getTeamMembers(TeamStore.getCurrentId()); - AsyncClient.getProfiles(); - AsyncClient.getDirectProfiles(); - AsyncClient.getChannelExtraInfo(); +function handleNewUserEvent(msg) { + AsyncClient.getUser(msg.user_id); + AsyncClient.getChannelStats(); + loadProfilesAndTeamMembersForDMSidebar(); } function handleLeaveTeamEvent(msg) { if (UserStore.getCurrentId() === msg.data.user_id) { - TeamStore.removeTeamMember(msg.broadcast.team_id); + TeamStore.removeMyTeamMember(msg.broadcast.team_id); - // if the are on the team begin removed redirect them to the root + // if they are on the team being removed redirect them to the root if (TeamStore.getCurrentId() === msg.broadcast.team_id) { TeamStore.setCurrentId(''); Client.setTeamId(''); browserHistory.push('/'); } - } else if (TeamStore.getCurrentId() === msg.broadcast.team_id) { - UserActions.getMoreDmList(); } } function handleDirectAddedEvent(msg) { AsyncClient.getChannel(msg.broadcast.channel_id); - AsyncClient.getDirectProfiles(); + loadProfilesAndTeamMembersForDMSidebar(); } function handleUserAddedEvent(msg) { if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) { - AsyncClient.getChannelExtraInfo(); + AsyncClient.getChannelStats(); } if (TeamStore.getCurrentId() === msg.data.team_id && UserStore.getCurrentId() === msg.data.user_id) { @@ -248,7 +246,7 @@ function handleUserRemovedEvent(msg) { $('#removed_from_channel').modal('show'); } } else if (ChannelStore.getCurrentId() === msg.broadcast.channel_id) { - AsyncClient.getChannelExtraInfo(); + AsyncClient.getChannelStats(); } } @@ -287,6 +285,10 @@ function handlePreferenceChangedEvent(msg) { function handleUserTypingEvent(msg) { GlobalActions.emitRemoteUserTypingEvent(msg.broadcast.channel_id, msg.data.user_id, msg.data.parent_id); + + if (UserStore.getStatus(msg.data.user_id) !== UserStatuses.ONLINE) { + StatusActions.loadStatusesByIds([msg.data.user_id]); + } } function handleStatusChangedEvent(msg) { @@ -301,4 +303,4 @@ function handleHelloEvent(msg) { function handleWebrtc(msg) { const data = msg.data; return WebrtcActions.handle(data); -}
\ No newline at end of file +} |