[CORL 133] API Review (#2197)

* refactor: removed unused subscription code

* refactor: removed management api's

* refactor: cleanup of connections

* refactor: refactored comments edge

* refactor: simplified connection resolving

* feat: added story connection edge

* fix: added story index

* feat: added user pagination and user edge

* fix: added filter to comment query

* fix: removed unused resolvers

* fix: creating a comment reply should require auth

* refactor: cleanup of graph files

* feat: removed display name, made username non-unique

* fix: fixed tests

* fix: fixed tests

* fix: added more api docs

* fix: fixed bug with installer

* refactor: fixes and updates

* fix: added linting for graphql, fixed schema

* feat: added docker build tests

* fix: upped output timeout

* fix: fixed stacktraces in production builds

* fix: removed `git add`

- `git add` was causing issues with
    partial staged changs on files

* feat: improved error messaging for auth

* refactor: cleaned up queue names

* fix: merge error
This commit is contained in:
Wyatt Johnson
2019-03-12 15:12:21 +01:00
committed by Kiwi
parent 37959f9398
commit d37333be89
125 changed files with 1269 additions and 1536 deletions
@@ -9,7 +9,7 @@ export default function getQueueConnection(
const root = store.getRoot();
if (queue === "rejected") {
return ConnectionHandler.getConnection(root, "RejectedQueue_comments", {
filter: { status: "REJECTED" },
status: "REJECTED",
});
}
const queuesRecord = root.getLinkedRecord("moderationQueues")!;
@@ -3,13 +3,11 @@ import React, { StatelessComponent } from "react";
import { PropTypesOf } from "talk-framework/types";
import { HorizontalGutter } from "talk-ui/components";
import DisplayNamesConfigContainer from "../containers/DisplayNamesConfigContainer";
import AuthIntegrationsConfig from "./AuthIntegrationsConfig";
interface Props {
disabled?: boolean;
auth: PropTypesOf<typeof AuthIntegrationsConfig>["auth"] &
PropTypesOf<typeof DisplayNamesConfigContainer>["auth"];
auth: PropTypesOf<typeof AuthIntegrationsConfig>["auth"];
onInitValues: (values: any) => void;
}
@@ -19,11 +17,6 @@ const AuthConfig: StatelessComponent<Props> = ({
onInitValues,
}) => (
<HorizontalGutter size="double" data-testid="configure-authContainer">
<DisplayNamesConfigContainer
disabled={disabled}
auth={auth}
onInitValues={onInitValues}
/>
<AuthIntegrationsConfig
disabled={disabled}
auth={auth}
@@ -1,93 +0,0 @@
import { Localized } from "fluent-react/compat";
import React, { StatelessComponent } from "react";
import { Field } from "react-final-form";
import { parseStringBool } from "talk-framework/lib/form";
import {
Flex,
FormField,
HorizontalGutter,
RadioButton,
Typography,
} from "talk-ui/components";
import Header from "../../../components/Header";
interface Props {
disabled?: boolean;
}
const DisplayNamesConfig: StatelessComponent<Props> = ({ disabled }) => (
<HorizontalGutter size="oneAndAHalf">
<Localized id="configure-auth-displayNamesConfig-title">
<Header>Display Names</Header>
</Localized>
<Localized id="configure-auth-displayNamesConfig-explanationShort">
<Typography variant="detail">
Some AUTH integrations include a Display Name as well as a User Name.
</Typography>
</Localized>
<Localized id="configure-auth-displayNamesConfig-explanationLong">
<Typography variant="detail">
A User Name has to be unique (there can only be one Juan_Doe, for
example), whereas a Display Name does not. If your AUTH provider allows
for Display Names, you can enable this option. This allows for fewer
strange names (Juan_Doe23245) however it could also be used to
spoof/impersonate another user.
</Typography>
</Localized>
<FormField>
<Flex direction="row" itemGutter="double">
<Field
name={"auth.displayName.enabled"}
type="radio"
parse={parseStringBool}
value
>
{({ input }) => (
<Localized id="configure-auth-displayNamesConfig-showDisplayNames">
<RadioButton
id={`${input.name}-true`}
name={input.name}
onChange={input.onChange}
onFocus={input.onFocus}
onBlur={input.onBlur}
checked={input.checked}
disabled={disabled}
value={input.value}
>
Show Display Names (if available)
</RadioButton>
</Localized>
)}
</Field>
<Field
name={"auth.displayName.enabled"}
type="radio"
parse={parseStringBool}
value={false}
>
{({ input }) => (
<Localized id="configure-auth-displayNamesConfig-hideDisplayNames">
<RadioButton
id={`${input.name}-false`}
name={input.name}
onChange={input.onChange}
onFocus={input.onFocus}
onBlur={input.onBlur}
checked={input.checked}
disabled={disabled}
value={input.value}
>
Hide Display Names (if available)
</RadioButton>
</Localized>
)}
</Field>
</Flex>
</FormField>
</HorizontalGutter>
);
export default DisplayNamesConfig;
@@ -104,7 +104,6 @@ const enhanced = withFragmentContainer<Props>({
...SSOConfigContainer_auth
...SSOConfigContainer_authReadOnly
...LocalAuthConfigContainer_auth
...DisplayNamesConfigContainer_auth
...OIDCConfigContainer_auth
...OIDCConfigContainer_authReadOnly
}
@@ -1,37 +0,0 @@
import React from "react";
import { graphql } from "react-relay";
import { DisplayNamesConfigContainer_auth as AuthData } from "talk-admin/__generated__/DisplayNamesConfigContainer_auth.graphql";
import { withFragmentContainer } from "talk-framework/lib/relay";
import DisplayNamesConfig from "../components/DisplayNamesConfig";
interface Props {
auth: AuthData;
onInitValues: (values: AuthData) => void;
disabled?: boolean;
}
class DisplayNamesConfigContainer extends React.Component<Props> {
constructor(props: Props) {
super(props);
props.onInitValues(props.auth);
}
public render() {
const { disabled } = this.props;
return <DisplayNamesConfig disabled={disabled} />;
}
}
const enhanced = withFragmentContainer<Props>({
auth: graphql`
fragment DisplayNamesConfigContainer_auth on Auth {
displayName {
enabled
}
}
`,
})(DisplayNamesConfigContainer);
export default enhanced;
@@ -36,8 +36,8 @@ const CreateUsername: StatelessComponent<CreateUsernameForm> = props => {
<HorizontalGutter size="oneAndAHalf">
<Localized id="createUsername-whatItIs">
<Typography variant="bodyCopy">
Your username is a unique identifier that will appear on all
of your comments.
Your username is an identifier that will appear on all of your
comments.
</Typography>
</Localized>
{submitError && (
@@ -79,7 +79,7 @@ const enhanced = (withPaginationContainer<
count: { type: "Int!", defaultValue: 5 }
cursor: { type: "Cursor" }
) {
comments(filter: { status: REJECTED }, first: $count, after: $cursor)
comments(status: REJECTED, first: $count, after: $cursor)
@connection(key: "RejectedQueue_comments") {
edges {
node {
@@ -11,7 +11,7 @@ exports[`accepts valid username 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
@@ -69,7 +69,7 @@ exports[`checks for invalid username 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
@@ -169,7 +169,7 @@ exports[`renders createUsername view 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
@@ -232,7 +232,7 @@ exports[`shows error when submitting empty form 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
@@ -303,7 +303,7 @@ exports[`shows server error 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="CallOut-root CallOut-colorError CallOut-fullWidth"
@@ -373,7 +373,7 @@ exports[`successfully sets username 1`] = `
<p
className="Typography-root Typography-bodyCopy Typography-colorTextPrimary"
>
Your username is a unique identifier that will appear on all of your comments.
Your username is an identifier that will appear on all of your comments.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
@@ -79,7 +79,7 @@ it("sign out when clicking on sign in as", async () => {
const restMock = sinon.mock(context.rest);
restMock
.expects("fetch")
.withArgs("/tenant/auth", {
.withArgs("/auth", {
method: "DELETE",
})
.once()
@@ -99,7 +99,7 @@ it("shows server error", async () => {
const restMock = sinon.mock(context.rest);
restMock
.expects("fetch")
.withArgs("/tenant/auth/local", {
.withArgs("/auth/local", {
method: "POST",
body: {
email: "hans@test.com",
@@ -133,7 +133,7 @@ it("submits form successfully", async () => {
const restMock = sinon.mock(context.rest);
restMock
.expects("fetch")
.withArgs("/tenant/auth/local", {
.withArgs("/auth/local", {
method: "POST",
body: {
email: "hans@test.com",
@@ -40,7 +40,7 @@ it("logs out", async () => {
const restMock = sinon.mock(context.rest);
restMock
.expects("fetch")
.withArgs("/tenant/auth", {
.withArgs("/auth", {
method: "DELETE",
})
.once()
@@ -1853,80 +1853,6 @@ exports[`renders configure auth 1`] = `
className="HorizontalGutter-root HorizontalGutter-double"
data-testid="configure-authContainer"
>
<div
className="HorizontalGutter-root HorizontalGutter-oneAndAHalf"
>
<h1
className="Typography-root Typography-heading1 Typography-colorTextPrimary Header-root"
>
Display Names
</h1>
<p
className="Typography-root Typography-detail Typography-colorTextPrimary"
>
Some Authentication Integrations include a Display Name as well as a User Name.
</p>
<p
className="Typography-root Typography-detail Typography-colorTextPrimary"
>
A User Name has to be unique (there can only be one Juan_Doe, for example),
whereas a Display Name does not. If your authentication provider allows for Display Names,
you can enable this option. This allows for fewer strange names (Juan_Doe23245)
however it could also be used to spoof/impersonate another user.
</p>
<div
className="HorizontalGutter-root FormField-root HorizontalGutter-half"
>
<div
className="Flex-root Flex-flex Flex-doubleItemGutter Flex-directionRow"
>
<div
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
>
<input
checked={false}
className="RadioButton-input"
disabled={false}
id="auth.displayName.enabled-true"
name="auth.displayName.enabled"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={true}
/>
<label
className="RadioButton-label"
htmlFor="auth.displayName.enabled-true"
>
Show Display Names (if available)
</label>
</div>
<div
className="Flex-root RadioButton-root Flex-flex Flex-alignCenter"
>
<input
checked={true}
className="RadioButton-input"
disabled={false}
id="auth.displayName.enabled-false"
name="auth.displayName.enabled"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
type="radio"
value={false}
/>
<label
className="RadioButton-label"
htmlFor="auth.displayName.enabled-false"
>
Hide Display Names (if available)
</label>
</div>
</div>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-double"
>
-6
View File
@@ -35,9 +35,6 @@ export const settings = {
},
},
auth: {
displayName: {
enabled: false,
},
integrations: {
local: {
enabled: true,
@@ -100,9 +97,6 @@ export const settingsWithEmptyAuth = {
...settings,
id: "settings",
auth: {
displayName: {
enabled: false,
},
integrations: {
local: {
enabled: true,
@@ -357,7 +357,7 @@ describe("rejected queue", () => {
const testRenderer = await createTestRenderer({
Query: {
comments: sinon.stub().callsFake((_, data) => {
expect(data).toEqual({ first: 5, filter: { status: "REJECTED" } });
expect(data).toEqual({ first: 5, status: "REJECTED" });
return {
edges: [
{
@@ -390,7 +390,7 @@ describe("rejected queue", () => {
s.onFirstCall().callsFake((_, data) => {
expect(data).toEqual({
first: 5,
filter: { status: "REJECTED" },
status: "REJECTED",
});
return {
edges: [
@@ -414,7 +414,7 @@ describe("rejected queue", () => {
expect(data).toEqual({
first: 10,
after: rejectedComments[1].createdAt,
filter: { status: "REJECTED" },
status: "REJECTED",
});
return {
edges: [
@@ -490,7 +490,7 @@ describe("rejected queue", () => {
const testRenderer = await createTestRenderer({
Query: {
comments: sinon.stub().callsFake((_, data) => {
expect(data).toEqual({ first: 5, filter: { status: "REJECTED" } });
expect(data).toEqual({ first: 5, status: "REJECTED" });
return {
edges: [
{