PLT-6139 (WebApp): Manage Private Channel Members (#5947)

Honour the policy setting for add/remove members from private channels
in the WebApp UI.
Этот коммит содержится в:
George Goldberg
2017-04-04 19:43:22 +01:00
коммит произвёл Harrison Healey
родитель 6bf080393d
Коммит 6bb65ef420
7 изменённых файлов: 148 добавлений и 60 удалений

Просмотреть файл

@@ -34,6 +34,7 @@ export default class PolicySettings extends AdminSettings {
config.TeamSettings.RestrictPrivateChannelManagement = this.state.restrictPrivateChannelManagement; config.TeamSettings.RestrictPrivateChannelManagement = this.state.restrictPrivateChannelManagement;
config.TeamSettings.RestrictPublicChannelDeletion = this.state.restrictPublicChannelDeletion; config.TeamSettings.RestrictPublicChannelDeletion = this.state.restrictPublicChannelDeletion;
config.TeamSettings.RestrictPrivateChannelDeletion = this.state.restrictPrivateChannelDeletion; config.TeamSettings.RestrictPrivateChannelDeletion = this.state.restrictPrivateChannelDeletion;
config.TeamSettings.RestrictPrivateChannelManageMembers = this.state.restrictPrivateChannelManageMembers;
return config; return config;
} }
@@ -49,7 +50,8 @@ export default class PolicySettings extends AdminSettings {
restrictPublicChannelManagement: config.TeamSettings.RestrictPublicChannelManagement, restrictPublicChannelManagement: config.TeamSettings.RestrictPublicChannelManagement,
restrictPrivateChannelManagement: config.TeamSettings.RestrictPrivateChannelManagement, restrictPrivateChannelManagement: config.TeamSettings.RestrictPrivateChannelManagement,
restrictPublicChannelDeletion: config.TeamSettings.RestrictPublicChannelDeletion, restrictPublicChannelDeletion: config.TeamSettings.RestrictPublicChannelDeletion,
restrictPrivateChannelDeletion: config.TeamSettings.RestrictPrivateChannelDeletion restrictPrivateChannelDeletion: config.TeamSettings.RestrictPrivateChannelDeletion,
restrictPrivateChannelManageMembers: config.TeamSettings.RestrictPrivateChannelManageMembers
}; };
} }
@@ -214,6 +216,29 @@ export default class PolicySettings extends AdminSettings {
/> />
} }
/> />
<DropdownSetting
id='restrictPrivateChannelManageMembers'
values={[
{value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAllChannel', 'All channel members')},
{value: Constants.PERMISSIONS_CHANNEL_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsChannelAdmin', 'Channel, Team and System Admins')},
{value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
{value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
]}
label={
<FormattedMessage
id='admin.general.policy.restrictPrivateChannelManageMembersTitle'
defaultMessage='Enable managing of private group members for:'
/>
}
value={this.state.restrictPrivateChannelManageMembers}
onChange={this.handleChange}
helpText={
<FormattedMessage
id='admin.general.policy.restrictPrivateChannelManageMembersDescription'
defaultMessage='Set policy on who can add and remove members from private groups.'
/>
}
/>
<DropdownSetting <DropdownSetting
id='restrictPrivateChannelDeletion' id='restrictPrivateChannelDeletion'
values={[ values={[

Просмотреть файл

@@ -269,6 +269,7 @@ export default class ChannelHeader extends React.Component {
); );
let channelTitle = channel.display_name; let channelTitle = channel.display_name;
const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
const isTeamAdmin = TeamStore.isTeamAdminForCurrentTeam();
const isSystemAdmin = UserStore.isSystemAdminForCurrentUser(); const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
const isChannelAdmin = ChannelStore.isChannelAdminForCurrentChannel(); const isChannelAdmin = ChannelStore.isChannelAdminForCurrentChannel();
const isDirect = (this.state.channel.type === Constants.DM_CHANNEL); const isDirect = (this.state.channel.type === Constants.DM_CHANNEL);
@@ -492,44 +493,65 @@ export default class ChannelHeader extends React.Component {
/> />
); );
dropdownContents.push( if (ChannelUtils.canManageMembers(channel, isSystemAdmin, isTeamAdmin, isChannelAdmin)) {
<li dropdownContents.push(
id='channelAddMembers' <li
key='add_members' id='channelAddMembers'
role='presentation' key='add_members'
> role='presentation'
<ToggleModalButton
ref='channelInviteModalButton'
role='menuitem'
dialogType={ChannelInviteModal}
dialogProps={{channel, currentUser: this.state.currentUser}}
> >
<FormattedMessage <ToggleModalButton
id='channel_header.addMembers' ref='channelInviteModalButton'
defaultMessage='Add Members' role='menuitem'
/> dialogType={ChannelInviteModal}
</ToggleModalButton> dialogProps={{channel, currentUser: this.state.currentUser}}
</li> >
); <FormattedMessage
id='channel_header.addMembers'
defaultMessage='Add Members'
/>
</ToggleModalButton>
</li>
);
dropdownContents.push( dropdownContents.push(
<li <li
id='channelManageMembers' id='channelManageMembers'
key='manage_members' key='manage_members'
role='presentation' role='presentation'
>
<a
role='menuitem'
href='#'
onClick={() => this.setState({showMembersModal: true})}
> >
<FormattedMessage <a
id='channel_header.manageMembers' role='menuitem'
defaultMessage='Manage Members' href='#'
/> onClick={() => this.setState({showMembersModal: true})}
</a> >
</li> <FormattedMessage
); id='channel_header.manageMembers'
defaultMessage='Manage Members'
/>
</a>
</li>
);
} else {
dropdownContents.push(
<li
id='channelViewMembers'
key='view_members'
role='presentation'
>
<a
role='menuitem'
href='#'
onClick={() => this.setState({showMembersModal: true})}
>
<FormattedMessage
id='channel_header.viewMembers'
defaultMessage='View Members'
/>
</a>
</li>
);
}
} }
const deleteOption = ( const deleteOption = (

Просмотреть файл

@@ -9,6 +9,7 @@ import {removeUserFromChannel, makeUserChannelAdmin, makeUserChannelMember} from
import * as AsyncClient from 'utils/async_client.jsx'; import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import {canManageMembers} from 'utils/channel_utils.jsx';
import React from 'react'; import React from 'react';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
@@ -91,8 +92,7 @@ export default class ChannelMembersDropdown extends React.Component {
// Checks if the current user has the power to remove this member from the channel. // Checks if the current user has the power to remove this member from the channel.
canRemoveMember() { canRemoveMember() {
// TODO: This will be implemented as part of PLT-5047. return canManageMembers(this.props.channel, UserStore.isSystemAdminForCurrentUser(), TeamStore.isTeamAdminForCurrentTeam(), ChannelStore.isChannelAdminForCurrentChannel());
return true;
} }
render() { render() {

Просмотреть файл

@@ -3,6 +3,12 @@
import MemberListChannel from './member_list_channel.jsx'; import MemberListChannel from './member_list_channel.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import {canManageMembers} from 'utils/channel_utils.jsx';
import React from 'react'; import React from 'react';
import {Modal} from 'react-bootstrap'; import {Modal} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
@@ -24,6 +30,30 @@ export default class ChannelMembersModal extends React.Component {
} }
render() { render() {
const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
const isTeamAdmin = TeamStore.isTeamAdminForCurrentTeam();
const isChannelAdmin = ChannelStore.isChannelAdminForCurrentChannel();
let addMembersButton = null;
if (canManageMembers(this.state.channel, isSystemAdmin, isTeamAdmin, isChannelAdmin)) {
addMembersButton = (
<a
id='showInviteModal'
className='btn btn-md btn-primary'
href='#'
onClick={() => {
this.props.showInviteModal();
this.onHide();
}}
>
<FormattedMessage
id='channel_members_modal.addNew'
defaultMessage=' Add New Members'
/>
</a>
);
}
return ( return (
<div> <div>
<Modal <Modal
@@ -40,20 +70,7 @@ export default class ChannelMembersModal extends React.Component {
defaultMessage=' Members' defaultMessage=' Members'
/> />
</Modal.Title> </Modal.Title>
<a {addMembersButton}
id='showInviteModal'
className='btn btn-md btn-primary'
href='#'
onClick={() => {
this.props.showInviteModal();
this.onHide();
}}
>
<FormattedMessage
id='channel_members_modal.addNew'
defaultMessage=' Add New Members'
/>
</a>
</Modal.Header> </Modal.Header>
<Modal.Body <Modal.Body
ref='modalBody' ref='modalBody'

Просмотреть файл

@@ -17,6 +17,7 @@ import * as AsyncClient from 'utils/async_client.jsx';
import Client from 'client/web_client.jsx'; import Client from 'client/web_client.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx'; import Constants from 'utils/constants.jsx';
import {canManageMembers} from 'utils/channel_utils.jsx';
import $ from 'jquery'; import $ from 'jquery';
import React from 'react'; import React from 'react';
@@ -86,10 +87,11 @@ export default class PopoverListMembers extends React.Component {
const popoverHtml = []; const popoverHtml = [];
const members = this.props.members; const members = this.props.members;
const teamMembers = UserStore.getProfilesUsernameMap(); const teamMembers = UserStore.getProfilesUsernameMap();
let isAdmin = false;
const currentUserId = UserStore.getCurrentId(); const currentUserId = UserStore.getCurrentId();
isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
const isTeamAdmin = TeamStore.isTeamAdminForCurrentTeam();
const isChannelAdmin = ChannelStore.isChannelAdminForCurrentChannel();
if (members && teamMembers) { if (members && teamMembers) {
members.sort((a, b) => { members.sort((a, b) => {
@@ -156,7 +158,7 @@ export default class PopoverListMembers extends React.Component {
defaultMessage='Manage Members' defaultMessage='Manage Members'
/> />
); );
if (!isAdmin && ChannelStore.isDefault(this.props.channel)) { if (!canManageMembers(this.props.channel, isSystemAdmin, isTeamAdmin, isChannelAdmin) && !ChannelStore.isDefault(this.props.channel)) {
membersName = ( membersName = (
<FormattedMessage <FormattedMessage
id='members_popover.viewMembers' id='members_popover.viewMembers'
@@ -217,7 +219,7 @@ export default class PopoverListMembers extends React.Component {
teamMembersModal = ( teamMembersModal = (
<TeamMembersModal <TeamMembersModal
onHide={() => this.setState({showTeamMembersModal: false})} onHide={() => this.setState({showTeamMembersModal: false})}
isAdmin={isAdmin} isAdmin={isTeamAdmin || isSystemAdmin}
/> />
); );
} }

Просмотреть файл

@@ -331,10 +331,12 @@
"admin.general.policy.restrictPrivateChannelCreationDescription": "Set policy on who can create private groups.", "admin.general.policy.restrictPrivateChannelCreationDescription": "Set policy on who can create private groups.",
"admin.general.policy.restrictPrivateChannelCreationTitle": "Enable private group creation for:", "admin.general.policy.restrictPrivateChannelCreationTitle": "Enable private group creation for:",
"admin.general.policy.restrictPrivateChannelDeletionCommandLineToolLink": "command line tool", "admin.general.policy.restrictPrivateChannelDeletionCommandLineToolLink": "command line tool",
"admin.general.policy.restrictPrivateChannelDeletionDescription": "Set policy on who can delete private groups. Deleted groups can be recovered from the database using a {commandLineToolLink}.", "admin.general.policy.restrictPrivateChannelDeletionDescription": "Set policy on who can delete private channels. Deleted channels can be recovered from the database using a {commandLineToolLink}.",
"admin.general.policy.restrictPrivateChannelDeletionTitle": "Enable private group deletion for:", "admin.general.policy.restrictPrivateChannelDeletionTitle": "Enable private channel deletion for:",
"admin.general.policy.restrictPrivateChannelManagementDescription": "Set policy on who can rename and set the header or purpose for private groups.", "admin.general.policy.restrictPrivateChannelManagementDescription": "Set policy on who can rename and set the header or purpose for private channels.",
"admin.general.policy.restrictPrivateChannelManagementTitle": "Enable private group renaming for:", "admin.general.policy.restrictPrivateChannelManagementTitle": "Enable private channel renaming for:",
"admin.general.policy.restrictPrivateChannelManageMembersDescription": "Set policy on who can add and remove members from private channels.",
"admin.general.policy.restrictPrivateChannelManageMembersTitle": "Enable managing of private channel members for:",
"admin.general.policy.restrictPublicChannelCreationDescription": "Set policy on who can create public channels.", "admin.general.policy.restrictPublicChannelCreationDescription": "Set policy on who can create public channels.",
"admin.general.policy.restrictPublicChannelCreationTitle": "Enable public channel creation for:", "admin.general.policy.restrictPublicChannelCreationTitle": "Enable public channel creation for:",
"admin.general.policy.restrictPublicChannelDeletionCommandLineToolLink": "command line tool", "admin.general.policy.restrictPublicChannelDeletionCommandLineToolLink": "command line tool",

Просмотреть файл

@@ -208,6 +208,26 @@ export function showDeleteOption(channel, isAdmin, isSystemAdmin, isChannelAdmin
return true; return true;
} }
export function canManageMembers(channel, isSystemAdmin, isTeamAdmin, isChannelAdmin) {
if (global.window.mm_license.IsLicensed !== 'true') {
return true;
}
if (channel.type === Constants.PRIVATE_CHANNEL) {
if (global.window.mm_config.RestrictPrivateChannelManageMembers === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
return false;
}
if (global.window.mm_config.RestrictPrivateChannelManageMembers === Constants.PERMISSIONS_TEAM_ADMIN && !isTeamAdmin && !isSystemAdmin) {
return false;
}
if (global.window.mm_config.RestrictPrivateChannelManageMembers === Constants.PERMISSIONS_CHANNEL_ADMIN && !isChannelAdmin && !isTeamAdmin && !isSystemAdmin) {
return false;
}
}
return true;
}
export function buildGroupChannelName(channelId) { export function buildGroupChannelName(channelId) {
const profiles = UserStore.getProfileListInChannel(channelId, true); const profiles = UserStore.getProfileListInChannel(channelId, true);
let displayName = ''; let displayName = '';