Skip to content
This repository has been archived by the owner on Jan 30, 2025. It is now read-only.

Commit

Permalink
allow moderators to delete comments
Browse files Browse the repository at this point in the history
  • Loading branch information
ceolinwill committed Apr 17, 2020
1 parent cea8539 commit 488bba8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 7 deletions.
16 changes: 16 additions & 0 deletions database/__tests__/ comments/delete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,19 @@ test('cannot delete comments from other users', async (done) => {
await firebase.assertFails(ref.delete());
done();
});

test('moderators can delete comments from other users', async (done) => {
const app = initializeFbApp({ uid: 'modUser' });
const ref = app.doc('comments/itemId');
await admin.doc('users/modUser').set({ role: 'moderator' });
await firebase.assertSucceeds(ref.delete());
done();
});

test('admins can delete comments from other users', async (done) => {
const app = initializeFbApp({ uid: 'adminUser' });
const ref = app.doc('comments/itemId');
await admin.doc('users/adminUser').set({ role: 'admin' });
await firebase.assertSucceeds(ref.delete());
done();
});
6 changes: 5 additions & 1 deletion database/firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,11 @@ service cloud.firestore {
&& request.resource.data.updatedById == request.auth.uid
&& isValidLanguage()
;
allow delete: if request.auth.uid == resource.data.createdById;
allow delete:
if request.auth.uid == resource.data.createdById
|| isModerator()
|| isAdmin()
;
}

match /feedback/{id} {
Expand Down
4 changes: 3 additions & 1 deletion src/components/CommentListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const CommentListItem = ({
const classes = useStyles();
const [snackbar, setSnackbar] = useState<SnackbarAction | null>(null);
const [liked, setLiked] = useState<boolean>(false);
const isAuthor = item.createdById === user?.uid;
const isModerator = user?.role === 'moderator' || user?.role === 'admin';

/**
* Toggle a comment like.
Expand Down Expand Up @@ -180,7 +182,7 @@ const CommentListItem = ({
</Fragment>
)}

{user?.uid === item.createdById && (
{(isAuthor || isModerator) && (
<IconButton edge="end" aria-label="delete" onClick={remove}>
<Delete />
</IconButton>
Expand Down
41 changes: 36 additions & 5 deletions src/components/DiscussionListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext } from 'react';
import { useContext, useState } from 'react';
import NextLink from 'next/link';
import {
Avatar,
Expand All @@ -7,19 +7,43 @@ import {
CardContent,
CardHeader,
CardActions,
IconButton,
Link,
Typography,
} from '@material-ui/core';
import { Comment } from '@zoonk/models';
import { GlobalContext } from '@zoonk/utils';
import { Delete } from '@material-ui/icons';
import { Comment, SnackbarAction } from '@zoonk/models';
import { deleteComment } from '@zoonk/services';
import { firebaseError, GlobalContext } from '@zoonk/utils';
import Snackbar from './Snackbar';

interface DiscussionListItemProps {
comment: Comment.Get;
}

const DiscussionListItem = ({ comment }: DiscussionListItemProps) => {
const { translate } = useContext(GlobalContext);
const { content, createdAt, createdBy, postId } = comment;
const { translate, user } = useContext(GlobalContext);
const [snackbar, setSnackbar] = useState<SnackbarAction | null>(null);
const { content, createdAt, createdBy, createdById, id, postId } = comment;
const isAuthor = createdById === user?.uid;
const isModerator = user?.role === 'moderator' || user?.role === 'admin';

/**
* Delete current comment.
*/
const remove = () => {
if (!user) {
setSnackbar({ type: 'error', msg: translate('need_to_be_loggedin') });
return;
}

if (window.confirm(translate('delete_confirmation'))) {
setSnackbar({ type: 'progress', msg: translate('deleting') });
deleteComment(id)
.then(() => setSnackbar({ type: 'success', msg: translate('deleted') }))
.catch((err) => setSnackbar(firebaseError(err, 'comment_delete')));
}
};

return (
<Card variant="outlined">
Expand Down Expand Up @@ -56,13 +80,20 @@ const DiscussionListItem = ({ comment }: DiscussionListItemProps) => {
<Typography variant="body2" color="textSecondary">
{content}
</Typography>
<Snackbar action={snackbar} />
</CardContent>
<CardActions disableSpacing>
<NextLink href="/posts/[id]" as={`/posts/${postId}`} passHref>
<Button component="a" color="primary">
{translate('see_discussion')}
</Button>
</NextLink>

{(isAuthor || isModerator) && (
<IconButton onClick={remove}>
<Delete />
</IconButton>
)}
</CardActions>
</Card>
);
Expand Down

1 comment on commit 488bba8

@vercel
Copy link

@vercel vercel bot commented on 488bba8 Apr 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.