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