mirror of
https://github.com/wassname/talk.git
synced 2026-07-24 13:20:47 +08:00
[next] Flag Improvements (#2114)
* fix: applied fix for reaction mutation * fix: removed comment length flag * feat: added additionalDetails field to flags * feat: added other flag type
This commit is contained in:
@@ -5,12 +5,17 @@ import {
|
||||
commitMutationPromiseNormalized,
|
||||
createMutationContainer,
|
||||
} from "talk-framework/lib/relay";
|
||||
import { Omit } from "talk-framework/types";
|
||||
|
||||
import { RemoveCommentReactionMutation as MutationTypes } from "talk-stream/__generated__/RemoveCommentReactionMutation.graphql";
|
||||
import { CreateCommentReactionInput } from "talk-stream/mutations/CreateCommentReactionMutation";
|
||||
|
||||
export type RemoveCommentReactionInput = Omit<
|
||||
MutationTypes["variables"]["input"],
|
||||
"clientMutationId"
|
||||
>;
|
||||
|
||||
const mutation = graphql`
|
||||
mutation RemoveCommentReactionMutation($input: CreateCommentReactionInput!) {
|
||||
mutation RemoveCommentReactionMutation($input: RemoveCommentReactionInput!) {
|
||||
removeCommentReaction(input: $input) {
|
||||
comment {
|
||||
...ReactionButtonContainer_comment
|
||||
@@ -22,7 +27,7 @@ const mutation = graphql`
|
||||
|
||||
let clientMutationId = 0;
|
||||
|
||||
function commit(environment: Environment, input: CreateCommentReactionInput) {
|
||||
function commit(environment: Environment, input: RemoveCommentReactionInput) {
|
||||
const source = environment.getStore().getSource();
|
||||
const currentCount = source.get(
|
||||
source.get(source.get(input.commentID)!.actionCounts.__ref)!.reaction.__ref
|
||||
@@ -60,5 +65,5 @@ export const withRemoveCommentReactionMutation = createMutationContainer(
|
||||
);
|
||||
|
||||
export type RemoveCommentReactionMutation = (
|
||||
input: CreateCommentReactionInput
|
||||
input: RemoveCommentReactionInput
|
||||
) => Promise<MutationTypes["response"]["removeCommentReaction"]>;
|
||||
|
||||
@@ -17,6 +17,13 @@ import {
|
||||
removeDontAgree,
|
||||
removeReaction,
|
||||
} from "talk-server/services/comments/actions";
|
||||
import { validateMaximumLength } from "./util";
|
||||
|
||||
/**
|
||||
* MAX_ADDITIONAL_DETAILS_LENGTH defines the maximum length for the
|
||||
* additionalDetails field.
|
||||
*/
|
||||
const MAX_ADDITIONAL_DETAILS_LENGTH = 500;
|
||||
|
||||
export const Comment = (ctx: TenantContext) => ({
|
||||
create: ({
|
||||
@@ -58,10 +65,16 @@ export const Comment = (ctx: TenantContext) => ({
|
||||
createDontAgree: ({
|
||||
commentID,
|
||||
commentRevisionID,
|
||||
additionalDetails,
|
||||
}: GQLCreateCommentDontAgreeInput) =>
|
||||
createDontAgree(ctx.mongo, ctx.redis, ctx.tenant, ctx.user!, {
|
||||
commentID,
|
||||
commentRevisionID,
|
||||
// TODO: (wyattjoh) move this validation to the schema when bug is fixed: https://github.com/apollographql/graphql-tools/issues/842
|
||||
additionalDetails: validateMaximumLength(
|
||||
MAX_ADDITIONAL_DETAILS_LENGTH,
|
||||
additionalDetails
|
||||
),
|
||||
}),
|
||||
removeDontAgree: ({ commentID }: GQLRemoveCommentDontAgreeInput) =>
|
||||
removeDontAgree(ctx.mongo, ctx.redis, ctx.tenant, ctx.user!, {
|
||||
@@ -71,10 +84,16 @@ export const Comment = (ctx: TenantContext) => ({
|
||||
commentID,
|
||||
commentRevisionID,
|
||||
reason,
|
||||
additionalDetails,
|
||||
}: GQLCreateCommentFlagInput) =>
|
||||
createFlag(ctx.mongo, ctx.redis, ctx.tenant, ctx.user!, {
|
||||
commentID,
|
||||
commentRevisionID,
|
||||
reason,
|
||||
// TODO: (wyattjoh) move this validation to the schema when bug is fixed: https://github.com/apollographql/graphql-tools/issues/842
|
||||
additionalDetails: validateMaximumLength(
|
||||
MAX_ADDITIONAL_DETAILS_LENGTH,
|
||||
additionalDetails
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { validateMaximumLength } from "./util";
|
||||
|
||||
it("limits to maximum when string is provided", () => {
|
||||
expect(() => validateMaximumLength(5, "123456")).toThrow();
|
||||
});
|
||||
|
||||
it("limits to maximum when string is not provided", () => {
|
||||
expect(validateMaximumLength(5)).toEqual(undefined);
|
||||
});
|
||||
|
||||
it("returns the string when string is provided and is within the length allowances", () => {
|
||||
expect(validateMaximumLength(5, "1234")).toEqual("1234");
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* validateMaximumLength will limit the value of an optional string to the
|
||||
* specified amount, otherwise will throw an error.
|
||||
*
|
||||
* @param maxLength maximum length to limit a value to
|
||||
* @param value the value that should be limited
|
||||
*/
|
||||
export function validateMaximumLength(maxLength: number, value?: string) {
|
||||
if (value && value.length > maxLength) {
|
||||
throw new Error(`Exceeded maximum length of ${maxLength} characters`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -46,6 +46,12 @@ enum COMMENT_FLAG_REPORTED_REASON {
|
||||
spam.
|
||||
"""
|
||||
COMMENT_REPORTED_SPAM
|
||||
|
||||
"""
|
||||
COMMENT_REPORTED_OTHER is used when a User reported a Comment that doesn't
|
||||
fit into the other reported reasons.
|
||||
"""
|
||||
COMMENT_REPORTED_OTHER
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -65,12 +71,6 @@ enum COMMENT_FLAG_DETECTED_REASON {
|
||||
"""
|
||||
COMMENT_DETECTED_SPAM
|
||||
|
||||
"""
|
||||
COMMENT_DETECTED_BODY_COUNT is used when the Comment was detected as exceeding
|
||||
the body length by the system.
|
||||
"""
|
||||
COMMENT_DETECTED_BODY_COUNT
|
||||
|
||||
"""
|
||||
COMMENT_DETECTED_TRUST is used when the Comment being left was done by a User
|
||||
that has a low karma/trust score.
|
||||
@@ -103,9 +103,9 @@ and COMMENT_FLAG_DETECTED_REASON types.
|
||||
enum COMMENT_FLAG_REASON {
|
||||
COMMENT_REPORTED_OFFENSIVE
|
||||
COMMENT_REPORTED_SPAM
|
||||
COMMENT_REPORTED_OTHER
|
||||
COMMENT_DETECTED_TOXIC
|
||||
COMMENT_DETECTED_SPAM
|
||||
COMMENT_DETECTED_BODY_COUNT
|
||||
COMMENT_DETECTED_TRUST
|
||||
COMMENT_DETECTED_LINKS
|
||||
COMMENT_DETECTED_BANNED_WORD
|
||||
@@ -137,9 +137,9 @@ type DontAgreeActionCounts {
|
||||
type FlagReasonActionCounts {
|
||||
COMMENT_REPORTED_OFFENSIVE: Int!
|
||||
COMMENT_REPORTED_SPAM: Int!
|
||||
COMMENT_REPORTED_OTHER: Int!
|
||||
COMMENT_DETECTED_TOXIC: Int!
|
||||
COMMENT_DETECTED_SPAM: Int!
|
||||
COMMENT_DETECTED_BODY_COUNT: Int!
|
||||
COMMENT_DETECTED_TRUST: Int!
|
||||
COMMENT_DETECTED_LINKS: Int!
|
||||
COMMENT_DETECTED_BANNED_WORD: Int!
|
||||
@@ -2230,6 +2230,12 @@ input CreateCommentDontAgreeInput {
|
||||
"""
|
||||
commentRevisionID: ID!
|
||||
|
||||
"""
|
||||
additionalDetails stores information from the User as to why the Flag was
|
||||
created or is relevant.
|
||||
"""
|
||||
additionalDetails: String
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
@@ -2297,6 +2303,12 @@ input CreateCommentFlagInput {
|
||||
"""
|
||||
reason: COMMENT_FLAG_REPORTED_REASON!
|
||||
|
||||
"""
|
||||
additionalDetails stores information from the User as to why the Flag was
|
||||
created or is relevant.
|
||||
"""
|
||||
additionalDetails: String
|
||||
|
||||
"""
|
||||
clientMutationId is required for Relay support.
|
||||
"""
|
||||
@@ -2964,8 +2976,8 @@ type Mutation {
|
||||
User on a Comment if it exists.
|
||||
"""
|
||||
removeCommentReaction(
|
||||
input: CreateCommentReactionInput!
|
||||
): CreateCommentReactionPayload @auth
|
||||
input: RemoveCommentReactionInput!
|
||||
): RemoveCommentReactionPayload @auth
|
||||
|
||||
"""
|
||||
createCommentDontAgree will create a DontAgree authored by the current logged in
|
||||
@@ -2980,8 +2992,8 @@ type Mutation {
|
||||
User on a Comment if it exists.
|
||||
"""
|
||||
removeCommentDontAgree(
|
||||
input: CreateCommentDontAgreeInput!
|
||||
): CreateCommentDontAgreePayload @auth
|
||||
input: RemoveCommentDontAgreeInput!
|
||||
): RemoveCommentDontAgreePayload @auth
|
||||
|
||||
"""
|
||||
createCommentFlag will create a Flag authored by the current logged in User on
|
||||
|
||||
@@ -5,7 +5,7 @@ Object {
|
||||
"DONT_AGREE": 1,
|
||||
"FLAG": 2,
|
||||
"FLAG__COMMENT_DETECTED_BANNED_WORD": 1,
|
||||
"FLAG__COMMENT_DETECTED_BODY_COUNT": 1,
|
||||
"FLAG__COMMENT_REPORTED_OTHER": 1,
|
||||
"REACTION": 3,
|
||||
}
|
||||
`;
|
||||
@@ -18,13 +18,13 @@ Object {
|
||||
"flag": Object {
|
||||
"reasons": Object {
|
||||
"COMMENT_DETECTED_BANNED_WORD": 1,
|
||||
"COMMENT_DETECTED_BODY_COUNT": 1,
|
||||
"COMMENT_DETECTED_LINKS": 0,
|
||||
"COMMENT_DETECTED_SPAM": 0,
|
||||
"COMMENT_DETECTED_SUSPECT_WORD": 0,
|
||||
"COMMENT_DETECTED_TOXIC": 0,
|
||||
"COMMENT_DETECTED_TRUST": 0,
|
||||
"COMMENT_REPORTED_OFFENSIVE": 0,
|
||||
"COMMENT_REPORTED_OTHER": 1,
|
||||
"COMMENT_REPORTED_SPAM": 0,
|
||||
},
|
||||
"total": 2,
|
||||
@@ -40,6 +40,6 @@ Object {
|
||||
"DONT_AGREE": 1,
|
||||
"FLAG": 2,
|
||||
"FLAG__COMMENT_DETECTED_BANNED_WORD": 1,
|
||||
"FLAG__COMMENT_DETECTED_BODY_COUNT": 1,
|
||||
"FLAG__COMMENT_REPORTED_OTHER": 1,
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("#encodeActionCounts", () => {
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_DETECTED_BODY_COUNT,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OTHER,
|
||||
},
|
||||
];
|
||||
const actionCounts = encodeActionCounts(...(actions as CommentAction[]));
|
||||
@@ -41,7 +41,7 @@ describe("#decodeActionCounts", () => {
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_DETECTED_BODY_COUNT,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OTHER,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -76,7 +76,7 @@ describe("#validateAction", () => {
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_DETECTED_BODY_COUNT,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OTHER,
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
@@ -109,7 +109,7 @@ describe("#validateAction", () => {
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.DONT_AGREE,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_DETECTED_BODY_COUNT,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_REPORTED_OTHER,
|
||||
},
|
||||
{
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
|
||||
@@ -75,6 +75,12 @@ export interface CommentAction extends TenantResource {
|
||||
*/
|
||||
reason?: FLAG_REASON;
|
||||
|
||||
/**
|
||||
* additionalDetails stores information from the User as to why the Flag was
|
||||
* created or is relevant.
|
||||
*/
|
||||
additionalDetails?: string;
|
||||
|
||||
/**
|
||||
* storyID represents the ID of the Story where the comment was left on.
|
||||
*/
|
||||
@@ -168,7 +174,7 @@ export async function createAction(
|
||||
tenantID: string,
|
||||
input: CreateActionInput
|
||||
): Promise<CreateActionResultObject> {
|
||||
const { metadata, ...filter } = input;
|
||||
const { metadata, additionalDetails, ...filter } = input;
|
||||
|
||||
// Create a new ID for the action.
|
||||
const id = uuid.v4();
|
||||
@@ -185,6 +191,7 @@ export async function createAction(
|
||||
const action: Readonly<CommentAction> = {
|
||||
...defaults,
|
||||
...input,
|
||||
additionalDetails,
|
||||
};
|
||||
|
||||
// Create the upsert/update operation.
|
||||
|
||||
@@ -226,7 +226,7 @@ export async function removeReaction(
|
||||
|
||||
export type CreateCommentDontAgree = Pick<
|
||||
CreateActionInput,
|
||||
"commentID" | "commentRevisionID"
|
||||
"commentID" | "commentRevisionID" | "additionalDetails"
|
||||
>;
|
||||
|
||||
export async function createDontAgree(
|
||||
@@ -240,6 +240,7 @@ export async function createDontAgree(
|
||||
actionType: ACTION_TYPE.DONT_AGREE,
|
||||
commentID: input.commentID,
|
||||
commentRevisionID: input.commentRevisionID,
|
||||
additionalDetails: input.additionalDetails,
|
||||
userID: author.id,
|
||||
});
|
||||
}
|
||||
@@ -262,7 +263,7 @@ export async function removeDontAgree(
|
||||
|
||||
export type CreateCommentFlag = Pick<
|
||||
CreateActionInput,
|
||||
"commentID" | "commentRevisionID"
|
||||
"commentID" | "commentRevisionID" | "additionalDetails"
|
||||
> & {
|
||||
reason: GQLCOMMENT_FLAG_REPORTED_REASON;
|
||||
};
|
||||
@@ -279,6 +280,7 @@ export async function createFlag(
|
||||
reason: input.reason,
|
||||
commentID: input.commentID,
|
||||
commentRevisionID: input.commentRevisionID,
|
||||
additionalDetails: input.additionalDetails,
|
||||
userID: author.id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import striptags from "striptags";
|
||||
|
||||
import { isNil } from "lodash";
|
||||
import {
|
||||
GQLCOMMENT_FLAG_REASON,
|
||||
GQLCOMMENT_STATUS,
|
||||
} from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { ACTION_TYPE } from "talk-server/models/action/comment";
|
||||
import { ModerationSettings } from "talk-server/models/settings";
|
||||
import {
|
||||
IntermediateModerationPhase,
|
||||
@@ -16,22 +11,26 @@ const testCharCount = (
|
||||
settings: Partial<ModerationSettings>,
|
||||
length: number
|
||||
) => {
|
||||
// settings.charCount.enable && settings.charCount && length > settings.charCount;
|
||||
|
||||
if (settings.charCount && settings.charCount.enabled) {
|
||||
if (!isNil(settings.charCount.min)) {
|
||||
if (length < settings.charCount.min) {
|
||||
return true;
|
||||
throw new Error(
|
||||
`Body did not meet minimum length requirement of ${
|
||||
settings.charCount.min
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isNil(settings.charCount.max)) {
|
||||
if (length > settings.charCount.max) {
|
||||
return true;
|
||||
throw new Error(
|
||||
`Body exceeded maximum length requirement of ${
|
||||
settings.charCount.max
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const commentLength: IntermediateModerationPhase = ({
|
||||
@@ -42,22 +41,8 @@ export const commentLength: IntermediateModerationPhase = ({
|
||||
const length = comment.body ? striptags(comment.body).length : 0;
|
||||
|
||||
// Reject if the comment is too long or too short.
|
||||
if (
|
||||
testCharCount(tenant, length) ||
|
||||
(story.settings && testCharCount(story.settings, length))
|
||||
) {
|
||||
return {
|
||||
status: GQLCOMMENT_STATUS.REJECTED,
|
||||
actions: [
|
||||
{
|
||||
userID: null,
|
||||
actionType: ACTION_TYPE.FLAG,
|
||||
reason: GQLCOMMENT_FLAG_REASON.COMMENT_DETECTED_BODY_COUNT,
|
||||
metadata: {
|
||||
count: length,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
testCharCount(tenant, length);
|
||||
if (story.settings) {
|
||||
testCharCount(story.settings, length);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user