Skip to content

Commit

Permalink
add create dsareport mutation, services, schema; plus some validation
Browse files Browse the repository at this point in the history
  • Loading branch information
kabeaty committed Oct 6, 2023
1 parent 621ee59 commit 4aaa508
Show file tree
Hide file tree
Showing 11 changed files with 335 additions and 20 deletions.
17 changes: 17 additions & 0 deletions client/src/core/client/framework/lib/validation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ReactNode } from "react";
import {
EMAIL_DOMAIN_REGEX,
EMAIL_REGEX,
ID_REGEX,
PASSWORD_MIN_LENGTH,
URL_REGEX,
USERNAME_MAX_LENGTH,
Expand Down Expand Up @@ -115,6 +116,22 @@ export const validateImageURL = createValidator(
INVALID_MEDIA_URL()
);

/**
* validateShareURL checks that a URL is valid and includes a valid commentID query param
*/
export const validateShareURL = (v: any) => {
if (!v) {
return false;
}
const shareURLArr = v.split("?commentID=");
if (!(shareURLArr.length === 2)) {
return false;
}
const isValidUrl = URL_REGEX.test(shareURLArr[0]);
const isValidCommentID = ID_REGEX.test(shareURLArr[1]);
return isValidUrl && isValidCommentID;
};

/**
* validateURL is a Validator that checks that the URL only contains valid characters.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { graphql } from "react-relay";
import { Environment } from "relay-runtime";

import {
commitMutationPromiseNormalized,
createMutation,
MutationInput,
} from "coral-framework/lib/relay";

import { CreateDSAReportMutation as MutationTypes } from "coral-stream/__generated__/CreateDSAReportMutation.graphql";

let clientMutationId = 0;

const CreateDSAReportMutation = createMutation(
"createDSAReport",
(environment: Environment, input: MutationInput<MutationTypes>) => {
const result = commitMutationPromiseNormalized<MutationTypes>(environment, {
mutation: graphql`
mutation CreateDSAReportMutation($input: CreateDSAReportInput!) {
createDSAReport(input: $input) {
dsaReport {
id
lawBrokenDescription
}
clientMutationId
}
}
`,
variables: {
input: {
userID: input.userID,
commentID: input.commentID,
lawBrokenDescription: input.lawBrokenDescription,
additionalInformation: input.additionalInformation,
submissionID: input.submissionID,
clientMutationId: (clientMutationId++).toString(),
},
},
});
return result;
}
);

export default CreateDSAReportMutation;
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import React, {
useMemo,
useState,
} from "react";
import { Field, Form, FormProps } from "react-final-form";
import { Field, Form } from "react-final-form";
import { graphql } from "react-relay";

import { getURLWithCommentID } from "coral-framework/helpers";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { parseBool } from "coral-framework/lib/form";
import { useMutation, withFragmentContainer } from "coral-framework/lib/relay";
import { required } from "coral-framework/lib/validation";
import { required, validateShareURL } from "coral-framework/lib/validation";
import CLASSES from "coral-stream/classes";
import UserBoxContainer from "coral-stream/common/UserBox";
import { ViewFullDiscussionEvent } from "coral-stream/events";
Expand Down Expand Up @@ -49,6 +49,7 @@ import { CommentContainer } from "../Comment";
import DeletedTombstoneContainer from "../DeletedTombstoneContainer";
import IgnoredTombstoneOrHideContainer from "../IgnoredTombstoneOrHideContainer";
import RejectedTombstoneContainer from "../PermalinkView/RejectedTombstoneContainer";
import CreateDSAReportMutation from "./CreateDSAReportMutation";

interface Props {
comment: CommentData | null;
Expand All @@ -58,15 +59,24 @@ interface Props {
refreshStream: boolean | null;
}

interface FormProps {
lawBrokenDescription: string;
additionalInformation: string;
}

const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
const { comment, story, viewer, settings } = props;
const setCommentID = useMutation(SetCommentIDMutation);
const createDSAReport = useMutation(CreateDSAReportMutation);
const { eventEmitter, window } = useCoralContext();
const [showAddAdditionalComment, setShowAddAdditionalComment] =
useState(false);
const [additionalComments, setAdditionalComments] = useState<null | string[]>(
null
);
const [addAdditionalCommentError, setAddAdditionalCommentError] = useState<
null | string
>(null);

const onShowAllComments = useCallback(
(e: MouseEvent<any>) => {
Expand All @@ -87,12 +97,48 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {

const commentVisible = comment && isPublished(comment.status);

const onSubmit = useCallback((input: FormProps, form: FormApi) => {}, []);
const onSubmit = useCallback(
async (input: FormProps, form: FormApi) => {
if (viewer && comment) {
// TODO: generate submissionID with uuid here for each if it's a multiple
// add report form comment and any additional commentIDs to comments
const comments = [comment.id];
if (additionalComments) {
for (const c of additionalComments) {
const cArr = c.split("?commentID=");
comments.push(cArr[1]);
}
}
try {
await createDSAReport({
userID: viewer.id,
commentID: comment.id,
lawBrokenDescription: input.lawBrokenDescription,
additionalInformation: input.additionalInformation,
});
} catch (e) {
// TODO: handle error
}
}
},
[additionalComments, viewer, comment, createDSAReport]
);

const isValidShareURL = useCallback((value: string) => {
return validateShareURL(value);
}, []);

const onAddCommentURL = useCallback(
(values: Record<string, any>) => {
if (values.additionalComment) {
// TODO: validate
// TODO: also ensure that it's not the same commentID as the report form
if (!isValidShareURL(values.additionalComment)) {
// TODO: Update to localize
setAddAdditionalCommentError("Please add a valid comment URL.");
return;
} else {
setAddAdditionalCommentError(null);
}
// if passes validation, add to additionalComments
if (additionalComments) {
setAdditionalComments([
Expand All @@ -107,9 +153,15 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
if (additionalComments && additionalComments.length < 9) {
setShowAddAdditionalComment(false);
}
// TODO: show a validation message if no value or value doesn't pass validation
// TODO: show a validation message if value doesn't pass validation
},
[setAdditionalComments, additionalComments, setShowAddAdditionalComment]
[
setAdditionalComments,
additionalComments,
setShowAddAdditionalComment,
isValidShareURL,
setAddAdditionalCommentError,
]
);

return (
Expand Down Expand Up @@ -243,13 +295,13 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
<HorizontalGutter spacing={4}>
<FormField>
<Field
name="lawDetails"
name="lawBrokenDescription"
validate={required}
id="reportIllegalContent-lawDetails"
id="reportIllegalContent-lawBrokenDescription"
>
{({ input }) => (
<>
<Localized id="comments-permalinkView-reportIllegalContent-lawDetails-inputLabel">
<Localized id="comments-permalinkView-reportIllegalContent-lawBrokenDescription-inputLabel">
<InputLabel htmlFor={input.name}>
What law do you believe has been broken? (required)
</InputLabel>
Expand All @@ -261,19 +313,19 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
</FormField>
<FormField>
<Field
name="additionalInfo"
name="additionalInformation"
validate={required}
id="reportIllegalContent-additionalInfo"
id="reportIllegalContent-additionalInformation"
>
{({ input }) => (
<>
<Localized id="comments-permalinkView-reportIllegalContent-additionalInfo-inputLabel">
<Localized id="comments-permalinkView-reportIllegalContent-additionalInformation-inputLabel">
<InputLabel htmlFor={input.name}>
Please include additional information why this comment
is illegal (required)
</InputLabel>
</Localized>
<Localized id="comments-permalinkView-reportIllegalContent-additionalInfo-helperText">
<Localized id="comments-permalinkView-reportIllegalContent-additionalInformation-helperText">
<HelperText>
To the best of your ability please give as much detail
to help us investigate this further.
Expand Down Expand Up @@ -305,9 +357,6 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
<>
<Field
name={`additionalComment`}
// TODO: validate that it's a valid share url
// validate uniqueness as well here?
// validate={required}
id={`reportIllegalContent-additionalComment`}
>
{({ input }: any) => (
Expand All @@ -326,6 +375,9 @@ const IllegalContentReportViewContainer: FunctionComponent<Props> = (props) => {
</>
)}
</Field>
{addAdditionalCommentError && (
<div>{addAdditionalCommentError}</div>
)}
{/* // TODO: Update localized */}
<Localized
id="comments-permalinkView-reportIllegalContent-additionalComments-"
Expand Down
2 changes: 2 additions & 0 deletions common/lib/helpers/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const USERNAME_REGEX = new RegExp(/^[a-zA-ZÀ-ÖØ-öø-ÿ0-9_.]+$/);
export const USERNAME_MAX_LENGTH = 30;
export const USERNAME_MIN_LENGTH = 3;

export const ID_REGEX = new RegExp(/^[a-zA-Z0-9-.]+$/);

export const PASSWORD_MIN_LENGTH = 8;

export const EMAIL_REGEX = new RegExp(/^\S+@\S+.\S+$/);
Expand Down
6 changes: 3 additions & 3 deletions locales/en-US/stream.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ comments-permalinkView-reportIllegalContent-description = Under the Digital Serv
your ability so our moderation team can make a decision and if necessary consult with our site's legal
department. Thank you for your support in making our communities safer to engage in.
comments-permalinkView-reportIllegalContent-reportingComment = You are reporting this comment
comments-permalinkView-reportIllegalContent-lawDetails-inputLabel = What law do you believe has been broken? (required)
comments-permalinkView-reportIllegalContent-additionalInfo-inputLabel = Please include additional information why this comment is illegal (required)
comments-permalinkView-reportIllegalContent-additionalInfo-helperText = To the best of your ability please give as much detail to help us investigate this further
comments-permalinkView-reportIllegalContent-lawBrokenDescription-inputLabel = What law do you believe has been broken? (required)
comments-permalinkView-reportIllegalContent-additionalInformation-inputLabel = Please include additional information why this comment is illegal (required)
comments-permalinkView-reportIllegalContent-additionalInformation-helperText = To the best of your ability please give as much detail to help us investigate this further
comments-permalinkView-reportIllegalContent-additionalComments-inputLabel = Have other comments you'd like to report for breaking this law?
comments-permalinkView-reportIllegalContent-bonafideBelief-checkbox = Bonafide belief statement
comments-permalinkView-reportIllegalContent-additionalComments-button = <Button></Button>Add additional comments
Expand Down
5 changes: 5 additions & 0 deletions server/src/core/server/data/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Config } from "coral-server/config";
import { CommentAction } from "coral-server/models/action/comment";
import { CommentModerationAction } from "coral-server/models/action/moderation/comment";
import { Comment } from "coral-server/models/comment";
import { DSAReport } from "coral-server/models/dsaReport/comment";
import { createCollection } from "coral-server/models/helpers";
import { Invite } from "coral-server/models/invite";
import { MigrationRecord } from "coral-server/models/migration";
Expand Down Expand Up @@ -35,6 +36,7 @@ export interface MongoContext {
Readonly<CommentModerationAction>
>;
seenComments(): Collection<Readonly<SeenComments>>;
dsaReports(): Collection<Readonly<DSAReport>>;
}

export class MongoContextImpl implements MongoContext {
Expand Down Expand Up @@ -83,6 +85,9 @@ export class MongoContextImpl implements MongoContext {
public seenComments(): Collection<Readonly<SeenComments>> {
return createCollection<SeenComments>("seenComments")(this.live);
}
public dsaReports(): Collection<Readonly<DSAReport>> {
return createCollection<DSAReport>("dsaReports")(this.live);
}
public archivedComments(): Collection<Readonly<Comment>> {
if (!this.archive) {
throw new Error(
Expand Down
16 changes: 16 additions & 0 deletions server/src/core/server/graph/mutators/Comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { hasTag } from "coral-server/models/comment";
import { addTag, removeTag } from "coral-server/services/comments";
import {
createDontAgree,
createDSAReport,
createFlag,
createReaction,
removeDontAgree,
Expand All @@ -28,6 +29,7 @@ import {
GQLCreateCommentInput,
GQLCreateCommentReactionInput,
GQLCreateCommentReplyInput,
GQLCreateDSAReportInput,
GQLEditCommentInput,
GQLFeatureCommentInput,
GQLMarkCommentsAsSeenInput,
Expand Down Expand Up @@ -206,6 +208,20 @@ export const Comments = (ctx: GraphContext) => ({
ctx.now,
ctx.req
),
createDSAReport: ({
commentID,
userID,
lawBrokenDescription,
additionalInformation,
submissionID,
}: GQLCreateDSAReportInput) =>
createDSAReport(ctx.mongo, ctx.tenant, {
commentID,
userID,
lawBrokenDescription,
additionalInformation,
submissionID,
}),
feature: async ({
commentID,
commentRevisionID,
Expand Down
4 changes: 4 additions & 0 deletions server/src/core/server/graph/resolvers/Mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export const Mutation: Required<GQLMutationTypeResolver<void>> = {
comment: await ctx.mutators.Comments.createFlag(input),
clientMutationId: input.clientMutationId,
}),
createDSAReport: async (source, { input }, ctx) => ({
dsaReport: await ctx.mutators.Comments.createDSAReport(input),
clientMutationId: input.clientMutationId,
}),
featureComment: async (
source,
{ input: { clientMutationId, ...input } },
Expand Down
Loading

0 comments on commit 4aaa508

Please sign in to comment.