Skip to content

Commit

Permalink
MM-9620: Add reactions permissions (mattermost#826)
Browse files Browse the repository at this point in the history
  • Loading branch information
jespino committed Feb 19, 2018
1 parent 2f85d77 commit 5fe4771
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 32 deletions.
5 changes: 5 additions & 0 deletions components/post_view/post_info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {addReaction, removePost} from 'mattermost-redux/actions/posts';
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
import {get, getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getConfig} from 'mattermost-redux/selectors/entities/general';

Expand All @@ -15,7 +16,11 @@ function mapStateToProps(state, ownProps) {
const config = getConfig(state);
const enableEmojiPicker = config.EnableEmojiPicker === 'true';

const channel = getChannel(state, {id: ownProps.post.channel_id}) || {};
const teamId = channel.team_id;

return {
teamId,
useMilitaryTime: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false),
isFlagged: get(state, Preferences.CATEGORY_FLAGGED_POST, ownProps.post.id, null) != null,
isMobile: state.views.channel.mobileView,
Expand Down
24 changes: 18 additions & 6 deletions components/post_view/post_info/post_info.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';
import {Posts} from 'mattermost-redux/constants';
import * as ReduxPostUtils from 'mattermost-redux/utils/post_utils';
import Permissions from 'mattermost-redux/constants/permissions';

import {emitEmojiPosted} from 'actions/post_actions.jsx';
import Constants from 'utils/constants.jsx';
Expand All @@ -17,6 +18,7 @@ import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx
import PostFlagIcon from 'components/post_view/post_flag_icon.jsx';
import PostTime from 'components/post_view/post_time.jsx';
import EmojiIcon from 'components/svg/emoji_icon';
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';

export default class PostInfo extends React.PureComponent {
static propTypes = {
Expand All @@ -26,6 +28,11 @@ export default class PostInfo extends React.PureComponent {
*/
post: PropTypes.object.isRequired,

/*
* The id of the team which belongs the post
*/
teamId: PropTypes.string.isRequired,

/*
* Function called when the comment icon is clicked
*/
Expand Down Expand Up @@ -197,14 +204,19 @@ export default class PostInfo extends React.PureComponent {
onEmojiClick={this.reactEmojiClick}
rightOffset={7}
/>
<button
className='reacticon__container color--link style--none'
onClick={this.toggleEmojiPicker}
<ChannelPermissionGate
channelId={post.channel_id}
teamId={this.props.teamId}
perms={[Permissions.ADD_REACTION]}
>
<EmojiIcon className='icon icon--emoji'/>
</button>
<button
className='reacticon__container color--link style--none'
onClick={this.toggleEmojiPicker}
>
<EmojiIcon className='icon icon--emoji'/>
</button>
</ChannelPermissionGate>
</span>

);
}
}
Expand Down
10 changes: 9 additions & 1 deletion components/post_view/reaction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {bindActionCreators} from 'redux';
import {addReaction, removeReaction} from 'mattermost-redux/actions/posts';
import {getMissingProfilesByIds} from 'mattermost-redux/actions/users';
import {getCurrentUserId, makeGetProfilesForReactions} from 'mattermost-redux/selectors/entities/users';
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
import {getEmojiImageUrl} from 'mattermost-redux/utils/emoji_utils';
import {haveIChannelPerm} from 'mattermost-redux/selectors/entities/roles';
import Permissions from 'mattermost-redux/constants/permissions';

import * as Emoji from 'utils/emoji.jsx';

Expand All @@ -28,13 +31,18 @@ function makeMapStateToProps() {
if (emoji) {
emojiImageUrl = getEmojiImageUrl(emoji);
}
const channel = getChannel(state, {id: ownProps.post.channel_id}) || {};
const teamId = channel.team_id;
const canAddReaction = haveIChannelPerm(state, {team: teamId, channel: ownProps.post.channel_id, perm: Permissions.ADD_REACTION});
const canRemoveReaction = haveIChannelPerm(state, {team: teamId, channel: ownProps.post.channel_id, perm: Permissions.REMOVE_REACTION});

return {
...ownProps,
profiles,
otherUsersCount: ownProps.reactions.length - profiles.length,
currentUserId: getCurrentUserId(state),
reactionCount: ownProps.reactions.length,
canAddReaction,
canRemoveReaction,
emojiImageUrl
};
};
Expand Down
28 changes: 20 additions & 8 deletions components/post_view/reaction/reaction.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ export default class Reaction extends React.PureComponent {
*/
reactions: PropTypes.arrayOf(PropTypes.object).isRequired,

/*
* True if the user has the permission to add a reaction in this channel
*/
canAddReaction: PropTypes.bool.isRequired,

/*
* True if user has the permission to remove his own reactions in this channel
*/
canRemoveReaction: PropTypes.bool.isRequired,

/*
* The URL of the emoji image
*/
Expand Down Expand Up @@ -205,16 +215,18 @@ export default class Reaction extends React.PureComponent {
let clickTooltip;
let className = 'post-reaction';
if (currentUserReacted) {
handleClick = this.removeReaction;
clickTooltip = (
<FormattedMessage
id='reaction.clickToRemove'
defaultMessage='(click to remove)'
/>
);
if (this.props.canRemoveReaction) {
handleClick = this.removeReaction;
clickTooltip = (
<FormattedMessage
id='reaction.clickToRemove'
defaultMessage='(click to remove)'
/>
);
}

className += ' post-reaction--current-user';
} else {
} else if (!currentUserReacted && this.props.canAddReaction) {
handleClick = this.addReaction;
clickTooltip = (
<FormattedMessage
Expand Down
5 changes: 5 additions & 0 deletions components/post_view/reaction_list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as Actions from 'mattermost-redux/actions/posts';
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
import {makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
import {getConfig} from 'mattermost-redux/selectors/entities/general';

Expand All @@ -17,7 +18,11 @@ function makeMapStateToProps() {
const config = getConfig(state);
const enableEmojiPicker = config.EnableEmojiPicker === 'true';

const channel = getChannel(state, {id: ownProps.post.channel_id}) || {};
const teamId = channel.team_id;

return {
teamId,
reactions: getReactionsForPost(state, ownProps.post.id),
emojis: getCustomEmojisByName(state),
enableEmojiPicker
Expand Down
31 changes: 22 additions & 9 deletions components/post_view/reaction_list/reaction_list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import PropTypes from 'prop-types';
import React from 'react';
import {OverlayTrigger, Tooltip} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
import Permissions from 'mattermost-redux/constants/permissions';

import {postListScrollChange} from 'actions/global_actions.jsx';
import {emitEmojiPosted} from 'actions/post_actions.jsx';
import Constants from 'utils/constants.jsx';
import Reaction from 'components/post_view/reaction';
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';

const DEFAULT_EMOJI_PICKER_RIGHT_OFFSET = 15;
const EMOJI_PICKER_WIDTH_OFFSET = 260;
Expand All @@ -23,6 +25,11 @@ export default class ReactionListView extends React.PureComponent {
*/
post: PropTypes.object.isRequired,

/*
* The id of the team which belongs the post
*/
teamId: PropTypes.string.isRequired,

/**
* The reactions to render
*/
Expand Down Expand Up @@ -161,17 +168,23 @@ export default class ReactionListView extends React.PureComponent {
delayShow={Constants.OVERLAY_TIME_DELAY}
overlay={addReactionTooltip}
>
<div
className='post-reaction'
onClick={this.toggleEmojiPicker}
<ChannelPermissionGate
channelId={this.props.post.channel_id}
teamId={this.props.teamId}
perms={[Permissions.ADD_REACTION]}
>
<span
className='post-reaction__add'
ref='addReactionButton'
<div
className='post-reaction'
onClick={this.toggleEmojiPicker}
>
{'+'}
</span>
</div>
<span
className='post-reaction__add'
ref='addReactionButton'
>
{'+'}
</span>
</div>
</ChannelPermissionGate>
</OverlayTrigger>
</span>
);
Expand Down
22 changes: 15 additions & 7 deletions components/rhs_comment/rhs_comment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';
import {Posts} from 'mattermost-redux/constants/index';
import * as ReduxPostUtils from 'mattermost-redux/utils/post_utils';
import Permissions from 'mattermost-redux/constants/permissions';

import {addReaction, emitEmojiPosted} from 'actions/post_actions.jsx';
import TeamStore from 'stores/team_store.jsx';
Expand All @@ -24,12 +25,14 @@ import ReactionListContainer from 'components/post_view/reaction_list';
import ProfilePicture from 'components/profile_picture.jsx';
import EmojiIcon from 'components/svg/emoji_icon';
import MattermostLogo from 'components/svg/mattermost_logo';
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';

import UserProfile from 'components/user_profile.jsx';

export default class RhsComment extends React.Component {
static propTypes = {
post: PropTypes.object,
teamId: PropTypes.object.isRequired,
lastPostCount: PropTypes.number,
user: PropTypes.object,
currentUser: PropTypes.object.isRequired,
Expand Down Expand Up @@ -360,15 +363,20 @@ export default class RhsComment extends React.Component {
spaceRequiredAbove={342}
spaceRequiredBelow={342}
/>
<button
className='reacticon__container reaction color--link style--none'
onClick={this.toggleEmojiPicker}
ref={'rhs_reacticon_' + post.id}
<ChannelPermissionGate
channelId={post.channel_id}
teamId={this.props.teamId}
perms={[Permissions.ADD_REACTION]}
>
<EmojiIcon className='icon icon--emoji'/>
</button>
<button
className='reacticon__container reaction color--link style--none'
onClick={this.toggleEmojiPicker}
ref={'rhs_reacticon_' + post.id}
>
<EmojiIcon className='icon icon--emoji'/>
</button>
</ChannelPermissionGate>
</span>

);
}

Expand Down
1 change: 1 addition & 0 deletions components/rhs_thread/rhs_thread.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ export default class RhsThread extends React.Component {
<Comment
ref={comPost.id}
post={comPost}
teamId={this.props.channel.team_id}
lastPostCount={(reverseCount >= 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1}
user={p}
currentUser={this.props.currentUser}
Expand Down
Loading

0 comments on commit 5fe4771

Please sign in to comment.