[MM-21923] Enforce channel mentions permission (#3875)

* MM-21923 Enforce channel mentions permission by hiding it from autocomplete and disabling @mention confirmation modal

Add tests for post_textbox channel mentions

* MM-21923 Set use channel mentions to true if server version is not minimum required

* MM-21923 Point to specific redux hash and update permission check to be easier to read

* MM-21923 Fix currentChannel.id
This commit is contained in:
Farhan Munshi 2020-02-26 20:41:47 -05:00 committed by GitHub
parent 99cc9c94c3
commit 7952b5aeb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 3 deletions

View file

@ -37,6 +37,7 @@ export default class AtMention extends PureComponent {
value: PropTypes.string,
isLandscape: PropTypes.bool.isRequired,
nestedScrollEnabled: PropTypes.bool,
useChannelMentions: PropTypes.bool.isRequired,
};
static defaultProps = {
@ -100,7 +101,7 @@ export default class AtMention extends PureComponent {
});
}
if (this.checkSpecialMentions(matchTerm)) {
if (this.props.useChannelMentions && this.checkSpecialMentions(matchTerm)) {
sections.push({
id: t('suggestion.mention.special'),
defaultMessage: 'Special Mentions',

View file

@ -4,6 +4,7 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
import {autocompleteUsers} from 'mattermost-redux/actions/users';
import {getCurrentChannelId, getDefaultChannel} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
@ -17,12 +18,26 @@ import {
} from 'app/selectors/autocomplete';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
import {Permissions} from 'mattermost-redux/constants';
import AtMention from './at_mention';
function mapStateToProps(state, ownProps) {
const {cursorPosition, isSearch} = ownProps;
const currentChannelId = getCurrentChannelId(state);
let useChannelMentions = true;
if (isMinimumServerVersion(state.entities.general.serverVersion, 5, 22)) {
useChannelMentions = haveIChannelPermission(
state,
{
channel: currentChannelId,
permission: Permissions.USE_CHANNEL_MENTIONS,
},
);
}
const value = ownProps.value.substring(0, cursorPosition);
const matchTerm = getMatchTermForAtMention(value, isSearch);
@ -47,6 +62,7 @@ function mapStateToProps(state, ownProps) {
requestStatus: state.requests.users.autocompleteUsers.status,
theme: getTheme(state),
isLandscape: isLandscape(state),
useChannelMentions,
};
}

View file

@ -4,10 +4,12 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {General} from 'mattermost-redux/constants';
import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
import {General, Permissions} from 'mattermost-redux/constants';
import {createPost} from 'mattermost-redux/actions/posts';
import {setStatus} from 'mattermost-redux/actions/users';
import {getCurrentChannel, isCurrentChannelReadOnly, getCurrentChannelStats} from 'mattermost-redux/selectors/entities/channels';
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
import {canUploadFilesOnMobile, getConfig} from 'mattermost-redux/selectors/entities/general';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId, getStatusForUserId} from 'mattermost-redux/selectors/entities/users';
@ -49,6 +51,17 @@ function mapStateToProps(state, ownProps) {
const currentChannelMembersCount = currentChannelStats?.member_count || 0; // eslint-disable-line camelcase
const isTimezoneEnabled = config?.ExperimentalTimezone === 'true';
let useChannelMentions = true;
if (isMinimumServerVersion(state.entities.general.serverVersion, 5, 22)) {
useChannelMentions = haveIChannelPermission(
state,
{
channel: currentChannel.id,
permission: Permissions.USE_CHANNEL_MENTIONS,
},
);
}
return {
currentChannel,
channelId: ownProps.channelId || (currentChannel ? currentChannel.id : ''),
@ -71,6 +84,7 @@ function mapStateToProps(state, ownProps) {
currentChannelMembersCount,
isTimezoneEnabled,
isLandscape: isLandscape(state),
useChannelMentions,
};
}

View file

@ -64,6 +64,9 @@ describe('PostTextBox', () => {
valueEvent: '',
isLandscape: false,
screenId: 'NavigationScreen1',
currentChannelMembersCount: 50,
enableConfirmNotificationsToChannel: true,
useChannelMentions: true,
};
test('should match, full snapshot', () => {
@ -117,6 +120,38 @@ describe('PostTextBox', () => {
expect(Alert.alert).toHaveBeenCalledTimes(1);
});
test('should send an alert when sending a message with a channel mention', () => {
const wrapper = shallowWithIntl(
<PostTextbox {...baseProps}/>,
);
const message = '@all';
const instance = wrapper.instance();
instance.handleTextChange(message);
expect(wrapper.state('value')).toBe(message);
instance.sendMessage();
expect(Alert.alert).toBeCalled();
expect(Alert.alert).toHaveBeenCalledWith('Confirm sending notifications to entire channel', expect.anything(), expect.anything());
});
test('should not send an alert when sending a message with a channel mention when the user does not have channel mentions permission', () => {
const wrapper = shallowWithIntl(
<PostTextbox
{...baseProps}
useChannelMentions={false}
/>,
);
const message = '@all';
const instance = wrapper.instance();
instance.handleTextChange(message);
expect(wrapper.state('value')).toBe(message);
instance.sendMessage();
expect(Alert.alert).not.toHaveBeenCalled();
});
test('should return correct @all (same for @channel)', () => {
for (const data of [
{

View file

@ -98,6 +98,7 @@ export default class PostTextBoxBase extends PureComponent {
currentChannel: PropTypes.object,
isLandscape: PropTypes.bool.isRequired,
screenId: PropTypes.string.isRequired,
useChannelMentions: PropTypes.bool.isRequired,
};
static defaultProps = {
@ -573,7 +574,7 @@ export default class PostTextBoxBase extends PureComponent {
const {value} = this.state;
const currentMembersCount = this.props.currentChannelMembersCount;
const notificationsToChannel = this.props.enableConfirmNotificationsToChannel;
const notificationsToChannel = this.props.enableConfirmNotificationsToChannel && this.props.useChannelMentions;
const toAllOrChannel = this.textContainsAtAllAtChannel(value);
if (value.indexOf('/') === 0) {