Skip to content

Commit

Permalink
Merge pull request #4366 from coralproject/feat/add-dsareports-initial
Browse files Browse the repository at this point in the history
Add DSAReport schema, mutation, model to DSA launch pad
  • Loading branch information
kabeaty authored Oct 13, 2023
2 parents a04a2f9 + 8457204 commit 60c91e9
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 1 deletion.
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/report";
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
21 changes: 21 additions & 0 deletions server/src/core/server/graph/mutators/DSAReports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import GraphContext from "coral-server/graph/context";
import { createDSAReport } from "coral-server/services/dsaReports/reports";

import { GQLCreateDSAReportInput } from "coral-server/graph/schema/__generated__/types";

export const DSAReports = (ctx: GraphContext) => ({
createDSAReport: ({
commentID,
userID,
lawBrokenDescription,
additionalInformation,
submissionID,
}: GQLCreateDSAReportInput) =>
createDSAReport(ctx.mongo, ctx.tenant, {
commentID,
userID,
lawBrokenDescription,
additionalInformation,
submissionID,
}),
});
2 changes: 2 additions & 0 deletions server/src/core/server/graph/mutators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import GraphContext from "coral-server/graph/context";

import { Actions } from "./Actions";
import { Comments } from "./Comments";
import { DSAReports } from "./DSAReports";
import { Redis } from "./Redis";
import { Settings } from "./Settings";
import { Sites } from "./Sites";
Expand All @@ -11,6 +12,7 @@ import { Users } from "./Users";
const root = (ctx: GraphContext) => ({
Actions: Actions(ctx),
Comments: Comments(ctx),
DSAReports: DSAReports(ctx),
Settings: Settings(ctx),
Stories: Stories(ctx),
Users: Users(ctx),
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.DSAReports.createDSAReport(input),
clientMutationId: input.clientMutationId,
}),
featureComment: async (
source,
{ input: { clientMutationId, ...input } },
Expand Down
120 changes: 119 additions & 1 deletion server/src/core/server/graph/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,6 @@ type BadgeConfiguration {
FlairBadgeConfiguration specifies the configuration for flair badges, including
whether they are enabled and any configured image urls.
"""

type FlairBadge {
name: String!
url: String!
Expand Down Expand Up @@ -3333,6 +3332,74 @@ type CommentModerationActionConnection {
pageInfo: PageInfo!
}

"""
DSAReportStatus keeps track of where a DSAReport is in the process of being reviewed
"""
enum DSAReportStatus {
AWAITING_REVIEW
UNDER_REVIEW
COMPLETED
}

"""
DSAReportDecision keeps track of whether a DSAReport was determined illegal or not
"""
enum DSAReportDecision {
LEGAL
ILLEGAL
}

type DSAReport {
id: ID!

"""
publicID is a reference ID to keep track of the DSAReport
"""
publicID: String!

"""
submissionID keeps track of comments that were submitted together in one form
"""
submissionID: String!

"""
user who submitted the DSAReport
"""
createdBy: User!

"""
commentID of the comment reported
"""
commentID: String!

"""
createdAt is when the DSAReport was created
"""
createdAt: Time!

"""
status of DSAReport
"""
status: DSAReportStatus

"""
lawBrokenDescription is the text entered by the submitting user to describe
which law is broken by the reported comment
"""
lawBrokenDescription: String!

"""
additionalInformation is more explanation entereted by the submitting user to
describe how the comment breaks the law
"""
additionalInformation: String!

"""
decision is the determination of whether the reported comment is illegal or not
"""
decision: DSAReportDecision
}

type CommentRevisionPerspectiveMetadata {
"""
score is the value detected from the perspective API. This is returned as the
Expand Down Expand Up @@ -6051,6 +6118,52 @@ type CreateCommentFlagPayload {
clientMutationId: String!
}

input CreateDSAReportInput {
"""
id of the reported comment
"""
commentID: ID!

"""
id of the user who submitted the DSAReport
"""
userID: ID!

"""
lawBrokenDescription is the text entered by the submitting user to describe
which law is broken by the reported comment
"""
lawBrokenDescription: String!

"""
additionalInformation is more explanation entereted by the submitting user to
describe how the comment breaks the law
"""
additionalInformation: String!

"""
submissionID keeps track of comments that were submitted together in one form
"""
submissionID: ID

"""
clientMutationId is required for Relay support.
"""
clientMutationId: String!
}

type CreateDSAReportPayload {
"""
dsaReport is the report that was newly created
"""
dsaReport: DSAReport

"""
clientMutationId is required for Relay support.
"""
clientMutationId: String!
}

##################
## createStory
##################
Expand Down Expand Up @@ -9768,6 +9881,11 @@ type Mutation {
flushRedis flushes the redis instance.
"""
flushRedis(input: FlushRedisInput!): FlushRedisPayload! @auth(roles: [ADMIN])

"""
createDSAReport creates a DSAReport for the provided comment
"""
createDSAReport(input: CreateDSAReportInput!): CreateDSAReportPayload!
}

##################
Expand Down
100 changes: 100 additions & 0 deletions server/src/core/server/models/dsaReport/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { v4 as uuid } from "uuid";

import { Sub } from "coral-common/common/lib/types";
import { MongoContext } from "coral-server/data/context";
import { FilterQuery } from "coral-server/models/helpers";
import { TenantResource } from "coral-server/models/tenant";

import { GQLDSAReportStatus } from "coral-server/graph/schema/__generated__/types";

export interface DSAReport extends TenantResource {
readonly id: string;

userID: string;

createdAt: Date;

lawBrokenDescription: string;

additionalInformation: string;

commentID: string;

submissionID?: string;

publicID: string;

status: GQLDSAReportStatus;
}

export type CreateDSAReportInput = Omit<
DSAReport,
"id" | "tenantID" | "createdAt" | "publicID" | "status"
>;

export interface CreateDSAReportResultObject {
/**
* dsaReport contains the resultant DSAReport that was created.
*/
dsaReport: DSAReport;
}

export async function createDSAReport(
mongo: MongoContext,
tenantID: string,
input: CreateDSAReportInput,
now = new Date()
): Promise<CreateDSAReportResultObject> {
const { userID, commentID, submissionID } = input;

// Create a new ID for the DSAReport.
const id = uuid();
let submissionIDToUse = submissionID;
if (!submissionIDToUse) {
submissionIDToUse = uuid();
}

// TODO: update how publicID generated
const publicID = uuid();

// defaults are the properties set by the application when a new DSAReport is
// created.
const defaults: Sub<DSAReport, CreateDSAReportInput> = {
id,
tenantID,
createdAt: now,
publicID,
status: GQLDSAReportStatus.AWAITING_REVIEW,
};

// Extract the filter parameters.
const filter: FilterQuery<DSAReport> = {
tenantID,
commentID,
userID,
};

// Merge the defaults with the input.
const report: Readonly<DSAReport> = {
...defaults,
...input,
submissionID: submissionIDToUse,
};

// check if there's already a dsareport submitted by this user for this comment
// and return a duplicate error if so
const alreadyExisting = await mongo.dsaReports().findOne(filter);

if (alreadyExisting) {
// TODO: update error thrown
throw new Error(
"dsa report submitted by user for this comment already exists"
);
}

await mongo.dsaReports().insertOne(report);

return {
dsaReport: report,
};
}
22 changes: 22 additions & 0 deletions server/src/core/server/services/dsaReports/reports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MongoContext } from "coral-server/data/context";
import { createDSAReport as createReport } from "coral-server/models/dsaReport/report";
import { Tenant } from "coral-server/models/tenant";

export interface CreateDSAReportInput {
commentID: string;
userID: string;
lawBrokenDescription: string;
additionalInformation: string;
submissionID?: string;
}

export async function createDSAReport(
mongo: MongoContext,
tenant: Tenant,
input: CreateDSAReportInput,
now = new Date()
) {
const result = await createReport(mongo, tenant.id, input, now);
const { dsaReport } = result;
return dsaReport;
}

0 comments on commit 60c91e9

Please sign in to comment.