fix(issues): only allow edit of own comments & do not allow non-admin delete of issues with comments (#2248)

This commit is contained in:
TheCatLady
2021-10-30 19:54:01 -04:00
committed by GitHub
parent 0828b008ba
commit bba09d69c1
5 changed files with 63 additions and 59 deletions

View File

@@ -302,7 +302,7 @@ issueRoutes.delete('/:issueId', async (req, res, next) => {
if ( if (
!req.user?.hasPermission(Permission.MANAGE_ISSUES) && !req.user?.hasPermission(Permission.MANAGE_ISSUES) &&
issue.createdBy.id !== req.user?.id (issue.createdBy.id !== req.user?.id || issue.comments.length > 1)
) { ) {
return next({ return next({
status: 401, status: 401,

View File

@@ -68,13 +68,10 @@ issueCommentRoutes.put<
where: { id: Number(req.params.commentId) }, where: { id: Number(req.params.commentId) },
}); });
if ( if (comment.user.id !== req.user?.id) {
!req.user?.hasPermission([Permission.MANAGE_ISSUES], { type: 'or' }) &&
comment.user.id !== req.user?.id
) {
return next({ return next({
status: 403, status: 403,
message: 'You do not have permission to edit this comment.', message: 'You can only edit your own comments.',
}); });
} }

View File

@@ -39,7 +39,7 @@ const IssueComment: React.FC<IssueCommentProps> = ({
const intl = useIntl(); const intl = useIntl();
const [showDeleteModal, setShowDeleteModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false);
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const { user, hasPermission } = useUser(); const { hasPermission } = useUser();
const EditCommentSchema = Yup.object().shape({ const EditCommentSchema = Yup.object().shape({
newMessage: Yup.string().required( newMessage: Yup.string().required(
@@ -59,8 +59,6 @@ const IssueComment: React.FC<IssueCommentProps> = ({
} }
}; };
const belongsToUser = comment.user.id === user?.id;
return ( return (
<div <div
className={`flex ${ className={`flex ${
@@ -98,7 +96,7 @@ const IssueComment: React.FC<IssueCommentProps> = ({
</Link> </Link>
<div className="relative flex-1"> <div className="relative flex-1">
<div className="w-full rounded-md shadow ring-1 ring-gray-500"> <div className="w-full rounded-md shadow ring-1 ring-gray-500">
{(belongsToUser || hasPermission(Permission.MANAGE_ISSUES)) && ( {(isActiveUser || hasPermission(Permission.MANAGE_ISSUES)) && (
<Menu <Menu
as="div" as="div"
className="absolute z-40 inline-block text-left top-2 right-1" className="absolute z-40 inline-block text-left top-2 right-1"
@@ -129,6 +127,7 @@ const IssueComment: React.FC<IssueCommentProps> = ({
className="absolute right-0 w-56 mt-2 origin-top-right bg-gray-700 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" className="absolute right-0 w-56 mt-2 origin-top-right bg-gray-700 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
> >
<div className="py-1"> <div className="py-1">
{isActiveUser && (
<Menu.Item> <Menu.Item>
{({ active }) => ( {({ active }) => (
<button <button
@@ -143,6 +142,7 @@ const IssueComment: React.FC<IssueCommentProps> = ({
</button> </button>
)} )}
</Menu.Item> </Menu.Item>
)}
<Menu.Item> <Menu.Item>
{({ active }) => ( {({ active }) => (
<button <button

View File

@@ -15,20 +15,22 @@ const messages = defineMessages({
}); });
interface IssueDescriptionProps { interface IssueDescriptionProps {
issueId: number;
description: string; description: string;
belongsToUser: boolean;
commentCount: number;
onEdit: (newDescription: string) => void; onEdit: (newDescription: string) => void;
onDelete: () => void; onDelete: () => void;
} }
const IssueDescription: React.FC<IssueDescriptionProps> = ({ const IssueDescription: React.FC<IssueDescriptionProps> = ({
issueId,
description, description,
belongsToUser,
commentCount,
onEdit, onEdit,
onDelete, onDelete,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const { user, hasPermission } = useUser(); const { hasPermission } = useUser();
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
return ( return (
@@ -37,7 +39,7 @@ const IssueDescription: React.FC<IssueDescriptionProps> = ({
<div className="font-semibold text-gray-100 lg:text-xl"> <div className="font-semibold text-gray-100 lg:text-xl">
{intl.formatMessage(messages.description)} {intl.formatMessage(messages.description)}
</div> </div>
{(hasPermission(Permission.MANAGE_ISSUES) || user?.id === issueId) && ( {(hasPermission(Permission.MANAGE_ISSUES) || belongsToUser) && (
<Menu as="div" className="relative inline-block text-left"> <Menu as="div" className="relative inline-block text-left">
{({ open }) => ( {({ open }) => (
<> <>
@@ -63,6 +65,7 @@ const IssueDescription: React.FC<IssueDescriptionProps> = ({
className="absolute right-0 w-56 mt-2 origin-top-right bg-gray-700 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" className="absolute right-0 w-56 mt-2 origin-top-right bg-gray-700 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
> >
<div className="py-1"> <div className="py-1">
{belongsToUser && (
<Menu.Item> <Menu.Item>
{({ active }) => ( {({ active }) => (
<button <button
@@ -77,7 +80,9 @@ const IssueDescription: React.FC<IssueDescriptionProps> = ({
</button> </button>
)} )}
</Menu.Item> </Menu.Item>
)}
{(hasPermission(Permission.MANAGE_ISSUES) ||
!commentCount) && (
<Menu.Item> <Menu.Item>
{({ active }) => ( {({ active }) => (
<button <button
@@ -92,6 +97,7 @@ const IssueDescription: React.FC<IssueDescriptionProps> = ({
</button> </button>
)} )}
</Menu.Item> </Menu.Item>
)}
</div> </div>
</Menu.Items> </Menu.Items>
</Transition> </Transition>

View File

@@ -260,7 +260,7 @@ const IssueDetails: React.FC = () => {
username: ( username: (
<Link <Link
href={ href={
issueData.createdBy.id === currentUser?.id belongsToUser
? '/profile' ? '/profile'
: `/users/${issueData.createdBy.id}` : `/users/${issueData.createdBy.id}`
} }
@@ -294,8 +294,9 @@ const IssueDetails: React.FC = () => {
<div className="relative z-10 flex mt-6 text-gray-300"> <div className="relative z-10 flex mt-6 text-gray-300">
<div className="flex-1 lg:pr-4"> <div className="flex-1 lg:pr-4">
<IssueDescription <IssueDescription
issueId={issueData.id}
description={firstComment.message} description={firstComment.message}
belongsToUser={belongsToUser}
commentCount={otherComments.length}
onEdit={(newMessage) => { onEdit={(newMessage) => {
editFirstComment(newMessage); editFirstComment(newMessage);
}} }}