mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 15:47:53 -05:00
Fix comment toggling and add permissions test
This commit is contained in:
parent
aab4c9aca6
commit
f9419ac8fc
7 changed files with 64 additions and 22 deletions
|
@ -191,7 +191,7 @@ const mutateStudioCommentsAllowed = shouldAllow => ((dispatch, getState) => {
|
|||
api({
|
||||
host: '',
|
||||
uri: `/site-api/comments/gallery/${studioId}/toggle-comments/`,
|
||||
method: 'PUT',
|
||||
method: 'POST',
|
||||
useCsrf: true
|
||||
}, (err, body, res) => {
|
||||
const error = normalizeError(err, body, res);
|
||||
|
|
|
@ -25,6 +25,10 @@ const selectCanDeleteCommentWithoutConfirm = state => selectIsAdmin(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 {
|
||||
selectCanEditInfo,
|
||||
selectCanAddProjects,
|
||||
|
@ -33,5 +37,7 @@ export {
|
|||
selectCanDeleteComment,
|
||||
selectCanDeleteCommentWithoutConfirm,
|
||||
selectCanReportComment,
|
||||
selectCanRestoreComment
|
||||
selectCanRestoreComment,
|
||||
selectCanEditCommentsAllowed,
|
||||
selectCanEditOpenToAll
|
||||
};
|
||||
|
|
|
@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
|
|||
import {connect} from 'react-redux';
|
||||
|
||||
import {selectStudioCommentsAllowed, selectIsLoadingInfo} from '../../redux/studio';
|
||||
import {selectCanEditInfo} from '../../redux/studio-permissions';
|
||||
import {
|
||||
mutateStudioCommentsAllowed, selectIsMutatingCommentsAllowed, selectCommentsAllowedMutationError
|
||||
} from '../../redux/studio-mutations';
|
||||
|
||||
const StudioCommentsAllowed = ({
|
||||
commentsAllowedError, isLoading, isMutating, commentsAllowed, canEditInfo, handleUpdate
|
||||
commentsAllowedError, isLoading, isMutating, commentsAllowed, handleUpdate
|
||||
}) => (
|
||||
<div>
|
||||
{isLoading ? (
|
||||
|
@ -19,12 +18,12 @@ const StudioCommentsAllowed = ({
|
|||
<div>
|
||||
<label>
|
||||
<input
|
||||
disabled={isMutating || !canEditInfo}
|
||||
disabled={isMutating}
|
||||
type="checkbox"
|
||||
checked={commentsAllowed}
|
||||
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>}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -34,7 +33,6 @@ const StudioCommentsAllowed = ({
|
|||
|
||||
StudioCommentsAllowed.propTypes = {
|
||||
commentsAllowedError: PropTypes.string,
|
||||
canEditInfo: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
isMutating: PropTypes.bool,
|
||||
commentsAllowed: PropTypes.bool,
|
||||
|
@ -44,7 +42,6 @@ StudioCommentsAllowed.propTypes = {
|
|||
export default connect(
|
||||
state => ({
|
||||
commentsAllowed: selectStudioCommentsAllowed(state),
|
||||
canEditInfo: selectCanEditInfo(state),
|
||||
isLoading: selectIsLoadingInfo(state),
|
||||
isMutating: selectIsMutatingCommentsAllowed(state),
|
||||
commentsAllowedError: selectCommentsAllowedMutationError(state)
|
||||
|
|
|
@ -14,11 +14,14 @@ import {
|
|||
selectCanDeleteComment,
|
||||
selectCanDeleteCommentWithoutConfirm,
|
||||
selectCanReportComment,
|
||||
selectCanRestoreComment
|
||||
selectCanRestoreComment,
|
||||
selectCanEditCommentsAllowed
|
||||
} from '../../redux/studio-permissions';
|
||||
import {selectStudioCommentsAllowed} from '../../redux/studio.js';
|
||||
|
||||
const StudioComments = ({
|
||||
comments,
|
||||
commentsAllowed,
|
||||
handleLoadMoreComments,
|
||||
handleNewComment,
|
||||
moreCommentsToLoad,
|
||||
|
@ -27,6 +30,7 @@ const StudioComments = ({
|
|||
shouldShowCommentComposer,
|
||||
canDeleteComment,
|
||||
canDeleteCommentWithoutConfirm,
|
||||
canEditCommentsAllowed,
|
||||
canReportComment,
|
||||
canRestoreComment,
|
||||
handleDeleteComment,
|
||||
|
@ -41,9 +45,9 @@ const StudioComments = ({
|
|||
return (
|
||||
<div>
|
||||
<h2>Comments</h2>
|
||||
<StudioCommentsAllowed />
|
||||
{canEditCommentsAllowed && <StudioCommentsAllowed />}
|
||||
<div>
|
||||
{shouldShowCommentComposer &&
|
||||
{shouldShowCommentComposer && commentsAllowed &&
|
||||
<ComposeComment
|
||||
postURI={postURI}
|
||||
onAddComment={handleNewComment}
|
||||
|
@ -88,6 +92,7 @@ const StudioComments = ({
|
|||
|
||||
StudioComments.propTypes = {
|
||||
comments: PropTypes.arrayOf(PropTypes.shape({})),
|
||||
commentsAllowed: PropTypes.bool,
|
||||
handleLoadMoreComments: PropTypes.func,
|
||||
handleNewComment: PropTypes.func,
|
||||
moreCommentsToLoad: PropTypes.bool,
|
||||
|
@ -95,6 +100,7 @@ StudioComments.propTypes = {
|
|||
shouldShowCommentComposer: PropTypes.bool,
|
||||
canDeleteComment: PropTypes.bool,
|
||||
canDeleteCommentWithoutConfirm: PropTypes.bool,
|
||||
canEditCommentsAllowed: PropTypes.bool,
|
||||
canReportComment: PropTypes.bool,
|
||||
canRestoreComment: PropTypes.bool,
|
||||
handleDeleteComment: PropTypes.func,
|
||||
|
@ -109,9 +115,11 @@ export default connect(
|
|||
comments: state.comments.comments,
|
||||
moreCommentsToLoad: state.comments.moreCommentsToLoad,
|
||||
replies: state.comments.replies,
|
||||
commentsAllowed: selectStudioCommentsAllowed(state),
|
||||
shouldShowCommentComposer: selectShowCommentComposer(state),
|
||||
canDeleteComment: selectCanDeleteComment(state),
|
||||
canDeleteCommentWithoutConfirm: selectCanDeleteCommentWithoutConfirm(state),
|
||||
canEditCommentsAllowed: selectCanEditCommentsAllowed(state),
|
||||
canReportComment: selectCanReportComment(state),
|
||||
canRestoreComment: selectCanRestoreComment(state),
|
||||
postURI: `/proxy/comments/studio/${state.studio.id}`
|
||||
|
|
|
@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
|
|||
import {connect} from 'react-redux';
|
||||
|
||||
import {selectStudioOpenToAll, selectIsLoadingInfo} from '../../redux/studio';
|
||||
import {selectCanEditInfo} from '../../redux/studio-permissions';
|
||||
import {
|
||||
mutateStudioOpenToAll, selectIsMutatingOpenToAll, selectOpenToAllMutationError
|
||||
} from '../../redux/studio-mutations';
|
||||
|
||||
const StudioOpenToAll = ({
|
||||
openToAllError, isLoading, isMutating, openToAll, canEditInfo, handleUpdate
|
||||
openToAllError, isLoading, isMutating, openToAll, handleUpdate
|
||||
}) => (
|
||||
<div>
|
||||
{isLoading ? (
|
||||
|
@ -19,12 +18,12 @@ const StudioOpenToAll = ({
|
|||
<div>
|
||||
<label>
|
||||
<input
|
||||
disabled={isMutating || !canEditInfo}
|
||||
disabled={isMutating}
|
||||
type="checkbox"
|
||||
checked={openToAll}
|
||||
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>}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -34,7 +33,6 @@ const StudioOpenToAll = ({
|
|||
|
||||
StudioOpenToAll.propTypes = {
|
||||
openToAllError: PropTypes.string,
|
||||
canEditInfo: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
isMutating: PropTypes.bool,
|
||||
openToAll: PropTypes.bool,
|
||||
|
@ -44,7 +42,6 @@ StudioOpenToAll.propTypes = {
|
|||
export default connect(
|
||||
state => ({
|
||||
openToAll: selectStudioOpenToAll(state),
|
||||
canEditInfo: selectCanEditInfo(state),
|
||||
isLoading: selectIsLoadingInfo(state),
|
||||
isMutating: selectIsMutatingOpenToAll(state),
|
||||
openToAllError: selectOpenToAllMutationError(state)
|
||||
|
|
|
@ -6,13 +6,13 @@ import StudioOpenToAll from './studio-open-to-all.jsx';
|
|||
|
||||
import {projectFetcher} from './lib/fetchers';
|
||||
import {projects} from './lib/redux-modules';
|
||||
import {selectCanAddProjects} from '../../redux/studio-permissions';
|
||||
import {selectCanAddProjects, selectCanEditOpenToAll} from '../../redux/studio-permissions';
|
||||
import Debug from './debug.jsx';
|
||||
|
||||
const {actions, selector: projectsSelector} = projects;
|
||||
|
||||
const StudioProjects = ({
|
||||
canAddProjects, items, error, loading, moreToLoad, onLoadMore
|
||||
canAddProjects, canEditOpenToAll, items, error, loading, moreToLoad, onLoadMore
|
||||
}) => {
|
||||
const {studioId} = useParams();
|
||||
|
||||
|
@ -25,7 +25,7 @@ const StudioProjects = ({
|
|||
return (
|
||||
<div>
|
||||
<h2>Projects</h2>
|
||||
<StudioOpenToAll />
|
||||
{canEditOpenToAll && <StudioOpenToAll />}
|
||||
{error && <Debug
|
||||
label="Error"
|
||||
data={error}
|
||||
|
@ -56,6 +56,7 @@ const StudioProjects = ({
|
|||
|
||||
StudioProjects.propTypes = {
|
||||
canAddProjects: PropTypes.bool,
|
||||
canEditOpenToAll: PropTypes.bool,
|
||||
items: PropTypes.array, // eslint-disable-line react/forbid-prop-types
|
||||
loading: PropTypes.bool,
|
||||
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
|
@ -65,7 +66,8 @@ StudioProjects.propTypes = {
|
|||
|
||||
const mapStateToProps = state => ({
|
||||
...projectsSelector(state),
|
||||
canAddProjects: selectCanAddProjects(state)
|
||||
canAddProjects: selectCanAddProjects(state),
|
||||
canEditOpenToAll: selectCanEditOpenToAll(state)
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
|
|
@ -6,7 +6,9 @@ import {
|
|||
selectCanDeleteCommentWithoutConfirm,
|
||||
selectCanReportComment,
|
||||
selectCanRestoreComment,
|
||||
selectCanFollowStudio
|
||||
selectCanFollowStudio,
|
||||
selectCanEditCommentsAllowed,
|
||||
selectCanEditOpenToAll
|
||||
} from '../../../src/redux/studio-permissions';
|
||||
|
||||
import {getInitialState as getInitialStudioState} from '../../../src/redux/studio';
|
||||
|
@ -176,4 +178,34 @@ describe('studio comments', () => {
|
|||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue