[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:
parent
99cc9c94c3
commit
7952b5aeb7
5 changed files with 70 additions and 3 deletions
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue