Skip to content

Commit

Permalink
notify reporting users of the decisions made on DSA reports
Browse files Browse the repository at this point in the history
  • Loading branch information
nick-funk committed Nov 10, 2023
1 parent 766a332 commit 7621a52
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 11 deletions.
3 changes: 2 additions & 1 deletion server/src/core/server/graph/mutators/DSAReports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const DSAReports = (ctx: GraphContext) => ({
reportID,
}: GQLChangeDSAReportStatusInput) =>
changeDSAReportStatus(ctx.mongo, ctx.tenant, { userID, status, reportID }),
makeDSAReportDecision: ({
makeDSAReportDecision: async ({
userID,
legality,
legalGrounds,
Expand All @@ -78,6 +78,7 @@ export const DSAReports = (ctx: GraphContext) => ({
ctx.broker,
ctx.notifications,
ctx.tenant,
await ctx.loaders.Comments.comment.load(commentID),
{
userID,
legality,
Expand Down
18 changes: 18 additions & 0 deletions server/src/core/server/locales/en-US/common.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ notifications-commentWasApproved-title = Comment was approved
notifications-commentWasApproved-body = The comment { $commentID } was approved.
notifications-commentWasRejected-title = Comment was rejected
notifications-commentWasRejected-body = The comment { $commentID } was rejected.
notifications-commentWasRejectedAndIllegal-title = Comment was deemed to contain illegal content and was rejected
notifications-commentWasRejectedAndIllegal-body =
The comment { $commentID } was rejected for containing illegal content.
Expand All @@ -61,3 +62,20 @@ notifications-dsaIllegalRejectedReason-information =
<br/>
{ $explanation }
notifications-dsaIllegalRejectedReason-informationNotFound = The reasoning for this decision cannot be found.
notifications-dsaReportDecisionMade-title = A decision was made on your DSA report
notifications-dsaReportDecision-legal = The report { $reportID } was determined to be legal.
notifications-dsaReportDecision-illegal = The report { $reportID } was determined to be illegal.
notifications-dsaReportDecision-legalInformation =
Grounds:
<br/>
{ $grounds }
<br/>
Explanation:
<br/>
{ $explanation }
notifications-dsaReportDecisionMade-body-withoutInfo = { $decision }
notifications-dsaReportDecisionMade-body-withInfo =
{ $decision }
<br/>
{ $information }
28 changes: 24 additions & 4 deletions server/src/core/server/services/dsaReports/reports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Config } from "coral-server/config";
import { DataCache } from "coral-server/data/cache/dataCache";
import { MongoContext } from "coral-server/data/context";
import { CoralEventPublisherBroker } from "coral-server/events/publisher";
import { Comment } from "coral-server/models/comment";
import {
changeDSAReportStatus as changeReportStatus,
createDSAReport as createReport,
createDSAReportNote as createReportNote,
createDSAReportShare as createReportShare,
deleteDSAReportNote as deleteReportNote,
makeDSAReportDecision as makeReportDecision,
retrieveDSAReport,
} from "coral-server/models/dsaReport/report";
import { Tenant } from "coral-server/models/tenant";
import { rejectComment } from "coral-server/stacks";
Expand Down Expand Up @@ -180,6 +182,7 @@ export async function makeDSAReportDecision(
broker: CoralEventPublisherBroker,
notifications: InternalNotificationContext,
tenant: Tenant,
comment: Readonly<Comment> | null,
input: MakeDSAReportDecisionInput,
now = new Date()
) {
Expand All @@ -190,11 +193,12 @@ export async function makeDSAReportDecision(
userID,
legalGrounds,
detailedExplanation,
reportID,
} = input;

// REJECT if ILLEGAL
if (input.legality === GQLDSAReportDecisionLegality.ILLEGAL) {
const comment = await rejectComment(
const rejectedComment = await rejectComment(
mongo,
redis,
cache,
Expand All @@ -210,19 +214,35 @@ export async function makeDSAReportDecision(
false
);

if (comment.authorID) {
if (rejectedComment.authorID) {
await notifications.create(tenant.id, tenant.locale, {
targetUserID: comment.authorID,
targetUserID: rejectedComment.authorID,
type: NotificationType.ILLEGAL_REJECTED,
comment,
comment: rejectedComment,
legal: {
legality: input.legality,
grounds: legalGrounds,
explanation: detailedExplanation,
},
});
}
}

const report = await retrieveDSAReport(mongo, tenant.id, reportID);
if (report) {
await notifications.create(tenant.id, tenant.locale, {
targetUserID: report.userID,
type: NotificationType.DSA_REPORT_DECISION_MADE,
comment,
report,
legal: {
legality: input.legality,
grounds: legalGrounds,
explanation: detailedExplanation,
},
});
}

const result = await makeReportDecision(mongo, tenant.id, input, now);

const { dsaReport } = result;
Expand Down
125 changes: 119 additions & 6 deletions server/src/core/server/services/notifications/internal/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ import {
import { retrieveUser } from "coral-server/models/user";
import { I18n, translate } from "coral-server/services/i18n";

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

export enum NotificationType {
COMMENT_FEATURED = "COMMENT_FEATURED",
COMMENT_APPROVED = "COMMENT_APPROVED",
COMMENT_REJECTED = "COMMENT_REJECTED",
ILLEGAL_REJECTED = "ILLEGAL_REJECTED",
DSA_REPORT_DECISION_MADE = "DSA_REPORT_DECISION_MADE",
}

export interface LegalExplanation {
export interface Legality {
legality: GQLDSAReportDecisionLegality;
grounds?: string;
explanation?: string;
}
Expand All @@ -28,10 +32,10 @@ export interface CreateNotificationInput {
targetUserID: string;
type: NotificationType;

comment?: Readonly<Comment>;
report?: Readonly<DSAReport>;
comment?: Readonly<Comment> | null;
report?: Readonly<DSAReport> | null;

legal?: LegalExplanation;
legal?: Legality;
}

interface CreationResult {
Expand All @@ -55,7 +59,7 @@ export class InternalNotificationContext {
lang: LanguageCode,
input: CreateNotificationInput
) {
const { type, targetUserID, comment, legal } = input;
const { type, targetUserID, comment, report, legal } = input;

const existingUser = retrieveUser(this.mongo, tenantID, targetUserID);
if (!existingUser) {
Expand Down Expand Up @@ -152,6 +156,21 @@ export class InternalNotificationContext {
now
);
result.attempted = true;
} else if (
type === NotificationType.DSA_REPORT_DECISION_MADE &&
comment &&
report
) {
result.notification = await this.createDSAReportDecisionMadeNotification(
lang,
tenantID,
targetUserID,
comment,
report,
legal,
now
);
result.attempted = true;
}

if (!result.notification && result.attempted) {
Expand All @@ -164,7 +183,7 @@ export class InternalNotificationContext {
tenantID: string,
targetUserID: string,
comment: Readonly<Comment>,
legal: LegalExplanation | undefined,
legal: Legality | undefined,
now: Date
) {
const reason = legal
Expand Down Expand Up @@ -216,6 +235,100 @@ export class InternalNotificationContext {
return notification;
}

private async createDSAReportDecisionMadeNotification(
lang: LanguageCode,
tenantID: string,
targetUserID: string,
comment: Readonly<Comment>,
report: Readonly<DSAReport>,
legal: Legality | undefined,
now: Date
) {
if (!legal) {
this.log.warn(
{ reportID: report.id, commentID: comment.id, targetUserID },
"attempted to notify of DSA report decision when legality was null or undefined"
);
return null;
}

let decision = "";
let information: string | null = null;
if (legal.legality === GQLDSAReportDecisionLegality.LEGAL) {
decision = this.translatePhrase(
lang,
"notifications-dsaReportDecision-legal",
`The report ${report.id} was determined to be legal.`,
{
reportID: report.id,
}
);
}
if (legal.legality === GQLDSAReportDecisionLegality.ILLEGAL) {
decision = this.translatePhrase(
lang,
"notifications-dsaReportDecision-illegal",
`The report ${report.id} was determined to be illegal.`,
{
reportID: report.id,
}
);
information = this.translatePhrase(
lang,
"notifications-dsaReportDecision-legalInformation",
`Grounds:
<br/>
${legal.grounds}
<br/>
Explanation:
<br/>
${legal.explanation}`,
{
grounds: legal.grounds,
explanation: legal.explanation,
}
);
}

const body = this.translatePhrase(
lang,
information
? "notifications-dsaReportDecisionMade-body-withInfo"
: "notifications-dsaReportDecisionMade-body-withoutInfo",
information
? `${decision}
<br/>
${information}`
: `${decision}`,
information
? {
decision,
information,
}
: {
decision,
}
).replace("\n", "<br/>");

const notification = await createNotification(this.mongo, {
id: uuid(),
tenantID,
createdAt: now,
ownerID: targetUserID,
title: this.translatePhrase(
lang,
"notifications-dsaReportDecisionMade-title",
"A decision was made on your DSA report"
),
body,
commentID: comment.id,
commentStatus: comment.status,
reportID: report.id,
});

return notification;
}

private translatePhrase(
lang: LanguageCode,
key: string,
Expand Down

0 comments on commit 7621a52

Please sign in to comment.