Fix comment toggling and add permissions test

This commit is contained in:
Paul Kaplan 2021-04-26 15:11:06 -04:00
parent aab4c9aca6
commit f9419ac8fc
7 changed files with 64 additions and 22 deletions

View file

@ -191,7 +191,7 @@ const mutateStudioCommentsAllowed = shouldAllow => ((dispatch, getState) => {
api({ api({
host: '', host: '',
uri: `/site-api/comments/gallery/${studioId}/toggle-comments/`, uri: `/site-api/comments/gallery/${studioId}/toggle-comments/`,
method: 'PUT', method: 'POST',
useCsrf: true useCsrf: true
}, (err, body, res) => { }, (err, body, res) => {
const error = normalizeError(err, body, res); const error = normalizeError(err, body, res);

View file

@ -25,6 +25,10 @@ const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(state);
const selectCanFollowStudio = state => selectIsLoggedIn(state); const selectCanFollowStudio = state => selectIsLoggedIn(state);
// Matching existing behavior, only the creator is allowed to toggle comments.
const selectCanEditCommentsAllowed = state => selectIsAdmin(state) || isCreator(state);
const selectCanEditOpenToAll = state => selectIsAdmin(state) || isManager(state);
export { export {
selectCanEditInfo, selectCanEditInfo,
selectCanAddProjects, selectCanAddProjects,
@ -33,5 +37,7 @@ export {
selectCanDeleteComment, selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm, selectCanDeleteCommentWithoutConfirm,
selectCanReportComment, selectCanReportComment,
selectCanRestoreComment selectCanRestoreComment,
selectCanEditCommentsAllowed,
selectCanEditOpenToAll
}; };

View file

@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {selectStudioCommentsAllowed, selectIsLoadingInfo} from '../../redux/studio'; import {selectStudioCommentsAllowed, selectIsLoadingInfo} from '../../redux/studio';
import {selectCanEditInfo} from '../../redux/studio-permissions';
import { import {
mutateStudioCommentsAllowed, selectIsMutatingCommentsAllowed, selectCommentsAllowedMutationError mutateStudioCommentsAllowed, selectIsMutatingCommentsAllowed, selectCommentsAllowedMutationError
} from '../../redux/studio-mutations'; } from '../../redux/studio-mutations';
const StudioCommentsAllowed = ({ const StudioCommentsAllowed = ({
commentsAllowedError, isLoading, isMutating, commentsAllowed, canEditInfo, handleUpdate commentsAllowedError, isLoading, isMutating, commentsAllowed, handleUpdate
}) => ( }) => (
<div> <div>
{isLoading ? ( {isLoading ? (
@ -19,12 +18,12 @@ const StudioCommentsAllowed = ({
<div> <div>
<label> <label>
<input <input
disabled={isMutating || !canEditInfo} disabled={isMutating}
type="checkbox" type="checkbox"
checked={commentsAllowed} checked={commentsAllowed}
onChange={e => handleUpdate(e.target.checked)} onChange={e => handleUpdate(e.target.checked)}
/> />
<h4>{commentsAllowed ? 'Comments allowed' : 'Comments not allowed'}</h4> <span>{commentsAllowed ? 'Comments allowed' : 'Comments not allowed'}</span>
{commentsAllowedError && <div>Error mutating commentsAllowed: {commentsAllowedError}</div>} {commentsAllowedError && <div>Error mutating commentsAllowed: {commentsAllowedError}</div>}
</label> </label>
</div> </div>
@ -34,7 +33,6 @@ const StudioCommentsAllowed = ({
StudioCommentsAllowed.propTypes = { StudioCommentsAllowed.propTypes = {
commentsAllowedError: PropTypes.string, commentsAllowedError: PropTypes.string,
canEditInfo: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
isMutating: PropTypes.bool, isMutating: PropTypes.bool,
commentsAllowed: PropTypes.bool, commentsAllowed: PropTypes.bool,
@ -44,7 +42,6 @@ StudioCommentsAllowed.propTypes = {
export default connect( export default connect(
state => ({ state => ({
commentsAllowed: selectStudioCommentsAllowed(state), commentsAllowed: selectStudioCommentsAllowed(state),
canEditInfo: selectCanEditInfo(state),
isLoading: selectIsLoadingInfo(state), isLoading: selectIsLoadingInfo(state),
isMutating: selectIsMutatingCommentsAllowed(state), isMutating: selectIsMutatingCommentsAllowed(state),
commentsAllowedError: selectCommentsAllowedMutationError(state) commentsAllowedError: selectCommentsAllowedMutationError(state)

View file

@ -14,11 +14,14 @@ import {
selectCanDeleteComment, selectCanDeleteComment,
selectCanDeleteCommentWithoutConfirm, selectCanDeleteCommentWithoutConfirm,
selectCanReportComment, selectCanReportComment,
selectCanRestoreComment selectCanRestoreComment,
selectCanEditCommentsAllowed
} from '../../redux/studio-permissions'; } from '../../redux/studio-permissions';
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
const StudioComments = ({ const StudioComments = ({
comments, comments,
commentsAllowed,
handleLoadMoreComments, handleLoadMoreComments,
handleNewComment, handleNewComment,
moreCommentsToLoad, moreCommentsToLoad,
@ -27,6 +30,7 @@ const StudioComments = ({
shouldShowCommentComposer, shouldShowCommentComposer,
canDeleteComment, canDeleteComment,
canDeleteCommentWithoutConfirm, canDeleteCommentWithoutConfirm,
canEditCommentsAllowed,
canReportComment, canReportComment,
canRestoreComment, canRestoreComment,
handleDeleteComment, handleDeleteComment,
@ -41,9 +45,9 @@ const StudioComments = ({
return ( return (
<div> <div>
<h2>Comments</h2> <h2>Comments</h2>
<StudioCommentsAllowed /> {canEditCommentsAllowed && <StudioCommentsAllowed />}
<div> <div>
{shouldShowCommentComposer && {shouldShowCommentComposer && commentsAllowed &&
<ComposeComment <ComposeComment
postURI={postURI} postURI={postURI}
onAddComment={handleNewComment} onAddComment={handleNewComment}
@ -88,6 +92,7 @@ const StudioComments = ({
StudioComments.propTypes = { StudioComments.propTypes = {
comments: PropTypes.arrayOf(PropTypes.shape({})), comments: PropTypes.arrayOf(PropTypes.shape({})),
commentsAllowed: PropTypes.bool,
handleLoadMoreComments: PropTypes.func, handleLoadMoreComments: PropTypes.func,
handleNewComment: PropTypes.func, handleNewComment: PropTypes.func,
moreCommentsToLoad: PropTypes.bool, moreCommentsToLoad: PropTypes.bool,
@ -95,6 +100,7 @@ StudioComments.propTypes = {
shouldShowCommentComposer: PropTypes.bool, shouldShowCommentComposer: PropTypes.bool,
canDeleteComment: PropTypes.bool, canDeleteComment: PropTypes.bool,
canDeleteCommentWithoutConfirm: PropTypes.bool, canDeleteCommentWithoutConfirm: PropTypes.bool,
canEditCommentsAllowed: PropTypes.bool,
canReportComment: PropTypes.bool, canReportComment: PropTypes.bool,
canRestoreComment: PropTypes.bool, canRestoreComment: PropTypes.bool,
handleDeleteComment: PropTypes.func, handleDeleteComment: PropTypes.func,
@ -109,9 +115,11 @@ export default connect(
comments: state.comments.comments, comments: state.comments.comments,
moreCommentsToLoad: state.comments.moreCommentsToLoad, moreCommentsToLoad: state.comments.moreCommentsToLoad,
replies: state.comments.replies, replies: state.comments.replies,
commentsAllowed: selectStudioCommentsAllowed(state),
shouldShowCommentComposer: selectShowCommentComposer(state), shouldShowCommentComposer: selectShowCommentComposer(state),
canDeleteComment: selectCanDeleteComment(state), canDeleteComment: selectCanDeleteComment(state),
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state), canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
canReportComment: selectCanReportComment(state), canReportComment: selectCanReportComment(state),
canRestoreComment: selectCanRestoreComment(state), canRestoreComment: selectCanRestoreComment(state),
postURI: `/proxy/comments/studio/${state.studio.id}` postURI: `/proxy/comments/studio/${state.studio.id}`

View file

@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {selectStudioOpenToAll, selectIsLoadingInfo} from '../../redux/studio'; import {selectStudioOpenToAll, selectIsLoadingInfo} from '../../redux/studio';
import {selectCanEditInfo} from '../../redux/studio-permissions';
import { import {
mutateStudioOpenToAll, selectIsMutatingOpenToAll, selectOpenToAllMutationError mutateStudioOpenToAll, selectIsMutatingOpenToAll, selectOpenToAllMutationError
} from '../../redux/studio-mutations'; } from '../../redux/studio-mutations';
const StudioOpenToAll = ({ const StudioOpenToAll = ({
openToAllError, isLoading, isMutating, openToAll, canEditInfo, handleUpdate openToAllError, isLoading, isMutating, openToAll, handleUpdate
}) => ( }) => (
<div> <div>
{isLoading ? ( {isLoading ? (
@ -19,12 +18,12 @@ const StudioOpenToAll = ({
<div> <div>
<label> <label>
<input <input
disabled={isMutating || !canEditInfo} disabled={isMutating}
type="checkbox" type="checkbox"
checked={openToAll} checked={openToAll}
onChange={e => handleUpdate(e.target.checked)} onChange={e => handleUpdate(e.target.checked)}
/> />
<h4>{openToAll ? 'Open to all' : 'Not open to all'}</h4> <span>{openToAll ? 'Open to all' : 'Not open to all'}</span>
{openToAllError && <div>Error mutating openToAll: {openToAllError}</div>} {openToAllError && <div>Error mutating openToAll: {openToAllError}</div>}
</label> </label>
</div> </div>
@ -34,7 +33,6 @@ const StudioOpenToAll = ({
StudioOpenToAll.propTypes = { StudioOpenToAll.propTypes = {
openToAllError: PropTypes.string, openToAllError: PropTypes.string,
canEditInfo: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
isMutating: PropTypes.bool, isMutating: PropTypes.bool,
openToAll: PropTypes.bool, openToAll: PropTypes.bool,
@ -44,7 +42,6 @@ StudioOpenToAll.propTypes = {
export default connect( export default connect(
state => ({ state => ({
openToAll: selectStudioOpenToAll(state), openToAll: selectStudioOpenToAll(state),
canEditInfo: selectCanEditInfo(state),
isLoading: selectIsLoadingInfo(state), isLoading: selectIsLoadingInfo(state),
isMutating: selectIsMutatingOpenToAll(state), isMutating: selectIsMutatingOpenToAll(state),
openToAllError: selectOpenToAllMutationError(state) openToAllError: selectOpenToAllMutationError(state)

View file

@ -6,13 +6,13 @@ import StudioOpenToAll from './studio-open-to-all.jsx';
import {projectFetcher} from './lib/fetchers'; import {projectFetcher} from './lib/fetchers';
import {projects} from './lib/redux-modules'; import {projects} from './lib/redux-modules';
import {selectCanAddProjects} from '../../redux/studio-permissions'; import {selectCanAddProjects, selectCanEditOpenToAll} from '../../redux/studio-permissions';
import Debug from './debug.jsx'; import Debug from './debug.jsx';
const {actions, selector: projectsSelector} = projects; const {actions, selector: projectsSelector} = projects;
const StudioProjects = ({ const StudioProjects = ({
canAddProjects, items, error, loading, moreToLoad, onLoadMore canAddProjects, canEditOpenToAll, items, error, loading, moreToLoad, onLoadMore
}) => { }) => {
const {studioId} = useParams(); const {studioId} = useParams();
@ -25,7 +25,7 @@ const StudioProjects = ({
return ( return (
<div> <div>
<h2>Projects</h2> <h2>Projects</h2>
<StudioOpenToAll /> {canEditOpenToAll && <StudioOpenToAll />}
{error && <Debug {error && <Debug
label="Error" label="Error"
data={error} data={error}
@ -56,6 +56,7 @@ const StudioProjects = ({
StudioProjects.propTypes = { StudioProjects.propTypes = {
canAddProjects: PropTypes.bool, canAddProjects: PropTypes.bool,
canEditOpenToAll: PropTypes.bool,
items: PropTypes.array, // eslint-disable-line react/forbid-prop-types items: PropTypes.array, // eslint-disable-line react/forbid-prop-types
loading: PropTypes.bool, loading: PropTypes.bool,
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
@ -65,7 +66,8 @@ StudioProjects.propTypes = {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
...projectsSelector(state), ...projectsSelector(state),
canAddProjects: selectCanAddProjects(state) canAddProjects: selectCanAddProjects(state),
canEditOpenToAll: selectCanEditOpenToAll(state)
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View file

@ -6,7 +6,9 @@ import {
selectCanDeleteCommentWithoutConfirm, selectCanDeleteCommentWithoutConfirm,
selectCanReportComment, selectCanReportComment,
selectCanRestoreComment, selectCanRestoreComment,
selectCanFollowStudio selectCanFollowStudio,
selectCanEditCommentsAllowed,
selectCanEditOpenToAll
} from '../../../src/redux/studio-permissions'; } from '../../../src/redux/studio-permissions';
import {getInitialState as getInitialStudioState} from '../../../src/redux/studio'; import {getInitialState as getInitialStudioState} from '../../../src/redux/studio';
@ -176,4 +178,34 @@ describe('studio comments', () => {
expect(selectCanFollowStudio(state)).toBe(expected); expect(selectCanFollowStudio(state)).toBe(expected);
}); });
}); });
describe('can set "comments allowed" on a studio', () => {
test.each([
['admin', true],
['curator', false],
['manager', false],
['creator', true],
['logged in', false],
['unconfirmed', false],
['logged out', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanEditCommentsAllowed(state)).toBe(expected);
});
});
describe('can set "open to all" on a studio', () => {
test.each([
['admin', true],
['curator', false],
['manager', true],
['creator', true],
['logged in', false],
['unconfirmed', false],
['logged out', false]
])('%s: %s', (role, expected) => {
setStateByRole(role);
expect(selectCanEditOpenToAll(state)).toBe(expected);
});
});
}); });