MM-21925: Enforces 'create_post' permission. (#3904)

* MM-21925: Enforces 'create_post' permission.

* MM-21925: Reverts adding 'can_post' check from post component.

* MM-21925: Removes unused variable and some duplicate imports.

* MM-21925: Removes unnecessary prop.

* MM-21925: Removes unused test prop.
This commit is contained in:
Martin Kraft 2020-03-13 09:17:42 -04:00 committed by GitHub
parent aa5951a2b2
commit fbd7fedfbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 11 deletions

View file

@ -50,6 +50,14 @@ function mapStateToProps(state, ownProps) {
const currentChannelStats = getCurrentChannelStats(state);
const currentChannelMembersCount = currentChannelStats?.member_count || 0; // eslint-disable-line camelcase
const isTimezoneEnabled = config?.ExperimentalTimezone === 'true';
const canPost = haveIChannelPermission(
state,
{
channel: currentChannel.id,
team: currentChannel.team_id,
permission: Permissions.CREATE_POST,
},
);
let useChannelMentions = true;
if (isMinimumServerVersion(state.entities.general.serverVersion, 5, 22)) {
@ -83,6 +91,7 @@ function mapStateToProps(state, ownProps) {
currentChannelMembersCount,
isTimezoneEnabled,
isLandscape: isLandscape(state),
canPost,
useChannelMentions,
};
}

View file

@ -63,6 +63,7 @@ describe('PostTextBox', () => {
valueEvent: '',
isLandscape: false,
screenId: 'NavigationScreen1',
canPost: true,
currentChannelMembersCount: 50,
enableConfirmNotificationsToChannel: true,
useChannelMentions: true,
@ -554,5 +555,15 @@ describe('PostTextBox', () => {
wrapper.setProps({value: 'value', channelId: 'channel-id2'});
expect(wrapper.state('value')).toEqual('value');
});
test('should be disabled without the create_post permission', () => {
const props = {...baseProps, canPost: false};
const wrapper = shallowWithIntl(
<PostTextbox {...props}/>,
);
expect(wrapper.find(PasteableTextInput).prop('editable')).toBe(false);
});
});

View file

@ -97,6 +97,7 @@ export default class PostTextBoxBase extends PureComponent {
currentChannel: PropTypes.object,
isLandscape: PropTypes.bool.isRequired,
screenId: PropTypes.string.isRequired,
canPost: PropTypes.bool.isRequired,
useChannelMentions: PropTypes.bool.isRequired,
};
@ -257,7 +258,7 @@ export default class PostTextBoxBase extends PureComponent {
};
getTextInputButton = (actionType) => {
const {channelIsReadOnly, theme} = this.props;
const {channelIsReadOnly, theme, canPost} = this.props;
const style = getStyleSheet(theme);
let button = null;
@ -265,7 +266,7 @@ export default class PostTextBoxBase extends PureComponent {
let iconColor = changeOpacity(theme.centerChannelColor, 0.64);
let isDisabled = false;
if (!channelIsReadOnly) {
if (!channelIsReadOnly && canPost) {
switch (actionType) {
case 'at':
isDisabled = this.state.value[this.state.value.length - 1] === '@';
@ -313,7 +314,7 @@ export default class PostTextBoxBase extends PureComponent {
}
getMediaButton = (actionType) => {
const {canUploadFiles, channelIsReadOnly, files, maxFileSize, theme} = this.props;
const {canUploadFiles, channelIsReadOnly, files, maxFileSize, theme, canPost} = this.props;
const style = getStyleSheet(theme);
let button = null;
const props = {
@ -328,7 +329,7 @@ export default class PostTextBoxBase extends PureComponent {
buttonContainerStyle: style.iconWrapper,
};
if (canUploadFiles && !channelIsReadOnly) {
if (canUploadFiles && !channelIsReadOnly && canPost) {
switch (actionType) {
case 'file':
button = (
@ -351,11 +352,11 @@ export default class PostTextBoxBase extends PureComponent {
}
getInputContainerStyle = () => {
const {channelIsReadOnly, theme} = this.props;
const {channelIsReadOnly, theme, canPost} = this.props;
const style = getStyleSheet(theme);
const inputContainerStyle = [style.inputContainer];
if (channelIsReadOnly) {
if (channelIsReadOnly || !canPost) {
inputContainerStyle.push(style.readonlyContainer);
}
@ -363,10 +364,10 @@ export default class PostTextBoxBase extends PureComponent {
};
getPlaceHolder = () => {
const {channelIsReadOnly, rootId} = this.props;
const {channelIsReadOnly, rootId, canPost} = this.props;
let placeholder;
if (channelIsReadOnly) {
if (channelIsReadOnly || !canPost) {
placeholder = {id: t('mobile.create_post.read_only'), defaultMessage: 'This channel is read-only.'};
} else if (rootId) {
placeholder = {id: t('create_comment.addComment'), defaultMessage: 'Add a comment...'};
@ -897,7 +898,7 @@ export default class PostTextBoxBase extends PureComponent {
renderTextBox = () => {
const {intl} = this.context;
const {channelDisplayName, channelIsArchived, channelIsReadOnly, theme, isLandscape, files, rootId} = this.props;
const {channelDisplayName, channelIsArchived, channelIsReadOnly, theme, isLandscape, files, rootId, canPost} = this.props;
const style = getStyleSheet(theme);
if (channelIsArchived) {
@ -949,12 +950,12 @@ export default class PostTextBoxBase extends PureComponent {
keyboardType={this.state.keyboardType}
onEndEditing={this.handleEndEditing}
disableFullscreenUI={true}
editable={!channelIsReadOnly}
editable={!channelIsReadOnly && canPost}
onPaste={this.handlePasteFiles}
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
onContentSizeChange={Platform.OS === 'android' ? this.handleInputSizeChange : null}
/>
{!channelIsReadOnly &&
{!channelIsReadOnly && canPost &&
<React.Fragment>
<FileUploadPreview
files={files}

View file

@ -56,6 +56,14 @@ export function makeMapStateToProps() {
let {canDelete} = ownProps;
let canFlag = true;
let canPin = true;
const canPost = haveIChannelPermission(
state,
{
channel: post.channel_id,
team: channel.team_id,
permission: Permissions.CREATE_POST,
},
);
if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
@ -83,6 +91,10 @@ export function makeMapStateToProps() {
}
}
if (!canPost) {
canReply = false;
}
if (ownProps.isSystemMessage) {
canAddReaction = false;
canReply = false;

View file

@ -41,6 +41,10 @@ describe('makeMapStateToProps', () => {
general: {
serverVersion: '5.18',
},
channels: {myMembers: {}},
teams: {myMembers: {}},
roles: {roles: {}},
users: {profiles: {}},
},
};

View file

@ -122,4 +122,10 @@ describe('PostOptions', () => {
expect(actions.deletePost).toBeCalled();
expect(actions.removePost).toBeCalled();
});
test('should not show reply option without create_post permission', () => {
const wrapper = getWrapper({canPost: false});
expect(wrapper.findWhere((node) => node.key() === 'reply')).toMatchObject({});
});
});