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:
parent
aa5951a2b2
commit
fbd7fedfbc
6 changed files with 54 additions and 11 deletions
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ describe('makeMapStateToProps', () => {
|
|||
general: {
|
||||
serverVersion: '5.18',
|
||||
},
|
||||
channels: {myMembers: {}},
|
||||
teams: {myMembers: {}},
|
||||
roles: {roles: {}},
|
||||
users: {profiles: {}},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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({});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue