From cfd52d9369720e298d813520abcd8bd87e4f0496 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Mon, 21 Jun 2021 16:06:40 -0400 Subject: [PATCH] Pass a customized comment component for studios --- src/redux/studio-permissions.js | 13 +++++++---- .../preview/comment/top-level-comment.jsx | 2 +- src/views/studio/studio-comment.js | 17 ++++++++++++++ src/views/studio/studio-comments.jsx | 23 +++---------------- test/unit/components/studio-comments.test.jsx | 6 +++++ test/unit/redux/studio-permissions.test.js | 23 +++++++++++-------- 6 files changed, 49 insertions(+), 35 deletions(-) create mode 100644 src/views/studio/studio-comment.js diff --git a/src/redux/studio-permissions.js b/src/redux/studio-permissions.js index 6881d24f2..93d6a8b75 100644 --- a/src/redux/studio-permissions.js +++ b/src/redux/studio-permissions.js @@ -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, diff --git a/src/views/preview/comment/top-level-comment.jsx b/src/views/preview/comment/top-level-comment.jsx index 04433daf4..d33dcaeb5 100644 --- a/src/views/preview/comment/top-level-comment.jsx +++ b/src/views/preview/comment/top-level-comment.jsx @@ -233,7 +233,7 @@ TopLevelComment.propTypes = { canReply: PropTypes.bool, canReport: PropTypes.bool, canRestore: PropTypes.bool, - commentComponent: PropTypes.element, + commentComponent: PropTypes.func, content: PropTypes.string, datetimeCreated: PropTypes.string, defaultExpanded: PropTypes.bool, diff --git a/src/views/studio/studio-comment.js b/src/views/studio/studio-comment.js new file mode 100644 index 000000000..8cb18978e --- /dev/null +++ b/src/views/studio/studio-comment.js @@ -0,0 +1,17 @@ +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); diff --git a/src/views/studio/studio-comments.jsx b/src/views/studio/studio-comments.jsx index 453684bf8..b0654e0d3 100644 --- a/src/views/studio/studio-comments.jsx +++ b/src/views/studio/studio-comments.jsx @@ -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 = ({ ( + jest.requireActual('../../../src/views/preview/comment/comment.jsx') +)); + describe('Studio comments', () => { test('if there are no comments, they get loaded', () => { const loadComments = jest.fn(); diff --git a/test/unit/redux/studio-permissions.test.js b/test/unit/redux/studio-permissions.test.js index 95333ec25..037265229 100644 --- a/test/unit/redux/studio-permissions.test.js +++ b/test/unit/redux/studio-permissions.test.js @@ -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); }); });