[MM-24891] [MM-24572] Add ability to specify default value when role not found for selector (#4277) (#4287)

* MM-24891 Allow permissions to have defaults set in case where roles not in state

* MM-24891 Add tests for haveIPermission

* MM-24891 Apply the defaults to more channel permission checks
This commit is contained in:
Farhan Munshi 2020-05-08 14:45:33 -04:00 committed by GitHub
parent 19a282ad41
commit 613ddc1250
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 121 additions and 47 deletions

View file

@ -34,6 +34,7 @@ function mapStateToProps(state, ownProps) {
{
channel: currentChannelId,
permission: Permissions.USE_CHANNEL_MENTIONS,
default: true,
},
);
}

View file

@ -60,6 +60,7 @@ export function mapStateToProps(state, ownProps) {
channel: currentChannel.id,
team: currentChannel.team_id,
permission: Permissions.CREATE_POST,
default: true,
},
);
@ -68,6 +69,7 @@ export function mapStateToProps(state, ownProps) {
{
channel: currentChannel.id,
permission: Permissions.USE_CHANNEL_MENTIONS,
default: true,
},
);
}

View file

@ -71,11 +71,13 @@ describe('mapStateToProps', () => {
channel: undefined,
team: undefined,
permission: Permissions.CREATE_POST,
default: true,
});
expect(roleSelectors.haveIChannelPermission).not.toHaveBeenCalledWith(state, {
channel: undefined,
permission: Permissions.USE_CHANNEL_MENTIONS,
default: true,
});
});
@ -90,11 +92,13 @@ describe('mapStateToProps', () => {
channel: undefined,
team: undefined,
permission: Permissions.CREATE_POST,
default: true,
});
expect(roleSelectors.haveIChannelPermission).toHaveBeenCalledWith(state, {
channel: undefined,
permission: Permissions.USE_CHANNEL_MENTIONS,
default: true,
});
});
});

View file

@ -43,6 +43,7 @@ function makeMapStateToProps() {
team: teamId,
channel: channelId,
permission: Permissions.ADD_REACTION,
default: true,
});
if (reactions) {
@ -54,6 +55,7 @@ function makeMapStateToProps() {
team: teamId,
channel: channelId,
permission: Permissions.REMOVE_REACTION,
default: true,
});
}

View file

@ -13,10 +13,12 @@ describe('Selectors.Roles', () => {
const team1 = TestHelper.fakeTeamWithId();
const team2 = TestHelper.fakeTeamWithId();
const team3 = TestHelper.fakeTeamWithId();
const team4 = TestHelper.fakeTeamWithId();
const myTeamMembers = {};
myTeamMembers[team1.id] = {roles: 'test_team1_role1 test_team1_role2'};
myTeamMembers[team2.id] = {roles: 'test_team2_role1 test_team2_role2'};
myTeamMembers[team3.id] = {};
myTeamMembers[team4.id] = {roles: 'test_team4_role_not_found'};
const channel1 = TestHelper.fakeChannelWithId(team1.id);
channel1.display_name = 'Channel Name';
@ -50,6 +52,7 @@ describe('Selectors.Roles', () => {
const channel11 = TestHelper.fakeChannelWithId(team1.id);
channel11.type = General.PRIVATE_CHANNEL;
const channel12 = TestHelper.fakeChannelWithId(team1.id);
const channel13 = TestHelper.fakeChannelWithId(team1.id);
const channels = {};
channels[channel1.id] = channel1;
@ -64,6 +67,7 @@ describe('Selectors.Roles', () => {
channels[channel10.id] = channel10;
channels[channel11.id] = channel11;
channels[channel12.id] = channel12;
channels[channel13.id] = channel13;
const channelsInTeam = {};
channelsInTeam[team1.id] = [channel1.id, channel2.id, channel5.id, channel6.id, channel8.id, channel10.id, channel11.id];
@ -87,6 +91,7 @@ describe('Selectors.Roles', () => {
myChannelMembers[channel10.id] = {roles: 'test_channel_c_role1 test_channel_c_role2'};
myChannelMembers[channel11.id] = {roles: 'test_channel_c_role1 test_channel_c_role2'};
myChannelMembers[channel12.id] = {};
myChannelMembers[channel13.id] = {roles: 'test_channel_not_found_role'};
const roles = {
test_team1_role1: {permissions: ['team1_role1']},
test_team2_role1: {permissions: ['team2_role1']},
@ -124,6 +129,7 @@ describe('Selectors.Roles', () => {
const teamsRoles = {};
teamsRoles[team1.id] = new Set(['test_team1_role1', 'test_team1_role2']);
teamsRoles[team2.id] = new Set(['test_team2_role1', 'test_team2_role2']);
teamsRoles[team4.id] = new Set(['test_team4_role_not_found']);
const channelsRoles = {};
channelsRoles[channel1.id] = new Set(['test_channel_a_role1', 'test_channel_a_role2']);
channelsRoles[channel2.id] = new Set(['test_channel_a_role1', 'test_channel_a_role2']);
@ -135,6 +141,7 @@ describe('Selectors.Roles', () => {
channelsRoles[channel9.id] = new Set(['test_channel_b_role1', 'test_channel_b_role2']);
channelsRoles[channel10.id] = new Set(['test_channel_c_role1', 'test_channel_c_role2']);
channelsRoles[channel11.id] = new Set(['test_channel_c_role1', 'test_channel_c_role2']);
channelsRoles[channel13.id] = new Set(['test_channel_not_found_role']);
const myRoles = {
system: new Set(['test_user_role', 'test_user_role2']),
team: teamsRoles,
@ -172,10 +179,18 @@ describe('Selectors.Roles', () => {
assert.equal(Selectors.haveISystemPermission(testState, {permission: 'invalid_permission'}), false);
});
it('should return my team permission on getMyTeamPermissions', () => {
assert.deepEqual(Selectors.getMyTeamPermissions(testState, {team: team1.id}), new Set([
'user_role2', 'team1_role1',
]));
it('should return my team permissions on getMyTeamPermissions', () => {
const {permissions, roleFound} = Selectors.getMyTeamPermissions(testState, {team: team1.id});
const expectedPermissions = new Set(['user_role2', 'team1_role1']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, true);
});
it('should return system permissions on getMyTeamPermissions when team not found', () => {
const {permissions, roleFound} = Selectors.getMyTeamPermissions(testState, {team: team4.id});
const expectedPermissions = new Set(['user_role2']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, false);
});
it('should return if i have a team permission on haveITeamPermission', () => {
@ -185,10 +200,17 @@ describe('Selectors.Roles', () => {
assert.equal(Selectors.haveITeamPermission(testState, {team: team1.id, permission: 'invalid_permission'}), false);
});
it('should return default if role not found in state on haveITeamPermission for team scoped permission', () => {
assert.equal(Selectors.haveITeamPermission(testState, {team: team4.id, permission: 'any_permission', default: true}), true);
assert.equal(Selectors.haveITeamPermission(testState, {team: team4.id, permission: 'any_permission', default: false}), false);
assert.equal(Selectors.haveITeamPermission(testState, {team: team1.id, permission: 'user_role2'}), true);
});
it('should return my team permission on getMyCurrentTeamPermissions', () => {
assert.deepEqual(Selectors.getMyCurrentTeamPermissions(testState), new Set([
'user_role2', 'team1_role1',
]));
const {permissions, roleFound} = Selectors.getMyCurrentTeamPermissions(testState);
const expectedPermissions = new Set(['user_role2', 'team1_role1']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, true);
});
it('should return if i have a team permission on haveICurrentTeamPermission', () => {
@ -199,9 +221,24 @@ describe('Selectors.Roles', () => {
});
it('should return my channel permission on getMyChannelPermissions', () => {
assert.deepEqual(Selectors.getMyChannelPermissions(testState, {team: team1.id, channel: channel1.id}), new Set([
'user_role2', 'team1_role1', 'channel_a_role1', 'channel_a_role2',
]));
const {permissions, roleFound} = Selectors.getMyChannelPermissions(testState, {team: team1.id, channel: channel1.id});
const expectedPermissions = new Set(['user_role2', 'team1_role1', 'channel_a_role1', 'channel_a_role2']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, true);
});
it('should only return my team permissions on getMyChannelPermissions when role not found', () => {
const {permissions, roleFound} = Selectors.getMyChannelPermissions(testState, {team: team1.id, channel: channel13.id});
const expectedPermissions = new Set(['user_role2', 'team1_role1']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, false);
});
it('should return my channel permission on getMyChannelPermissions when channel roles not found', () => {
const {permissions, roleFound} = Selectors.getMyChannelPermissions(testState, {team: team1.id, channel: channel1.id});
const expectedPermissions = new Set(['user_role2', 'team1_role1', 'channel_a_role1', 'channel_a_role2']);
assert.deepEqual(permissions, expectedPermissions);
assert.equal(roleFound, true);
});
it('should return if i have a channel permission on haveIChannelPermission', () => {
@ -212,10 +249,11 @@ describe('Selectors.Roles', () => {
assert.equal(Selectors.haveIChannelPermission(testState, {team: team1.id, channel: channel1.id, permission: 'channel_b_role1'}), false);
});
it('should return my current channel permission on getMyCurrentChannelPermissions', () => {
assert.deepEqual(Selectors.getMyCurrentChannelPermissions(testState), new Set([
'user_role2', 'team1_role1', 'channel_a_role1', 'channel_a_role2',
]));
it('should return default if role not found in state on haveIChannelPermission for channel scoped permission', () => {
assert.equal(Selectors.haveIChannelPermission(testState, {team: team1.id, channel: channel13.id, permission: 'any_permission', default: true}), true);
assert.equal(Selectors.haveIChannelPermission(testState, {team: team1.id, channel: channel13.id, permission: 'any_permission', default: false}), false);
assert.equal(Selectors.haveIChannelPermission(testState, {team: team1.id, channel: channel13.id, permission: 'user_role2'}), true);
assert.equal(Selectors.haveIChannelPermission(testState, {team: team1.id, channel: channel13.id, permission: 'team1_role1'}), true);
});
it('should return if i have a channel permission on haveICurrentChannelPermission', () => {

View file

@ -1,15 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as reselect from 'reselect';
import {getCurrentUser, getCurrentChannelId} from '@mm-redux/selectors/entities/common';
import {getCurrentChannelId} from '@mm-redux/selectors/entities/common';
import {getTeamMemberships, getCurrentTeamId} from './teams';
import * as types from '@mm-redux/types';
import {getMySystemPermissions, getMySystemRoles, getRoles, PermissionsOptions} from '@mm-redux/selectors/entities/roles_helpers';
import {GlobalState} from '@mm-redux/types/store';
import {Dictionary} from '@mm-redux/types/utilities';
import {Role} from '@mm-redux/types/roles';
import {Channel} from '@mm-redux/types/channels';
import {Team} from '@mm-redux/types/teams';
export {getMySystemPermissions, getMySystemRoles, getRoles};
@ -73,21 +71,23 @@ export const getMyCurrentTeamPermissions = reselect.createSelector(
getMySystemPermissions,
getCurrentTeamId,
(myTeamRoles, roles, systemPermissions, teamId) => {
const permissions = new Set();
const permissions = new Set<string>();
let roleFound = false;
if (myTeamRoles[teamId]) {
for (const roleName of myTeamRoles[teamId]) {
if (roles[roleName]) {
for (const permission of roles[roleName].permissions) {
permissions.add(permission);
}
roleFound = true;
}
}
}
for (const permission of systemPermissions) {
permissions.add(permission);
}
return permissions;
}
return {permissions, roleFound};
},
);
export const getMyCurrentChannelPermissions = reselect.createSelector(
@ -95,22 +95,24 @@ export const getMyCurrentChannelPermissions = reselect.createSelector(
getRoles,
getMyCurrentTeamPermissions,
getCurrentChannelId,
(myChannelRoles, roles, teamPermissions, channelId) => {
const permissions = new Set();
(myChannelRoles, roles, {permissions: teamPermissions, roleFound: teamRoleFound}, channelId) => {
const permissions = new Set<string>();
let roleFound = false;
if (myChannelRoles[channelId]) {
for (const roleName of myChannelRoles[channelId]) {
if (roles[roleName]) {
for (const permission of roles[roleName].permissions) {
permissions.add(permission);
}
roleFound = true && teamRoleFound;
}
}
}
for (const permission of teamPermissions) {
permissions.add(permission);
}
return permissions;
}
return {permissions, roleFound};
},
);
export const getMyTeamPermissions = reselect.createSelector(
@ -119,21 +121,23 @@ export const getMyTeamPermissions = reselect.createSelector(
getMySystemPermissions,
(state: GlobalState, options: PermissionsOptions) => options.team,
(myTeamRoles, roles, systemPermissions, teamId) => {
const permissions = new Set();
const permissions = new Set<string>();
let roleFound = false;
if (myTeamRoles[teamId!]) {
for (const roleName of myTeamRoles[teamId!]) {
if (roles[roleName]) {
for (const permission of roles[roleName].permissions) {
permissions.add(permission);
}
roleFound = true;
}
}
}
for (const permission of systemPermissions) {
permissions.add(permission);
}
return permissions;
}
return {permissions, roleFound};
},
);
export const getMyChannelPermissions = reselect.createSelector(
@ -141,22 +145,24 @@ export const getMyChannelPermissions = reselect.createSelector(
getRoles,
getMyTeamPermissions,
(state, options: PermissionsOptions) => options.channel,
(myChannelRoles, roles, teamPermissions, channelId) => {
const permissions = new Set();
(myChannelRoles, roles, {permissions: teamPermissions, roleFound: teamRoleFound}, channelId) => {
const permissions = new Set<string>();
let roleFound = false;
if (myChannelRoles[channelId!]) {
for (const roleName of myChannelRoles[channelId!]) {
if (roles[roleName]) {
for (const permission of roles[roleName].permissions) {
permissions.add(permission);
}
roleFound = true && teamRoleFound;
}
}
}
for (const permission of teamPermissions) {
permissions.add(permission);
}
return permissions;
}
return {permissions, roleFound};
},
);
export const haveISystemPermission = reselect.createSelector(
@ -169,32 +175,48 @@ export const haveISystemPermission = reselect.createSelector(
export const haveITeamPermission = reselect.createSelector(
getMyTeamPermissions,
(state, options) => options.permission,
(permissions, permission) => {
return permissions.has(permission);
}
(state, options) => options,
({permissions, roleFound}, options) => {
const hasPermission = permissions.has(options.permission);
if (roleFound) {
return hasPermission;
}
return options.default === true || hasPermission;
},
);
export const haveIChannelPermission = reselect.createSelector(
getMyChannelPermissions,
(state, options) => options.permission,
(permissions, permission) => {
return permissions.has(permission);
}
(state, options) => options,
({permissions, roleFound}, options) => {
const hasPermission = permissions.has(options.permission);
if (roleFound) {
return hasPermission;
}
return options.default === true || hasPermission;
},
);
export const haveICurrentTeamPermission = reselect.createSelector(
getMyCurrentTeamPermissions,
(state: GlobalState, options: PermissionsOptions) => options.permission,
(permissions, permission) => {
return permissions.has(permission);
}
(state: GlobalState, options: PermissionsOptions) => options,
({permissions, roleFound}, options) => {
const hasPermission = permissions.has(options.permission);
if (roleFound) {
return hasPermission;
}
return options.default === true || hasPermission;
},
);
export const haveICurrentChannelPermission = reselect.createSelector(
getMyCurrentChannelPermissions,
(state: GlobalState, options: PermissionsOptions) => options.permission,
(permissions, permission) => {
return permissions.has(permission);
}
(state: GlobalState, options: PermissionsOptions) => options,
({permissions, roleFound}, options) => {
const hasPermission = permissions.has(options.permission);
if (roleFound) {
return hasPermission;
}
return options.default === true || hasPermission;
},
);

View file

@ -9,6 +9,7 @@ export type PermissionsOptions = {
channel?: string;
team?: string;
permission: string;
default?: boolean;
};
export function getRoles(state: GlobalState) {

View file

@ -65,6 +65,7 @@ export function makeMapStateToProps() {
channel: post.channel_id,
team: channel.team_id,
permission: Permissions.CREATE_POST,
default: true,
},
);
}
@ -74,6 +75,7 @@ export function makeMapStateToProps() {
team: currentTeamId,
channel: post.channel_id,
permission: Permissions.ADD_REACTION,
default: true,
});
}

View file

@ -156,6 +156,7 @@ describe('makeMapStateToProps', () => {
channel: undefined,
team: undefined,
permission: Permissions.CREATE_POST,
default: true,
});
});
@ -176,6 +177,7 @@ describe('makeMapStateToProps', () => {
channel: undefined,
team: undefined,
permission: Permissions.CREATE_POST,
default: true,
});
});
});