Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methodOfRedress to DSA tenant settings #4395

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { graphql } from "react-relay";

import { FieldSet, FormField, HelperText, Label } from "coral-ui/components/v2";

import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import ConfigBoxWithToggleField from "../Auth/ConfigBoxWithToggleField";
import OnOffField from "../../OnOffField";
import DSAMethodOfRedressOptions from "./DSAMethodOfRedressOptions";

// eslint-disable-next-line no-unused-expressions
graphql`
fragment DSAConfigContainer_formValues on Settings {
dsa {
enabled
methodOfRedress
}
}
`;
Expand All @@ -20,17 +25,37 @@ interface Props {

export const DSAConfigContainer: FunctionComponent<Props> = ({ disabled }) => {
return (
<ConfigBoxWithToggleField
<ConfigBox
data-testid="configure-general-dsaConfig"
title={
<Localized id="configure-general-dsaConfig-title">
<Header container="h2">DSA Features (TODO)</Header>
<Header container="h2">Digital services act</Header>
</Localized>
}
name="dsa.enabled"
disabled={disabled}
>
{(disabledInside) => <>TODO</>}
</ConfigBoxWithToggleField>
<FormField container={<FieldSet />}>
<Localized id="configure-general-dsaConfig-reportingAndModerationExperience">
<Label component="legend">
DSA reporting and moderation experience
</Label>
</Localized>
<OnOffField name="dsa.enabled" disabled={disabled} />
</FormField>

<FormField container={<FieldSet />}>
<Localized id="configure-general-dsaConfig-methodOfRedress">
<Label component="legend">Select your method of redress</Label>
</Localized>
<Localized id="configure-general-dsaConfig-methodOfRedress-explanation">
<HelperText>
Let users know if and how they can appeal a moderation decision
</HelperText>
</Localized>
<DSAMethodOfRedressOptions
name="dsa.methodOfRedress"
disabled={disabled}
/>
</FormField>
</ConfigBox>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";

import { Validator } from "coral-framework/lib/validation";
import { RadioButton } from "coral-ui/components/v2";

interface Props {
validate?: Validator;
name: string;
disabled: boolean;
format?: (value: any, name: string) => any;
testIDs?: {
on: string;
off: string;
};
className?: string;
}

export enum DSAMethodOfRedress {
None = "NONE",
Email = "EMAIL",
URL = "URL",
}

export const parseVal = (v: any, name: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this parseVal and format? Seems like it works fine without them?

Copy link
Contributor Author

@nick-funk nick-funk Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it wasn't working for me without them, but I can try again

if (v === DSAMethodOfRedress.None) {
return DSAMethodOfRedress.None;
}
if (v === DSAMethodOfRedress.Email) {
return DSAMethodOfRedress.Email;
}
if (v === DSAMethodOfRedress.URL) {
return DSAMethodOfRedress.URL;
}

return DSAMethodOfRedress.None;
};

export const format = (v: string, name: string) => {
return v;
};

const DSAMethodOfRedressOptions: FunctionComponent<Props> = ({
name,
disabled,
className,
}) => (
<div className={className}>
<Field
name={name}
type="radio"
value={DSAMethodOfRedress.None}
parse={parseVal}
format={format}
>
{({ input }) => (
<RadioButton {...input} id={`${input.name}-none`} disabled={disabled}>
<Localized id="configure-general-dsaConfig-methodOfRedress-none">
<span>None</span>
</Localized>
</RadioButton>
)}
</Field>
<Field
name={name}
type="radio"
value={DSAMethodOfRedress.Email}
parse={parseVal}
format={format}
>
{({ input }) => (
<RadioButton {...input} id={`${input.name}-email`} disabled={disabled}>
<Localized id="configure-general-dsaConfig-methodOfRedress-email">
<span>Email</span>
</Localized>
</RadioButton>
)}
</Field>
<Field
name={name}
type="radio"
parse={parseVal}
value={DSAMethodOfRedress.URL}
format={format}
>
{({ input }) => {
return (
<RadioButton {...input} id={`${input.name}-url`} disabled={disabled}>
<Localized id="configure-general-dsaConfig-methodOfRedress-url">
<span>URL</span>
</Localized>
</RadioButton>
);
}}
</Field>
</div>
);

export default DSAMethodOfRedressOptions;
2 changes: 2 additions & 0 deletions client/src/core/client/admin/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
GQLCOMMENT_STATUS,
GQLCommentModerationAction,
GQLCommentsConnection,
GQLDSA_METHOD_OF_REDRESS,
GQLDSAReport,
GQLDSAReportDecisionLegality,
GQLDSAReportStatus,
Expand Down Expand Up @@ -235,6 +236,7 @@ export const settings = createFixture<GQLSettings>({
},
dsa: {
enabled: false,
methodOfRedress: GQLDSA_METHOD_OF_REDRESS.NONE,
},
});

Expand Down
11 changes: 10 additions & 1 deletion locales/en-US/admin.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -1612,7 +1612,16 @@ configure-general-rte-spoilerDesc =
Words and phrases formatted as Spoiler are hidden behind a
dark background until the reader chooses to reveal the text.

configure-general-dsaConfig-title = DSA Features (TODO)
configure-general-dsaConfig-title = Digital services act
configure-general-dsaConfig-reportingAndModerationExperience =
DSA reporting and moderation experience
configure-general-dsaConfig-methodOfRedress =
Select your method of redress
configure-general-dsaConfig-methodOfRedress-explanation =
Let users know if and how they can appeal a moderation decision
configure-general-dsaConfig-methodOfRedress-none = None
configure-general-dsaConfig-methodOfRedress-email = Email
configure-general-dsaConfig-methodOfRedress-url = URL

configure-account-features-title = Commenter account management features
configure-account-features-explanation =
Expand Down
9 changes: 8 additions & 1 deletion server/src/core/server/graph/resolvers/DSAConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import * as settings from "coral-server/models/settings";

import { GQLDSAConfigurationTypeResolver } from "coral-server/graph/schema/__generated__/types";
import {
GQLDSA_METHOD_OF_REDRESS,
GQLDSAConfigurationTypeResolver,
} from "coral-server/graph/schema/__generated__/types";

export const DSAConfiguration: GQLDSAConfigurationTypeResolver<settings.RTEConfiguration> =
{
enabled: (config, args, { tenant }) =>
tenant.dsa && tenant.dsa.enabled ? tenant.dsa.enabled : false,
methodOfRedress: (config, args, { tenant }) =>
tenant.dsa && tenant.dsa.methodOfRedress
? tenant.dsa.methodOfRedress
: GQLDSA_METHOD_OF_REDRESS.NONE,
};
22 changes: 22 additions & 0 deletions server/src/core/server/graph/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1948,12 +1948,24 @@ type RTEConfiguration {
sarcasm: Boolean!
}

enum DSA_METHOD_OF_REDRESS {
NONE
EMAIL
URL
}

type DSAConfiguration {
"""
enabled when true turns on the European Union DSA compliance
features for commenting, reporting, and moderation flows.
"""
enabled: Boolean!

"""
methodOfRedress lets users know if and how they can appeal a
moderation decision
"""
methodOfRedress: DSA_METHOD_OF_REDRESS!
}

"""
Expand Down Expand Up @@ -6053,7 +6065,17 @@ DSAConfigurationInput specifies the configuration for DSA European Union
moderation and reporting features.
"""
input DSAConfigurationInput {
"""
enabled when true turns on the European Union DSA compliance
features for commenting, reporting, and moderation flows.
"""
enabled: Boolean

"""
methodOfRedress lets users know if and how they can appeal a
moderation decision
"""
methodOfRedress: DSA_METHOD_OF_REDRESS
}

"""
Expand Down
2 changes: 2 additions & 0 deletions server/src/core/server/models/tenant/tenant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { dotize } from "coral-server/utils/dotize";

import {
GQLAnnouncement,
GQLDSA_METHOD_OF_REDRESS,
GQLFEATURE_FLAG,
GQLMODERATION_MODE,
GQLSettings,
Expand Down Expand Up @@ -301,6 +302,7 @@ export async function createTenant(
},
dsa: {
enabled: false,
methodOfRedress: GQLDSA_METHOD_OF_REDRESS.NONE,
},
};

Expand Down
2 changes: 2 additions & 0 deletions server/src/core/server/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Token, User } from "coral-server/models/user";
import {
GQLCOMMENT_STATUS,
GQLDIGEST_FREQUENCY,
GQLDSA_METHOD_OF_REDRESS,
GQLMODERATION_MODE,
GQLUSER_ROLE,
} from "coral-server/graph/schema/__generated__/types";
Expand Down Expand Up @@ -186,6 +187,7 @@ export const createTenantFixture = (
emailDomainModeration: [],
dsa: {
enabled: false,
methodOfRedress: GQLDSA_METHOD_OF_REDRESS.NONE,
},
embeddedComments: {
allowReplies: true,
Expand Down