[CORL-882] option to reject all a user's comments when banning (#2827)

* show comment counts for stories in story table

* remove debug code

* add rejector task

* connect comment rejection job to user banning

* localize strings

* remove debug code

* remove debug code

* resolve merge conflicts

* add documentation to rejectExistingComments

* clean up rejector task

* add TODO about broker

* make rejectExistingComments nullable
This commit is contained in:
Tessa Thornton
2020-02-21 12:38:40 -05:00
committed by GitHub
parent ca52cc3253
commit d6db287c55
24 changed files with 491 additions and 120 deletions
@@ -191,9 +191,13 @@ const ModerateCardContainer: FunctionComponent<Props> = ({
}, [comment]);
const handleBanConfirm = useCallback(
async (message: string) => {
async (rejectExistingComments: boolean, message: string) => {
if (comment.author) {
await banUser({ userID: comment.author.id, message });
await banUser({
userID: comment.author.id,
message,
rejectExistingComments,
});
}
setShowBanModal(false);
},
@@ -22,7 +22,7 @@ interface Props {
username: string | null;
open: boolean;
onClose: () => void;
onConfirm: (message?: string) => void;
onConfirm: (rejectExistingComments: boolean, message?: string) => void;
getMessage: GetMessage;
}
@@ -44,8 +44,8 @@ const BanModal: FunctionComponent<Props> = ({
}, [getMessage, username]);
const onFormSubmit = useCallback(
({ emailMessage }) => {
onConfirm(emailMessage);
({ emailMessage, rejectExistingComments }) => {
onConfirm(rejectExistingComments, emailMessage);
},
[onConfirm]
);
@@ -83,12 +83,22 @@ const BanModal: FunctionComponent<Props> = ({
onSubmit={onFormSubmit}
initialValues={{
showMessage: false,
rejectExistingComments: false,
emailMessage: getDefaultMessage,
}}
>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<HorizontalGutter spacing={3}>
<Field type="checkbox" name="rejectExistingComments">
{({ input }) => (
<Localized id="community-banModal-reject-existing">
<CheckBox {...input} id="banModal-rejectExisting">
Reject all comments by this user
</CheckBox>
</Localized>
)}
</Field>
<Field type="checkbox" name="showMessage">
{({ input }) => (
<Localized id="community-banModal-customize">
@@ -111,8 +111,8 @@ const UserStatusChangeContainer: FunctionComponent<Props> = props => {
);
const handleBanConfirm = useCallback(
message => {
banUser({ userID: user.id, message });
(rejectExistingComments, message) => {
banUser({ userID: user.id, message, rejectExistingComments });
setShowBanned(false);
},
[user, setShowBanned]
@@ -4,18 +4,25 @@
padding-top: 15px;
padding-bottom: 15px;
}
.authorColumn {
vertical-align: top;
word-break: break-word;
padding-top: 15px;
padding-bottom: 15px;
}
.publishDateColumn {
vertical-align: top;
padding-top: 15px;
padding-bottom: 15px;
}
.statusColumn {
}
.siteColumn {
}
.meta {
color: var(--v2-colors-mono-100);
}
.authorName {
font-weight: var(--v2-font-weight-primary-semi-bold);
}
.reportedCountColumn,
.pendingCountColumn,
.totalCountColumn {
text-align: center;
}
.boldColumn {
font-weight: var(--v2-font-weight-primary-semi-bold);
}
@@ -1,10 +1,16 @@
import cn from "classnames";
import { Link } from "found";
import React, { FunctionComponent } from "react";
import NotAvailable from "coral-admin/components/NotAvailable";
import { getModerationLink } from "coral-framework/helpers";
import { PropTypesOf } from "coral-framework/types";
import { TableCell, TableRow, TextLink } from "coral-ui/components/v2";
import {
HorizontalGutter,
TableCell,
TableRow,
TextLink,
} from "coral-ui/components/v2";
import StoryStatus from "./StoryStatus";
@@ -20,27 +26,51 @@ interface Props {
siteName: string;
siteID: string;
multisite: boolean;
reportedCount: number | null;
pendingCount: number | null;
totalCount: number;
}
const UserRow: FunctionComponent<Props> = props => (
<TableRow>
<TableCell className={styles.titleColumn}>
<Link to={getModerationLink({ storyID: props.storyID })} as={TextLink}>
{props.title || <NotAvailable />}
</Link>
<HorizontalGutter>
<p>
<Link
to={getModerationLink({ storyID: props.storyID })}
as={TextLink}
>
{props.title || <NotAvailable />}
</Link>
</p>
{(props.author || props.publishDate) && (
<p className={styles.meta}>
<span className={styles.authorName}>{props.author}</span>{" "}
{props.publishDate}
</p>
)}
</HorizontalGutter>
</TableCell>
<TableCell className={styles.authorColumn}>
{props.author || <NotAvailable />}
<TableCell
className={cn(styles.reportedCountColumn, {
[styles.boldColumn]: props.reportedCount && props.reportedCount > 0,
})}
>
{props.reportedCount}
</TableCell>
{props.multisite && (
<TableCell className={styles.siteColumn}>
<Link to={getModerationLink({ siteID: props.siteID })} as={TextLink}>
{props.siteName}
</Link>
</TableCell>
)}
<TableCell className={styles.publishDateColumn}>
{props.publishDate || <NotAvailable />}
<TableCell
className={cn(styles.pendingCountColumn, {
[styles.boldColumn]: props.pendingCount && props.pendingCount > 0,
})}
>
{props.pendingCount}
</TableCell>
<TableCell
className={cn(styles.totalCountColumn, {
[styles.boldColumn]: props.totalCount && props.totalCount > 0,
})}
>
{props.totalCount}
</TableCell>
<TableCell className={styles.statusColumn}>
<StoryStatus story={props.story} viewer={props.viewer} />
@@ -30,6 +30,9 @@ const StoryRowContainer: FunctionComponent<Props> = props => {
siteName={props.story.site.name}
siteID={props.story.site.id}
multisite={props.multisite}
totalCount={props.story.commentCounts.totalPublished}
reportedCount={props.story.moderationQueues.reported.count}
pendingCount={props.story.moderationQueues.pending.count}
publishDate={
publishedAt
? new Intl.DateTimeFormat(locales, {
@@ -61,6 +64,17 @@ const enhanced = withFragmentContainer<Props>({
author
publishedAt
}
commentCounts {
totalPublished
}
moderationQueues {
reported {
count
}
pending {
count
}
}
site {
name
id
@@ -1,25 +1,31 @@
$tableHeaderAltTextColor: var(--v2-colors-mono-100);
.titleColumn {
width: 50%;
width: 60%;
}
.titleColumnNarrow {
width: 32.5%;
}
.authorColumn {
width: 17.5%;
}
.publishDateColumn {
width: 17.5%;
width: 42.5%;
}
.statusColumn {
width: 15%;
width: 14%;
}
.siteColumn {
width: 17.5%;
.reportedCountColumn {
width: 9%;
}
.pendingCountColumn {
width: 9%;
}
.totalCountColumn {
width: 9%;
}
.clickToModerate {
font-size: var(--v2-font-size-2);
font-weight: var(--v2-font-weight-primary-semi-bold);
color: $tableHeaderAltTextColor;
}
.reportedCountColumn,
.pendingCountColumn,
.totalCountColumn {
text-align: center;
}
@@ -1,5 +1,4 @@
import { Localized } from "@fluent/react/compat";
import cn from "classnames";
import React, { FunctionComponent } from "react";
import AutoLoadMore from "coral-admin/components/AutoLoadMore";
@@ -38,11 +37,7 @@ const StoryTable: FunctionComponent<Props> = props => (
<Table fullWidth>
<TableHead>
<TableRow>
<TableCell
className={cn(styles.titleColumn, {
[styles.titleColumnNarrow]: props.multisite,
})}
>
<TableCell className={styles.titleColumn}>
<Localized id="stories-column-title">
<span>Title</span>
</Localized>{" "}
@@ -55,19 +50,19 @@ const StoryTable: FunctionComponent<Props> = props => (
</span>
</TableCell>
<Localized id="stories-column-author">
<TableCell className={styles.authorColumn}>Author</TableCell>
</Localized>
{props.multisite && (
<Localized id="stories-column-site">
<TableCell className={styles.siteColumn}>Site</TableCell>
</Localized>
)}
<Localized id="stories-column-publishDate">
<TableCell className={styles.publishDateColumn}>
Publish Date
<Localized id="stories-column-reportedCount">
<TableCell className={styles.reportedCountColumn}>
Reported
</TableCell>
</Localized>
<Localized id="stories-column-pendingCount">
<TableCell className={styles.pendingCountColumn}>
Pending
</TableCell>
</Localized>
<Localized id="stories-column-totalCount">
<TableCell className={styles.totalCountColumn}>Total</TableCell>
</Localized>
<Localized id="stories-column-status">
<TableCell className={styles.statusColumn}>Status</TableCell>
</Localized>
+39
View File
@@ -492,6 +492,19 @@ export const stories = createFixtures<GQLStory>([
title: "Finally a Cure for Cancer",
publishedAt: "2018-11-29T16:01:51.897Z",
},
commentCounts: {
totalPublished: 5,
},
moderationQueues: {
reported: {
id: "reported",
count: 3,
},
pending: {
id: "pending",
count: 2,
},
},
site: sites[0],
},
{
@@ -506,6 +519,19 @@ export const stories = createFixtures<GQLStory>([
title: "First Colony on Mars",
publishedAt: "2018-11-29T16:01:51.897Z",
},
commentCounts: {
totalPublished: 5,
},
moderationQueues: {
reported: {
id: "reported",
count: 3,
},
pending: {
id: "pending",
count: 2,
},
},
site: sites[1],
},
{
@@ -515,6 +541,19 @@ export const stories = createFixtures<GQLStory>([
isClosed: true,
status: GQLSTORY_STATUS.CLOSED,
url: "",
commentCounts: {
totalPublished: 5,
},
moderationQueues: {
reported: {
id: "reported",
count: 3,
},
pending: {
id: "pending",
count: 2,
},
},
metadata: {
author: undefined,
title: "World hunger has been defeated",
@@ -155,14 +155,19 @@ exports[`renders empty stories 1`] = `
</span>
</th>
<th
className="TableCell-root StoryTable-authorColumn TableCell-header"
className="TableCell-root StoryTable-reportedCountColumn TableCell-header"
>
Author
Reported
</th>
<th
className="TableCell-root StoryTable-publishDateColumn TableCell-header"
className="TableCell-root StoryTable-pendingCountColumn TableCell-header"
>
Publish Date
Pending
</th>
<th
className="TableCell-root StoryTable-totalCountColumn TableCell-header"
>
Total
</th>
<th
className="TableCell-root StoryTable-statusColumn TableCell-header"
@@ -180,23 +185,45 @@ exports[`renders empty stories 1`] = `
<td
className="TableCell-root StoryRow-titleColumn TableCell-body"
>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-1"
onClick={[Function]}
<div
className="Box-root HorizontalGutter-root HorizontalGutter-full"
>
Finally a Cure for Cancer
</a>
<p>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-1"
onClick={[Function]}
>
Finally a Cure for Cancer
</a>
</p>
<p
className="StoryRow-meta"
>
<span
className="StoryRow-authorName"
>
Vin Hoa
</span>
11/29/2018, 4:01 PM
</p>
</div>
</td>
<td
className="TableCell-root StoryRow-authorColumn TableCell-body"
className="TableCell-root StoryRow-reportedCountColumn StoryRow-boldColumn TableCell-body"
>
Vin Hoa
3
</td>
<td
className="TableCell-root StoryRow-publishDateColumn TableCell-body"
className="TableCell-root StoryRow-pendingCountColumn StoryRow-boldColumn TableCell-body"
>
11/29/2018, 4:01 PM
2
</td>
<td
className="TableCell-root StoryRow-totalCountColumn StoryRow-boldColumn TableCell-body"
>
5
</td>
<td
className="TableCell-root StoryRow-statusColumn TableCell-body"
@@ -251,23 +278,45 @@ exports[`renders empty stories 1`] = `
<td
className="TableCell-root StoryRow-titleColumn TableCell-body"
>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-2"
onClick={[Function]}
<div
className="Box-root HorizontalGutter-root HorizontalGutter-full"
>
First Colony on Mars
</a>
<p>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-2"
onClick={[Function]}
>
First Colony on Mars
</a>
</p>
<p
className="StoryRow-meta"
>
<span
className="StoryRow-authorName"
>
Linh Nguyen
</span>
11/29/2018, 4:01 PM
</p>
</div>
</td>
<td
className="TableCell-root StoryRow-authorColumn TableCell-body"
className="TableCell-root StoryRow-reportedCountColumn StoryRow-boldColumn TableCell-body"
>
Linh Nguyen
3
</td>
<td
className="TableCell-root StoryRow-publishDateColumn TableCell-body"
className="TableCell-root StoryRow-pendingCountColumn StoryRow-boldColumn TableCell-body"
>
11/29/2018, 4:01 PM
2
</td>
<td
className="TableCell-root StoryRow-totalCountColumn StoryRow-boldColumn TableCell-body"
>
5
</td>
<td
className="TableCell-root StoryRow-statusColumn TableCell-body"
@@ -478,14 +527,19 @@ exports[`renders stories 1`] = `
</span>
</th>
<th
className="TableCell-root StoryTable-authorColumn TableCell-header"
className="TableCell-root StoryTable-reportedCountColumn TableCell-header"
>
Author
Reported
</th>
<th
className="TableCell-root StoryTable-publishDateColumn TableCell-header"
className="TableCell-root StoryTable-pendingCountColumn TableCell-header"
>
Publish Date
Pending
</th>
<th
className="TableCell-root StoryTable-totalCountColumn TableCell-header"
>
Total
</th>
<th
className="TableCell-root StoryTable-statusColumn TableCell-header"
@@ -503,23 +557,45 @@ exports[`renders stories 1`] = `
<td
className="TableCell-root StoryRow-titleColumn TableCell-body"
>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-1"
onClick={[Function]}
<div
className="Box-root HorizontalGutter-root HorizontalGutter-full"
>
Finally a Cure for Cancer
</a>
<p>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-1"
onClick={[Function]}
>
Finally a Cure for Cancer
</a>
</p>
<p
className="StoryRow-meta"
>
<span
className="StoryRow-authorName"
>
Vin Hoa
</span>
11/29/2018, 4:01 PM
</p>
</div>
</td>
<td
className="TableCell-root StoryRow-authorColumn TableCell-body"
className="TableCell-root StoryRow-reportedCountColumn StoryRow-boldColumn TableCell-body"
>
Vin Hoa
3
</td>
<td
className="TableCell-root StoryRow-publishDateColumn TableCell-body"
className="TableCell-root StoryRow-pendingCountColumn StoryRow-boldColumn TableCell-body"
>
11/29/2018, 4:01 PM
2
</td>
<td
className="TableCell-root StoryRow-totalCountColumn StoryRow-boldColumn TableCell-body"
>
5
</td>
<td
className="TableCell-root StoryRow-statusColumn TableCell-body"
@@ -574,23 +650,45 @@ exports[`renders stories 1`] = `
<td
className="TableCell-root StoryRow-titleColumn TableCell-body"
>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-2"
onClick={[Function]}
<div
className="Box-root HorizontalGutter-root HorizontalGutter-full"
>
First Colony on Mars
</a>
<p>
<a
className="TextLink-root"
href="/admin/moderate/stories/story-2"
onClick={[Function]}
>
First Colony on Mars
</a>
</p>
<p
className="StoryRow-meta"
>
<span
className="StoryRow-authorName"
>
Linh Nguyen
</span>
11/29/2018, 4:01 PM
</p>
</div>
</td>
<td
className="TableCell-root StoryRow-authorColumn TableCell-body"
className="TableCell-root StoryRow-reportedCountColumn StoryRow-boldColumn TableCell-body"
>
Linh Nguyen
3
</td>
<td
className="TableCell-root StoryRow-publishDateColumn TableCell-body"
className="TableCell-root StoryRow-pendingCountColumn StoryRow-boldColumn TableCell-body"
>
11/29/2018, 4:01 PM
2
</td>
<td
className="TableCell-root StoryRow-totalCountColumn StoryRow-boldColumn TableCell-body"
>
5
</td>
<td
className="TableCell-root StoryRow-statusColumn TableCell-body"
@@ -45,8 +45,9 @@ const BanUserMutation = createMutation(
`,
variables: {
input: {
message: input.message,
userID: input.userID,
message: input.message,
rejectExistingComments: input.rejectExistingComments,
clientMutationId: clientMutationId.toString(),
},
},
@@ -38,6 +38,7 @@ const UserBanPopoverContainer: FunctionComponent<Props> = ({
banUser({
userID: user.id,
commentID: comment.id,
rejectExistingComments: false,
message: getMessage(
localeBundles,
"common-banEmailTemplate",
@@ -229,6 +229,7 @@ it("ban user", async () => {
banUser: ({ variables }) => {
expectAndFail(variables).toMatchObject({
userID: firstComment.author!.id,
rejectExistingComments: false,
});
return {
user: pureMerge<typeof firstComment.author>(firstComment.author, {