From b1474a37b7153d53f95ec6f212abaaaf86dcdccf Mon Sep 17 00:00:00 2001 From: enahum Date: Thu, 8 Dec 2016 18:01:55 -0300 Subject: [PATCH] Include team to the store (#103) * Include team to the store * addressing feedback * Fix getTeamMember --- src/actions/teams.js | 167 +++++++++++++++++- src/actions/users.js | 3 +- src/client/client.js | 76 ++++++--- src/constants/constants.js | 3 + src/constants/teams.js | 34 ++++ src/reducers/entities/teams.js | 82 +++++++-- src/reducers/requests/helpers.js | 1 - src/reducers/requests/teams.js | 90 +++++++++- test/actions/teams.test.js | 283 ++++++++++++++++++++++++++++++- test/actions/users.test.js | 1 - 10 files changed, 691 insertions(+), 49 deletions(-) diff --git a/src/actions/teams.js b/src/actions/teams.js index 6689158eb..0cf84cff6 100644 --- a/src/actions/teams.js +++ b/src/actions/teams.js @@ -1,15 +1,16 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import {bindClientFunc} from './helpers.js'; import Client from 'client'; -import {TeamsTypes} from 'constants'; +import {batchActions} from 'redux-batched-actions'; +import {Constants, TeamsTypes} from 'constants'; +import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; export function selectTeam(team) { return async (dispatch, getState) => { dispatch({ type: TeamsTypes.SELECT_TEAM, - teamId: team.id + data: team.id }, getState); }; } @@ -22,3 +23,163 @@ export function fetchTeams() { 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) => { + try { + dispatch({type: TeamsTypes.CREATE_TEAM_REQUEST}, getState); + const created = await Client.createTeam(team); + 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_MEMBER, + data: member + }, + { + type: TeamsTypes.SELECT_TEAM, + data: created.id + }, + { + type: TeamsTypes.CREATE_TEAM_SUCCESS + } + ]), getState); + } catch (err) { + forceLogoutIfNecessary(err, dispatch); + dispatch({type: TeamsTypes.CREATE_TEAM_FAILURE, error: err}, 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) => { + try { + dispatch({type: TeamsTypes.TEAM_MEMBERS_REQUEST}, getState); + const member = await Client.getTeamMember(teamId, userId); + dispatch(batchActions([ + { + type: TeamsTypes.RECEIVED_MEMBERS_IN_TEAM, + data: [member] + }, + { + type: TeamsTypes.TEAM_MEMBERS_SUCCESS + } + ]), getState); + } catch (error) { + forceLogoutIfNecessary(error, dispatch); + dispatch({type: TeamsTypes.TEAM_MEMBERS_FAILURE, error}, getState); + } + }; +} + +export function getTeamMembersByIds(teamId, userIds) { + return bindClientFunc( + Client.getTeamMemberByIds, + TeamsTypes.TEAM_MEMBERS_REQUEST, + [TeamsTypes.RECEIVED_MEMBERS_IN_TEAM, TeamsTypes.TEAM_MEMBERS_SUCCESS], + TeamsTypes.TEAM_MEMBERS_FAILURE, + teamId, + userIds + ); +} + +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) => { + try { + dispatch({type: TeamsTypes.ADD_TEAM_MEMBER_REQUEST}, getState); + await Client.addUserToTeam(teamId, userId); + 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); + } catch (err) { + forceLogoutIfNecessary(err, dispatch); + dispatch({type: TeamsTypes.ADD_TEAM_MEMBER_FAILURE, error: err}, getState); + } + }; +} + +export function removeUserFromTeam(teamId, userId) { + return async (dispatch, getState) => { + try { + dispatch({type: TeamsTypes.REMOVE_TEAM_MEMBER_REQUEST}, getState); + await Client.removeUserFromTeam(teamId, userId); + 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); + } catch (err) { + forceLogoutIfNecessary(err, dispatch); + dispatch({type: TeamsTypes.REMOVE_TEAM_MEMBER_FAILURE, error: err}, getState); + } + }; +} diff --git a/src/actions/users.js b/src/actions/users.js index 0a66ba3ec..39346ce44 100644 --- a/src/actions/users.js +++ b/src/actions/users.js @@ -7,8 +7,7 @@ import Client from 'client'; // TODO: uncomment when PLT-4167 is merged // import {Constants, UsersTypes, TeamsTypes} from 'constants'; import {Constants, UsersTypes} from 'constants'; -import {bindClientFunc} from 'actions/helpers'; -import {forceLogoutIfNecessary} from './helpers'; +import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; export function login(loginId, password, mfaToken = '') { return async (dispatch, getState) => { diff --git a/src/client/client.js b/src/client/client.js index b2c942687..1dd77218e 100644 --- a/src/client/client.js +++ b/src/client/client.js @@ -319,13 +319,6 @@ export default class Client { ); }; - getInitialLoad = async () => { - return this.doFetch( - `${this.getUsersRoute()}/initial_load`, - {method: 'get'} - ); - }; - // Team routes createTeam = async (team) => { @@ -335,14 +328,21 @@ export default class Client { ); }; - getAllTeams = async() => { + 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() => { + getMyTeamMembers = async () => { return this.doFetch( `${this.getTeamsRoute()}/members`, {method: 'get'} @@ -356,23 +356,37 @@ export default class Client { ); }; - addUserToTeamFromInvite = async (inviteId, data, hash) => { + getTeamMember = async (teamId, userId) => { return this.doFetch( - `${this.getTeamsRoute()}/add_user_to_team_from_invite`, - {method: 'post', body: JSON.stringify({hash, data, invite_id: inviteId})} + `${this.getTeamNeededRoute(teamId)}/members/${userId}`, + {method: 'get'} ); }; - addChannelMember = async (teamId, channelId, userId) => { + getTeamMemberByIds = async (teamId, userIds) => { return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/add`, + `${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})} ); }; - removeChannelMember = async (teamId, channelId, userId) => { + removeUserFromTeam = async (teamId, userId) => { return this.doFetch( - `${this.getChannelNeededRoute(teamId, channelId)}/remove`, + `${this.getTeamNeededRoute(teamId)}/remove_user_from_team`, {method: 'post', body: JSON.stringify({user_id: userId})} ); }; @@ -393,7 +407,7 @@ export default class Client { ); }; - getChannel = async(teamId, channelId) => { + getChannel = async (teamId, channelId) => { return this.doFetch( `${this.getChannelNeededRoute(teamId, channelId)}/`, {method: 'get'} @@ -428,55 +442,69 @@ export default class Client { ); }; - leaveChannel = async(teamId, channelId) => { + leaveChannel = async (teamId, channelId) => { return this.doFetch( `${this.getChannelNeededRoute(teamId, channelId)}/leave`, {method: 'post'} ); }; - joinChannel = async(teamId, channelId) => { + joinChannel = async (teamId, channelId) => { return this.doFetch( `${this.getChannelNeededRoute(teamId, channelId)}/join`, {method: 'post'} ); }; - joinChannelByName = async(teamId, channelName) => { + joinChannelByName = async (teamId, channelName) => { return this.doFetch( `${this.getChannelNameRoute(teamId, channelName)}/join`, {method: 'post'} ); }; - deleteChannel = async(teamId, channelId) => { + deleteChannel = async (teamId, channelId) => { return this.doFetch( `${this.getChannelNeededRoute(teamId, channelId)}/delete`, {method: 'post'} ); }; - updateLastViewedAt = async(teamId, channelId, active) => { + updateLastViewedAt = async (teamId, channelId, active) => { return this.doFetch( `${this.getChannelNeededRoute(teamId, channelId)}/update_last_viewed_at`, {method: 'post', body: JSON.stringify({active})} ); }; - getMoreChannels = async(teamId, offset, limit) => { + getMoreChannels = async (teamId, offset, limit) => { return this.doFetch( `${this.getChannelsRoute(teamId)}/more/${offset}/${limit}`, {method: 'get'} ); }; - getChannelStats = async(teamId, channelId) => { + 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})} + ); + }; + // Post routes fetchPosts = (teamId, channelId, onRequest, onSuccess, onFailure) => { return this.doFetch( diff --git a/src/constants/constants.js b/src/constants/constants.js index 830d6e1bf..a117a6fa8 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -6,6 +6,9 @@ const Constants = { PROFILE_CHUNK_SIZE: 100, CHANNELS_CHUNK_SIZE: 50, + TEAM_USER_ROLE: 'team_user', + TEAM_ADMIN_ROLE: 'team_admin', + CHANNEL_USER_ROLE: 'channel_user', CHANNEL_ADMIN_ROLE: 'channel_admin', diff --git a/src/constants/teams.js b/src/constants/teams.js index 14bea65e6..11eed7231 100644 --- a/src/constants/teams.js +++ b/src/constants/teams.js @@ -8,6 +8,38 @@ const TeamTypes = keymirror({ 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, @@ -15,6 +47,8 @@ const TeamTypes = keymirror({ 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 }); diff --git a/src/reducers/entities/teams.js b/src/reducers/entities/teams.js index 5047ff344..196dc5497 100644 --- a/src/reducers/entities/teams.js +++ b/src/reducers/entities/teams.js @@ -7,7 +7,8 @@ import {TeamsTypes, UsersTypes} from 'constants'; function currentId(state = '', action) { switch (action.type) { case TeamsTypes.SELECT_TEAM: - return action.teamId; + return action.data; + default: return state; } @@ -16,32 +17,44 @@ function currentId(state = '', action) { 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) { - const nextState = {...state}; - 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.team; Reflect.deleteProperty(nextState, data.team_id); return nextState; } case UsersTypes.LOGOUT_SUCCESS: return {}; + default: return state; } @@ -49,13 +62,44 @@ function myMembers(state = {}, action) { function membersInTeam(state = {}, action) { switch (action.type) { - default: + 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; + 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 + }; + } + 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; } -} - -function membersNotInTeam(state = {}, action) { - switch (action.type) { + case UsersTypes.LOGOUT_SUCCESS: + return {}; default: return state; } @@ -63,6 +107,15 @@ function membersNotInTeam(state = {}, action) { 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; } @@ -70,6 +123,16 @@ function stats(state = {}, action) { 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; } @@ -89,9 +152,6 @@ export default combineReducers({ // 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 a Set of user ids that aren't members in the team - membersNotInTeam, - // object where every key is the team id and has an object with the team stats stats, diff --git a/src/reducers/requests/helpers.js b/src/reducers/requests/helpers.js index a80f3ede9..c856596c9 100644 --- a/src/reducers/requests/helpers.js +++ b/src/reducers/requests/helpers.js @@ -21,7 +21,6 @@ export function handleRequest(REQUEST, SUCCESS, FAILURE, state, action) { return { ...state, status: RequestStatus.SUCCESS, - data: action.data, error: null }; case FAILURE: diff --git a/src/reducers/requests/teams.js b/src/reducers/requests/teams.js index 5dab01efc..9c7f86f19 100644 --- a/src/reducers/requests/teams.js +++ b/src/reducers/requests/teams.js @@ -16,6 +16,94 @@ function allTeams(state = initialRequestState(), 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 + allTeams, + getAllTeamListings, + createTeam, + updateTeam, + getMyTeamMembers, + getTeamMembers, + getTeamStats, + addUserToTeam, + removeUserFromTeam }); diff --git a/test/actions/teams.test.js b/test/actions/teams.test.js index e989b9aac..e541f905b 100644 --- a/test/actions/teams.test.js +++ b/test/actions/teams.test.js @@ -10,6 +10,21 @@ import {RequestStatus} from 'constants'; import TestHelper from 'test_helper'; describe('Actions.Teams', () => { + it('selectTeam', (done) => { + TestHelper.initBasic(Client).then(() => { + const store = configureStore(); + + store.subscribe(() => { + const currentTeamId = store.getState().entities.teams.currentId; + assert.ok(currentTeamId); + assert.equal(currentTeamId, TestHelper.basicTeam.id); + done(); + }); + + Actions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); + }); + }); + it('fetchTeams', (done) => { TestHelper.initBasic(Client).then(() => { const store = configureStore(); @@ -33,18 +48,274 @@ describe('Actions.Teams', () => { }); }); - it('selectTeam', (done) => { + it('getAllTeamListings', (done) => { + TestHelper.initBasic(Client).then(async () => { + const store = configureStore(); + + store.subscribe(() => { + const teamsRequest = store.getState().requests.teams.getAllTeamListings; + const teams = store.getState().entities.teams.teams; + const openIds = store.getState().entities.teams.openTeamIds; + + if (teamsRequest.status === RequestStatus.SUCCESS || teamsRequest.status === RequestStatus.FAILURE) { + if (teamsRequest.error) { + done(new Error(JSON.stringify(teamsRequest.error))); + } else { + assert.ok(Object.keys(teams).length > 0); + for (const teamId in teams) { + if (teams.hasOwnProperty(teamId)) { + assert.ok(openIds.has(teamId)); + } + } + done(); + } + } + }); + + const team = TestHelper.fakeTeam(); + team.allow_open_invite = true; + await Client.createTeam(team); + Actions.getAllTeamListings()(store.dispatch, store.getState); + }); + }); + + it('createTeam', (done) => { TestHelper.initBasic(Client).then(() => { const store = configureStore(); store.subscribe(() => { - const currentTeamId = store.getState().entities.teams.currentId; - assert.ok(currentTeamId); - assert.equal(currentTeamId, TestHelper.basicTeam.id); - done(); + const createRequest = store.getState().requests.teams.createTeam; + const teams = store.getState().entities.teams.teams; + const members = store.getState().entities.teams.myMembers; + const current = store.getState().entities.teams.currentId; + + if (createRequest.status === RequestStatus.SUCCESS || createRequest.status === RequestStatus.FAILURE) { + if (createRequest.error) { + done(new Error(JSON.stringify(createRequest.error))); + } else { + const teamId = Object.keys(teams)[0]; + assert.strictEqual(Object.keys(teams).length, 1); + assert.strictEqual(current, teamId); + assert.ok(members[teamId]); + done(); + } + } }); - Actions.selectTeam(TestHelper.basicTeam)(store.dispatch, store.getState); + Actions.createTeam( + TestHelper.basicUser.id, + TestHelper.fakeTeam() + )(store.dispatch, store.getState); + }); + }); + + it('updateTeam', (done) => { + TestHelper.initBasic(Client).then(() => { + const store = configureStore(); + const displayName = 'The Updated Team'; + const description = 'This is a team created by unit tests'; + + store.subscribe(() => { + const updateRequest = store.getState().requests.teams.updateTeam; + const teams = store.getState().entities.teams.teams; + + if (updateRequest.status === RequestStatus.SUCCESS || updateRequest.status === RequestStatus.FAILURE) { + if (updateRequest.error) { + done(new Error(JSON.stringify(updateRequest.error))); + } else { + const team = teams[TestHelper.basicTeam.id]; + assert.ok(team); + assert.strictEqual(team.display_name, displayName); + assert.strictEqual(team.description, description); + done(); + } + } + }); + + const team = { + ...TestHelper.basicTeam, + display_name: displayName, + description + }; + Actions.updateTeam(team)(store.dispatch, store.getState); + }); + }); + + // TODO: uncomment when PLT-4167 is merged + // it('getMyTeamMembers', (done) => { + // TestHelper.initBasic(Client).then(() => { + // const store = configureStore(); + // + // store.subscribe(() => { + // const membersRequest = store.getState().requests.teams.getMyTeamMembers; + // const members = store.getState().entities.teams.myMembers; + // + // if (membersRequest.status === RequestStatus.SUCCESS || membersRequest.status === RequestStatus.FAILURE) { + // if (membersRequest.error) { + // done(new Error(JSON.stringify(membersRequest.error))); + // } else { + // assert.ok(members); + // assert.ok(members[TestHelper.basicTeam.id]); + // done(); + // } + // } + // }); + // + // Actions.getMyTeamMembers()(store.dispatch, store.getState); + // }); + // }); + + it.only('getTeamMember', (done) => { + TestHelper.initBasic(Client).then(async () => { + const store = configureStore(); + + const user = await TestHelper.basicClient.createUserWithInvite( + TestHelper.fakeUser(), + null, + null, + TestHelper.basicTeam.invite_id + ); + + store.subscribe(() => { + const membersRequest = store.getState().requests.teams.getTeamMembers; + const members = store.getState().entities.teams.membersInTeam; + + if (membersRequest.status === RequestStatus.SUCCESS || membersRequest.status === RequestStatus.FAILURE) { + if (membersRequest.error) { + done(new Error(JSON.stringify(membersRequest.error))); + } else { + assert.ok(members[TestHelper.basicTeam.id]); + assert.ok(members[TestHelper.basicTeam.id].has(user.id)); + done(); + } + } + }); + + Actions.getTeamMember(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); + }); + }); + + it('getTeamMembersByIds', (done) => { + TestHelper.initBasic(Client).then(async () => { + const store = configureStore(); + + 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 + ); + + store.subscribe(() => { + const membersRequest = store.getState().requests.teams.getTeamMembers; + const members = store.getState().entities.teams.membersInTeam; + + if (membersRequest.status === RequestStatus.SUCCESS || membersRequest.status === RequestStatus.FAILURE) { + if (membersRequest.error) { + done(new Error(JSON.stringify(membersRequest.error))); + } else { + assert.ok(members[TestHelper.basicTeam.id]); + assert.ok(members[TestHelper.basicTeam.id].has(user1.id)); + assert.ok(members[TestHelper.basicTeam.id].has(user2.id)); + done(); + } + } + }); + + Actions.getTeamMembersByIds( + TestHelper.basicTeam.id, + [user1.id, user2.id] + )(store.dispatch, store.getState); + }); + }).timeout(3000); + + it('getTeamStats', (done) => { + TestHelper.initBasic(Client).then(() => { + const store = configureStore(); + + store.subscribe(() => { + const stats = store.getState().entities.teams.stats; + const statsRequest = store.getState().requests.teams.getTeamStats; + + if (statsRequest.status === RequestStatus.SUCCESS) { + const stat = stats[TestHelper.basicTeam.id]; + assert.ok(stat); + assert.equal(stat.total_member_count, 1); + assert.equal(stat.active_member_count, 1); + done(); + } else if (statsRequest.status === RequestStatus.FAILURE) { + done(new Error(JSON.stringify(statsRequest.error))); + } + }); + + Actions.getTeamStats(TestHelper.basicTeam.id)(store.dispatch, store.getState); + }); + }); + + it('addUserToTeam', (done) => { + TestHelper.initBasic(Client).then(async () => { + const store = configureStore(); + const user = await TestHelper.basicClient.createUser(TestHelper.fakeUser()); + + store.subscribe(() => { + const membersRequest = store.getState().requests.teams.addUserToTeam; + const members = store.getState().entities.teams.membersInTeam; + + if (membersRequest.status === RequestStatus.SUCCESS || membersRequest.status === RequestStatus.FAILURE) { + if (membersRequest.error) { + done(new Error(JSON.stringify(membersRequest.error))); + } else { + assert.ok(members[TestHelper.basicTeam.id]); + assert.ok(members[TestHelper.basicTeam.id].has(user.id)); + done(); + } + } + }); + + Actions.addUserToTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); + }); + }); + + it('removeUserFromTeam', (done) => { + TestHelper.initBasic(Client).then(async () => { + const store = configureStore(); + const user = await TestHelper.basicClient.createUser(TestHelper.fakeUser()); + + store.subscribe(() => { + const addRequest = store.getState().requests.teams.addUserToTeam; + const removeRequest = store.getState().requests.teams.removeUserFromTeam; + const members = store.getState().entities.teams.membersInTeam; + + if (removeRequest.status === RequestStatus.SUCCESS || removeRequest.status === RequestStatus.FAILURE) { + if (removeRequest.error) { + done(new Error(JSON.stringify(removeRequest.error))); + } else { + assert.ok(members[TestHelper.basicTeam.id]); + assert.ok(!members[TestHelper.basicTeam.id].has(user.id)); + done(); + } + } + + if (removeRequest.status === RequestStatus.NOT_STARTED && + (addRequest.status === RequestStatus.SUCCESS || addRequest.status === RequestStatus.FAILURE)) { + if (addRequest.error) { + done(new Error(JSON.stringify(addRequest.error))); + } else { + assert.ok(members[TestHelper.basicTeam.id]); + assert.ok(members[TestHelper.basicTeam.id].has(user.id)); + Actions.removeUserFromTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); + } + } + }); + + Actions.addUserToTeam(TestHelper.basicTeam.id, user.id)(store.dispatch, store.getState); }); }); }); diff --git a/test/actions/users.test.js b/test/actions/users.test.js index e2da3e8aa..2beef05c5 100644 --- a/test/actions/users.test.js +++ b/test/actions/users.test.js @@ -86,7 +86,6 @@ describe('Actions.Users', () => { 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.membersNotInTeam, {}, 'members NOT 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');