1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

F #3951: Fix redirect when access via url (#163)

This commit is contained in:
Sergio Betanzos 2020-08-22 03:57:47 +02:00 committed by GitHub
parent cf68d2f2f0
commit e0f5264bd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 164 additions and 133 deletions

View File

@ -1,10 +1,12 @@
const START_AUTH = 'START_AUTH';
const SELECT_FILTER_GROUP = 'SELECT_FILTER_GROUP';
const SUCCESS_AUTH = 'SUCCESS_AUTH';
const FAILURE_AUTH = 'FAILURE_AUTH';
const LOGOUT = 'LOGOUT';
const Actions = {
START_AUTH,
SELECT_FILTER_GROUP,
SUCCESS_AUTH,
FAILURE_AUTH,
LOGOUT
@ -15,6 +17,10 @@ module.exports = {
startAuth: () => ({
type: START_AUTH
}),
selectFilterGroup: payload => ({
type: SELECT_FILTER_GROUP,
payload
}),
successAuth: payload => ({
type: SUCCESS_AUTH,
payload

View File

@ -13,46 +13,46 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
import React, { Suspense } from 'react';
import React from 'react';
import { StaticRouter, BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import {
CssBaseline,
ThemeProvider,
createMuiTheme,
responsiveFontSizes
} from '@material-ui/core';
import { CssBaseline, ThemeProvider } from '@material-ui/core';
import themeOne from 'client/assets/theme';
import theme from 'client/assets/theme';
import { TranslateProvider } from 'client/components/HOC';
import Router from 'client/router';
const theme = createMuiTheme(themeOne);
const App = ({ location, context, store }) => {
React.useEffect(() => {
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
const App = ({ location, context, store }) => (
<ThemeProvider theme={responsiveFontSizes(theme)}>
<CssBaseline />
<Provider store={store}>
{location && context ? (
// server build
<StaticRouter location={location} context={context}>
<TranslateProvider>
<Router />
</TranslateProvider>
</StaticRouter>
) : (
// browser build
<BrowserRouter>
<TranslateProvider>
<Router />
</TranslateProvider>
</BrowserRouter>
)}
</Provider>
</ThemeProvider>
);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Provider store={store}>
<TranslateProvider>
{location && context ? (
// server build
<StaticRouter location={location} context={context}>
<Router />
</StaticRouter>
) : (
// browser build
<BrowserRouter>
<Router />
</BrowserRouter>
)}
</TranslateProvider>
</Provider>
</ThemeProvider>
);
};
App.propTypes = {
location: PropTypes.string,

View File

@ -1,4 +1,6 @@
export default {
import { createMuiTheme, responsiveFontSizes } from '@material-ui/core';
const theme = createMuiTheme({
typography: {
fontFamily: ['Ubuntu', 'Lato'].join(',')
},
@ -82,4 +84,6 @@ export default {
hint: 'rgba(0, 0, 0, 0.38)'
}
}
};
});
export default responsiveFontSizes(theme);

View File

@ -17,19 +17,23 @@ import React, { Fragment, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Redirect } from 'react-router-dom';
import { LinearProgress } from '@material-ui/core';
import useAuth from 'client/hooks/useAuth';
import { PATH } from 'client/router/endpoints';
const AuthLayout = ({ children }) => {
const { isLogging, isLogged, getAuthInfo } = useAuth();
const { isLoginInProcess, isLogged, firstRender, getAuthInfo } = useAuth();
useEffect(() => {
if (isLogged && !isLogging) {
if (isLogged && !isLoginInProcess) {
getAuthInfo();
}
}, [isLogged, isLogging]);
}, [isLogged, isLoginInProcess]);
if (!isLogged) {
if (firstRender) {
return <LinearProgress style={{ width: '100%' }} />;
} else if (!isLogged && !isLoginInProcess) {
return <Redirect to={PATH.LOGIN} />;
}

View File

@ -23,14 +23,12 @@ import useAuth from 'client/hooks/useAuth';
import { PATH } from 'client/router/endpoints';
const GuessLayout = ({ children }) => {
const { isLogging, isLogged, firstRender } = useAuth();
if (isLogged && !isLogging) {
return <Redirect to={PATH.DASHBOARD} />;
}
const { isLoginInProcess, isLogged, firstRender } = useAuth();
if (firstRender) {
return <LinearProgress style={{ width: '100%' }} />;
} else if (isLogged && !isLoginInProcess) {
return <Redirect to={PATH.DASHBOARD} />;
}
return <Fragment>{children}</Fragment>;

View File

@ -16,13 +16,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
makeStyles,
AppBar,
Toolbar,
IconButton,
Typography
} from '@material-ui/core';
import { AppBar, Toolbar, IconButton, Typography } from '@material-ui/core';
import MenuIcon from '@material-ui/icons/Menu';
import useGeneral from 'client/hooks/useGeneral';
@ -34,27 +28,30 @@ const Header = ({ title }) => {
const classes = headerStyles();
const { isOpenMenu, openMenu } = useGeneral();
return (
<AppBar position="fixed" data-cy="header">
<Toolbar>
<IconButton
onClick={() => openMenu(!isOpenMenu)}
edge="start"
color="inherit"
>
<MenuIcon />
</IconButton>
<Typography
variant="h6"
className={classes.title}
data-cy="header-title"
>
{title}
</Typography>
<User />
<Zone />
</Toolbar>
</AppBar>
return React.useMemo(
() => (
<AppBar position="fixed" data-cy="header">
<Toolbar>
<IconButton
onClick={() => openMenu(!isOpenMenu)}
edge="start"
color="inherit"
>
<MenuIcon />
</IconButton>
<Typography
variant="h6"
className={classes.title}
data-cy="header-title"
>
{title}
</Typography>
<User />
<Zone />
</Toolbar>
</AppBar>
),
[isOpenMenu, openMenu]
);
};

View File

@ -1,12 +1,12 @@
import { makeStyles } from '@material-ui/core';
export default makeStyles(theme => {
export default makeStyles(theme =>
// const getColor = theme.palette.type === 'light' ? darken : lighten;
// const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken;
// color: getColor(theme.palette.error.main, 0.6),
// backgroundColor: getBackgroundColor(theme.palette.error.main, 0.9)
return {
({
root: {
display: 'flex',
flexDirection: 'column',
@ -15,7 +15,7 @@ export default makeStyles(theme => {
paper: {
overflow: 'hidden',
padding: theme.spacing(3),
height: 400
minHeight: 400
},
logo: {
display: 'block',
@ -31,5 +31,5 @@ export default makeStyles(theme => {
helper: {
animation: '1s ease-out 0s 1'
}
};
});
})
);

View File

@ -15,13 +15,23 @@
import React, { useEffect } from 'react';
import { makeStyles, Card, CardContent, Typography } from '@material-ui/core';
import {
makeStyles,
Card,
Chip,
CardContent,
Typography,
LinearProgress,
Box
} from '@material-ui/core';
import useGeneral from 'client/hooks/useGeneral';
import useOpennebula from 'client/hooks/useOpennebula';
const useStyles = makeStyles({
root: {
minWidth: 275
card: {
minWidth: 275,
marginBottom: '2em'
},
title: {
fontSize: 14
@ -30,23 +40,43 @@ const useStyles = makeStyles({
function Users() {
const classes = useStyles();
const { users, getUsers } = useOpennebula();
const { isLoading } = useGeneral();
const { users, groups, getUsers } = useOpennebula();
useEffect(() => {
getUsers();
if (!isLoading) {
getUsers();
}
}, [getUsers]);
console.log(users);
const getGroupById = id => groups?.find(({ ID }) => ID === id);
return (
<div>
<Card className={classes.root}>
<CardContent>
<Typography className={classes.title} gutterBottom>
Word of the Day
</Typography>
</CardContent>
</Card>
</div>
<>
{isLoading && <LinearProgress style={{ width: '100%' }} />}
{users?.map(({ ID, NAME, GROUPS }, index) => (
<Card key={`user-${index}`} className={classes.card}>
<CardContent>
<Box display="flex" alignItems="center">
<Typography className={classes.title}>{NAME}</Typography>
{[GROUPS?.ID ?? []].flat().map(id => {
const group = getGroupById(id);
return group ? (
<Chip
style={{ margin: '0 0.5em' }}
key={`group-${index}-${id}`}
size="small"
color="primary"
clickable
label={group.NAME}
/>
) : null;
})}
</Box>
</CardContent>
</Card>
))}
</>
);
}

View File

@ -9,6 +9,7 @@ import * as serviceUsers from 'client/services/users';
import * as serviceGroups from 'client/services/groups';
import {
startAuth,
selectFilterGroup,
successAuth,
failureAuth,
logout as logoutRequest
@ -23,7 +24,7 @@ export default function useAuth() {
const {
jwt,
error,
isLogging,
isLoginInProcess,
isLoading,
firstRender,
filterPool,
@ -55,8 +56,9 @@ export default function useAuth() {
successAuth({
jwt: token,
user: { ID: id },
isLoading: ONEADMIN_ID !== id, // is not oneadmin
isLogging: ONEADMIN_ID !== id // is not oneadmin
isLoginInProcess: ONEADMIN_ID !== id // is not oneadmin
// isLoading: ONEADMIN_ID !== id, // is not oneadmin
// isLogging: ONEADMIN_ID !== id // is not oneadmin
})
);
}
@ -67,13 +69,13 @@ export default function useAuth() {
dispatch(failureAuth({ error: err }));
});
},
[baseURL, jwtName]
[dispatch, baseURL, jwtName]
);
const logout = useCallback(() => {
removeStoreData([jwtName]);
dispatch(logoutRequest());
}, [jwtName]);
}, [dispatch, jwtName]);
const getAuthInfo = useCallback(() => {
dispatch(startAuth());
@ -87,17 +89,12 @@ export default function useAuth() {
})
)
.catch(err => dispatch(failureAuth({ error: err })));
}, [baseURL, jwtName]);
}, [dispatch, baseURL, jwtName]);
const setPrimaryGroup = useCallback(
values => {
if (values?.group === FILTER_POOL.ALL_RESOURCES) {
dispatch(
successAuth({
isLogging: false,
filterPool: FILTER_POOL.ALL_RESOURCES
})
);
dispatch(selectFilterGroup({ filterPool: FILTER_POOL.ALL_RESOURCES }));
} else {
dispatch(startAuth());
@ -105,16 +102,15 @@ export default function useAuth() {
.changeGroup({ id: authUser.ID, ...values })
.then(() =>
dispatch(
successAuth({
filterPool: FILTER_POOL.PRIMARY_GROUP_RESOURCES,
isLogging: false
selectFilterGroup({
filterPool: FILTER_POOL.PRIMARY_GROUP_RESOURCES
})
)
)
.catch(err => dispatch(failureAuth({ error: err })));
}
},
[authUser, jwtName]
[dispatch, authUser, jwtName]
);
return {
@ -125,7 +121,7 @@ export default function useAuth() {
authUser,
isOneAdmin: authUser?.ID === ONEADMIN_ID,
isLogged: Boolean(jwt),
isLogging,
isLoginInProcess,
isLoading,
firstRender,
error,

View File

@ -7,13 +7,10 @@ import {
startOneRequest,
failureOneRequest
} from 'client/actions/pool';
import * as servicesGroups from 'client/services/groups';
import * as servicesUsers from 'client/services/users';
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export default function useOpennebula() {
const dispatch = useDispatch();
const { groups, users } = useSelector(
@ -23,22 +20,18 @@ export default function useOpennebula() {
const getGroups = useCallback(() => {
dispatch(startOneRequest());
return delay(2000).then(() =>
servicesGroups
.getGroups()
.then(data => dispatch(setGroups(data)))
.catch(() => dispatch(failureOneRequest('Unauthorized')))
);
return servicesGroups
.getGroups()
.then(data => dispatch(setGroups(data)))
.catch(err => dispatch(failureOneRequest({ error: err })));
}, [dispatch]);
const getUsers = useCallback(() => {
dispatch(startOneRequest());
return delay(2000).then(() =>
servicesUsers
.getUsers()
.then(data => dispatch(setUsers(data)))
.catch(() => dispatch(failureOneRequest('Unauthorized')))
);
return servicesUsers
.getUsers()
.then(data => dispatch(setUsers(data)))
.catch(err => dispatch(failureOneRequest({ error: err })));
}, [dispatch]);
return {

View File

@ -29,7 +29,7 @@ const initial = {
group: null,
error: null,
filterPool: FILTER_POOL.ALL_RESOURCES,
isLogging: false,
isLoginInProcess: false,
isLoading: false,
firstRender: true
};
@ -51,12 +51,20 @@ const authentication = (state = initial, action) => {
isLoading: false,
...action.payload
};
case UserActions.SELECT_FILTER_GROUP:
return {
...state,
isLoading: false,
isLoginInProcess: false,
...action.payload
};
case UserActions.FAILURE_AUTH:
return {
...state,
jwt: null,
firstRender: false,
isLoading: false,
isLoginInProcess: false,
...action.payload
};
case UserActions.LOGOUT:

View File

@ -22,7 +22,7 @@ import Error404 from 'client/containers/Error404';
import endpoints from './endpoints';
function Routes() {
function Router() {
const renderRoute = ({
label = '',
path = '',
@ -54,10 +54,10 @@ function Routes() {
{endpoints?.map(({ routes, ...endpoint }) =>
endpoint.path ? renderRoute(endpoint) : routes?.map(renderRoute)
)}
<Route component={() => <Error404 />} />
<Route component={Error404} />
</Switch>
);
}
export default Routes;
export default Router;
export { endpoints };

View File

@ -73,11 +73,6 @@ router.get('*', (req, res) => {
</html>
`;
if (context.url) {
res.writeHead(301, { Location: context.url });
res.end();
} else {
res.send(html);
}
res.send(html);
});
module.exports = router;