Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
scratch-www
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
scratch-www
Commits
e331c20d
Unverified
Commit
e331c20d
authored
Jun 23, 2021
by
Paul Kaplan
Committed by
GitHub
Jun 23, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5649 from paulkaplan/no-report-own-comments
Fix permissions issues on studio comments
parents
5b17870c
810465bf
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
53 additions
and
37 deletions
+53
-37
src/redux/studio-permissions.js
src/redux/studio-permissions.js
+8
-5
src/views/preview/comment/top-level-comment.jsx
src/views/preview/comment/top-level-comment.jsx
+5
-3
src/views/studio/studio-comment.js
src/views/studio/studio-comment.js
+17
-0
src/views/studio/studio-comments.jsx
src/views/studio/studio-comments.jsx
+3
-20
test/unit/components/studio-comments.test.jsx
test/unit/components/studio-comments.test.jsx
+6
-0
test/unit/redux/studio-permissions.test.js
test/unit/redux/studio-permissions.test.js
+14
-9
No files found.
src/redux/studio-permissions.js
View file @
e331c20d
...
@@ -18,14 +18,18 @@ const selectCanAddProjects = state =>
...
@@ -18,14 +18,18 @@ const selectCanAddProjects = state =>
// This isn't "canComment" since they could be muted, but comment composer handles that
// This isn't "canComment" since they could be muted, but comment composer handles that
const
selectShowCommentComposer
=
state
=>
selectIsSocial
(
state
);
const
selectShowCommentComposer
=
state
=>
selectIsSocial
(
state
);
const
selectCanReportComment
=
state
=>
selectIsSocial
(
state
);
const
selectCanReportComment
=
(
state
,
commentUsername
)
=>
selectIsLoggedIn
(
state
)
&&
selectUsername
(
state
)
!==
commentUsername
;
const
selectCanRestoreComment
=
state
=>
selectIsAdmin
(
state
);
const
selectCanRestoreComment
=
state
=>
selectIsAdmin
(
state
);
// On the project page, project owners can delete comments with a confirmation,
// On the project page, project owners can delete comments with a confirmation,
// and admins can delete comments without 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.
// 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.
// Admins can delete comments without a confirmation.
const
selectCanDeleteAnyComment
=
state
=>
selectIsAdmin
(
state
);
const
selectCanDeleteComment
=
(
state
,
commentUsername
)
=>
{
const
selectCanDeleteOwnComment
=
state
=>
isCreator
(
state
)
||
isManager
(
state
);
if
(
selectIsAdmin
(
state
))
return
true
;
if
(
isManager
(
state
)
&&
selectUsername
(
state
)
===
commentUsername
)
return
true
;
return
false
;
};
const
selectCanDeleteCommentWithoutConfirm
=
state
=>
selectIsAdmin
(
state
);
const
selectCanDeleteCommentWithoutConfirm
=
state
=>
selectIsAdmin
(
state
);
const
selectCanFollowStudio
=
state
=>
selectIsLoggedIn
(
state
);
const
selectCanFollowStudio
=
state
=>
selectIsLoggedIn
(
state
);
...
@@ -82,8 +86,7 @@ export {
...
@@ -82,8 +86,7 @@ export {
selectCanAddProjects
,
selectCanAddProjects
,
selectCanFollowStudio
,
selectCanFollowStudio
,
selectShowCommentComposer
,
selectShowCommentComposer
,
selectCanDeleteAnyComment
,
selectCanDeleteComment
,
selectCanDeleteOwnComment
,
selectCanDeleteCommentWithoutConfirm
,
selectCanDeleteCommentWithoutConfirm
,
selectCanReportComment
,
selectCanReportComment
,
selectCanRestoreComment
,
selectCanRestoreComment
,
...
...
src/views/preview/comment/top-level-comment.jsx
View file @
e331c20d
...
@@ -131,7 +131,7 @@ class TopLevelComment extends React.Component {
...
@@ -131,7 +131,7 @@ class TopLevelComment extends React.Component {
return
(
return
(
<
FlexRow
className=
"comment-container"
>
<
FlexRow
className=
"comment-container"
>
<
Comm
ent
<
this
.
props
.
commentCompon
ent
highlighted=
{
highlightedCommentId
===
id
}
highlighted=
{
highlightedCommentId
===
id
}
postURI=
{
postURI
}
postURI=
{
postURI
}
onAddComment=
{
this
.
handleAddComment
}
onAddComment=
{
this
.
handleAddComment
}
...
@@ -173,7 +173,7 @@ class TopLevelComment extends React.Component {
...
@@ -173,7 +173,7 @@ class TopLevelComment extends React.Component {
<
React
.
Fragment
<
React
.
Fragment
key=
{
`reply-and-status-${reply.id}`
}
key=
{
`reply-and-status-${reply.id}`
}
>
>
<
Comm
ent
<
this
.
props
.
commentCompon
ent
author=
{
reply
.
author
}
author=
{
reply
.
author
}
canDelete=
{
canDelete
}
canDelete=
{
canDelete
}
canDeleteWithoutConfirm=
{
canDeleteWithoutConfirm
}
canDeleteWithoutConfirm=
{
canDeleteWithoutConfirm
}
...
@@ -233,6 +233,7 @@ TopLevelComment.propTypes = {
...
@@ -233,6 +233,7 @@ TopLevelComment.propTypes = {
canReply
:
PropTypes
.
bool
,
canReply
:
PropTypes
.
bool
,
canReport
:
PropTypes
.
bool
,
canReport
:
PropTypes
.
bool
,
canRestore
:
PropTypes
.
bool
,
canRestore
:
PropTypes
.
bool
,
commentComponent
:
PropTypes
.
func
,
content
:
PropTypes
.
string
,
content
:
PropTypes
.
string
,
datetimeCreated
:
PropTypes
.
string
,
datetimeCreated
:
PropTypes
.
string
,
defaultExpanded
:
PropTypes
.
bool
,
defaultExpanded
:
PropTypes
.
bool
,
...
@@ -260,7 +261,8 @@ TopLevelComment.defaultProps = {
...
@@ -260,7 +261,8 @@ TopLevelComment.defaultProps = {
defaultExpanded
:
false
,
defaultExpanded
:
false
,
hasThreadLimit
:
false
,
hasThreadLimit
:
false
,
moreRepliesToLoad
:
false
,
moreRepliesToLoad
:
false
,
threadHasReplyStatus
:
false
threadHasReplyStatus
:
false
,
commentComponent
:
Comment
};
};
module
.
exports
=
TopLevelComment
;
module
.
exports
=
TopLevelComment
;
src/views/studio/studio-comment.js
0 → 100644
View file @
e331c20d
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
);
src/views/studio/studio-comments.jsx
View file @
e331c20d
...
@@ -10,19 +10,17 @@ import TopLevelComment from '../preview/comment/top-level-comment.jsx';
...
@@ -10,19 +10,17 @@ import TopLevelComment from '../preview/comment/top-level-comment.jsx';
import
studioCommentActions
from
'
../../redux/studio-comment-actions.js
'
;
import
studioCommentActions
from
'
../../redux/studio-comment-actions.js
'
;
import
StudioCommentsAllowed
from
'
./studio-comments-allowed.jsx
'
;
import
StudioCommentsAllowed
from
'
./studio-comments-allowed.jsx
'
;
import
StudioCommentsNotAllowed
from
'
./studio-comments-not-allowed.jsx
'
;
import
StudioCommentsNotAllowed
from
'
./studio-comments-not-allowed.jsx
'
;
import
{
selectIsAdmin
,
selectHasFetchedSession
,
selectUsername
}
from
'
../../redux/session
'
;
import
{
selectIsAdmin
,
selectHasFetchedSession
}
from
'
../../redux/session
'
;
import
{
import
{
selectShowCommentComposer
,
selectShowCommentComposer
,
selectCanDeleteAnyComment
,
selectCanDeleteOwnComment
,
selectCanDeleteCommentWithoutConfirm
,
selectCanDeleteCommentWithoutConfirm
,
selectCanReportComment
,
selectCanRestoreComment
,
selectCanRestoreComment
,
selectCanEditCommentsAllowed
,
selectCanEditCommentsAllowed
,
selectShowCommentsList
,
selectShowCommentsList
,
selectShowCommentsGloballyOffError
selectShowCommentsGloballyOffError
}
from
'
../../redux/studio-permissions
'
;
}
from
'
../../redux/studio-permissions
'
;
import
{
selectStudioCommentsAllowed
}
from
'
../../redux/studio.js
'
;
import
{
selectStudioCommentsAllowed
}
from
'
../../redux/studio.js
'
;
import
StudioComment
from
'
./studio-comment.js
'
;
const
StudioComments
=
({
const
StudioComments
=
({
comments
,
comments
,
...
@@ -37,12 +35,8 @@ const StudioComments = ({
...
@@ -37,12 +35,8 @@ const StudioComments = ({
shouldShowCommentComposer
,
shouldShowCommentComposer
,
shouldShowCommentsList
,
shouldShowCommentsList
,
shouldShowCommentsGloballyOffError
,
shouldShowCommentsGloballyOffError
,
username
,
canDeleteAnyComment
,
canDeleteOwnComment
,
canDeleteCommentWithoutConfirm
,
canDeleteCommentWithoutConfirm
,
canEditCommentsAllowed
,
canEditCommentsAllowed
,
canReportComment
,
canRestoreComment
,
canRestoreComment
,
handleDeleteComment
,
handleDeleteComment
,
handleRestoreComment
,
handleRestoreComment
,
...
@@ -127,12 +121,9 @@ const StudioComments = ({
...
@@ -127,12 +121,9 @@ const StudioComments = ({
<
TopLevelComment
<
TopLevelComment
hasThreadLimit
hasThreadLimit
author=
{
comment
.
author
}
author=
{
comment
.
author
}
canDelete=
{
canDeleteAnyComment
||
(
canDeleteOwnComment
&&
comment
.
author
.
username
===
username
)
}
canDeleteWithoutConfirm=
{
canDeleteCommentWithoutConfirm
}
canDeleteWithoutConfirm=
{
canDeleteCommentWithoutConfirm
}
canReply=
{
shouldShowCommentComposer
&&
commentsAllowed
}
canReport=
{
canReportComment
}
canRestore=
{
canRestoreComment
}
canRestore=
{
canRestoreComment
}
commentComponent=
{
StudioComment
}
content=
{
comment
.
content
}
content=
{
comment
.
content
}
datetimeCreated=
{
comment
.
datetime_created
}
datetimeCreated=
{
comment
.
datetime_created
}
defaultExpanded=
{
singleCommentId
}
defaultExpanded=
{
singleCommentId
}
...
@@ -190,12 +181,8 @@ StudioComments.propTypes = {
...
@@ -190,12 +181,8 @@ StudioComments.propTypes = {
shouldShowCommentComposer
:
PropTypes
.
bool
,
shouldShowCommentComposer
:
PropTypes
.
bool
,
shouldShowCommentsGloballyOffError
:
PropTypes
.
bool
,
shouldShowCommentsGloballyOffError
:
PropTypes
.
bool
,
shouldShowCommentsList
:
PropTypes
.
bool
,
shouldShowCommentsList
:
PropTypes
.
bool
,
username
:
PropTypes
.
string
,
canDeleteAnyComment
:
PropTypes
.
bool
,
canDeleteOwnComment
:
PropTypes
.
bool
,
canDeleteCommentWithoutConfirm
:
PropTypes
.
bool
,
canDeleteCommentWithoutConfirm
:
PropTypes
.
bool
,
canEditCommentsAllowed
:
PropTypes
.
bool
,
canEditCommentsAllowed
:
PropTypes
.
bool
,
canReportComment
:
PropTypes
.
bool
,
canRestoreComment
:
PropTypes
.
bool
,
canRestoreComment
:
PropTypes
.
bool
,
handleDeleteComment
:
PropTypes
.
func
,
handleDeleteComment
:
PropTypes
.
func
,
handleRestoreComment
:
PropTypes
.
func
,
handleRestoreComment
:
PropTypes
.
func
,
...
@@ -217,16 +204,12 @@ export default connect(
...
@@ -217,16 +204,12 @@ export default connect(
isAdmin
:
selectIsAdmin
(
state
),
isAdmin
:
selectIsAdmin
(
state
),
moreCommentsToLoad
:
state
.
comments
.
moreCommentsToLoad
,
moreCommentsToLoad
:
state
.
comments
.
moreCommentsToLoad
,
replies
:
state
.
comments
.
replies
,
replies
:
state
.
comments
.
replies
,
username
:
selectUsername
(
state
),
commentsAllowed
:
selectStudioCommentsAllowed
(
state
),
commentsAllowed
:
selectStudioCommentsAllowed
(
state
),
shouldShowCommentComposer
:
selectShowCommentComposer
(
state
),
shouldShowCommentComposer
:
selectShowCommentComposer
(
state
),
shouldShowCommentsGloballyOffError
:
selectShowCommentsGloballyOffError
(
state
),
shouldShowCommentsGloballyOffError
:
selectShowCommentsGloballyOffError
(
state
),
shouldShowCommentsList
:
selectShowCommentsList
(
state
),
shouldShowCommentsList
:
selectShowCommentsList
(
state
),
canDeleteAnyComment
:
selectCanDeleteAnyComment
(
state
),
canDeleteOwnComment
:
selectCanDeleteOwnComment
(
state
),
canDeleteCommentWithoutConfirm
:
selectCanDeleteCommentWithoutConfirm
(
state
),
canDeleteCommentWithoutConfirm
:
selectCanDeleteCommentWithoutConfirm
(
state
),
canEditCommentsAllowed
:
selectCanEditCommentsAllowed
(
state
),
canEditCommentsAllowed
:
selectCanEditCommentsAllowed
(
state
),
canReportComment
:
selectCanReportComment
(
state
),
canRestoreComment
:
selectCanRestoreComment
(
state
),
canRestoreComment
:
selectCanRestoreComment
(
state
),
postURI
:
`/proxy/comments/studio/
${
state
.
studio
.
id
}
`
postURI
:
`/proxy/comments/studio/
${
state
.
studio
.
id
}
`
}),
}),
...
...
test/unit/components/studio-comments.test.jsx
View file @
e331c20d
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
mountWithIntl
}
from
'
../../helpers/intl-helpers.jsx
'
;
import
{
mountWithIntl
}
from
'
../../helpers/intl-helpers.jsx
'
;
import
{
StudioComments
}
from
'
../../../src/views/studio/studio-comments.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
'
,
()
=>
{
describe
(
'
Studio comments
'
,
()
=>
{
test
(
'
if there are no comments, they get loaded
'
,
()
=>
{
test
(
'
if there are no comments, they get loaded
'
,
()
=>
{
const
loadComments
=
jest
.
fn
();
const
loadComments
=
jest
.
fn
();
...
...
test/unit/redux/studio-permissions.test.js
View file @
e331c20d
...
@@ -2,8 +2,7 @@ import {
...
@@ -2,8 +2,7 @@ import {
selectCanEditInfo
,
selectCanEditInfo
,
selectCanAddProjects
,
selectCanAddProjects
,
selectShowCommentComposer
,
selectShowCommentComposer
,
selectCanDeleteAnyComment
,
selectCanDeleteComment
,
selectCanDeleteOwnComment
,
selectCanDeleteCommentWithoutConfirm
,
selectCanDeleteCommentWithoutConfirm
,
selectCanReportComment
,
selectCanReportComment
,
selectCanRestoreComment
,
selectCanRestoreComment
,
...
@@ -189,17 +188,22 @@ describe('studio comments', () => {
...
@@ -189,17 +188,22 @@ describe('studio comments', () => {
describe
(
'
can report comment
'
,
()
=>
{
describe
(
'
can report comment
'
,
()
=>
{
test
.
each
([
test
.
each
([
[
'
logged in
'
,
true
],
[
'
logged in
'
,
true
],
[
'
unconfirmed
'
,
fals
e
],
[
'
unconfirmed
'
,
tru
e
],
[
'
logged out
'
,
false
],
[
'
logged out
'
,
false
],
[
'
muted creator
'
,
true
],
[
'
muted creator
'
,
true
],
[
'
muted logged in
'
,
true
]
[
'
muted logged in
'
,
true
]
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
setStateByRole
(
role
);
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
([
test
.
each
([
[
'
admin
'
,
true
],
[
'
admin
'
,
true
],
[
'
curator
'
,
false
],
[
'
curator
'
,
false
],
...
@@ -212,13 +216,13 @@ describe('studio comments', () => {
...
@@ -212,13 +216,13 @@ describe('studio comments', () => {
[
'
muted logged in
'
,
false
]
[
'
muted logged in
'
,
false
]
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
setStateByRole
(
role
);
setStateByRole
(
role
);
expect
(
selectCanDelete
AnyComment
(
state
)).
toBe
(
expected
);
expect
(
selectCanDelete
Comment
(
state
,
'
not me
'
)).
toBe
(
expected
);
});
});
});
});
describe
(
'
can delete own comment
'
,
()
=>
{
describe
(
'
can delete
my
own comment
'
,
()
=>
{
test
.
each
([
test
.
each
([
[
'
admin
'
,
false
],
// This is false here because we check for `canDeleteAnyComment` separately
[
'
admin
'
,
true
],
[
'
curator
'
,
false
],
[
'
curator
'
,
false
],
[
'
manager
'
,
true
],
[
'
manager
'
,
true
],
[
'
creator
'
,
true
],
[
'
creator
'
,
true
],
...
@@ -231,7 +235,8 @@ describe('studio comments', () => {
...
@@ -231,7 +235,8 @@ describe('studio comments', () => {
[
'
muted logged in
'
,
false
]
[
'
muted logged in
'
,
false
]
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
])(
'
%s: %s
'
,
(
role
,
expected
)
=>
{
setStateByRole
(
role
);
setStateByRole
(
role
);
expect
(
selectCanDeleteOwnComment
(
state
)).
toBe
(
expected
);
const
loggedInUsername
=
selectUsername
(
state
);
expect
(
selectCanDeleteComment
(
state
,
loggedInUsername
)).
toBe
(
expected
);
});
});
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment