[IMPROVE] Check permission to create a room (#3233)
* [IMPROVE] Check permission to create new message, channels, teams * Show or not the button to create at RoomListView * Check permission for each button inside NewMessageView * Check permission to create private or public channel * Minor tweak * Refactor to create a function tuserHasRolePermission * Refactor to use only one function at rocketchat to check the user permission * Minor tweaks * Reactive create channel * reactive new message view, and handleHasPermission out of constructor * handleHasPermission to didMount in roomListView * remove console.log * Call the function in componentDidMount * Changed === to dequal, to check array Co-authored-by: Gerzon Z <gerzonc@icloud.com> Co-authored-by: Gerzon Z <gerzonzcanario@gmail.com> Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
2a19054bf6
commit
da6af286c6
|
@ -18,6 +18,10 @@ const PERMISSIONS = [
|
|||
'archive-room',
|
||||
'auto-translate',
|
||||
'create-invite-links',
|
||||
'create-c',
|
||||
'create-p',
|
||||
'create-d',
|
||||
'start-discussion',
|
||||
'create-team',
|
||||
'delete-c',
|
||||
'delete-message',
|
||||
|
|
|
@ -1380,17 +1380,19 @@ const RocketChat = {
|
|||
* Returns an array of boolean for each permission from permissions arg
|
||||
*/
|
||||
async hasPermission(permissions, rid) {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
let roomRoles = [];
|
||||
try {
|
||||
// get the room from database
|
||||
const room = await subsCollection.find(rid);
|
||||
// get room roles
|
||||
roomRoles = room.roles || [];
|
||||
} catch (error) {
|
||||
console.log('hasPermission -> Room not found');
|
||||
return permissions.map(() => false);
|
||||
if (rid) {
|
||||
const db = database.active;
|
||||
const subsCollection = db.get('subscriptions');
|
||||
try {
|
||||
// get the room from database
|
||||
const room = await subsCollection.find(rid);
|
||||
// get room roles
|
||||
roomRoles = room.roles || [];
|
||||
} catch (error) {
|
||||
console.log('hasPermission -> Room not found');
|
||||
return permissions.map(() => false);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -21,6 +21,7 @@ import { Review } from '../utils/review';
|
|||
import { getUserSelector } from '../selectors/login';
|
||||
import { events, logEvent } from '../utils/log';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import sharedStyles from './Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -79,10 +80,13 @@ class CreateChannelView extends React.Component {
|
|||
users: PropTypes.array.isRequired,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
token: PropTypes.string,
|
||||
roles: PropTypes.array
|
||||
}),
|
||||
theme: PropTypes.string,
|
||||
teamId: PropTypes.string
|
||||
teamId: PropTypes.string,
|
||||
createPublicChannelPermission: PropTypes.array,
|
||||
createPrivateChannelPermission: PropTypes.array
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -96,14 +100,20 @@ class CreateChannelView extends React.Component {
|
|||
readOnly: false,
|
||||
encrypted: false,
|
||||
broadcast: false,
|
||||
isTeam
|
||||
isTeam,
|
||||
permissions: []
|
||||
};
|
||||
this.setHeader();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.handleHasPermission();
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { channelName, type, readOnly, broadcast, encrypted } = this.state;
|
||||
const { users, isFetching, encryptionEnabled, theme } = this.props;
|
||||
const { channelName, type, readOnly, broadcast, encrypted, permissions } = this.state;
|
||||
const { users, isFetching, encryptionEnabled, theme, createPublicChannelPermission, createPrivateChannelPermission } =
|
||||
this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
|
@ -122,18 +132,37 @@ class CreateChannelView extends React.Component {
|
|||
if (nextState.broadcast !== broadcast) {
|
||||
return true;
|
||||
}
|
||||
if (nextState.permissions !== permissions) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.isFetching !== isFetching) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.encryptionEnabled !== encryptionEnabled) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.createPublicChannelPermission, createPublicChannelPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.createPrivateChannelPermission, createPrivateChannelPermission)) {
|
||||
return true;
|
||||
}
|
||||
if (!dequal(nextProps.users, users)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { createPublicChannelPermission, createPrivateChannelPermission } = this.props;
|
||||
if (
|
||||
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
|
||||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission)
|
||||
) {
|
||||
this.handleHasPermission();
|
||||
}
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { navigation } = this.props;
|
||||
const { isTeam } = this.state;
|
||||
|
@ -208,12 +237,21 @@ class CreateChannelView extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
handleHasPermission = async () => {
|
||||
const { createPublicChannelPermission, createPrivateChannelPermission } = this.props;
|
||||
const permissions = [createPublicChannelPermission, createPrivateChannelPermission];
|
||||
const permissionsToCreate = await RocketChat.hasPermission(permissions);
|
||||
this.setState({ permissions: permissionsToCreate });
|
||||
};
|
||||
|
||||
renderType() {
|
||||
const { type, isTeam } = this.state;
|
||||
const { type, isTeam, permissions } = this.state;
|
||||
const isDisabled = permissions.filter(r => r === true).length <= 1;
|
||||
|
||||
return this.renderSwitch({
|
||||
id: 'type',
|
||||
value: type,
|
||||
value: permissions[1] ? type : false,
|
||||
disabled: isDisabled,
|
||||
label: isTeam ? 'Private_Team' : 'Private_Channel',
|
||||
onValueChange: value => {
|
||||
logEvent(events.CR_TOGGLE_TYPE);
|
||||
|
@ -373,7 +411,9 @@ const mapStateToProps = state => ({
|
|||
isFetching: state.createChannel.isFetching,
|
||||
encryptionEnabled: state.encryption.enabled,
|
||||
users: state.selectedUsers.users,
|
||||
user: getUserSelector(state)
|
||||
user: getUserSelector(state),
|
||||
createPublicChannelPermission: state.permissions['create-c'],
|
||||
createPrivateChannelPermission: state.permissions['create-p']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
|
|||
import { FlatList, StyleSheet, Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import { dequal } from 'dequal';
|
||||
import * as List from '../containers/List';
|
||||
|
||||
import Touch from '../utils/touch';
|
||||
import database from '../lib/database';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
|
@ -57,13 +58,19 @@ class NewMessageView extends React.Component {
|
|||
baseUrl: PropTypes.string,
|
||||
user: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
token: PropTypes.string,
|
||||
roles: PropTypes.array
|
||||
}),
|
||||
create: PropTypes.func,
|
||||
maxUsers: PropTypes.number,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
serverVersion: PropTypes.string
|
||||
serverVersion: PropTypes.string,
|
||||
createTeamPermission: PropTypes.array,
|
||||
createDirectMessagePermission: PropTypes.array,
|
||||
createPublicChannelPermission: PropTypes.array,
|
||||
createPrivateChannelPermission: PropTypes.array,
|
||||
createDiscussionPermission: PropTypes.array
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -71,7 +78,8 @@ class NewMessageView extends React.Component {
|
|||
this.init();
|
||||
this.state = {
|
||||
search: [],
|
||||
chats: []
|
||||
chats: [],
|
||||
permissions: []
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -90,6 +98,30 @@ class NewMessageView extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.handleHasPermission();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
createTeamPermission,
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createDirectMessagePermission,
|
||||
createDiscussionPermission
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
!dequal(createTeamPermission, prevProps.createTeamPermission) ||
|
||||
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
|
||||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission) ||
|
||||
!dequal(createDirectMessagePermission, prevProps.createDirectMessagePermission) ||
|
||||
!dequal(createDiscussionPermission, prevProps.createDiscussionPermission)
|
||||
) {
|
||||
this.handleHasPermission();
|
||||
}
|
||||
}
|
||||
|
||||
onSearchChangeText(text) {
|
||||
this.search(text);
|
||||
}
|
||||
|
@ -161,20 +193,43 @@ class NewMessageView extends React.Component {
|
|||
Navigation.navigate('CreateDiscussionView');
|
||||
};
|
||||
|
||||
handleHasPermission = async () => {
|
||||
const {
|
||||
createTeamPermission,
|
||||
createDirectMessagePermission,
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createDiscussionPermission
|
||||
} = this.props;
|
||||
const permissions = [
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createTeamPermission,
|
||||
createDirectMessagePermission,
|
||||
createDiscussionPermission
|
||||
];
|
||||
const permissionsToCreate = await RocketChat.hasPermission(permissions);
|
||||
this.setState({ permissions: permissionsToCreate });
|
||||
};
|
||||
|
||||
renderHeader = () => {
|
||||
const { maxUsers, theme, serverVersion } = this.props;
|
||||
const { permissions } = this.state;
|
||||
|
||||
return (
|
||||
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='new-message-view-search' />
|
||||
<View style={styles.buttonContainer}>
|
||||
{this.renderButton({
|
||||
onPress: this.createChannel,
|
||||
title: I18n.t('Create_Channel'),
|
||||
icon: 'channel-public',
|
||||
testID: 'new-message-view-create-channel',
|
||||
first: true
|
||||
})}
|
||||
{compareServerVersion(serverVersion, '3.13.0', methods.greaterThanOrEqualTo)
|
||||
{permissions[0] || permissions[1]
|
||||
? this.renderButton({
|
||||
onPress: this.createChannel,
|
||||
title: I18n.t('Create_Channel'),
|
||||
icon: 'channel-public',
|
||||
testID: 'new-message-view-create-channel',
|
||||
first: true
|
||||
})
|
||||
: null}
|
||||
{compareServerVersion(serverVersion, '3.13.0', methods.greaterThanOrEqualTo) && permissions[2]
|
||||
? this.renderButton({
|
||||
onPress: this.createTeam,
|
||||
title: I18n.t('Create_Team'),
|
||||
|
@ -182,7 +237,7 @@ class NewMessageView extends React.Component {
|
|||
testID: 'new-message-view-create-team'
|
||||
})
|
||||
: null}
|
||||
{maxUsers > 2
|
||||
{maxUsers > 2 && permissions[3]
|
||||
? this.renderButton({
|
||||
onPress: this.createGroupChat,
|
||||
title: I18n.t('Create_Direct_Messages'),
|
||||
|
@ -190,12 +245,14 @@ class NewMessageView extends React.Component {
|
|||
testID: 'new-message-view-create-direct-message'
|
||||
})
|
||||
: null}
|
||||
{this.renderButton({
|
||||
onPress: this.createDiscussion,
|
||||
title: I18n.t('Create_Discussion'),
|
||||
icon: 'discussions',
|
||||
testID: 'new-message-view-create-discussion'
|
||||
})}
|
||||
{permissions[4]
|
||||
? this.renderButton({
|
||||
onPress: this.createDiscussion,
|
||||
title: I18n.t('Create_Discussion'),
|
||||
icon: 'discussions',
|
||||
testID: 'new-message-view-create-discussion'
|
||||
})
|
||||
: null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
@ -261,7 +318,12 @@ const mapStateToProps = state => ({
|
|||
isMasterDetail: state.app.isMasterDetail,
|
||||
baseUrl: state.server.server,
|
||||
maxUsers: state.settings.DirectMesssage_maxUsers || 1,
|
||||
user: getUserSelector(state)
|
||||
user: getUserSelector(state),
|
||||
createTeamPermission: state.permissions['create-team'],
|
||||
createDirectMessagePermission: state.permissions['create-d'],
|
||||
createPublicChannelPermission: state.permissions['create-c'],
|
||||
createPrivateChannelPermission: state.permissions['create-p'],
|
||||
createDiscussionPermission: state.permissions['start-discussion']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -89,7 +89,12 @@ const shouldUpdateProps = [
|
|||
'refreshing',
|
||||
'queueSize',
|
||||
'inquiryEnabled',
|
||||
'encryptionBanner'
|
||||
'encryptionBanner',
|
||||
'createTeamPermission',
|
||||
'createDirectMessagePermission',
|
||||
'createPublicChannelPermission',
|
||||
'createPrivateChannelPermission',
|
||||
'createDiscussionPermission'
|
||||
];
|
||||
const getItemLayout = (data, index) => ({
|
||||
length: ROW_HEIGHT,
|
||||
|
@ -106,7 +111,7 @@ class RoomsListView extends React.Component {
|
|||
username: PropTypes.string,
|
||||
token: PropTypes.string,
|
||||
statusLivechat: PropTypes.string,
|
||||
roles: PropTypes.object
|
||||
roles: PropTypes.array
|
||||
}),
|
||||
server: PropTypes.string,
|
||||
searchText: PropTypes.string,
|
||||
|
@ -135,6 +140,11 @@ class RoomsListView extends React.Component {
|
|||
queueSize: PropTypes.number,
|
||||
inquiryEnabled: PropTypes.bool,
|
||||
encryptionBanner: PropTypes.string,
|
||||
createTeamPermission: PropTypes.array,
|
||||
createDirectMessagePermission: PropTypes.array,
|
||||
createPublicChannelPermission: PropTypes.array,
|
||||
createPrivateChannelPermission: PropTypes.array,
|
||||
createDiscussionPermission: PropTypes.array,
|
||||
initAdd: PropTypes.func
|
||||
};
|
||||
|
||||
|
@ -152,7 +162,8 @@ class RoomsListView extends React.Component {
|
|||
loading: true,
|
||||
chatsUpdate: [],
|
||||
chats: [],
|
||||
item: {}
|
||||
item: {},
|
||||
canCreateRoom: false
|
||||
};
|
||||
this.setHeader();
|
||||
this.getSubscriptions();
|
||||
|
@ -160,6 +171,7 @@ class RoomsListView extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
const { navigation, closeServerDropdown } = this.props;
|
||||
this.handleHasPermission();
|
||||
this.mounted = true;
|
||||
|
||||
if (isTablet) {
|
||||
|
@ -203,7 +215,7 @@ class RoomsListView extends React.Component {
|
|||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { chatsUpdate, searching, item } = this.state;
|
||||
const { chatsUpdate, searching, item, canCreateRoom } = this.state;
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
const propsUpdated = shouldUpdateProps.some(key => nextProps[key] !== this.props[key]);
|
||||
if (propsUpdated) {
|
||||
|
@ -222,6 +234,10 @@ class RoomsListView extends React.Component {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (nextState.canCreateRoom !== canCreateRoom) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextState.item?.rid !== item?.rid) {
|
||||
return true;
|
||||
}
|
||||
|
@ -257,7 +273,20 @@ class RoomsListView extends React.Component {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { sortBy, groupByType, showFavorites, showUnread, rooms, isMasterDetail, insets } = this.props;
|
||||
const {
|
||||
sortBy,
|
||||
groupByType,
|
||||
showFavorites,
|
||||
showUnread,
|
||||
rooms,
|
||||
isMasterDetail,
|
||||
insets,
|
||||
createTeamPermission,
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createDirectMessagePermission,
|
||||
createDiscussionPermission
|
||||
} = this.props;
|
||||
const { item } = this.state;
|
||||
|
||||
if (
|
||||
|
@ -278,6 +307,17 @@ class RoomsListView extends React.Component {
|
|||
if (insets.left !== prevProps.insets.left || insets.right !== prevProps.insets.right) {
|
||||
this.setHeader();
|
||||
}
|
||||
|
||||
if (
|
||||
!dequal(createTeamPermission, prevProps.createTeamPermission) ||
|
||||
!dequal(createPublicChannelPermission, prevProps.createPublicChannelPermission) ||
|
||||
!dequal(createPrivateChannelPermission, prevProps.createPrivateChannelPermission) ||
|
||||
!dequal(createDirectMessagePermission, prevProps.createDirectMessagePermission) ||
|
||||
!dequal(createDiscussionPermission, prevProps.createDiscussionPermission)
|
||||
) {
|
||||
this.handleHasPermission();
|
||||
this.setHeader();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -297,10 +337,31 @@ class RoomsListView extends React.Component {
|
|||
console.countReset(`${this.constructor.name}.render calls`);
|
||||
}
|
||||
|
||||
handleHasPermission = async () => {
|
||||
const {
|
||||
createTeamPermission,
|
||||
createDirectMessagePermission,
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createDiscussionPermission
|
||||
} = this.props;
|
||||
const permissions = [
|
||||
createPublicChannelPermission,
|
||||
createPrivateChannelPermission,
|
||||
createTeamPermission,
|
||||
createDirectMessagePermission,
|
||||
createDiscussionPermission
|
||||
];
|
||||
const permissionsToCreate = await RocketChat.hasPermission(permissions);
|
||||
const canCreateRoom = permissionsToCreate.filter(r => r === true).length > 0;
|
||||
this.setState({ canCreateRoom }, () => this.setHeader());
|
||||
};
|
||||
|
||||
getHeader = () => {
|
||||
const { searching } = this.state;
|
||||
const { searching, canCreateRoom } = this.state;
|
||||
const { navigation, isMasterDetail, insets } = this.props;
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: searching ? 0 : 3 });
|
||||
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerLeft: () =>
|
||||
|
@ -327,7 +388,9 @@ class RoomsListView extends React.Component {
|
|||
headerRight: () =>
|
||||
searching ? null : (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
|
||||
{canCreateRoom ? (
|
||||
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' />
|
||||
<HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' />
|
||||
</HeaderButton.Container>
|
||||
|
@ -963,7 +1026,12 @@ const mapStateToProps = state => ({
|
|||
rooms: state.room.rooms,
|
||||
queueSize: getInquiryQueueSelector(state).length,
|
||||
inquiryEnabled: state.inquiry.enabled,
|
||||
encryptionBanner: state.encryption.banner
|
||||
encryptionBanner: state.encryption.banner,
|
||||
createTeamPermission: state.permissions['create-team'],
|
||||
createDirectMessagePermission: state.permissions['create-d'],
|
||||
createPublicChannelPermission: state.permissions['create-c'],
|
||||
createPrivateChannelPermission: state.permissions['create-p'],
|
||||
createDiscussionPermission: state.permissions['start-discussion']
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
Loading…
Reference in New Issue