Skip to content

Commit

Permalink
MM-14410: Adds ability to retrieve groups that are associated (or not…
Browse files Browse the repository at this point in the history
…-associated) to teams. (mattermost#821)

* Bump release v5.6.0

* MM-14410: Adds ability to retrieve groups that are associated (or not-associated) to teams.

* MM-14410: Flow updates.
  • Loading branch information
mkraft authored May 10, 2019
1 parent 6c48a65 commit 5819fa4
Show file tree
Hide file tree
Showing 13 changed files with 501 additions and 10 deletions.
17 changes: 17 additions & 0 deletions src/action_types/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,21 @@ export default keyMirror({
GET_GROUP_SUCCESS: null,
GET_GROUP_FAILURE: null,
RECEIVED_GROUP: null,

RECEIVED_GROUPS: null,

GET_GROUPS_ASSOCIATED_TO_TEAM_REQUEST: null,
GET_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS: null,
GET_GROUPS_ASSOCIATED_TO_TEAM_FAILURE: null,
RECEIVED_GROUPS_ASSOCIATED_TO_TEAM: null,

GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_REQUEST: null,
GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS: null,
GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_FAILURE: null,
RECEIVED_ALL_GROUPS_ASSOCIATED_TO_TEAM: null,

GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_REQUEST: null,
GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_SUCCESS: null,
GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_FAILURE: null,
RECEIVED_GROUPS_NOT_ASSOCIATED_TO_TEAM: null,
});
69 changes: 61 additions & 8 deletions src/actions/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ export function linkGroupSyncable(groupID: string, syncableID: string, syncableT
return {error};
}

const dispatches = [];

let type;
switch (syncableType) {
case Groups.SYNCABLE_TYPE_TEAM:
dispatches.push({type: GroupTypes.RECEIVED_GROUPS_ASSOCIATED_TO_TEAM, data: {teamID: syncableID, groups: [{id: groupID}]}});
type = GroupTypes.LINKED_GROUP_TEAM;
break;
case Groups.SYNCABLE_TYPE_CHANNEL:
Expand All @@ -42,10 +45,9 @@ export function linkGroupSyncable(groupID: string, syncableID: string, syncableT
console.warn(`unhandled syncable type ${syncableType}`); // eslint-disable-line no-console
}

dispatch(batchActions([
{type: GroupTypes.LINK_GROUP_SYNCABLE_SUCCESS, data: null},
{type, data},
]));
dispatches.push(...[{type: GroupTypes.LINK_GROUP_SYNCABLE_SUCCESS, data: null}, {type, data}]);

dispatch(batchActions(dispatches));

return {data: true};
};
Expand All @@ -66,12 +68,15 @@ export function unlinkGroupSyncable(groupID: string, syncableID: string, syncabl
return {error};
}

const dispatches = [];

let type;
const data = {group_id: groupID, syncable_id: syncableID};
switch (syncableType) {
case Groups.SYNCABLE_TYPE_TEAM:
type = GroupTypes.UNLINKED_GROUP_TEAM;
data.syncable_id = syncableID;
dispatches.push({type: GroupTypes.RECEIVED_GROUPS_NOT_ASSOCIATED_TO_TEAM, data: {teamID: syncableID, groups: [{id: groupID}]}});
break;
case Groups.SYNCABLE_TYPE_CHANNEL:
type = GroupTypes.UNLINKED_GROUP_CHANNEL;
Expand All @@ -81,10 +86,9 @@ export function unlinkGroupSyncable(groupID: string, syncableID: string, syncabl
console.warn(`unhandled syncable type ${syncableType}`); // eslint-disable-line no-console
}

dispatch(batchActions([
{type: GroupTypes.UNLINK_GROUP_SYNCABLE_SUCCESS, data: null},
{type, data},
]));
dispatches.push(...[{type: GroupTypes.UNLINK_GROUP_SYNCABLE_SUCCESS, data: null}, {type, data}]);

dispatch(batchActions(dispatches));

return {data: true};
};
Expand Down Expand Up @@ -163,3 +167,52 @@ export function getGroup(id: string): ActionFunc {
],
});
}

export function getGroupsNotAssociatedToTeam(teamID: string, q: string = '', page: number = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc {
return bindClientFunc({
clientFunc: Client4.getGroupsNotAssociatedToTeam,
onRequest: GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_REQUEST,
onSuccess: [GroupTypes.RECEIVED_GROUPS, GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_SUCCESS],
onFailure: GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_FAILURE,
params: [
teamID,
q,
page,
perPage,
],
});
}

export function getAllGroupsAssociatedToTeam(teamID: string): ActionFunc {
return bindClientFunc({
clientFunc: async (param1) => {
const result = await Client4.getAllGroupsAssociatedToTeam(param1);
result.teamID = param1;
return result;
},
onRequest: GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_REQUEST,
onSuccess: [GroupTypes.RECEIVED_ALL_GROUPS_ASSOCIATED_TO_TEAM, GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS],
onFailure: GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_FAILURE,
params: [
teamID,
],
});
}

export function getGroupsAssociatedToTeam(teamID: string, q: string = '', page: number = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc {
return bindClientFunc({
clientFunc: async (param1, param2, param3, param4) => {
const result = await Client4.getGroupsAssociatedToTeam(param1, param2, param3, param4);
return {groups: result.groups, totalGroupCount: result.total_group_count, teamID: param1};
},
onRequest: GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_REQUEST,
onSuccess: [GroupTypes.RECEIVED_GROUPS_ASSOCIATED_TO_TEAM, GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS],
onFailure: GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_FAILURE,
params: [
teamID,
q,
page,
perPage,
],
});
}
181 changes: 181 additions & 0 deletions test/actions/groups.test.js → src/actions/groups.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,185 @@ describe('Actions.Groups', () => {
assert.ok(syncables[groupID].teams.length === beforeTeamsLength - 1);
assert.ok(syncables[groupID].channels.length === beforeChannelsLength - 1);
});

it('getAllGroupsAssociatedToTeam', async () => {
const teamID = '5rgoajywb3nfbdtyafbod47ryb';

const response = {
groups: [
{
id: 'xh585kyz3tn55q6ipfo57btwnc',
name: '9uobsi3xb3y5tfjb3ze7umnh1o',
display_name: 'abc',
description: '',
source: 'ldap',
remote_id: 'abc',
create_at: 1553808969975,
update_at: 1553808969975,
delete_at: 0,
has_syncables: false,
member_count: 2,
},
{
id: 'tnd8zod9f3fdtqosxjmhwucbth',
name: 'nobctj4brfgtpj3a1peiyq47tc',
display_name: 'engineering',
description: '',
source: 'ldap',
remote_id: 'engineering',
create_at: 1553808971099,
update_at: 1553808971099,
delete_at: 0,
has_syncables: false,
member_count: 8,
},
{
id: 'qhdp6g7aubbpiyja7c4sgpe7tc',
name: 'x5bjwa4kwirpmqudhp5dterine',
display_name: 'qa',
description: '',
source: 'ldap',
remote_id: 'qa',
create_at: 1553808971548,
update_at: 1553808971548,
delete_at: 0,
has_syncables: false,
member_count: 2,
},
],
total_group_count: 3,
};

nock(Client4.getBaseRoute()).
get(`/teams/${teamID}/groups?paginate=false`).
reply(200, response);

await Actions.getAllGroupsAssociatedToTeam(teamID)(store.dispatch, store.getState);

const state = store.getState();
const request = state.requests.groups.getAllGroupsAssociatedToTeam;
if (request.status === RequestStatus.FAILURE) {
throw new Error('getGroup request failed err=' + request.error);
}

const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID];
assert.strictEqual(groupIDs.length, response.groups.length);
groupIDs.forEach((id) => {
assert.ok(response.groups.map((group) => group.id).includes(id));
});
});

it('getGroupsAssociatedToTeam', async () => {
const teamID = '5rgoajywb3nfbdtyafbod47ryb';

store = await configureStore({
entities: {
teams: {
groupsAssociatedToTeam: {
[teamID]: ['existing1', 'existing2'],
},
},
},
});

const response = {
groups: [
{
id: 'tnd8zod9f3fdtqosxjmhwucbth',
name: 'nobctj4brfgtpj3a1peiyq47tc',
display_name: 'engineering',
description: '',
source: 'ldap',
remote_id: 'engineering',
create_at: 1553808971099,
update_at: 1553808971099,
delete_at: 0,
has_syncables: false,
member_count: 8,
},
{
id: 'qhdp6g7aubbpiyja7c4sgpe7tc',
name: 'x5bjwa4kwirpmqudhp5dterine',
display_name: 'qa',
description: '',
source: 'ldap',
remote_id: 'qa',
create_at: 1553808971548,
update_at: 1553808971548,
delete_at: 0,
has_syncables: false,
member_count: 2,
},
],
total_group_count: 3,
};

nock(Client4.getBaseRoute()).
get(`/teams/${teamID}/groups?page=100&per_page=60&q=0&include_member_count=true`).
reply(200, response);

await Actions.getGroupsAssociatedToTeam(teamID, 0, 100)(store.dispatch, store.getState);

const state = store.getState();
const request = state.requests.groups.getGroupsAssociatedToTeam;
if (request.status === RequestStatus.FAILURE) {
throw new Error('getGroup request failed err=' + request.error);
}

const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID];
var expectedIDs = ['existing1', 'existing2'].concat(response.groups.map((group) => group.id));
assert.strictEqual(groupIDs.length, expectedIDs.length);
groupIDs.forEach((id) => {
assert.ok(expectedIDs.includes(id));
});
});

it('getGroupsNotAssociatedToTeam', async () => {
const teamID = '5rgoajywb3nfbdtyafbod47ryb';

store = await configureStore({
entities: {
teams: {
groupsAssociatedToTeam: {
[teamID]: ['existing1', 'existing2'],
},
},
},
});

const response = [
{
id: 'existing1',
name: 'nobctj4brfgtpj3a1peiyq47tc',
display_name: 'engineering',
description: '',
source: 'ldap',
remote_id: 'engineering',
create_at: 1553808971099,
update_at: 1553808971099,
delete_at: 0,
has_syncables: false,
member_count: 8,
},
];

nock(Client4.getBaseRoute()).
get(`/groups?not_associated_to_team=${teamID}&page=100&per_page=60&q=0&include_member_count=true`).
reply(200, response);

await Actions.getGroupsNotAssociatedToTeam(teamID, 0, 100)(store.dispatch, store.getState);

const state = store.getState();
const request = state.requests.groups.getGroupsNotAssociatedToTeam;
if (request.status === RequestStatus.FAILURE) {
throw new Error('getGroup request failed err=' + request.error);
}

const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID];
var expectedIDs = ['existing2'].concat(response.map((group) => group.id));
assert.strictEqual(groupIDs.length, expectedIDs.length);
groupIDs.forEach((id) => {
assert.ok(expectedIDs.includes(id));
});
});
});
23 changes: 23 additions & 0 deletions src/client/client4.js
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,29 @@ export default class Client4 {
);
};

getGroupsNotAssociatedToTeam = async (teamID, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => {
this.trackEvent('api', 'api_groups_get_not_associated_to_team', {team_id: teamID});
return this.doFetch(
`${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_team: teamID, page, per_page: perPage, q, include_member_count: true})}`,
{method: 'get'}
);
};

getGroupsAssociatedToTeam = async (teamID, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => {
this.trackEvent('api', 'api_groups_get_not_associated_to_team', {team_id: teamID});
return this.doFetch(
`${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true})}`,
{method: 'get'}
);
};

getAllGroupsAssociatedToTeam = async (teamID) => {
return this.doFetch(
`${this.getBaseRoute()}/teams/${teamID}/groups?paginate=false`,
{method: 'get'}
);
};

// Redirect Location

getRedirectLocation = async (urlParam) => {
Expand Down
10 changes: 10 additions & 0 deletions src/reducers/entities/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ function syncables(state = {}, action) {
};
}
case GroupTypes.UNLINKED_GROUP_TEAM: {
if (!state[action.data.group_id]) {
return state;
}
const nextTeams = state[action.data.group_id].teams.slice();

const index = nextTeams.findIndex((groupTeam) => {
Expand Down Expand Up @@ -135,6 +138,13 @@ function groups(state = {}, action) {
[action.data.id]: action.data,
};
}
case GroupTypes.RECEIVED_GROUPS: {
const nextState = {...state};
for (const group of action.data) {
nextState[group.id] = group;
}
return nextState;
}
default:
return state;
}
Expand Down
Loading

0 comments on commit 5819fa4

Please sign in to comment.