Unverified Commit e331c20d authored by Paul Kaplan's avatar Paul Kaplan Committed by GitHub

Merge pull request #5649 from paulkaplan/no-report-own-comments

Fix permissions issues on studio comments
parents 5b17870c 810465bf
......@@ -18,14 +18,18 @@ const selectCanAddProjects = state =>
// This isn't "canComment" since they could be muted, but comment composer handles that
const selectShowCommentComposer = state => selectIsSocial(state);
const selectCanReportComment = state => selectIsSocial(state);
const selectCanReportComment = (state, commentUsername) =>
selectIsLoggedIn(state) && selectUsername(state) !== commentUsername;
const selectCanRestoreComment = state => selectIsAdmin(state);
// On the project page, project owners can delete comments with a confirmation,
// and admins can delete comments without a confirmation.
// On the studio page, studio creators and managers have the ability to delete *their own* comments with confirmation.
// Admins can delete comments without a confirmation.
const selectCanDeleteAnyComment = state => selectIsAdmin(state);
const selectCanDeleteOwnComment = state => isCreator(state) || isManager(state);
const selectCanDeleteComment = (state, commentUsername) => {
if (selectIsAdmin(state)) return true;
if (isManager(state) && selectUsername(state) === commentUsername) return true;
return false;
};
const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(state);
const selectCanFollowStudio = state => selectIsLoggedIn(state);
......@@ -82,8 +86,7 @@ export {
selectCanAddProjects,
selectCanFollowStudio,
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,
......
......@@ -131,7 +131,7 @@ class TopLevelComment extends React.Component {
return (
<FlexRow className="comment-container">
<Comment
<this.props.commentComponent
highlighted={highlightedCommentId === id}
postURI={postURI}
onAddComment={this.handleAddComment}
......@@ -173,7 +173,7 @@ class TopLevelComment extends React.Component {
<React.Fragment
key={`reply-and-status-${reply.id}`}
>
<Comment
<this.props.commentComponent
author={reply.author}
canDelete={canDelete}
canDeleteWithoutConfirm={canDeleteWithoutConfirm}
......@@ -233,6 +233,7 @@ TopLevelComment.propTypes = {
canReply: PropTypes.bool,
canReport: PropTypes.bool,
canRestore: PropTypes.bool,
commentComponent: PropTypes.func,
content: PropTypes.string,
datetimeCreated: PropTypes.string,
defaultExpanded: PropTypes.bool,
......@@ -260,7 +261,8 @@ TopLevelComment.defaultProps = {
defaultExpanded: false,
hasThreadLimit: false,
moreRepliesToLoad: false,
threadHasReplyStatus: false
threadHasReplyStatus: false,
commentComponent: Comment
};
module.exports = TopLevelComment;
import {connect} from 'react-redux';
import Comment from '../preview/comment/comment.jsx';
import {
selectCanDeleteComment,
selectCanReportComment,
selectShowCommentComposer
} from '../../redux/studio-permissions';
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
export default connect(
(state, ownProps) => ({
canReport: selectCanReportComment(state, ownProps.author.username),
canDelete: selectCanDeleteComment(state, ownProps.author.username),
canReply: selectShowCommentComposer(state) && selectStudioCommentsAllowed(state)
})
)(Comment);
......@@ -10,19 +10,17 @@ import TopLevelComment from '../preview/comment/top-level-comment.jsx';
import studioCommentActions from '../../redux/studio-comment-actions.js';
import StudioCommentsAllowed from './studio-comments-allowed.jsx';
import StudioCommentsNotAllowed from './studio-comments-not-allowed.jsx';
import {selectIsAdmin, selectHasFetchedSession, selectUsername} from '../../redux/session';
import {selectIsAdmin, selectHasFetchedSession} from '../../redux/session';
import {
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,
selectCanEditCommentsAllowed,
selectShowCommentsList,
selectShowCommentsGloballyOffError
} from '../../redux/studio-permissions';
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
import StudioComment from './studio-comment.js';
const StudioComments = ({
comments,
......@@ -37,12 +35,8 @@ const StudioComments = ({
shouldShowCommentComposer,
shouldShowCommentsList,
shouldShowCommentsGloballyOffError,
username,
canDeleteAnyComment,
canDeleteOwnComment,
canDeleteCommentWithoutConfirm,
canEditCommentsAllowed,
canReportComment,
canRestoreComment,
handleDeleteComment,
handleRestoreComment,
......@@ -127,12 +121,9 @@ const StudioComments = ({
<TopLevelComment
hasThreadLimit
author={comment.author}
canDelete={canDeleteAnyComment ||
(canDeleteOwnComment && comment.author.username === username)}
canDeleteWithoutConfirm={canDeleteCommentWithoutConfirm}
canReply={shouldShowCommentComposer && commentsAllowed}
canReport={canReportComment}
canRestore={canRestoreComment}
commentComponent={StudioComment}
content={comment.content}
datetimeCreated={comment.datetime_created}
defaultExpanded={singleCommentId}
......@@ -190,12 +181,8 @@ StudioComments.propTypes = {
shouldShowCommentComposer: PropTypes.bool,
shouldShowCommentsGloballyOffError: PropTypes.bool,
shouldShowCommentsList: PropTypes.bool,
username: PropTypes.string,
canDeleteAnyComment: PropTypes.bool,
canDeleteOwnComment: PropTypes.bool,
canDeleteCommentWithoutConfirm: PropTypes.bool,
canEditCommentsAllowed: PropTypes.bool,
canReportComment: PropTypes.bool,
canRestoreComment: PropTypes.bool,
handleDeleteComment: PropTypes.func,
handleRestoreComment: PropTypes.func,
......@@ -217,16 +204,12 @@ export default connect(
isAdmin: selectIsAdmin(state),
moreCommentsToLoad: state.comments.moreCommentsToLoad,
replies: state.comments.replies,
username: selectUsername(state),
commentsAllowed: selectStudioCommentsAllowed(state),
shouldShowCommentComposer: selectShowCommentComposer(state),
shouldShowCommentsGloballyOffError: selectShowCommentsGloballyOffError(state),
shouldShowCommentsList: selectShowCommentsList(state),
canDeleteAnyComment: selectCanDeleteAnyComment(state),
canDeleteOwnComment: selectCanDeleteOwnComment(state),
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
canReportComment: selectCanReportComment(state),
canRestoreComment: selectCanRestoreComment(state),
postURI: `/proxy/comments/studio/${state.studio.id}`
}),
......
import React from 'react';
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
import {StudioComments} from '../../../src/views/studio/studio-comments.jsx';
// Replace customized studio comment with default comment to avoid redux issues in the test
jest.mock('../../../src/views/studio/studio-comment.js', () => (
jest.requireActual('../../../src/views/preview/comment/comment.jsx')
));
describe('Studio comments', () => {
test('if there are no comments, they get loaded', () => {
const loadComments = jest.fn();
......
......@@ -2,8 +2,7 @@ import {
selectCanEditInfo,
selectCanAddProjects,
selectShowCommentComposer,
selectCanDeleteAnyComment,
selectCanDeleteOwnComment,
selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm,
selectCanReportComment,
selectCanRestoreComment,
......@@ -189,17 +188,22 @@ describe('studio comments', () => {
describe('can report comment', () => {
test.each([
['logged in', true],
['unconfirmed', false],
['unconfirmed', true],
['logged out', false],
['muted creator', true],
['muted logged in', true]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanReportComment(state)).toBe(expected);
expect(selectCanReportComment(state, 'not me')).toBe(expected);
});
test('cannot report your own comment', () => {
setStateByRole('logged in');
const loggedInUsername = selectUsername(state);
expect(selectCanReportComment(state, loggedInUsername)).toBe(false);
});
});
describe('can delete any comment', () => {
describe('can delete others comments', () => {
test.each([
['admin', true],
['curator', false],
......@@ -212,13 +216,13 @@ describe('studio comments', () => {
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanDeleteAnyComment(state)).toBe(expected);
expect(selectCanDeleteComment(state, 'not me')).toBe(expected);
});
});
describe('can delete own comment', () => {
describe('can delete my own comment', () => {
test.each([
['admin', false], // This is false here because we check for `canDeleteAnyComment` separately
['admin', true],
['curator', false],
['manager', true],
['creator', true],
......@@ -231,7 +235,8 @@ describe('studio comments', () => {
['muted logged in', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanDeleteOwnComment(state)).toBe(expected);
const loggedInUsername = selectUsername(state);
expect(selectCanDeleteComment(state, loggedInUsername)).toBe(expected);
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment