From 6a779a79fc2685330ea193317f0b0e8f7b31eb01 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 7 Dec 2020 11:55:59 +0300 Subject: [PATCH 1/6] Login with next, alternative implementation --- cvat-ui/src/actions/auth-actions.ts | 8 +++++--- cvat-ui/src/components/cvat-app.tsx | 12 +++++++++--- cvat-ui/src/components/login-page/login-page.tsx | 11 ++++++++--- .../components/login-with-token/login-with-token.tsx | 8 +++++--- cvat-ui/src/index.tsx | 2 ++ cvat-ui/src/reducers/auth-reducer.ts | 8 +++++--- cvat-ui/src/reducers/interfaces.ts | 1 + 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/cvat-ui/src/actions/auth-actions.ts b/cvat-ui/src/actions/auth-actions.ts index 9db70b5a4334..0ea9a93755e8 100644 --- a/cvat-ui/src/actions/auth-actions.ts +++ b/cvat-ui/src/actions/auth-actions.ts @@ -40,7 +40,7 @@ export const authActions = { authorizeSuccess: (user: any) => createAction(AuthActionTypes.AUTHORIZED_SUCCESS, { user }), authorizeFailed: (error: any) => createAction(AuthActionTypes.AUTHORIZED_FAILED, { error }), login: () => createAction(AuthActionTypes.LOGIN), - loginSuccess: (user: any) => createAction(AuthActionTypes.LOGIN_SUCCESS, { user }), + loginSuccess: (user: any, next: string | null) => createAction(AuthActionTypes.LOGIN_SUCCESS, { user, next }), loginFailed: (error: any) => createAction(AuthActionTypes.LOGIN_FAILED, { error }), register: () => createAction(AuthActionTypes.REGISTER), registerSuccess: (user: any) => createAction(AuthActionTypes.REGISTER_SUCCESS, { user }), @@ -98,14 +98,16 @@ export const registerAsync = ( } }; -export const loginAsync = (username: string, password: string): ThunkAction => async (dispatch) => { +export const loginAsync = (username: string, password: string, next: string | null): ThunkAction => async ( + dispatch, +) => { dispatch(authActions.login()); try { await cvat.server.login(username, password); const users = await cvat.users.get({ self: true }); - dispatch(authActions.loginSuccess(users[0])); + dispatch(authActions.loginSuccess(users[0], next)); } catch (error) { dispatch(authActions.loginFailed(error)); } diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index b3c742cd9862..cfefaa7d9d64 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -64,6 +64,7 @@ interface CVATAppProps { authActionsInitialized: boolean; notifications: NotificationsState; user: any; + next: string | null; isModelPluginActive: boolean; } @@ -231,16 +232,19 @@ class CVATApplication extends React.PureComponent )} - + {/* eslint-disable-next-line */} @@ -337,7 +341,9 @@ class CVATApplication extends React.PureComponent - + 1 ? `/auth/login/?next=${location.pathname}` : '/auth/login'} + /> ); diff --git a/cvat-ui/src/components/login-page/login-page.tsx b/cvat-ui/src/components/login-page/login-page.tsx index f252606f1ce1..9e00e841137d 100644 --- a/cvat-ui/src/components/login-page/login-page.tsx +++ b/cvat-ui/src/components/login-page/login-page.tsx @@ -15,7 +15,8 @@ import CookieDrawer from './cookie-policy-drawer'; interface LoginPageComponentProps { fetching: boolean; renderResetPassword: boolean; - onLogin: (username: string, password: string) => void; + next: string; + onLogin: (username: string, password: string, next: string | null) => void; } function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps): JSX.Element { @@ -27,7 +28,11 @@ function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps xl: { span: 4 }, }; - const { fetching, onLogin, renderResetPassword } = props; + const { + fetching, onLogin, renderResetPassword, location, + } = props; + + const search = new URLSearchParams(location.search); return ( <> @@ -37,7 +42,7 @@ function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps { - onLogin(loginData.username, loginData.password); + onLogin(loginData.username, loginData.password, search.get('next')); }} /> diff --git a/cvat-ui/src/components/login-with-token/login-with-token.tsx b/cvat-ui/src/components/login-with-token/login-with-token.tsx index cadb05426c71..b40ca03af5f7 100644 --- a/cvat-ui/src/components/login-with-token/login-with-token.tsx +++ b/cvat-ui/src/components/login-with-token/login-with-token.tsx @@ -3,15 +3,17 @@ // SPDX-License-Identifier: MIT import React, { useEffect } from 'react'; -import { Redirect, useParams } from 'react-router'; +import { Redirect, useParams, useLocation } from 'react-router'; import { useCookies } from 'react-cookie'; export default function LoginWithTokenComponent(): JSX.Element { - const { sessionId, token } = useParams(); + const location = useLocation(); + const { sessionId, token } = useParams<{ sessionId: string; token: string }>(); const [cookies, setCookie] = useCookies(['sessionid', 'csrftoken']); const expires1y = new Date(new Date().setFullYear(new Date().getFullYear() + 1)); const expires2w = new Date(new Date().setDate(new Date().getDate() + 13)); + const search = new URLSearchParams(location.search); setCookie('sessionid', sessionId, { path: '/', expires: expires2w }); setCookie('csrftoken', token, { path: '/', expires: expires1y }); @@ -24,7 +26,7 @@ export default function LoginWithTokenComponent(): JSX.Element { ); if (cookies.sessionid && cookies.csrftoken) { - return ; + return ; } return <>; } diff --git a/cvat-ui/src/index.tsx b/cvat-ui/src/index.tsx index 31188f77bb82..1d527605811e 100644 --- a/cvat-ui/src/index.tsx +++ b/cvat-ui/src/index.tsx @@ -45,6 +45,7 @@ interface StateToProps { allowResetPassword: boolean; notifications: NotificationsState; user: any; + next: string | null; keyMap: Record; isModelPluginActive: boolean; } @@ -91,6 +92,7 @@ function mapStateToProps(state: CombinedState): StateToProps { allowResetPassword: auth.allowResetPassword, notifications: state.notifications, user: auth.user, + next: auth.next, keyMap: shortcuts.keyMap, isModelPluginActive: plugins.list.MODELS, }; diff --git a/cvat-ui/src/reducers/auth-reducer.ts b/cvat-ui/src/reducers/auth-reducer.ts index eac8449b0307..2e226c20039b 100644 --- a/cvat-ui/src/reducers/auth-reducer.ts +++ b/cvat-ui/src/reducers/auth-reducer.ts @@ -10,6 +10,7 @@ const defaultState: AuthState = { initialized: false, fetching: false, user: null, + next: null, authActionsFetching: false, authActionsInitialized: false, allowChangePassword: false, @@ -40,6 +41,7 @@ export default function (state = defaultState, action: AuthActions | BoundariesA ...state, fetching: false, user: action.payload.user, + next: action.payload.next, }; case AuthActionTypes.LOGIN_FAILED: return { @@ -94,9 +96,9 @@ export default function (state = defaultState, action: AuthActions | BoundariesA return { ...state, showChangePasswordDialog: - typeof action.payload.showChangePasswordDialog === 'undefined' - ? !state.showChangePasswordDialog - : action.payload.showChangePasswordDialog, + typeof action.payload.showChangePasswordDialog === 'undefined' ? + !state.showChangePasswordDialog : + action.payload.showChangePasswordDialog, }; case AuthActionTypes.REQUEST_PASSWORD_RESET: return { diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 088be88d04aa..8a518d68f1d8 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -14,6 +14,7 @@ export interface AuthState { initialized: boolean; fetching: boolean; user: any; + next: string | null; authActionsFetching: boolean; authActionsInitialized: boolean; showChangePasswordDialog: boolean; From d296f91a2cd6535056ddd11662465838b7acfa07 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 7 Dec 2020 12:32:22 +0300 Subject: [PATCH 2/6] Updated version & changelog --- CHANGELOG.md | 1 + cvat-ui/package-lock.json | 2 +- cvat-ui/package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbfb1374496d..205b76579992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added documentation on how to mount cloud starage(AWS S3 bucket, Azure container, Google Drive) as FUSE () - Added ability to work with share files without copying inside () - Tooltips in label selectors () +- Page redirect after login using `next` query parameter () ### Changed diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index 45c2f0f475cc..866cc47fad00 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.11.5", + "version": "1.12.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/cvat-ui/package.json b/cvat-ui/package.json index b3f718c574ab..b4e9637f56dc 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.11.5", + "version": "1.12.0", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { From e22dd019e370daf25e6f37c2dadd30f355784241 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 7 Dec 2020 12:36:55 +0300 Subject: [PATCH 3/6] Fixed models initialization --- cvat-ui/src/components/cvat-app.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index cfefaa7d9d64..093f9ff4b5f5 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -244,7 +244,11 @@ class CVATApplication extends React.PureComponent Date: Mon, 7 Dec 2020 16:34:46 +0300 Subject: [PATCH 4/6] Fixed tests --- tests/cypress/support/commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cypress/support/commands.js b/tests/cypress/support/commands.js index aa48a82f4d5b..b3d06fc8a859 100644 --- a/tests/cypress/support/commands.js +++ b/tests/cypress/support/commands.js @@ -23,6 +23,7 @@ Cypress.Commands.add('logout', (username = Cypress.env('user')) => { }); cy.get('.anticon-logout').click(); cy.url().should('include', '/auth/login'); + cy.visit('/auth/login'); // clear query parameter "next" }); Cypress.Commands.add('userRegistration', (firstName, lastName, userName, emailAddr, password) => { From ccaca4526de569742b8a8c3fe8c5e1d2f3dd4e11 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 8 Dec 2020 20:01:22 +0300 Subject: [PATCH 5/6] Fixed one more usecase, simplified the code --- cvat-ui/src/actions/auth-actions.ts | 8 +++----- cvat-ui/src/components/cvat-app.tsx | 7 ++++--- cvat-ui/src/components/login-page/login-page.tsx | 9 ++------- .../src/components/login-with-token/login-with-token.tsx | 2 +- cvat-ui/src/index.tsx | 2 -- cvat-ui/src/reducers/auth-reducer.ts | 2 -- cvat-ui/src/reducers/interfaces.ts | 1 - 7 files changed, 10 insertions(+), 21 deletions(-) diff --git a/cvat-ui/src/actions/auth-actions.ts b/cvat-ui/src/actions/auth-actions.ts index 0ea9a93755e8..9db70b5a4334 100644 --- a/cvat-ui/src/actions/auth-actions.ts +++ b/cvat-ui/src/actions/auth-actions.ts @@ -40,7 +40,7 @@ export const authActions = { authorizeSuccess: (user: any) => createAction(AuthActionTypes.AUTHORIZED_SUCCESS, { user }), authorizeFailed: (error: any) => createAction(AuthActionTypes.AUTHORIZED_FAILED, { error }), login: () => createAction(AuthActionTypes.LOGIN), - loginSuccess: (user: any, next: string | null) => createAction(AuthActionTypes.LOGIN_SUCCESS, { user, next }), + loginSuccess: (user: any) => createAction(AuthActionTypes.LOGIN_SUCCESS, { user }), loginFailed: (error: any) => createAction(AuthActionTypes.LOGIN_FAILED, { error }), register: () => createAction(AuthActionTypes.REGISTER), registerSuccess: (user: any) => createAction(AuthActionTypes.REGISTER_SUCCESS, { user }), @@ -98,16 +98,14 @@ export const registerAsync = ( } }; -export const loginAsync = (username: string, password: string, next: string | null): ThunkAction => async ( - dispatch, -) => { +export const loginAsync = (username: string, password: string): ThunkAction => async (dispatch) => { dispatch(authActions.login()); try { await cvat.server.login(username, password); const users = await cvat.users.get({ self: true }); - dispatch(authActions.loginSuccess(users[0], next)); + dispatch(authActions.loginSuccess(users[0])); } catch (error) { dispatch(authActions.loginFailed(error)); } diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index 8220a603bf93..a7c5079ef331 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -64,7 +64,6 @@ interface CVATAppProps { authActionsInitialized: boolean; notifications: NotificationsState; user: any; - next: string | null; isModelPluginActive: boolean; } @@ -238,7 +237,6 @@ class CVATApplication extends React.PureComponent )} - + {/* eslint-disable-next-line */} diff --git a/cvat-ui/src/components/login-page/login-page.tsx b/cvat-ui/src/components/login-page/login-page.tsx index 9e00e841137d..59f92cce82f8 100644 --- a/cvat-ui/src/components/login-page/login-page.tsx +++ b/cvat-ui/src/components/login-page/login-page.tsx @@ -15,7 +15,6 @@ import CookieDrawer from './cookie-policy-drawer'; interface LoginPageComponentProps { fetching: boolean; renderResetPassword: boolean; - next: string; onLogin: (username: string, password: string, next: string | null) => void; } @@ -28,11 +27,7 @@ function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps xl: { span: 4 }, }; - const { - fetching, onLogin, renderResetPassword, location, - } = props; - - const search = new URLSearchParams(location.search); + const { fetching, onLogin, renderResetPassword } = props; return ( <> @@ -42,7 +37,7 @@ function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps { - onLogin(loginData.username, loginData.password, search.get('next')); + onLogin(loginData.username, loginData.password); }} /> diff --git a/cvat-ui/src/components/login-with-token/login-with-token.tsx b/cvat-ui/src/components/login-with-token/login-with-token.tsx index b40ca03af5f7..6d896c0d1d1c 100644 --- a/cvat-ui/src/components/login-with-token/login-with-token.tsx +++ b/cvat-ui/src/components/login-with-token/login-with-token.tsx @@ -26,7 +26,7 @@ export default function LoginWithTokenComponent(): JSX.Element { ); if (cookies.sessionid && cookies.csrftoken) { - return ; + return ; } return <>; } diff --git a/cvat-ui/src/index.tsx b/cvat-ui/src/index.tsx index 1d527605811e..31188f77bb82 100644 --- a/cvat-ui/src/index.tsx +++ b/cvat-ui/src/index.tsx @@ -45,7 +45,6 @@ interface StateToProps { allowResetPassword: boolean; notifications: NotificationsState; user: any; - next: string | null; keyMap: Record; isModelPluginActive: boolean; } @@ -92,7 +91,6 @@ function mapStateToProps(state: CombinedState): StateToProps { allowResetPassword: auth.allowResetPassword, notifications: state.notifications, user: auth.user, - next: auth.next, keyMap: shortcuts.keyMap, isModelPluginActive: plugins.list.MODELS, }; diff --git a/cvat-ui/src/reducers/auth-reducer.ts b/cvat-ui/src/reducers/auth-reducer.ts index 2e226c20039b..54af7c756bb5 100644 --- a/cvat-ui/src/reducers/auth-reducer.ts +++ b/cvat-ui/src/reducers/auth-reducer.ts @@ -10,7 +10,6 @@ const defaultState: AuthState = { initialized: false, fetching: false, user: null, - next: null, authActionsFetching: false, authActionsInitialized: false, allowChangePassword: false, @@ -41,7 +40,6 @@ export default function (state = defaultState, action: AuthActions | BoundariesA ...state, fetching: false, user: action.payload.user, - next: action.payload.next, }; case AuthActionTypes.LOGIN_FAILED: return { diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 89217eefe4dc..e1b215f978ed 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -14,7 +14,6 @@ export interface AuthState { initialized: boolean; fetching: boolean; user: any; - next: string | null; authActionsFetching: boolean; authActionsInitialized: boolean; showChangePasswordDialog: boolean; From e9fc542dbc88bd6d11d6fae9bfe53fdba26c5c44 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 8 Dec 2020 20:03:05 +0300 Subject: [PATCH 6/6] Aborted extra change --- cvat-ui/src/components/login-page/login-page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-ui/src/components/login-page/login-page.tsx b/cvat-ui/src/components/login-page/login-page.tsx index 59f92cce82f8..f252606f1ce1 100644 --- a/cvat-ui/src/components/login-page/login-page.tsx +++ b/cvat-ui/src/components/login-page/login-page.tsx @@ -15,7 +15,7 @@ import CookieDrawer from './cookie-policy-drawer'; interface LoginPageComponentProps { fetching: boolean; renderResetPassword: boolean; - onLogin: (username: string, password: string, next: string | null) => void; + onLogin: (username: string, password: string) => void; } function LoginPageComponent(props: LoginPageComponentProps & RouteComponentProps): JSX.Element {