15088: Removes navigation after second login
authorEric Biagiotti <ebiagiotti@veritasgenetics.com>
Mon, 6 May 2019 19:48:36 +0000 (15:48 -0400)
committerEric Biagiotti <ebiagiotti@veritasgenetics.com>
Mon, 6 May 2019 19:48:36 +0000 (15:48 -0400)
- Deletes link account session data if the user logs off
- Second login goes directly to arvados login
- After second login, page refresh or navigation cancels link operation

Arvados-DCO-1.1-Signed-off-by: Eric Biagiotti <ebiagiotti@veritasgenetics.com>

src/store/auth/auth-action.ts
src/store/link-account-panel/link-account-panel-actions.ts
src/store/link-account-panel/link-account-panel-reducer.ts
src/store/workbench/workbench-actions.ts
src/views-components/main-app-bar/account-menu.tsx
src/views/main-panel/main-panel-root.tsx
src/views/main-panel/main-panel.tsx

index bd6852807459a0790cd254923a83726ba04ac523..1198ff8dba40569693937a6a8f13b74dd4c5a76a 100644 (file)
@@ -78,7 +78,10 @@ export const login = (uuidPrefix: string, homeCluster: string) => (dispatch: Dis
     dispatch(authActions.LOGIN());
 };
 
-export const logout = () => (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+export const logout = (deleteLinkData: boolean = false) => (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+    if (deleteLinkData) {
+        services.linkAccountService.removeFromSession();
+    }
     services.authService.removeApiToken();
     services.authService.removeUser();
     removeAuthorizationHeader(services.apiClient);
index 17baa4f567dda252a80a8e6b78136ce6e01ca9fa..5d853b5761ed4b05e80b4a8d09087044e46ca913 100644 (file)
@@ -8,7 +8,7 @@ import { ServiceRepository } from "~/services/services";
 import { setBreadcrumbs } from "~/store/breadcrumbs/breadcrumbs-actions";
 import { snackbarActions, SnackbarKind } from "~/store/snackbar/snackbar-actions";
 import { LinkAccountType, AccountToLink } from "~/models/link-account";
-import { logout, saveApiToken, saveUser } from "~/store/auth/auth-action";
+import { saveApiToken, saveUser } from "~/store/auth/auth-action";
 import { unionize, ofType, UnionOf } from '~/common/unionize';
 import { UserResource } from "~/models/user";
 import { GroupResource } from "~/models/group";
@@ -28,6 +28,7 @@ export const linkAccountPanelActions = unionize({
         targetUser: UserResource | undefined,
         userToLink: UserResource | undefined,
         error: LinkAccountPanelError }>(),
+    HAS_SESSION_DATA: {}
 });
 
 export type LinkAccountPanelAction = UnionOf<typeof linkAccountPanelActions>;
@@ -69,7 +70,6 @@ export const linkFailed = () =>
 export const loadLinkAccountPanel = () =>
     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         dispatch(setBreadcrumbs([{ label: 'Link account'}]));
-
         const curUser = getState().auth.user;
         const curToken = getState().auth.apiToken;
         if (curUser && curToken) {
@@ -78,6 +78,16 @@ export const loadLinkAccountPanel = () =>
 
             // If there is link account session data, then the user has logged in a second time
             if (linkAccountData) {
+
+                // If the window is refreshed after the second login, cancel the linking
+                if (window.performance) {
+                    if (performance.navigation.type === PerformanceNavigation.TYPE_BACK_FORWARD ||
+                        performance.navigation.type === PerformanceNavigation.TYPE_RELOAD) {
+                        dispatch(cancelLinking());
+                        return;
+                    }
+                }
+
                 // Use the token of the user we are getting data for. This avoids any admin/non-admin permissions
                 // issues since a user will always be able to query the api server for their own user data.
                 dispatch(saveApiToken(linkAccountData.token));
@@ -137,7 +147,8 @@ export const saveAccountLinkData = (t: LinkAccountType) =>
     (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         const accountToLink = {type: t, userUuid: services.authService.getUuid(), token: services.authService.getApiToken()} as AccountToLink;
         services.linkAccountService.saveToSession(accountToLink);
-        dispatch(logout());
+        const auth = getState().auth;
+        services.authService.login(auth.localCluster, auth.remoteHosts[auth.homeCluster]);
     };
 
 export const getAccountLinkData = () =>
index 9e0bd3f74e3b852cbeeaa6078f2e0a5b667b7213..93987ff3eaac78b4157f9bb9249aae5f49f8123c 100644 (file)
@@ -7,6 +7,7 @@ import { UserResource } from "~/models/user";
 
 export enum LinkAccountPanelStatus {
     INITIAL,
+    HAS_SESSION_DATA,
     LINKING,
     ERROR
 }
@@ -54,5 +55,8 @@ export const linkAccountPanelReducer = (state: LinkAccountPanelState = initialSt
         }),
         LINK_INVALID: ({originatingUser, targetUser, userToLink, error}) => ({
             ...state, originatingUser, targetUser, userToLink, error, status: LinkAccountPanelStatus.ERROR
+        }),
+        HAS_SESSION_DATA: () => ({
+            ...state, status: LinkAccountPanelStatus.HAS_SESSION_DATA
         })
     });
\ No newline at end of file
index 163a18858b407b3fd612113a1877076f3d821ca6..0cffcaceaeaaef03af2c5b1e942146bd81ba832b 100644 (file)
@@ -59,7 +59,7 @@ import { CopyFormDialogData } from '~/store/copy-dialog/copy-dialog';
 import { loadWorkflowPanel, workflowPanelActions } from '~/store/workflow-panel/workflow-panel-actions';
 import { loadSshKeysPanel } from '~/store/auth/auth-action-ssh';
 import { loadMyAccountPanel } from '~/store/my-account/my-account-panel-actions';
-import { loadLinkAccountPanel } from '~/store/link-account-panel/link-account-panel-actions';
+import { loadLinkAccountPanel, linkAccountPanelActions } from '~/store/link-account-panel/link-account-panel-actions';
 import { loadSiteManagerPanel } from '~/store/auth/auth-action-session';
 import { workflowPanelColumns } from '~/views/workflow-panel/workflow-panel-view';
 import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions';
@@ -95,6 +95,7 @@ import { groupDetailsPanelColumns } from '~/views/group-details-panel/group-deta
 import { DataTableFetchMode } from "~/components/data-table/data-table";
 import { loadPublicFavoritePanel, publicFavoritePanelActions } from '~/store/public-favorites-panel/public-favorites-action';
 import { publicFavoritePanelColumns } from '~/views/public-favorites-panel/public-favorites-panel';
+import { USER_LINK_ACCOUNT_KEY } from '~/services/link-account-service/link-account-service';
 
 export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
 
@@ -135,6 +136,10 @@ export const loadWorkbench = () =>
             dispatch(computeNodesActions.SET_COLUMNS({ columns: computeNodePanelColumns }));
             dispatch(apiClientAuthorizationsActions.SET_COLUMNS({ columns: apiClientAuthorizationPanelColumns }));
 
+            if (sessionStorage.getItem(USER_LINK_ACCOUNT_KEY)) {
+                dispatch(linkAccountPanelActions.HAS_SESSION_DATA());
+            }
+
             dispatch<any>(initSidePanelTree());
             if (router.location) {
                 const match = matchRootRoute(router.location.pathname);
index 93aeadae804aab4fdc12d016937b7834bd4ec5b1..1b8424c040b296b43db2b388c21368b8f76b7628 100644 (file)
@@ -83,6 +83,6 @@ export const AccountMenu = withStyles(styles)(
                             className={classes.link}>
                             Switch to Workbench v1</a></MenuItem>
                     <Divider />
-                    <MenuItem onClick={() => dispatch(logout())}>Logout</MenuItem>
+                    <MenuItem onClick={() => dispatch(logout(true))}>Logout</MenuItem>
                 </DropdownMenu>
                 : null));
index 4c64b0b850bc7e2e39e5ef446af61ac5a2a66fa1..51287fa8c00c4445a573e837232262a435580b63 100644 (file)
@@ -11,6 +11,7 @@ import { LoginPanel } from '~/views/login-panel/login-panel';
 import { InactivePanel } from '~/views/inactive-panel/inactive-panel';
 import { WorkbenchLoadingScreen } from '~/views/workbench/workbench-loading-screen';
 import { MainAppBar } from '~/views-components/main-app-bar/main-app-bar';
+import { LinkAccountPanel } from '~/views/link-account-panel/link-account-panel';
 
 type CssRules = 'root';
 
@@ -28,23 +29,24 @@ export interface MainPanelRootDataProps {
     loading: boolean;
     buildInfo: string;
     uuidPrefix: string;
+    isNotLinking: boolean;
 }
 
 type MainPanelRootProps = MainPanelRootDataProps & WithStyles<CssRules>;
 
 export const MainPanelRoot = withStyles(styles)(
-    ({ classes, loading, working, user, buildInfo, uuidPrefix }: MainPanelRootProps) =>
+    ({ classes, loading, working, user, buildInfo, uuidPrefix, isNotLinking }: MainPanelRootProps) =>
         loading
             ? <WorkbenchLoadingScreen />
-            : <>
-                <MainAppBar
+            : <> { isNotLinking ? <>
+               <MainAppBar
                     user={user}
                     buildInfo={buildInfo}
                     uuidPrefix={uuidPrefix}>
                     {working ? <LinearProgress color="secondary" /> : null}
                 </MainAppBar>
                 <Grid container direction="column" className={classes.root}>
-                    {user ? (user.isActive ? <WorkbenchPanel /> : <InactivePanel />) : <LoginPanel />}
-                </Grid>
-            </>
+                    { user ? (user.isActive ? <WorkbenchPanel /> : <InactivePanel />) : <LoginPanel />}
+               </Grid>
+            </> : user ? <LinkAccountPanel/> : <LoginPanel /> } </>
 );
index 5009f12987ab59d215a0f697124319ef7bfa5efa..178db25c222878339d456913d0f647e6916a5659 100644 (file)
@@ -7,6 +7,7 @@ import { connect } from 'react-redux';
 import { MainPanelRoot, MainPanelRootDataProps } from '~/views/main-panel/main-panel-root';
 import { isSystemWorking } from '~/store/progress-indicator/progress-indicator-reducer';
 import { isWorkbenchLoading } from '~/store/workbench/workbench-actions';
+import { LinkAccountPanelStatus } from '~/store/link-account-panel/link-account-panel-reducer';
 
 const mapStateToProps = (state: RootState): MainPanelRootDataProps => {
     return {
@@ -14,7 +15,8 @@ const mapStateToProps = (state: RootState): MainPanelRootDataProps => {
         working: isSystemWorking(state.progressIndicator),
         loading: isWorkbenchLoading(state),
         buildInfo: state.appInfo.buildInfo,
-        uuidPrefix: state.auth.localCluster
+        uuidPrefix: state.auth.localCluster,
+        isNotLinking: state.linkAccountPanel.status === LinkAccountPanelStatus.INITIAL
     };
 };