Advanced permissions phase 1 (#1571)

* [XYZ-45] New permissions implementation

* Changing mattermost-redux branch in packages.json

* Changed yarn.lock file to point to advanced-permissions-phase-1

* MM-9620: Add reactions permissions (#1451)

* Fixing some code styles warnings

* Fix mobile app to use latest Mattermost redux

* Some merge errors fixed
This commit is contained in:
Jesús Espino 2018-04-04 17:01:39 +02:00 committed by Elias Nahum
parent 683ebc3faa
commit f91abf3ea9
9 changed files with 92 additions and 45 deletions

View file

@ -12,6 +12,7 @@ import {
getSortedDirectChannelIds,
} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getTheme, getFavoritesPreferences} from 'mattermost-redux/selectors/entities/preferences';
import {showCreateOption} from 'mattermost-redux/utils/channel_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
@ -26,9 +27,10 @@ function mapStateToProps(state) {
const publicChannelIds = getSortedPublicChannelIds(state);
const privateChannelIds = getSortedPrivateChannelIds(state);
const directChannelIds = getSortedDirectChannelIds(state);
const currentTeamId = getCurrentTeamId(state);
return {
canCreatePrivateChannels: showCreateOption(state, config, license, General.PRIVATE_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
canCreatePrivateChannels: showCreateOption(state, config, license, currentTeamId, General.PRIVATE_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
unreadChannelIds,
favoriteChannelIds,
publicChannelIds,

View file

@ -8,8 +8,10 @@ import {createPost, deletePost, removePost} from 'mattermost-redux/actions/posts
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {getMyPreferences, getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamUrl} from 'mattermost-redux/selectors/entities/teams';
import {isPostFlagged} from 'mattermost-redux/utils/post_utils';
import {getCurrentTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {canDeletePost, canEditPost, isPostFlagged} from 'mattermost-redux/utils/post_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import {insertToDraft, setPostTooltipVisible} from 'app/actions/views/channel';
import {addReaction} from 'app/actions/views/emoji';
@ -23,6 +25,9 @@ function mapStateToProps(state, ownProps) {
const {config, license} = state.entities.general;
const roles = getCurrentUserId(state) ? getCurrentUserRoles(state) : '';
const myPreferences = getMyPreferences(state);
const currentUserId = getCurrentUserId(state);
const currentTeamId = getCurrentTeamId(state);
const currentChannelId = getCurrentChannelId(state);
let isFirstReply = true;
let isLastReply = true;
@ -51,17 +56,25 @@ function mapStateToProps(state, ownProps) {
const {deviceWidth} = getDimensions(state);
let canDelete = false;
let canEdit = false;
if (post) {
canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin(roles), isSystemAdmin(roles));
canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post);
}
return {
config,
canDelete,
canEdit,
currentTeamUrl: getCurrentTeamUrl(state),
currentUserId: getCurrentUserId(state),
currentUserId,
deviceWidth,
post,
isFirstReply,
isLastReply,
commentedOnPost,
license,
roles,
theme: getTheme(state),
isFlagged: isPostFlagged(post.id, myPreferences),
};

View file

@ -26,8 +26,7 @@ import {getToolTipVisible} from 'app/utils/tooltip';
import {Posts} from 'mattermost-redux/constants';
import DelayedAction from 'mattermost-redux/utils/delayed_action';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {canDeletePost, canEditPost, isPostEphemeral, isPostPendingOrFailed, isSystemMessage} from 'mattermost-redux/utils/post_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import {editDisable, isPostEphemeral, isPostPendingOrFailed, isSystemMessage} from 'mattermost-redux/utils/post_utils';
import Config from 'assets/config';
@ -56,8 +55,9 @@ export default class Post extends PureComponent {
license: PropTypes.object.isRequired,
managedConfig: PropTypes.object.isRequired,
navigator: PropTypes.object,
canEdit: PropTypes.bool.isRequired,
canDelete: PropTypes.bool.isRequired,
onPermalinkPress: PropTypes.func,
roles: PropTypes.string,
shouldRenderReplyButton: PropTypes.bool,
showFullDate: PropTypes.bool,
showLongPost: PropTypes.bool,
@ -79,32 +79,26 @@ export default class Post extends PureComponent {
constructor(props) {
super(props);
const {config, license, currentUserId, roles, post} = props;
const {config, license, currentUserId, post} = props;
this.editDisableAction = new DelayedAction(this.handleEditDisable);
if (post) {
this.state = {
canEdit: canEditPost(config, license, currentUserId, post, this.editDisableAction),
canDelete: canDeletePost(config, license, currentUserId, post, isAdmin(roles), isSystemAdmin(roles)),
};
} else {
this.state = {
canEdit: false,
canDelete: false,
};
editDisable(config, license, currentUserId, post, this.editDisableAction);
}
this.state = {
canEdit: this.props.canEdit,
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.config !== this.props.config ||
nextProps.license !== this.props.license ||
nextProps.currentUserId !== this.props.currentUserId ||
nextProps.post !== this.props.post ||
nextProps.roles !== this.props.roles) {
const {config, license, currentUserId, roles, post} = nextProps;
nextProps.post !== this.props.post) {
const {config, license, currentUserId, post} = nextProps;
editDisable(config, license, currentUserId, post, this.editDisableAction);
this.setState({
canEdit: canEditPost(config, license, currentUserId, post, this.editDisableAction),
canDelete: canDeletePost(config, license, currentUserId, post, isAdmin(roles), isSystemAdmin(roles)),
canEdit: nextProps.canEdit,
});
}
}
@ -446,7 +440,7 @@ export default class Post extends PureComponent {
<View style={{maxWidth: postWidth}}>
<PostBody
ref={'postBody'}
canDelete={this.state.canDelete}
canDelete={this.props.canDelete}
canEdit={this.state.canEdit}
highlight={highlight}
isSearchResult={isSearchResult}

View file

@ -9,13 +9,13 @@ import {
General,
Posts,
} from 'mattermost-redux/constants';
import {getCurrentChannel, getMyCurrentChannelMembership} from 'mattermost-redux/selectors/entities/channels';
import {getChannel, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels';
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamMembership} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {hasNewPermissions} from 'mattermost-redux/selectors/entities/general';
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
import Permissions from 'mattermost-redux/constants/permissions';
import {canManageMembersOldPermissions} from 'mattermost-redux/utils/channel_utils';
import {
isEdited,
isPostEphemeral,
@ -28,6 +28,17 @@ const POST_TIMEOUT = 20000;
function mapStateToProps(state, ownProps) {
const post = getPost(state, ownProps.postId);
const channel = getChannel(state, post.channel_id) || {};
const teamId = channel.team_id;
let canAddReaction = true;
if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
team: teamId,
channel: post.channel_id,
permission: Permissions.ADD_REACTION,
});
}
let isFailed = post.failed;
let isPending = post.id === post.pending_post_id;
@ -38,12 +49,7 @@ function mapStateToProps(state, ownProps) {
isPending = false;
}
const channel = getCurrentChannel(state);
const user = getCurrentUser(state);
const teamMember = getCurrentTeamMembership(state);
const channelMember = getMyCurrentChannelMembership(state);
const {config, license} = state.entities.general;
const isUserCanManageMembers = canManageMembersOldPermissions(channel, user, teamMember, channelMember, config, license);
const isUserCanManageMembers = canManageChannelMembers(state);
const isEphemeralPost = isPostEphemeral(post);
let isPostAddChannelMember = false;
@ -70,6 +76,7 @@ function mapStateToProps(state, ownProps) {
isSystemMessage: isSystemMessage(post),
message: post.message,
theme: getTheme(state),
canAddReaction,
};
}

View file

@ -53,6 +53,7 @@ export default class PostBody extends PureComponent {
managedConfig: PropTypes.object,
message: PropTypes.string,
navigator: PropTypes.object.isRequired,
canAddReaction: PropTypes.bool,
onAddReaction: PropTypes.func,
onCopyPermalink: PropTypes.func,
onCopyText: PropTypes.func,
@ -114,6 +115,7 @@ export default class PostBody extends PureComponent {
const {
canEdit,
canDelete,
canAddReaction,
hasBeenDeleted,
isPending,
isFailed,
@ -130,10 +132,12 @@ export default class PostBody extends PureComponent {
// we should check for the user roles and permissions
if (!isPendingOrFailedPost && !isSystemMessage && !isPostEphemeral) {
actions.push({
text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}),
onPress: this.props.onAddReaction,
});
if (canAddReaction) {
actions.push({
text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}),
onPress: this.props.onAddReaction,
});
}
if (managedConfig.copyAndPasteProtection !== 'true') {
actions.push({

View file

@ -5,9 +5,13 @@ import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getReactionsForPost, removeReaction} from 'mattermost-redux/actions/posts';
import {makeGetReactionsForPost} from 'mattermost-redux/selectors/entities/posts';
import {makeGetReactionsForPost, getPost} from 'mattermost-redux/selectors/entities/posts';
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
import {hasNewPermissions} from 'mattermost-redux/selectors/entities/general';
import Permissions from 'mattermost-redux/constants/permissions';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
import {addReaction} from 'app/actions/views/emoji';
@ -16,6 +20,25 @@ import Reactions from './reactions';
function makeMapStateToProps() {
const getReactionsForPostSelector = makeGetReactionsForPost();
return function mapStateToProps(state, ownProps) {
const post = getPost(state, ownProps.postId);
const channel = getChannel(state, post.channel_id) || {};
const teamId = channel.team_id;
let canAddReaction = true;
let canRemoveReaction = true;
if (hasNewPermissions(state)) {
canAddReaction = haveIChannelPermission(state, {
team: teamId,
channel: post.channel_id,
permission: Permissions.ADD_REACTION,
});
canRemoveReaction = haveIChannelPermission(state, {
team: teamId,
channel: post.channel_id,
permission: Permissions.REMOVE_REACTION,
});
}
const currentUserId = getCurrentUserId(state);
const reactionsForPost = getReactionsForPostSelector(state, ownProps.postId);
@ -38,6 +61,8 @@ function makeMapStateToProps() {
highlightedReactions,
reactions: reactionsByName,
theme: getTheme(state),
canAddReaction,
canRemoveReaction,
};
};
}

View file

@ -28,7 +28,9 @@ export default class Reactions extends PureComponent {
postId: PropTypes.string.isRequired,
reactions: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
canAddReaction: PropTypes.bool,
canRemoveReaction: PropTypes.bool.isRequired,
}
static defaultProps = {
position: 'right',
@ -41,9 +43,9 @@ export default class Reactions extends PureComponent {
handleReactionPress = (emoji, remove) => {
const {actions, postId} = this.props;
if (remove) {
if (remove && this.props.canRemoveReaction) {
actions.removeReaction(postId, emoji);
} else {
} else if (!remove && this.props.canAddReaction) {
actions.addReaction(postId, emoji);
}
};

View file

@ -57,8 +57,8 @@ function mapStateToProps(state) {
}
return {
canDeleteChannel: showDeleteOption(config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
canEditChannel: showManagementOptions(config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
canDeleteChannel: showDeleteOption(state, config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
canEditChannel: showManagementOptions(state, config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
currentChannel,
currentChannelCreatorName,
currentChannelMemberCount,

View file

@ -36,7 +36,7 @@ function mapStateToProps(state) {
const channels = joinableChannels(state);
return {
canCreateChannels: showCreateOption(config, license, General.OPEN_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
canCreateChannels: showCreateOption(state, config, license, currentTeamId, General.OPEN_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
currentUserId,
currentTeamId,
channels,