MM-59540 Ensure user has invite team permission in order to change setting (#28670)
* ensure user has invite team permission in order to change setting * add tests and handle UI * lint fixes * revert changes to invite section input * update tests * revert bad merge --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
11b66de686
Коммит
790103fae0
@@ -251,6 +251,12 @@ func patchTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if changing "AllowOpenInvite" or "AllowedDomains", user must have InviteUser permission
|
||||||
|
if (team.AllowOpenInvite != nil || team.AllowedDomains != nil) && !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionInviteUser) {
|
||||||
|
c.SetPermissionError(model.PermissionInviteUser)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if oldTeam, err := c.App.GetTeam(c.Params.TeamId); err == nil {
|
if oldTeam, err := c.App.GetTeam(c.Params.TeamId); err == nil {
|
||||||
auditRec.AddEventPriorState(oldTeam)
|
auditRec.AddEventPriorState(oldTeam)
|
||||||
auditRec.AddEventObjectType("team")
|
auditRec.AddEventObjectType("team")
|
||||||
|
|||||||
@@ -618,6 +618,39 @@ func TestPatchTeam(t *testing.T) {
|
|||||||
_, _, err = client.PatchTeam(context.Background(), th.BasicTeam.Id, patch)
|
_, _, err = client.PatchTeam(context.Background(), th.BasicTeam.Id, patch)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Changing AllowOpenInvite requires InviteUser permission", func(t *testing.T) {
|
||||||
|
th.LoginTeamAdmin()
|
||||||
|
team2 := &model.Team{DisplayName: "Name", Name: GenerateTestTeamName(), Email: th.GenerateTestEmail(), Type: model.TeamOpen, AllowOpenInvite: true}
|
||||||
|
team2, _, _ = th.Client.CreateTeam(context.Background(), team2)
|
||||||
|
|
||||||
|
patch2 := &model.TeamPatch{
|
||||||
|
AllowOpenInvite: model.NewPointer(false),
|
||||||
|
AllowedDomains: model.NewPointer("test.com"),
|
||||||
|
}
|
||||||
|
|
||||||
|
rteam2, _, err3 := th.Client.PatchTeam(context.Background(), team2.Id, patch2)
|
||||||
|
require.NoError(t, err3)
|
||||||
|
require.Equal(t, team2.Id, rteam2.Id)
|
||||||
|
require.False(t, rteam2.AllowOpenInvite)
|
||||||
|
|
||||||
|
// remove invite user permission from team admin and user roles
|
||||||
|
th.RemovePermissionFromRole(model.PermissionInviteUser.Id, model.TeamAdminRoleId)
|
||||||
|
th.RemovePermissionFromRole(model.PermissionInviteUser.Id, model.TeamUserRoleId)
|
||||||
|
|
||||||
|
patch2 = &model.TeamPatch{
|
||||||
|
AllowOpenInvite: model.NewPointer(true),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err3 = th.Client.PatchTeam(context.Background(), rteam2.Id, patch2)
|
||||||
|
require.Error(t, err3)
|
||||||
|
|
||||||
|
patch2 = &model.TeamPatch{
|
||||||
|
AllowedDomains: model.NewPointer("testDomain.com"),
|
||||||
|
}
|
||||||
|
_, _, err3 = th.Client.PatchTeam(context.Background(), rteam2.Id, patch2)
|
||||||
|
require.Error(t, err3)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRestoreTeam(t *testing.T) {
|
func TestRestoreTeam(t *testing.T) {
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
|
import {Permissions} from 'mattermost-redux/constants';
|
||||||
|
import {haveITeamPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||||
|
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||||
|
|
||||||
import {isModalOpen} from 'selectors/views/modals';
|
import {isModalOpen} from 'selectors/views/modals';
|
||||||
|
|
||||||
import {ModalIdentifiers} from 'utils/constants';
|
import {ModalIdentifiers} from 'utils/constants';
|
||||||
@@ -12,9 +16,12 @@ import type {GlobalState} from 'types/store';
|
|||||||
import TeamSettingsModal from './team_settings_modal';
|
import TeamSettingsModal from './team_settings_modal';
|
||||||
|
|
||||||
function mapStateToProps(state: GlobalState) {
|
function mapStateToProps(state: GlobalState) {
|
||||||
|
const teamId = getCurrentTeamId(state);
|
||||||
|
const canInviteUsers = haveITeamPermission(state, teamId, Permissions.INVITE_USER);
|
||||||
const modalId = ModalIdentifiers.TEAM_SETTINGS;
|
const modalId = ModalIdentifiers.TEAM_SETTINGS;
|
||||||
return {
|
return {
|
||||||
show: isModalOpen(state, modalId),
|
show: isModalOpen(state, modalId),
|
||||||
|
canInviteUsers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {renderWithContext} from 'tests/react_testing_utils';
|
|||||||
|
|
||||||
describe('components/team_settings_modal', () => {
|
describe('components/team_settings_modal', () => {
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
isCloud: false,
|
|
||||||
onExited: jest.fn(),
|
onExited: jest.fn(),
|
||||||
|
canInviteUsers: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should hide the modal when the close button is clicked', async () => {
|
test('should hide the modal when the close button is clicked', async () => {
|
||||||
@@ -25,5 +25,31 @@ describe('components/team_settings_modal', () => {
|
|||||||
fireEvent.click(screen.getByText('Close'));
|
fireEvent.click(screen.getByText('Close'));
|
||||||
expect(modal.className).toBe('fade modal');
|
expect(modal.className).toBe('fade modal');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should display access tab when can invite users', async () => {
|
||||||
|
const props = {...baseProps, canInviteUsers: true};
|
||||||
|
renderWithContext(
|
||||||
|
<TeamSettingsModal
|
||||||
|
{...props}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
const infoButton = screen.getByRole('tab', {name: 'info'});
|
||||||
|
expect(infoButton).toBeDefined();
|
||||||
|
const accessButton = screen.getByRole('tab', {name: 'access'});
|
||||||
|
expect(accessButton).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not display access tab when can not invite users', async () => {
|
||||||
|
const props = {...baseProps, canInviteUsers: false};
|
||||||
|
renderWithContext(
|
||||||
|
<TeamSettingsModal
|
||||||
|
{...props}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
const tabs = screen.getAllByRole('tab');
|
||||||
|
expect(tabs.length).toEqual(1);
|
||||||
|
const infoButton = screen.getByRole('tab', {name: 'info'});
|
||||||
|
expect(infoButton).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ const SettingsSidebar = React.lazy(() => import('components/settings_sidebar'));
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onExited: () => void;
|
onExited: () => void;
|
||||||
|
canInviteUsers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TeamSettingsModal = ({onExited}: Props) => {
|
const TeamSettingsModal = ({onExited, canInviteUsers}: Props) => {
|
||||||
const [activeTab, setActiveTab] = useState('info');
|
const [activeTab, setActiveTab] = useState('info');
|
||||||
const [show, setShow] = useState<boolean>(true);
|
const [show, setShow] = useState<boolean>(true);
|
||||||
const [hasChanges, setHasChanges] = useState<boolean>(false);
|
const [hasChanges, setHasChanges] = useState<boolean>(false);
|
||||||
@@ -49,8 +50,10 @@ const TeamSettingsModal = ({onExited}: Props) => {
|
|||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{name: 'info', uiName: formatMessage({id: 'team_settings_modal.infoTab', defaultMessage: 'Info'}), icon: 'icon icon-information-outline', iconTitle: formatMessage({id: 'generic_icons.info', defaultMessage: 'Info Icon'})},
|
{name: 'info', uiName: formatMessage({id: 'team_settings_modal.infoTab', defaultMessage: 'Info'}), icon: 'icon icon-information-outline', iconTitle: formatMessage({id: 'generic_icons.info', defaultMessage: 'Info Icon'})},
|
||||||
{name: 'access', uiName: formatMessage({id: 'team_settings_modal.accessTab', defaultMessage: 'Access'}), icon: 'icon icon-account-multiple-outline', iconTitle: formatMessage({id: 'generic_icons.member', defaultMessage: 'Member Icon'})},
|
|
||||||
];
|
];
|
||||||
|
if (canInviteUsers) {
|
||||||
|
tabs.push({name: 'access', uiName: formatMessage({id: 'team_settings_modal.accessTab', defaultMessage: 'Access'}), icon: 'icon icon-account-multiple-outline', iconTitle: formatMessage({id: 'generic_icons.member', defaultMessage: 'Member Icon'})});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user