From db959b5d3cbeba59c35667ba9e60ba6de1940a1d Mon Sep 17 00:00:00 2001 From: Alexander Madsen <alexander.madsen@ess.eu> Date: Tue, 5 Sep 2023 08:28:16 +0000 Subject: [PATCH] CE-1891: Reroute no access to 401 page --- src/App.js | 4 +- src/components/common/User/UserProfile.js | 20 ++-- .../navigation/NotFoundView/NotFoundView.js | 11 +- src/views/IOC/IOCDetailsContainer.js | 28 ++++- .../UserPage/UserDetailsAccessControl.js | 16 +++ src/views/UserPage/UserDetailsContainer.js | 66 +++++++++++ src/views/UserPage/UserPageView.js | 103 ++++-------------- 7 files changed, 143 insertions(+), 105 deletions(-) create mode 100644 src/views/UserPage/UserDetailsAccessControl.js create mode 100644 src/views/UserPage/UserDetailsContainer.js diff --git a/src/App.js b/src/App.js index fc9d901f..865e1f67 100644 --- a/src/App.js +++ b/src/App.js @@ -27,7 +27,7 @@ import { RecordDetailsView } from "./views/records/RecordDetailsView"; import { TestErrorView } from "./views/TestErrorView"; import { GlobalAppBarContext } from "@ess-ics/ce-ui-common"; import { applicationTitle } from "./components/common/Helper"; -import { UserPageView } from "./views/UserPage/UserPageView"; +import { UserDetailsAccessControl } from "./views/UserPage/UserDetailsAccessControl"; // setting up the application (TAB)title function App() { @@ -115,7 +115,7 @@ function App() { /> <Route path="/user/:userName" - element={<UserPageView />} + element={<UserDetailsAccessControl />} exact /> <Route diff --git a/src/components/common/User/UserProfile.js b/src/components/common/User/UserProfile.js index d7a89168..103ea39d 100644 --- a/src/components/common/User/UserProfile.js +++ b/src/components/common/User/UserProfile.js @@ -1,8 +1,8 @@ import React from "react"; -import { Avatar, Card, CardHeader, Typography } from "@mui/material"; +import { Avatar, Card, CardHeader } from "@mui/material"; import { KeyValueTable } from "@ess-ics/ce-ui-common/dist/components/common/KeyValueTable"; -export function UserProfile({ userInfo, errorMessage }) { +export function UserProfile({ userInfo }) { const userData = { username: userInfo?.loginName, avatar: ( @@ -22,16 +22,12 @@ export function UserProfile({ userInfo, errorMessage }) { component: "h2" }} /> - {errorMessage ? ( - <Typography>{errorMessage}</Typography> - ) : ( - <KeyValueTable - obj={userData} - variant="overline" - sx={{ border: 0 }} - valueOptions={{ headerName: "" }} - /> - )} + <KeyValueTable + obj={userData} + variant="overline" + sx={{ border: 0 }} + valueOptions={{ headerName: "" }} + /> </Card> ); } diff --git a/src/components/navigation/NotFoundView/NotFoundView.js b/src/components/navigation/NotFoundView/NotFoundView.js index bc08f94b..6188bcca 100644 --- a/src/components/navigation/NotFoundView/NotFoundView.js +++ b/src/components/navigation/NotFoundView/NotFoundView.js @@ -8,14 +8,15 @@ import { ServerErrorPage, RootPaper } from "@ess-ics/ce-ui-common"; const propTypes = { /** String containing message of page not found. Otherwise defaults to a generic "Page Not Found" message */ - message: string + message: string, + status: string }; -export default function NotFoundView({ message }) { +export default function NotFoundView({ message, status }) { return ( <RootPaper> <ServerErrorPage - status={"404"} + status={status} message={message} supportHref={window.SUPPORT_URL} /> @@ -24,3 +25,7 @@ export default function NotFoundView({ message }) { } NotFoundView.propTypes = propTypes; + +NotFoundView.defaultProps = { + status: "404" +}; diff --git a/src/views/IOC/IOCDetailsContainer.js b/src/views/IOC/IOCDetailsContainer.js index c27adf57..ab907931 100644 --- a/src/views/IOC/IOCDetailsContainer.js +++ b/src/views/IOC/IOCDetailsContainer.js @@ -1,21 +1,39 @@ -import React, { useState } from "react"; +import React, { useEffect, useContext, useState } from "react"; import { IOCDetailsView } from "./IOCDetailsView"; import { LinearProgress } from "@mui/material"; import NotFoundView from "../../components/navigation/NotFoundView/NotFoundView"; import { onFetchEntityError } from "../../components/common/Helper"; import { useIOC } from "../../api/SwaggerApi"; +import { userContext } from "@ess-ics/ce-ui-common/dist/contexts/User"; +import useUrlState from "@ahooksjs/use-url-state"; export function IOCDetailsContainer({ id }) { - const [notFoundError, setNotFoundError] = useState(); + const { user } = useContext(userContext); + const [urlState] = useUrlState(); + const [error, setError] = useState(null); + const [ioc, getIOC /* reset*/, , loading] = useIOC(id, (m, s) => { // handle error code 404, and define custom message on the UI because BE sends back generic error message - onFetchEntityError(m, s, setNotFoundError); + onFetchEntityError(m, s, setError); }); + useEffect(() => { + // user logs in => clear error message, and try to re-request userInfo + if (user) { + setError(null); + } else if (!user && urlState?.tab) { + // user is not logged in => show a message + setError({ message: "Unauthorized", status: "401" }); + } + }, [urlState, user]); + return ( <> - {notFoundError ? ( - <NotFoundView /> + {error ? ( + <NotFoundView + message={error?.message} + status={error?.status} + /> ) : ioc ? ( <IOCDetailsView ioc={ioc} diff --git a/src/views/UserPage/UserDetailsAccessControl.js b/src/views/UserPage/UserDetailsAccessControl.js new file mode 100644 index 00000000..be5aa906 --- /dev/null +++ b/src/views/UserPage/UserDetailsAccessControl.js @@ -0,0 +1,16 @@ +import React from "react"; +import { RootContainer } from "../../components/common/Container/RootContainer"; +import AccessControl from "../../components/auth/AccessControl"; +import { UserDetailsContainer } from "./UserDetailsContainer"; +import { useParams } from "react-router-dom"; + +export function UserDetailsAccessControl() { + const { userName } = useParams(); + return ( + <RootContainer> + <AccessControl allowedRoles={[]}> + <UserDetailsContainer userName={userName} /> + </AccessControl> + </RootContainer> + ); +} diff --git a/src/views/UserPage/UserDetailsContainer.js b/src/views/UserPage/UserDetailsContainer.js new file mode 100644 index 00000000..0aac2aa7 --- /dev/null +++ b/src/views/UserPage/UserDetailsContainer.js @@ -0,0 +1,66 @@ +import React, { useContext, useEffect, useState } from "react"; +import { UserPageView } from "./UserPageView"; +import { LinearProgress } from "@mui/material"; +import NotFoundView from "../../components/navigation/NotFoundView/NotFoundView"; +import { useUserInfo } from "../../api/SwaggerApi"; +import { userContext } from "@ess-ics/ce-ui-common/dist/contexts/User"; + +export function UserDetailsContainer({ userName }) { + const { user } = useContext(userContext); + const [error, setError] = useState(null); + + const [userInfo, getUserInfo, ,] = useUserInfo(userName, (m, s) => { + // log error message for userInfo + console.warn(m); + + // user not found + if (s === 404) { + setError({ message: "Page not found", status: `${s}` }); + // do not show snackbar error + return false; + } + + // user doesn't have permission to fetch userInfo + if (s === 401) { + setError({ message: "Unauthorized", status: `${s}` }); + // do not show snackbar error + return false; + } + }); + + useEffect(() => { + // user logs in => clear error message, and try to re-request userInfo + if (user) { + setError(null); + } else { + // user is not logged in => show a message + setError({ message: "Unauthorized", status: "401" }); + } + }, [user]); + + useEffect(() => { + // request userInfo only if user is logged in + if (user) { + getUserInfo(); + } + }, [getUserInfo, userName, user]); + + return ( + <> + {error ? ( + <NotFoundView + status={error?.status ?? "404"} + message={error?.message} + /> + ) : user?.loginName === userName ? ( + <UserPageView + userName={userName} + user={user} + userInfo={userInfo} + /> + ) : ( + <LinearProgress color="primary" /> + )} + </> + ); +} diff --git a/src/views/UserPage/UserPageView.js b/src/views/UserPage/UserPageView.js index e0f8b093..f0885d8b 100644 --- a/src/views/UserPage/UserPageView.js +++ b/src/views/UserPage/UserPageView.js @@ -1,12 +1,8 @@ -import React, { useContext, useState } from "react"; +import React from "react"; import { Grid } from "@mui/material"; import { styled } from "@mui/material/styles"; import { RootContainer } from "../../components/common/Container/RootContainer"; -import { useParams } from "react-router-dom"; -import { useUserInfo } from "../../api/SwaggerApi"; -import { userContext } from "@ess-ics/ce-ui-common/dist/contexts/User"; import { UserProfile } from "../../components/common/User/UserProfile"; -import { useEffect } from "react"; import { UserIocList } from "../../components/common/User/UserIOCList"; import { UserOperationList } from "../../components/common/User/UserOperationList"; @@ -23,90 +19,31 @@ const StyledRootContainer = styled(RootContainer)(({ theme }) => ({ } })); -export function UserPageView() { - const { userName } = useParams(); - const { user } = useContext(userContext); - const [errorMessage, setErrorMessage] = useState(); - - const [userInfo, getUserInfo, ,] = useUserInfo(userName, (m, s) => { - // log error message for userInfo - console.warn(m); - // user not found - if (s === 404) { - setErrorMessage("User not found!"); - // do not show snackbar error - return false; - } - - // user doesn't have permission to fetch userInfo - if (s === 401) { - setErrorMessage("No activity"); - // do not show snackbar error - return false; - } - // show any other errors with snackbar - }); - - useEffect(() => { - // user logs in => clear error message, and try to re-request userInfo - if (user) { - setErrorMessage(null); - } else { - // user is not logged in => show a message - setErrorMessage("No activity!"); - } - }, [user]); - - useEffect(() => { - // request userInfo only if user is logged in - if (user) { - getUserInfo(); - } - }, [getUserInfo, userName, user]); - - // content for userActivity, e.g. operations that the user done, or IOCs that owns - const userActivityContent = ( - <> - <Grid - item - xs={12} - > - <UserOperationList userName={userName} /> - </Grid> - - <Grid - item - xs={12} - > - <UserIocList userName={userName} /> - </Grid> - </> - ); - - // show userPage for everyone, but hide userActivity for non-logged in users, and for not existing user - const content = ( - <> - <Grid - item - xs={12} - > - <UserProfile - userInfo={userInfo} - errorMessage={errorMessage} - /> - </Grid> - - {user && !errorMessage && userActivityContent} - </> - ); - +export function UserPageView({ userName, userInfo }) { return ( <StyledRootContainer> <Grid container spacing={1} > - {content} + <Grid + item + xs={12} + > + <UserProfile userInfo={userInfo} /> + </Grid> + <Grid + item + xs={12} + > + <UserOperationList userName={userName} /> + </Grid> + <Grid + item + xs={12} + > + <UserIocList userName={userName} /> + </Grid> </Grid> </StyledRootContainer> ); -- GitLab