mirror of
https://github.com/wassname/talk.git
synced 2026-08-13 12:40:11 +08:00
[CORL-845] Account Linking (#2818)
* feat: added new linking backend * feat: added duplicateEmail to hash * fix: stored the duplicate email on the user * feat: initial implmentation of account linking in auth * test: fix unit tests * fix+test: translations and tests added * chore+test: rename view to LINK_ACCOUNT + more tests * feat+test: account linking admin + more tests * feat: Handle incomplete accounts * chore: add some comments * feat: expose duplicateEmail through graphql and impl for stream * feat: admin to use duplicateEmail from graphql * fix: no need to validate password for account linking * fix: dont validate password * fix: no need to render error message when account was incomplete * chore: log to console when encountering incomplete account * chore: adjust comment * chore: simplify + add comments * chore: wording * chore: comments Co-authored-by: Vinh <vinh@vinh.tech> Co-authored-by: Kim Gardner <kgardnr@gmail.com>
This commit is contained in:
co-authored by
Vinh
Kim Gardner
parent
7497e33046
commit
dcb2a10e72
@@ -0,0 +1,34 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { ERROR_CODES } from "coral-common/errors";
|
||||
import { InvalidRequestError } from "coral-framework/lib/errors";
|
||||
import { useMutation } from "coral-framework/lib/relay";
|
||||
import { SignOutMutation } from "coral-stream/mutations";
|
||||
|
||||
/**
|
||||
* useHandleIncompleteAccount logs out a user when it
|
||||
* encounters a `USER_NOT_ENTITLED` during a query. It accepts
|
||||
* `data` from a `QueryRenderer`. Should only be used on Queries
|
||||
* that normally does not fail except when the account
|
||||
* is incomplete. Returns `true` if account was incomplete.
|
||||
*/
|
||||
const useHandleIncompleteAccount = () => {
|
||||
const signOut = useMutation(SignOutMutation);
|
||||
return useCallback(
|
||||
(data: { error: Error | null }) => {
|
||||
if (
|
||||
data.error instanceof InvalidRequestError &&
|
||||
data.error.code === ERROR_CODES.USER_NOT_ENTITLED
|
||||
) {
|
||||
// eslint-disable-next-line
|
||||
console.log("Coral: User account is incomplete. Perform logout.")
|
||||
signOut();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[signOut]
|
||||
);
|
||||
};
|
||||
|
||||
export default useHandleIncompleteAccount;
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
withLocalStateContainer,
|
||||
} from "coral-framework/lib/relay";
|
||||
import Spinner from "coral-stream/common/Spinner";
|
||||
import useHandleIncompleteAccount from "coral-stream/common/useHandleIncompleteAccount";
|
||||
import { Delay } from "coral-ui/components";
|
||||
|
||||
import { PermalinkViewQuery as QueryTypes } from "coral-stream/__generated__/PermalinkViewQuery.graphql";
|
||||
@@ -50,6 +51,7 @@ export const render = ({ error, props }: QueryRenderData<QueryTypes>) => {
|
||||
const PermalinkViewQuery: FunctionComponent<Props> = ({
|
||||
local: { commentID, storyID, storyURL },
|
||||
}) => {
|
||||
const handleIncompleteAccount = useHandleIncompleteAccount();
|
||||
return (
|
||||
<QueryRenderer<QueryTypes>
|
||||
query={graphql`
|
||||
@@ -77,7 +79,12 @@ const PermalinkViewQuery: FunctionComponent<Props> = ({
|
||||
storyID,
|
||||
storyURL,
|
||||
}}
|
||||
render={render}
|
||||
render={data => {
|
||||
if (handleIncompleteAccount(data)) {
|
||||
return null;
|
||||
}
|
||||
return render(data);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
withLocalStateContainer,
|
||||
} from "coral-framework/lib/relay";
|
||||
import Spinner from "coral-stream/common/Spinner";
|
||||
import useHandleIncompleteAccount from "coral-stream/common/useHandleIncompleteAccount";
|
||||
import { Delay, Flex } from "coral-ui/components";
|
||||
|
||||
import { COMMENTS_TAB } from "coral-stream/__generated__/StreamContainerLocal.graphql";
|
||||
@@ -67,6 +68,7 @@ const StreamQuery: FunctionComponent<Props> = props => {
|
||||
const {
|
||||
local: { storyID, storyURL, commentsTab },
|
||||
} = props;
|
||||
const handleIncompleteAccount = useHandleIncompleteAccount();
|
||||
return (
|
||||
<>
|
||||
<QueryRenderer<QueryTypes>
|
||||
@@ -88,6 +90,9 @@ const StreamQuery: FunctionComponent<Props> = props => {
|
||||
storyURL,
|
||||
}}
|
||||
render={data => {
|
||||
if (handleIncompleteAccount(data)) {
|
||||
return null;
|
||||
}
|
||||
return render(data, commentsTab);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
withLocalStateContainer,
|
||||
} from "coral-framework/lib/relay";
|
||||
import Spinner from "coral-stream/common/Spinner";
|
||||
import useHandleIncompleteAccount from "coral-stream/common/useHandleIncompleteAccount";
|
||||
import { CallOut, Delay } from "coral-ui/components";
|
||||
|
||||
import { ProfileQuery as QueryTypes } from "coral-stream/__generated__/ProfileQuery.graphql";
|
||||
@@ -79,28 +80,36 @@ export const render = ({ error, props }: QueryRenderData<QueryTypes>) => {
|
||||
|
||||
const ProfileQuery: FunctionComponent<Props> = ({
|
||||
local: { storyID, storyURL },
|
||||
}) => (
|
||||
<QueryRenderer<QueryTypes>
|
||||
query={graphql`
|
||||
query ProfileQuery($storyID: ID, $storyURL: String) {
|
||||
story: stream(id: $storyID, url: $storyURL) {
|
||||
...ProfileContainer_story
|
||||
}) => {
|
||||
const handleIncompleteAccount = useHandleIncompleteAccount();
|
||||
return (
|
||||
<QueryRenderer<QueryTypes>
|
||||
query={graphql`
|
||||
query ProfileQuery($storyID: ID, $storyURL: String) {
|
||||
story: stream(id: $storyID, url: $storyURL) {
|
||||
...ProfileContainer_story
|
||||
}
|
||||
viewer {
|
||||
...ProfileContainer_viewer
|
||||
}
|
||||
settings {
|
||||
...ProfileContainer_settings
|
||||
}
|
||||
}
|
||||
viewer {
|
||||
...ProfileContainer_viewer
|
||||
`}
|
||||
variables={{
|
||||
storyID,
|
||||
storyURL,
|
||||
}}
|
||||
render={data => {
|
||||
if (handleIncompleteAccount(data)) {
|
||||
return null;
|
||||
}
|
||||
settings {
|
||||
...ProfileContainer_settings
|
||||
}
|
||||
}
|
||||
`}
|
||||
variables={{
|
||||
storyID,
|
||||
storyURL,
|
||||
}}
|
||||
render={render}
|
||||
/>
|
||||
);
|
||||
return render(data);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const enhanced = withLocalStateContainer(
|
||||
graphql`
|
||||
|
||||
@@ -89,6 +89,9 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
it("renders permalink view", async () => {
|
||||
// axe checking takes a bit of time.
|
||||
jest.setTimeout(10000);
|
||||
|
||||
const tabPane = await waitForElement(() =>
|
||||
within(testRenderer.root).getByTestID("current-tab-pane")
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user