From 9e8fb26f4b52a8cd068dc2e6ee361a56c6d8462d Mon Sep 17 00:00:00 2001 From: Chris Duarte Date: Fri, 24 Feb 2017 18:20:28 -0800 Subject: [PATCH] PLT-5604 Add/Remove members from pubic channels doesn't match the webapp functionality (#289) * PLT-5604 Add/Remove members from pubic channels doesn't match the webapp functionality * Review feedback * Fix spelling of ChannelMembersTitle * Use selector to consolidate auth logic for channel member mgmt --- app/components/custom_list/member_list_row.js | 3 +- app/scenes/channel_info/channel_info.js | 10 +++--- .../channel_info/channel_info_container.js | 8 ++--- app/scenes/channel_members/channel_members.js | 8 ++--- .../channel_members_container.js | 9 ++--- .../channel_members/channel_members_title.js | 33 +++++++------------ .../channel_members/remove_member_button.js | 15 +++------ service/selectors/entities/channels.js | 22 ++++++++++++- 8 files changed, 53 insertions(+), 55 deletions(-) diff --git a/app/components/custom_list/member_list_row.js b/app/components/custom_list/member_list_row.js index edc1116a1..7470fab8a 100644 --- a/app/components/custom_list/member_list_row.js +++ b/app/components/custom_list/member_list_row.js @@ -31,7 +31,6 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { color: theme.centerChannelColor }, textContainer: { - flex: 1, flexDirection: 'row', marginLeft: 5 }, @@ -99,7 +98,7 @@ function MemberListRow(props) { size={40} /> - + {displayName} diff --git a/app/scenes/channel_info/channel_info.js b/app/scenes/channel_info/channel_info.js index 171491333..d351f0aed 100644 --- a/app/scenes/channel_info/channel_info.js +++ b/app/scenes/channel_info/channel_info.js @@ -44,7 +44,7 @@ class ChannelInfo extends PureComponent { currentChannelMemberCount: PropTypes.number, isFavorite: PropTypes.bool.isRequired, leaveChannelRequest: PropTypes.object.isRequired, - isAdmin: PropTypes.bool.isRequired, + canManageUsers: PropTypes.bool.isRequired, actions: PropTypes.shape({ getChannelStats: PropTypes.func.isRequired, goToChannelMembers: PropTypes.func.isRequired, @@ -143,7 +143,7 @@ class ChannelInfo extends PureComponent { currentChannel, currentChannelCreatorName, currentChannelMemberCount, - isAdmin + canManageUsers } = this.props; return ( @@ -180,15 +180,15 @@ class ChannelInfo extends PureComponent { - {isAdmin && this.renderLeaveOrDeleteChannelRow() && + {canManageUsers && this.renderLeaveOrDeleteChannelRow() && f.id); const isFavorite = favoriteChannels.indexOf(currentChannel.id) > -1; const leaveChannelRequest = state.requests.channels.leaveChannel; - const currentUserRoles = getCurrentUserRoles(state); - const isAdmin = currentUserRoles.includes('_admin'); return { ...ownProps, @@ -34,7 +32,7 @@ function mapStateToProps(state, ownProps) { isFavorite, leaveChannelRequest, theme: getTheme(state), - isAdmin + canManageUsers: canManageChannelMembers(state) }; } diff --git a/app/scenes/channel_members/channel_members.js b/app/scenes/channel_members/channel_members.js index b25759bc7..94c9430d8 100644 --- a/app/scenes/channel_members/channel_members.js +++ b/app/scenes/channel_members/channel_members.js @@ -14,7 +14,6 @@ import MemberList from 'app/components/custom_list'; import {createMembersSections, loadingText} from 'app/utils/member_list'; import MemberListRow from 'app/components/custom_list/member_list_row'; import {displayUsername} from 'service/utils/user_utils'; -import {Constants} from 'service/constants'; import {makeStyleSheetFromTheme} from 'app/utils/theme'; import ChannelMembersTitle from './channel_members_title'; @@ -40,7 +39,7 @@ class ChannelMembers extends PureComponent { currentTeam: PropTypes.object, preferences: PropTypes.object, requestStatus: PropTypes.string, - isAdmin: PropTypes.bool.isRequired, + canManageUsers: PropTypes.bool.isRequired, subscribeToHeaderEvent: React.PropTypes.func, unsubscribeFromHeaderEvent: React.PropTypes.func, actions: PropTypes.shape({ @@ -171,8 +170,7 @@ class ChannelMembers extends PureComponent { } render() { - const {currentChannel, isAdmin, theme} = this.props; - const canManage = (isAdmin && currentChannel.type !== Constants.DM_CHANNEL && currentChannel.name !== Constants.DEFAULT_CHANNEL); + const {canManageUsers, theme} = this.props; const style = getStyleFromTheme(theme); return ( @@ -184,7 +182,7 @@ class ChannelMembers extends PureComponent { preferences={this.props.preferences} loading={this.props.requestStatus === 'started'} loadingText={loadingText} - selectable={canManage} + selectable={canManageUsers} onRowSelect={this.handleRowSelect} renderRow={this.renderMemberRow} createSections={createMembersSections} diff --git a/app/scenes/channel_members/channel_members_container.js b/app/scenes/channel_members/channel_members_container.js index 52774d9c2..1fad713ec 100644 --- a/app/scenes/channel_members/channel_members_container.js +++ b/app/scenes/channel_members/channel_members_container.js @@ -7,19 +7,16 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {goBack} from 'app/actions/navigation'; import {handleRemoveChannelMembers} from 'app/actions/views/channel_members'; -import {getCurrentChannel, getCurrentChannelStats} from 'service/selectors/entities/channels'; +import {getCurrentChannel, getCurrentChannelStats, canManageChannelMembers} from 'service/selectors/entities/channels'; import {getMyPreferences, getTheme} from 'service/selectors/entities/preferences'; import {getCurrentTeam} from 'service/selectors/entities/teams'; -import {getProfilesInCurrentChannel, getCurrentUserRoles} from 'service/selectors/entities/users'; +import {getProfilesInCurrentChannel} from 'service/selectors/entities/users'; import {getProfilesInChannel} from 'service/actions/users'; import ChannelMembers from './channel_members'; function mapStateToProps(state) { const currentChannelMemberCount = getCurrentChannelStats(state) && getCurrentChannelStats(state).member_count; - const currentUserRoles = getCurrentUserRoles(state); - - const isAdmin = currentUserRoles.includes('_admin'); return { theme: getTheme(state), @@ -30,7 +27,7 @@ function mapStateToProps(state) { currentTeam: getCurrentTeam(state), preferences: getMyPreferences(state), requestStatus: state.requests.users.getProfilesInChannel.status, - isAdmin + canManageUsers: canManageChannelMembers(state) }; } diff --git a/app/scenes/channel_members/channel_members_title.js b/app/scenes/channel_members/channel_members_title.js index 2d41f16a3..f74384e98 100644 --- a/app/scenes/channel_members/channel_members_title.js +++ b/app/scenes/channel_members/channel_members_title.js @@ -3,51 +3,42 @@ import React, {PropTypes} from 'react'; import {connect} from 'react-redux'; -import { - View -} from 'react-native'; +import {View} from 'react-native'; -import {getCurrentUserRoles} from 'service/selectors/entities/users'; -import {getCurrentChannel} from 'service/selectors/entities/channels'; +import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels'; import {getTheme} from 'service/selectors/entities/preferences'; -import {Constants} from 'service/constants'; import FormattedText from 'app/components/formatted_text'; -function ChannelMemberTitle(props) { - const {currentChannel, isAdmin} = props; - const manage = (isAdmin && currentChannel.type !== Constants.DM_CHANNEL && currentChannel.name !== Constants.DEFAULT_CHANNEL); +function ChannelMembersTitle(props) { + const {canManageUsers} = props; return ( ); } -ChannelMemberTitle.propTypes = { - isAdmin: PropTypes.bool, +ChannelMembersTitle.propTypes = { + canManageUsers: PropTypes.bool.isRequired, currentChannel: PropTypes.object.isRequired, - theme: PropTypes.object + theme: PropTypes.object.isRequired }; -ChannelMemberTitle.defaultProps = { +ChannelMembersTitle.defaultProps = { theme: {} }; function mapStateToProps(state) { - const currentUserRoles = getCurrentUserRoles(state); - - const isAdmin = currentUserRoles.includes('_admin'); - return { - isAdmin, + canManageUsers: canManageChannelMembers(state), currentChannel: getCurrentChannel(state), theme: getTheme(state) }; } -export default connect(mapStateToProps)(ChannelMemberTitle); +export default connect(mapStateToProps)(ChannelMembersTitle); diff --git a/app/scenes/channel_members/remove_member_button.js b/app/scenes/channel_members/remove_member_button.js index 2ed671eb7..bc6bbe169 100644 --- a/app/scenes/channel_members/remove_member_button.js +++ b/app/scenes/channel_members/remove_member_button.js @@ -10,14 +10,12 @@ import { import FormattedText from 'app/components/formatted_text'; -import {getCurrentUserRoles} from 'service/selectors/entities/users'; -import {getCurrentChannel} from 'service/selectors/entities/channels'; +import {getCurrentChannel, canManageChannelMembers} from 'service/selectors/entities/channels'; import {getTheme} from 'service/selectors/entities/preferences'; -import {Constants} from 'service/constants'; function RemoveMemberButton(props) { - const {currentChannel, isAdmin} = props; - if (!isAdmin || currentChannel.type === Constants.DM_CHANNEL || currentChannel.name === Constants.DEFAULT_CHANNEL) { + const {canManageUsers} = props; + if (!canManageUsers) { return null; } @@ -39,7 +37,7 @@ function RemoveMemberButton(props) { RemoveMemberButton.propTypes = { emitter: PropTypes.func.isRequired, - isAdmin: PropTypes.bool.isRequired, + canManageUsers: PropTypes.bool.isRequired, currentChannel: PropTypes.object.isRequired, theme: PropTypes.object }; @@ -49,11 +47,8 @@ RemoveMemberButton.defaultProps = { }; function mapStateToProps(state) { - const currentUserRoles = getCurrentUserRoles(state); - - const isAdmin = currentUserRoles.includes('_admin'); return { - isAdmin, + canManageUsers: canManageChannelMembers(state), currentChannel: getCurrentChannel(state), theme: getTheme(state) }; diff --git a/service/selectors/entities/channels.js b/service/selectors/entities/channels.js index 77941176c..d6d4c5ee3 100644 --- a/service/selectors/entities/channels.js +++ b/service/selectors/entities/channels.js @@ -2,7 +2,8 @@ // See License.txt for license information. import {createSelector} from 'reselect'; -import {getCurrentTeamId} from 'service/selectors/entities/teams'; +import {getCurrentTeamId, getCurrentTeamMembership} from 'service/selectors/entities/teams'; +import {getCurrentUserId, getUsers} from 'service/selectors/entities/users'; import {buildDisplayableChannelList, getNotMemberChannels, completeDirectChannelInfo} from 'service/utils/channel_utils'; import {Constants} from 'service/constants'; @@ -150,3 +151,22 @@ export const getAutocompleteChannelWithSections = createSelector( return channels; } ); + +export const canManageChannelMembers = createSelector( + getCurrentChannel, + getCurrentChannelMembership, + getCurrentTeamMembership, + getUsers, + getCurrentUserId, + (channel, channelMembership, teamMembership, allUsers, currentUserId) => { + const user = allUsers[currentUserId]; + const roles = `${channelMembership.roles} ${teamMembership.roles} ${user.roles}`; + if (channel.type === Constants.DM_CHANNEL || channel.name === Constants.DEFAULT_CHANNEL) { + return false; + } + if (channel.type === Constants.OPEN_CHANNEL) { + return true; + } + return roles.includes('_admin'); + } +);