Un-feature a comment when it is rejected (#2555)

Also decrements the featured count for the story if rejected using the
in-stream moderation.

CORL-554
This commit is contained in:
Nick Funk
2019-09-18 10:17:32 -06:00
committed by Kim Gardner
parent 2cc32d4332
commit 741739bc16
7 changed files with 87 additions and 16 deletions
@@ -44,12 +44,16 @@ const ModerationActionsContainer: FunctionComponent<Props> = ({
}
approve({ commentID: comment.id, commentRevisionID: comment.revision.id });
}, [approve, comment]);
const onReject = useCallback(() => {
const onReject = useCallback(async () => {
if (!comment.revision) {
return;
}
reject({ commentID: comment.id, commentRevisionID: comment.revision.id });
}, [approve, comment]);
await reject({
commentID: comment.id,
commentRevisionID: comment.revision.id,
storyID: story.id,
});
}, [approve, comment, story]);
const onFeature = useCallback(() => {
if (!comment.revision) {
return;
@@ -47,7 +47,11 @@ const ModerationDropdownContainer: FunctionComponent<Props> = ({
/>
</Dropdown>
) : (
<UserBanPopoverContainer comment={comment} onDismiss={onDismiss} />
<UserBanPopoverContainer
comment={comment}
story={story}
onDismiss={onDismiss}
/>
)}
</div>
);
@@ -76,6 +80,7 @@ const enhanced = withFragmentContainer<Props>({
fragment ModerationDropdownContainer_story on Story {
id
...ModerationActionsContainer_story
...UserBanPopoverContainer_story
}
`,
viewer: graphql`
@@ -13,33 +13,54 @@ let clientMutationId = 0;
const RejectCommentMutation = createMutation(
"rejectComment",
(environment: Environment, input: MutationInput<MutationTypes>) =>
(
environment: Environment,
input: MutationInput<MutationTypes> & { storyID: string }
) =>
commitMutationPromiseNormalized<MutationTypes>(environment, {
mutation: graphql`
mutation RejectCommentMutation($input: RejectCommentInput!) {
rejectComment(input: $input) {
comment {
status
tags {
code
}
story {
commentCounts {
tags {
FEATURED
}
}
}
}
clientMutationId
}
}
`,
variables: {
input: {
commentID: input.commentID,
commentRevisionID: input.commentRevisionID,
clientMutationId: (clientMutationId++).toString(),
},
},
optimisticResponse: {
rejectComment: {
comment: {
id: input.commentID,
status: GQLCOMMENT_STATUS.REJECTED,
story: {
commentCounts: {
tags: {
FEATURED: 0,
},
},
},
},
clientMutationId: clientMutationId.toString(),
},
},
variables: {
input: {
...input,
clientMutationId: (clientMutationId++).toString(),
},
},
updater: store => {
store.get(input.commentID)!.setValue("REJECT", "lastViewerAction");
},
@@ -7,6 +7,7 @@ import { useCoralContext } from "coral-framework/lib/bootstrap";
import { getMessage } from "coral-framework/lib/i18n";
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
import { UserBanPopoverContainer_comment } from "coral-stream/__generated__/UserBanPopoverContainer_comment.graphql";
import { UserBanPopoverContainer_story } from "coral-stream/__generated__/UserBanPopoverContainer_story.graphql";
import CLASSES from "coral-stream/classes";
import { Box, Button, Flex, Typography } from "coral-ui/components";
@@ -18,10 +19,12 @@ import styles from "./UserBanPopoverContainer.css";
interface Props {
onDismiss: () => void;
comment: UserBanPopoverContainer_comment;
story: UserBanPopoverContainer_story;
}
const UserBanPopoverContainer: FunctionComponent<Props> = ({
comment,
story,
onDismiss,
}) => {
const user = comment.author!;
@@ -41,10 +44,14 @@ const UserBanPopoverContainer: FunctionComponent<Props> = ({
),
});
if (!rejected && comment.revision) {
reject({ commentID: comment.id, commentRevisionID: comment.revision.id });
reject({
commentID: comment.id,
commentRevisionID: comment.revision.id,
storyID: story.id,
});
}
onDismiss();
}, [user, banUser, onDismiss, localeBundles]);
}, [user, banUser, onDismiss, localeBundles, comment, story]);
return (
<Box className={cn(styles.root, CLASSES.banUserPopover.$root)} p={3}>
<Localized id="comments-userBanPopover-title" $username={user.username}>
@@ -98,6 +105,11 @@ const enhanced = withFragmentContainer<Props>({
}
}
`,
story: graphql`
fragment UserBanPopoverContainer_story on Story {
id
}
`,
})(UserBanPopoverContainer);
export default enhanced;
@@ -12,7 +12,18 @@ import {
import { featuredTag, moderators, settings, stories } from "../../fixtures";
import create from "./create";
const story = stories[0];
function createStory() {
const base = stories[0];
for (const edge of base.comments.edges) {
const node = edge.node;
node.story = base;
}
return base;
}
const story = createStory();
const firstComment = story.comments.edges[0].node;
const viewer = moderators[0];
@@ -33,6 +44,7 @@ async function createTestRenderer(
),
initLocalState: (localRecord, source, environment) => {
localRecord.setValue(story.id, "storyID");
if (params.initLocalState) {
params.initLocalState(localRecord, source, environment);
}
@@ -1,8 +1,11 @@
import TenantContext from "coral-server/graph/tenant/context";
import { hasTag } from "coral-server/models/comment";
import { removeTag } from "coral-server/services/comments";
import { approve, reject } from "coral-server/services/comments/moderation";
import {
GQLApproveCommentInput,
GQLRejectCommentInput,
GQLTAG,
} from "../schema/__generated__/types";
export const Actions = (ctx: TenantContext) => ({
@@ -17,5 +20,12 @@ export const Actions = (ctx: TenantContext) => ({
commentID: input.commentID,
commentRevisionID: input.commentRevisionID,
moderatorID: ctx.user!.id,
}),
}).then(comment =>
// if a comment was previously featured
// and is now rejected, we need to remove the
// featured tag
hasTag(comment, GQLTAG.FEATURED)
? removeTag(ctx.mongo, ctx.tenant, comment.id, GQLTAG.FEATURED)
: comment
),
});
+8 -1
View File
@@ -1,4 +1,7 @@
import { GQLCOMMENT_STATUS } from "coral-server/graph/tenant/schema/__generated__/types";
import {
GQLCOMMENT_STATUS,
GQLTAG,
} from "coral-server/graph/tenant/schema/__generated__/types";
import { Comment } from "./comment";
import { MODERATOR_STATUSES, PUBLISHED_STATUSES } from "./constants";
@@ -73,3 +76,7 @@ export function calculateRejectionRate(counts: CommentStatusCounts): number {
return rejected / (published + rejected);
}
export function hasTag(comment: Pick<Comment, "tags">, tag: GQLTAG) {
return comment.tags.some(v => v.type === tag);
}