mirror of
https://github.com/wassname/talk.git
synced 2026-07-05 14:45:40 +08:00
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:
+7
-3
@@ -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;
|
||||
|
||||
+6
-1
@@ -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`
|
||||
|
||||
+28
-7
@@ -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");
|
||||
},
|
||||
|
||||
+14
-2
@@ -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
|
||||
),
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user