[CORL-1180] Moderation + Editing Improvements (#3020)

* fix: handle moderating edited comments better

* fix: add back deleted audit trail entry

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Wyatt Johnson
2020-07-16 19:59:51 +00:00
committed by GitHub
co-authored by kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
parent 4f5c0e285c
commit 5b589bfe2b
9 changed files with 98 additions and 21 deletions
@@ -47,6 +47,13 @@ export function getLatestRevision(
return comment.revisions[comment.revisions.length - 1];
}
export function hasRevision(
comment: Pick<Comment, "revisions">,
revisionID: string
): boolean {
return comment.revisions.some((revision) => revision.id === revisionID);
}
export function calculateRejectionRate(counts: CommentStatusCounts): number {
const published = calculateTotalPublishedCommentCount(counts);
const rejected = counts[GQLCOMMENT_STATUS.REJECTED];
@@ -5,7 +5,12 @@ import {
createCommentModerationAction,
CreateCommentModerationActionInput,
} from "coral-server/models/action/moderation/comment";
import { updateCommentStatus } from "coral-server/models/comment";
import {
getLatestRevision,
hasRevision,
retrieveComment,
updateCommentStatus,
} from "coral-server/models/comment";
import { Tenant } from "coral-server/models/tenant";
export type Moderate = CreateCommentModerationActionInput;
@@ -18,18 +23,32 @@ export default async function moderate(
) {
// TODO: wrap these operations in a transaction?
// Create the moderation action in the audit log.
const action = await createCommentModerationAction(
mongo,
tenant.id,
input,
now
);
if (!action) {
// TODO: wrap in better error?
throw new Error("could not create moderation action");
// Get the comment that we're moderating.
const comment = await retrieveComment(mongo, tenant.id, input.commentID);
if (!comment) {
throw new CommentNotFoundError(input.commentID, input.commentRevisionID);
}
// Get the latest revision on that comment.
const revision = getLatestRevision(comment);
// Ensure that the latest revision is the same revision that we're moderating.
if (revision.id !== input.commentRevisionID) {
// The revision has been updated since then! Ensure that this revision ID
// does exist.
if (!hasRevision(comment, input.commentRevisionID)) {
throw new CommentNotFoundError(input.commentID, input.commentRevisionID);
}
// The comment has this revision, it just isn't the latest one. Return the
// same comment back because we didn't modify anything.
return { before: comment, after: null };
}
// TODO: (wyattjoh) this is a pretty race condition prone check here, replace
// with a more concrete query that can prevent the comment being edited in the
// time it takes to go from the above block to the next block.
// Update the Comment's status.
const result = await updateCommentStatus(
mongo,
@@ -42,5 +61,17 @@ export default async function moderate(
throw new CommentNotFoundError(input.commentID, input.commentRevisionID);
}
// Create the moderation action in the audit log.
const action = await createCommentModerationAction(
mongo,
tenant.id,
input,
now
);
if (!action) {
// TODO: wrap in better error?
throw new Error("could not create moderation action");
}
return result;
}
+5
View File
@@ -32,6 +32,11 @@ const approveComment = async (
now
);
// If the comment hasn't been updated, skip the rest of the steps.
if (!result.after) {
return result.before;
}
// Update all the comment counts on stories and users.
const counts = await updateAllCommentCounts(mongo, redis, {
...result,
+5
View File
@@ -37,6 +37,11 @@ const rejectComment = async (
now
);
// If the comment hasn't been updated, skip the rest of the steps.
if (!result.after) {
return result.before;
}
// Update all the comment counts on stories and users.
const counts = await updateAllCommentCounts(mongo, redis, {
...result,