diff --git a/src/core/client/auth/local/local.graphql b/src/core/client/auth/local/local.graphql index 54c52fb90..04fcade18 100644 --- a/src/core/client/auth/local/local.graphql +++ b/src/core/client/auth/local/local.graphql @@ -6,6 +6,10 @@ enum View { } type Local { + authToken: String + authExp: Int + authJTI: String + loggedIn: Boolean! view: View! } diff --git a/src/core/client/stream/components/UserBoxAuthenticated.spec.tsx b/src/core/client/stream/components/UserBoxAuthenticated.spec.tsx index 5e658f287..cf7ae17f4 100644 --- a/src/core/client/stream/components/UserBoxAuthenticated.spec.tsx +++ b/src/core/client/stream/components/UserBoxAuthenticated.spec.tsx @@ -6,10 +6,21 @@ import { PropTypesOf } from "talk-framework/types"; import UserBoxAuthenticated from "./UserBoxAuthenticated"; -it("renders correctly", () => { +it("renders correctly with logout button", () => { const props: PropTypesOf = { onSignOut: noop, username: "Username", + showLogoutButton: true, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders correctly without logout button", () => { + const props: PropTypesOf = { + onSignOut: noop, + username: "Username", + showLogoutButton: false, }; const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); diff --git a/src/core/client/stream/components/UserBoxAuthenticated.tsx b/src/core/client/stream/components/UserBoxAuthenticated.tsx index 68c7fba00..19c4d5053 100644 --- a/src/core/client/stream/components/UserBoxAuthenticated.tsx +++ b/src/core/client/stream/components/UserBoxAuthenticated.tsx @@ -4,8 +4,9 @@ import React, { StatelessComponent } from "react"; import { Button, Flex, Typography } from "talk-ui/components"; export interface UserBoxAuthenticatedProps { - onSignOut: () => void; + onSignOut?: () => void; username: string; + showLogoutButton?: boolean; } const UserBoxAuthenticated: StatelessComponent< @@ -27,21 +28,23 @@ const UserBoxAuthenticated: StatelessComponent< {"Signed in as ."} - - } - > - - {"Not you? "} - - + {props.showLogoutButton && ( + + } + > + + {"Not you? "} + + + )} ); }; diff --git a/src/core/client/stream/components/UserBoxUnauthenticated.spec.tsx b/src/core/client/stream/components/UserBoxUnauthenticated.spec.tsx index f9683c1e8..2e45eba2e 100644 --- a/src/core/client/stream/components/UserBoxUnauthenticated.spec.tsx +++ b/src/core/client/stream/components/UserBoxUnauthenticated.spec.tsx @@ -10,6 +10,17 @@ it("renders correctly", () => { const props: PropTypesOf = { onSignIn: noop, onRegister: noop, + showRegisterButton: true, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders correctly hides showRegisterButton", () => { + const props: PropTypesOf = { + onSignIn: noop, + onRegister: noop, + showRegisterButton: false, }; const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); diff --git a/src/core/client/stream/components/UserBoxUnauthenticated.tsx b/src/core/client/stream/components/UserBoxUnauthenticated.tsx index 013a10fc7..a7a7dc0ff 100644 --- a/src/core/client/stream/components/UserBoxUnauthenticated.tsx +++ b/src/core/client/stream/components/UserBoxUnauthenticated.tsx @@ -8,7 +8,8 @@ import styles from "./UserBoxUnauthenticated.css"; export interface UserBoxUnauthenticatedProps { onSignIn: () => void; - onRegister: () => void; + onRegister?: () => void; + showRegisterButton?: boolean; } const UserBoxUnauthenticated: StatelessComponent< @@ -40,16 +41,18 @@ const UserBoxUnauthenticated: StatelessComponent< Sign in - - - + {props.showRegisterButton && ( + + + + )} ); }; diff --git a/src/core/client/stream/components/__snapshots__/UserBoxAuthenticated.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/UserBoxAuthenticated.spec.tsx.snap index 0899da755..b0cd3f064 100644 --- a/src/core/client/stream/components/__snapshots__/UserBoxAuthenticated.spec.tsx.snap +++ b/src/core/client/stream/components/__snapshots__/UserBoxAuthenticated.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders correctly 1`] = ` +exports[`renders correctly with logout button 1`] = ` `; + +exports[`renders correctly without logout button 1`] = ` + + } + > + + Signed in as <username></username>. + + + +`; diff --git a/src/core/client/stream/components/__snapshots__/UserBoxUnauthenticated.spec.tsx.snap b/src/core/client/stream/components/__snapshots__/UserBoxUnauthenticated.spec.tsx.snap index 13857622c..c51fcd0e2 100644 --- a/src/core/client/stream/components/__snapshots__/UserBoxUnauthenticated.spec.tsx.snap +++ b/src/core/client/stream/components/__snapshots__/UserBoxUnauthenticated.spec.tsx.snap @@ -52,3 +52,44 @@ exports[`renders correctly 1`] = ` `; + +exports[`renders correctly hides showRegisterButton 1`] = ` + + + + + Join the conversation + + + + | + + + + + Sign in + + + +`; diff --git a/src/core/client/stream/containers/UserBoxContainer.spec.tsx b/src/core/client/stream/containers/UserBoxContainer.spec.tsx index 7439e50b1..2d6d3600a 100644 --- a/src/core/client/stream/containers/UserBoxContainer.spec.tsx +++ b/src/core/client/stream/containers/UserBoxContainer.spec.tsx @@ -9,7 +9,7 @@ import { UserBoxContainer } from "./UserBoxContainer"; // Remove relay refs so we can stub the props. const UserBoxContainerN = removeFragmentRefs(UserBoxContainer); -it("renders correctly", () => { +it("renders fully", () => { const props: PropTypesOf = { local: { authPopup: { @@ -17,8 +17,212 @@ it("renders correctly", () => { focus: false, view: "SIGN_IN", }, + authJTI: "JTI", }, me: null, + settings: { + auth: { + integrations: { + facebook: { + enabled: true, + allowRegistration: true, + }, + google: { + enabled: false, + allowRegistration: true, + }, + sso: { + enabled: false, + allowRegistration: true, + }, + local: { + enabled: true, + allowRegistration: true, + }, + oidc: [], + }, + }, + }, + // tslint:disable-next-line:no-empty + showAuthPopup: async () => {}, + // tslint:disable-next-line:no-empty + setAuthPopupState: async () => {}, + // tslint:disable-next-line:no-empty + signOut: async () => {}, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders without logout button", () => { + const props: PropTypesOf = { + local: { + authPopup: { + open: false, + focus: false, + view: "SIGN_IN", + }, + authJTI: null, + }, + me: null, + settings: { + auth: { + integrations: { + facebook: { + enabled: true, + allowRegistration: true, + }, + google: { + enabled: false, + allowRegistration: true, + }, + sso: { + enabled: false, + allowRegistration: true, + }, + local: { + enabled: true, + allowRegistration: true, + }, + oidc: [], + }, + }, + }, + // tslint:disable-next-line:no-empty + showAuthPopup: async () => {}, + // tslint:disable-next-line:no-empty + setAuthPopupState: async () => {}, + // tslint:disable-next-line:no-empty + signOut: async () => {}, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders sso only", () => { + const props: PropTypesOf = { + local: { + authPopup: { + open: false, + focus: false, + view: "SIGN_IN", + }, + authJTI: "JTI", + }, + me: null, + settings: { + auth: { + integrations: { + facebook: { + enabled: false, + allowRegistration: true, + }, + google: { + enabled: false, + allowRegistration: true, + }, + sso: { + enabled: true, + allowRegistration: true, + }, + local: { + enabled: false, + allowRegistration: true, + }, + oidc: [], + }, + }, + }, + // tslint:disable-next-line:no-empty + showAuthPopup: async () => {}, + // tslint:disable-next-line:no-empty + setAuthPopupState: async () => {}, + // tslint:disable-next-line:no-empty + signOut: async () => {}, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders sso only without logut button", () => { + const props: PropTypesOf = { + local: { + authPopup: { + open: false, + focus: false, + view: "SIGN_IN", + }, + authJTI: "JTI", + }, + me: null, + settings: { + auth: { + integrations: { + facebook: { + enabled: false, + allowRegistration: true, + }, + google: { + enabled: false, + allowRegistration: true, + }, + sso: { + enabled: true, + allowRegistration: true, + }, + local: { + enabled: false, + allowRegistration: true, + }, + oidc: [], + }, + }, + }, + // tslint:disable-next-line:no-empty + showAuthPopup: async () => {}, + // tslint:disable-next-line:no-empty + setAuthPopupState: async () => {}, + // tslint:disable-next-line:no-empty + signOut: async () => {}, + }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); +}); + +it("renders without register button", () => { + const props: PropTypesOf = { + local: { + authPopup: { + open: false, + focus: false, + view: "SIGN_IN", + }, + authJTI: "JTI", + }, + me: null, + settings: { + auth: { + integrations: { + facebook: { + enabled: true, + allowRegistration: false, + }, + google: { + enabled: false, + allowRegistration: false, + }, + sso: { + enabled: false, + allowRegistration: true, + }, + local: { + enabled: true, + allowRegistration: false, + }, + oidc: [], + }, + }, + }, // tslint:disable-next-line:no-empty showAuthPopup: async () => {}, // tslint:disable-next-line:no-empty diff --git a/src/core/client/stream/containers/UserBoxContainer.tsx b/src/core/client/stream/containers/UserBoxContainer.tsx index 8c4c22430..0dcf97f63 100644 --- a/src/core/client/stream/containers/UserBoxContainer.tsx +++ b/src/core/client/stream/containers/UserBoxContainer.tsx @@ -8,6 +8,7 @@ import { } from "talk-framework/lib/relay"; import { SignOutMutation, withSignOutMutation } from "talk-framework/mutations"; import { UserBoxContainer_me as MeData } from "talk-stream/__generated__/UserBoxContainer_me.graphql"; +import { UserBoxContainer_settings as SettingsData } from "talk-stream/__generated__/UserBoxContainer_settings.graphql"; import { UserBoxContainerLocal as Local } from "talk-stream/__generated__/UserBoxContainerLocal.graphql"; import UserBoxUnauthenticated from "talk-stream/components/UserBoxUnauthenticated"; import { @@ -24,6 +25,7 @@ import UserBoxAuthenticated from "../components/UserBoxAuthenticated"; interface InnerProps { local: Local; me: MeData | null; + settings: SettingsData; showAuthPopup: ShowAuthPopupMutation; setAuthPopupState: SetAuthPopupStateMutation; signOut: SignOutMutation; @@ -37,6 +39,31 @@ export class UserBoxContainer extends Component { private handleRegister = () => this.props.showAuthPopup({ view: "SIGN_UP" }); private handleSignOut = () => this.props.signOut(); + private get supportsLogout() { + return !!this.props.local.authJTI; + } + + private get supportsRegister() { + const integrations = this.props.settings.auth.integrations; + return ( + (integrations.facebook.allowRegistration && + integrations.facebook.enabled) || + (integrations.google.allowRegistration && integrations.google.enabled) || + (integrations.local.allowRegistration && integrations.local.enabled) || + integrations.oidc.some(c => c.allowRegistration && c.enabled) + ); + } + + private get weControlAuth() { + const integrations = this.props.settings.auth.integrations; + return ( + integrations.facebook.enabled || + integrations.google.enabled || + integrations.local.enabled || + integrations.oidc.some(c => c.enabled) + ); + } + public render() { const { local: { @@ -48,13 +75,17 @@ export class UserBoxContainer extends Component { if (me) { return ( ); } + if (!this.weControlAuth) { + return null; + } + return ( <> { /> ); @@ -87,6 +121,7 @@ const enhanced = withSignOutMutation( focus view } + authJTI } ` )( @@ -96,6 +131,34 @@ const enhanced = withSignOutMutation( username } `, + settings: graphql` + fragment UserBoxContainer_settings on Settings { + auth { + integrations { + local { + enabled + allowRegistration + } + sso { + enabled + allowRegistration + } + oidc { + enabled + allowRegistration + } + google { + enabled + allowRegistration + } + facebook { + enabled + allowRegistration + } + } + } + } + `, })(UserBoxContainer) ) ) diff --git a/src/core/client/stream/containers/__snapshots__/UserBoxContainer.spec.tsx.snap b/src/core/client/stream/containers/__snapshots__/UserBoxContainer.spec.tsx.snap index 252cf95b8..02095fe21 100644 --- a/src/core/client/stream/containers/__snapshots__/UserBoxContainer.spec.tsx.snap +++ b/src/core/client/stream/containers/__snapshots__/UserBoxContainer.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renders correctly 1`] = ` +exports[`renders fully 1`] = ` + +`; + +exports[`renders sso only 1`] = `""`; + +exports[`renders sso only without logut button 1`] = `""`; + +exports[`renders without logout button 1`] = ` + + + + +`; + +exports[`renders without register button 1`] = ` + + + `; diff --git a/src/core/client/stream/tabs/comments/components/PermalinkView.tsx b/src/core/client/stream/tabs/comments/components/PermalinkView.tsx index 469f14027..ed7193cb2 100644 --- a/src/core/client/stream/tabs/comments/components/PermalinkView.tsx +++ b/src/core/client/stream/tabs/comments/components/PermalinkView.tsx @@ -20,7 +20,8 @@ export interface PermalinkViewProps { PropTypesOf["comment"] | null; settings: PropTypesOf["settings"] & - PropTypesOf["settings"]; + PropTypesOf["settings"] & + PropTypesOf["settings"]; showAllCommentsHref: string | null; onShowAllComments: (e: MouseEvent) => void; } @@ -35,7 +36,7 @@ const PermalinkView: StatelessComponent = ({ }) => { return ( - + diff --git a/src/core/client/stream/tabs/comments/components/Stream.tsx b/src/core/client/stream/tabs/comments/components/Stream.tsx index d8e3744da..caf86de28 100644 --- a/src/core/client/stream/tabs/comments/components/Stream.tsx +++ b/src/core/client/stream/tabs/comments/components/Stream.tsx @@ -19,7 +19,8 @@ export interface StreamProps { } & PropTypesOf["story"] & PropTypesOf["story"]; settings: PropTypesOf["settings"] & - PropTypesOf["settings"]; + PropTypesOf["settings"] & + PropTypesOf["settings"]; comments: ReadonlyArray< { id: string } & PropTypesOf["comment"] & PropTypesOf["comment"] @@ -38,7 +39,7 @@ const Stream: StatelessComponent = props => { return ( - + {props.me ? ( ) : ( diff --git a/src/core/client/stream/tabs/comments/components/__snapshots__/PermalinkView.spec.tsx.snap b/src/core/client/stream/tabs/comments/components/__snapshots__/PermalinkView.spec.tsx.snap index fded9cedd..caf15e087 100644 --- a/src/core/client/stream/tabs/comments/components/__snapshots__/PermalinkView.spec.tsx.snap +++ b/src/core/client/stream/tabs/comments/components/__snapshots__/PermalinkView.spec.tsx.snap @@ -7,6 +7,7 @@ exports[`renders comment not found 1`] = ` > @@ -128,6 +136,14 @@ exports[`when there is more disables load more button 1`] = ` > @@ -260,6 +276,14 @@ exports[`when there is more renders a load more button 1`] = ` > @@ -392,6 +416,14 @@ exports[`when use is logged in renders correctly 1`] = ` > ({ fragment PermalinkViewContainer_settings on Settings { ...ConversationThreadContainer_settings ...ReplyListContainer1_settings + ...UserBoxContainer_settings } `, })(PermalinkViewContainer) diff --git a/src/core/client/stream/tabs/comments/containers/StreamContainer.tsx b/src/core/client/stream/tabs/comments/containers/StreamContainer.tsx index 059d54dd5..a4084ef91 100644 --- a/src/core/client/stream/tabs/comments/containers/StreamContainer.tsx +++ b/src/core/client/stream/tabs/comments/containers/StreamContainer.tsx @@ -112,6 +112,7 @@ const enhanced = withPaginationContainer< fragment StreamContainer_settings on Settings { ...ReplyListContainer1_settings ...CommentContainer_settings + ...UserBoxContainer_settings } `, }, diff --git a/src/core/client/stream/tabs/profile/components/Profile.spec.tsx b/src/core/client/stream/tabs/profile/components/Profile.spec.tsx index 69c92942a..f9e3ab0cb 100644 --- a/src/core/client/stream/tabs/profile/components/Profile.spec.tsx +++ b/src/core/client/stream/tabs/profile/components/Profile.spec.tsx @@ -12,6 +12,7 @@ it("renders correctly", () => { const props: PropTypesOf = { story: {}, me: {}, + settings: {}, }; const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); diff --git a/src/core/client/stream/tabs/profile/components/Profile.tsx b/src/core/client/stream/tabs/profile/components/Profile.tsx index 5af8dee37..f791d9baf 100644 --- a/src/core/client/stream/tabs/profile/components/Profile.tsx +++ b/src/core/client/stream/tabs/profile/components/Profile.tsx @@ -9,12 +9,13 @@ export interface ProfileProps { story: PropTypesOf["story"]; me: PropTypesOf["me"] & PropTypesOf["me"]; + settings: PropTypesOf["settings"]; } const Profile: StatelessComponent = props => { return ( - + ); diff --git a/src/core/client/stream/tabs/profile/components/__snapshots__/Profile.spec.tsx.snap b/src/core/client/stream/tabs/profile/components/__snapshots__/Profile.spec.tsx.snap index 752ac28ca..cc3c3ff5e 100644 --- a/src/core/client/stream/tabs/profile/components/__snapshots__/Profile.spec.tsx.snap +++ b/src/core/client/stream/tabs/profile/components/__snapshots__/Profile.spec.tsx.snap @@ -6,6 +6,7 @@ exports[`renders correctly 1`] = ` > { public render() { - return ; + return ( + + ); } } const enhanced = withFragmentContainer({ @@ -29,6 +37,11 @@ const enhanced = withFragmentContainer({ ...CommentHistoryContainer_me } `, + settings: graphql` + fragment ProfileContainer_settings on Settings { + ...UserBoxContainer_settings + } + `, })(StreamContainer); export default enhanced; diff --git a/src/core/client/stream/tabs/profile/queries/ProfileQuery.tsx b/src/core/client/stream/tabs/profile/queries/ProfileQuery.tsx index d9d8dfdd3..564f77d45 100644 --- a/src/core/client/stream/tabs/profile/queries/ProfileQuery.tsx +++ b/src/core/client/stream/tabs/profile/queries/ProfileQuery.tsx @@ -40,7 +40,13 @@ export const render = ({ ); } - return ; + return ( + + ); } return ; @@ -58,6 +64,9 @@ const ProfileQuery: StatelessComponent = ({ me { ...ProfileContainer_me } + settings { + ...ProfileContainer_settings + } } `} variables={{ diff --git a/src/core/client/stream/test/comments/create.ts b/src/core/client/stream/test/comments/create.ts index d7995a51e..9f4de0c26 100644 --- a/src/core/client/stream/test/comments/create.ts +++ b/src/core/client/stream/test/comments/create.ts @@ -7,6 +7,7 @@ export default function create(params: CreateParams) { if (params.initLocalState) { localRecord.setValue("COMMENTS", "activeTab"); localRecord.setValue(false, "loggedIn"); + localRecord.setValue("jti", "authJTI"); params.initLocalState(localRecord, source, environment); } }, diff --git a/src/core/client/stream/test/fixtures.ts b/src/core/client/stream/test/fixtures.ts index 2fd35fdfe..fff492da7 100644 --- a/src/core/client/stream/test/fixtures.ts +++ b/src/core/client/stream/test/fixtures.ts @@ -6,6 +6,27 @@ import { } from "talk-framework/testHelpers"; export const settings = { + auth: { + integrations: { + facebook: { + enabled: false, + allowRegistration: true, + }, + google: { + enabled: false, + allowRegistration: true, + }, + sso: { + enabled: false, + allowRegistration: true, + }, + local: { + enabled: true, + allowRegistration: true, + }, + oidc: [], + }, + }, reaction: { icon: "thumb_up", label: "Respect", diff --git a/src/core/client/stream/test/profile/create.ts b/src/core/client/stream/test/profile/create.ts index 377a8caee..a10c66f2d 100644 --- a/src/core/client/stream/test/profile/create.ts +++ b/src/core/client/stream/test/profile/create.ts @@ -6,6 +6,7 @@ export default function create(params: CreateParams) { initLocalState: (localRecord, source, environment) => { if (params.initLocalState) { localRecord.setValue("PROFILE", "activeTab"); + localRecord.setValue("jti", "authJTI"); params.initLocalState(localRecord, source, environment); } }, diff --git a/src/core/client/stream/test/profile/loadMore.spec.tsx b/src/core/client/stream/test/profile/loadMore.spec.tsx index ab20961b5..50f7cd423 100644 --- a/src/core/client/stream/test/profile/loadMore.spec.tsx +++ b/src/core/client/stream/test/profile/loadMore.spec.tsx @@ -4,7 +4,7 @@ import sinon from "sinon"; import { timeout } from "talk-common/utils"; import { createSinonStub } from "talk-framework/testHelpers"; -import { comments, meWithComments, stories } from "../fixtures"; +import { comments, meWithComments, settings, stories } from "../fixtures"; import create from "./create"; let testRenderer: ReactTestRenderer; @@ -54,6 +54,7 @@ beforeEach(() => { const resolvers = { Query: { + settings: sinon.stub().returns(settings), story: createSinonStub( s => s.throws(), s => diff --git a/src/core/client/stream/test/profile/renderProfile.spec.tsx b/src/core/client/stream/test/profile/renderProfile.spec.tsx index c3395a2f9..fa9727732 100644 --- a/src/core/client/stream/test/profile/renderProfile.spec.tsx +++ b/src/core/client/stream/test/profile/renderProfile.spec.tsx @@ -4,13 +4,14 @@ import sinon from "sinon"; import { timeout } from "talk-common/utils"; import { createSinonStub } from "talk-framework/testHelpers"; -import { meWithComments, stories } from "../fixtures"; +import { meWithComments, settings, stories } from "../fixtures"; import create from "./create"; let testRenderer: ReactTestRenderer; beforeEach(() => { const resolvers = { Query: { + settings: sinon.stub().returns(settings), story: createSinonStub( s => s.throws(), s =>