Skip to content

Commit

Permalink
Web: Refactored routes to improve compatibility with react-router v6 (#…
Browse files Browse the repository at this point in the history
…330)

* Refactored routes to improve compatibility with react-router v6

* Fixed ProtectedRoute
  • Loading branch information
psrok1 committed Mar 26, 2021
1 parent b611dec commit f431423
Show file tree
Hide file tree
Showing 25 changed files with 246 additions and 279 deletions.
250 changes: 100 additions & 150 deletions mwdb/web/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ import RelationsPlot from "./components/RelationsPlot";
import UserPasswordRecover from "./components/UserPasswordRecover";
import ShowPendingUsers from "./components/ShowPendingUsers";
import Docs from "./components/Docs";
import RemoteShowSample from "./components/Remote/RemoteShowSample";
import RemoteShowConfig from "./components/Remote/RemoteShowConfig";
import RemoteShowTextBlob from "./components/Remote/RemoteShowTextBlob";
import RemoteRecentSamples from "./components/Remote/RemoteRecentSamples";
import RemoteRecentConfigs from "./components/Remote/RemoteRecentConfigs";
import RemoteRecentBlobs from "./components/Remote/RemoteRecentBlobs";
import RemoteDiffTextBlob from "./components/Remote/RemoteDiffTextBlob";
import RemoteSearch from "./components/Remote/RemoteSearch";
import RemoteViews from "./components/Remote/RemoteViews";

import { library } from "@fortawesome/fontawesome-svg-core";
import {
Expand Down Expand Up @@ -69,10 +62,14 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { faStar as farStar } from "@fortawesome/free-regular-svg-icons";

import { AuthContext } from "@mwdb-web/commons/auth";
import { ConfigContext } from "@mwdb-web/commons/config";
import { fromPlugin } from "@mwdb-web/commons/extensions";
import { ErrorBoundary, ProtectedRoute } from "@mwdb-web/commons/ui";
import {
ErrorBoundary,
ProtectedRoute,
AdministrativeRoute,
AttributeRoute,
} from "@mwdb-web/commons/ui";
import { Extendable } from "./commons/extensions";

library.add(faTimes);
Expand Down Expand Up @@ -101,26 +98,6 @@ library.add(faThumbtack);
library.add(faStar);
library.add(farStar);

function AuthenticatedRoute(args) {
const auth = useContext(AuthContext);
return <ProtectedRoute condition={auth.isAuthenticated} {...args} />;
}

function AdministrativeRoute(args) {
const auth = useContext(AuthContext);
return <ProtectedRoute condition={auth.isAdmin} {...args} />;
}

function AttributeRoute(args) {
const auth = useContext(AuthContext);
return (
<ProtectedRoute
condition={auth.hasCapability("managing_attributes")}
{...args}
/>
);
}

function DefaultRoute() {
const location = useLocation();
return (
Expand All @@ -142,131 +119,104 @@ export default function App() {

const routeSwitch = config.config ? (
<Switch>
<Route exact path="/login" component={UserLogin} />
<Route exact path="/login">
<UserLogin />
</Route>
{config.config["is_registration_enabled"] ? (
<Route exact path="/register" component={UserRegister} />
<Route exact path="/register">
<UserRegister />
</Route>
) : (
[]
)}
<Route
exact
path="/recover_password"
component={UserPasswordRecover}
/>
<Route exact path="/setpasswd/:token" component={UserSetPassword} />
<AuthenticatedRoute exact path="/" component={RecentSamples} />
<AuthenticatedRoute
exact
path="/configs"
component={RecentConfigs}
/>
<AuthenticatedRoute exact path="/blobs" component={RecentBlobs} />
<AuthenticatedRoute exact path="/upload" component={Upload} />
<AuthenticatedRoute path="/search" component={Search} />
<AuthenticatedRoute path="/search_help" component={SearchHelp} />
<AuthenticatedRoute
exact
path="/configs/stats"
component={ConfigStats}
/>
<AuthenticatedRoute exact path="/about" component={About} />
<AuthenticatedRoute exact path="/docs" component={Docs} />
<AuthenticatedRoute
exact
path="/profile/:login"
component={UserProfile}
/>
<Route exact path="/recover_password">
<UserPasswordRecover />
</Route>
<Route exact path="/setpasswd/:token">
<UserSetPassword />
</Route>
<ProtectedRoute exact path="/">
<RecentSamples />
</ProtectedRoute>
<ProtectedRoute exact path="/configs">
<RecentConfigs />
</ProtectedRoute>
<ProtectedRoute exact path="/blobs">
<RecentBlobs />
</ProtectedRoute>
<ProtectedRoute exact path="/upload">
<Upload />
</ProtectedRoute>
<ProtectedRoute exact path="/search">
<Search />
</ProtectedRoute>
<ProtectedRoute exact path="/search_help">
<SearchHelp />
</ProtectedRoute>
<ProtectedRoute exact path="/configs/stats">
<ConfigStats />
</ProtectedRoute>
<ProtectedRoute exact path="/about">
<About />
</ProtectedRoute>
<ProtectedRoute exact path="/docs">
<Docs />
</ProtectedRoute>
<ProtectedRoute exact path="/profile/:login">
<UserProfile />
</ProtectedRoute>
<Redirect from="/sample/:hash" to="/file/:hash" />
<AuthenticatedRoute path="/file/:hash" component={ShowSample} />
<AuthenticatedRoute path="/config/:hash" component={ShowConfig} />
<AuthenticatedRoute path="/blob/:hash" component={ShowTextBlob} />
<AuthenticatedRoute
path="/diff/:current/:previous"
component={DiffTextBlob}
/>
<AuthenticatedRoute path="/relations" component={RelationsPlot} />
<AuthenticatedRoute
exact
path="/user_groups"
component={UserGroups}
/>
<AdministrativeRoute
exact
path="/user/:login"
component={UserUpdate}
/>
<AdministrativeRoute exact path="/users" component={ShowUsers} />
<AdministrativeRoute
exact
path="/users/pending"
component={ShowPendingUsers}
/>
<AdministrativeRoute
exact
path="/users/new"
component={UserCreate}
/>
<AdministrativeRoute exact path="/groups" component={ShowGroups} />
<AdministrativeRoute
exact
path="/groups/new"
component={GroupRegister}
/>
<AdministrativeRoute
exact
path="/group/:name"
component={GroupUpdate}
/>
<AttributeRoute
exact
path="/attribute/:metakey"
component={AttributeUpdate}
/>
<AttributeRoute
exact
path="/attributes"
component={ManageAttributes}
/>
<AttributeRoute
exact
path="/attributes/new"
component={AttributeDefine}
/>
<AuthenticatedRoute
exact
path="/remote/:remote"
component={RemoteRecentSamples}
/>
<AuthenticatedRoute
exact
path="/remote/:remote/configs"
component={RemoteRecentConfigs}
/>
<AuthenticatedRoute
exact
path="/remote/:remote/blobs"
component={RemoteRecentBlobs}
/>
<AuthenticatedRoute
path="/remote/:remote/file/:hash"
component={RemoteShowSample}
/>
<AuthenticatedRoute
path="/remote/:remote/config/:hash"
component={RemoteShowConfig}
/>
<AuthenticatedRoute
path="/remote/:remote/blob/:hash"
component={RemoteShowTextBlob}
/>
<AuthenticatedRoute
path="/remote/:remote/diff/:current/:previous"
component={RemoteDiffTextBlob}
/>
<AuthenticatedRoute
path="/remote/:remote/search"
component={RemoteSearch}
/>
<ProtectedRoute path="/file/:hash">
<ShowSample />
</ProtectedRoute>
<ProtectedRoute path="/config/:hash">
<ShowConfig />
</ProtectedRoute>
<ProtectedRoute path="/blob/:hash">
<ShowTextBlob />
</ProtectedRoute>
<ProtectedRoute path="/diff/:current/:previous">
<DiffTextBlob />
</ProtectedRoute>
<ProtectedRoute path="/relations">
<RelationsPlot />
</ProtectedRoute>
<ProtectedRoute exact path="/user_groups">
<UserGroups />
</ProtectedRoute>
<AdministrativeRoute exact path="/user/:login">
<UserUpdate />
</AdministrativeRoute>
<AdministrativeRoute exact path="/users">
<ShowUsers />
</AdministrativeRoute>
<AdministrativeRoute exact path="/users/pending">
<ShowPendingUsers />
</AdministrativeRoute>
<AdministrativeRoute exact path="/users/new">
<UserCreate />
</AdministrativeRoute>
<AdministrativeRoute exact path="/groups">
<ShowGroups />
</AdministrativeRoute>
<AdministrativeRoute exact path="/groups/new">
<GroupRegister />
</AdministrativeRoute>
<AdministrativeRoute exact path="/group/:name">
<GroupUpdate />
</AdministrativeRoute>
<AttributeRoute exact path="/attribute/:metakey">
<AttributeUpdate />
</AttributeRoute>
<AttributeRoute exact path="/attributes">
<ManageAttributes />
</AttributeRoute>
<AttributeRoute exact path="/attributes/new">
<AttributeDefine />
</AttributeRoute>
<ProtectedRoute path="/remote/:remote">
<RemoteViews />
</ProtectedRoute>
{fromPlugin("routes")}
<DefaultRoute />
</Switch>
Expand Down
72 changes: 54 additions & 18 deletions mwdb/web/src/commons/ui/ProtectedRoute.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,60 @@
import React, { useContext } from "react";
import { Route } from "react-router-dom";

import { Alert } from "./ErrorBoundary";
import { useLocation } from "react-router";
import { Redirect, Route } from "react-router-dom";

import { AuthContext } from "../auth";

export default function ProtectedRoute(props) {
export function ConditionalRoute({ children, condition, fallback, ...props }) {
return <Route {...props}>{condition ? children : fallback}</Route>;
}

export function ProtectedRoute({ children, condition, ...props }) {
const auth = useContext(AuthContext);
const location = useLocation();
return (
<ConditionalRoute
condition={auth.isAuthenticated}
fallback={
<Redirect
to={{
pathname: "/login",
state: {
prevLocation: location,
error:
"You need to authenticate before accessing this page",
},
}}
/>
}
{...props}
>
{condition || condition === undefined ? (
children
) : (
<Redirect
to={{
pathname: "/",
state: {
error: `You don't have permission to access '${location.pathname}'`,
},
}}
/>
)}
</ConditionalRoute>
);
}

export function AdministrativeRoute(args) {
const auth = useContext(AuthContext);
return <ProtectedRoute condition={auth.isAdmin} {...args} />;
}

export function AttributeRoute(args) {
const auth = useContext(AuthContext);
function routeRender(renderProps) {
if (!auth.isAuthenticated) {
auth.logout("You need to authenticate before accessing this page");
return [];
}
return props.condition ? (
<props.component {...renderProps} />
) : (
<div className="container-fluid">
<Alert error="You don't have permission to see that page" />
</div>
);
}
return <Route {...props} component={undefined} render={routeRender} />;
return (
<ProtectedRoute
condition={auth.hasCapability("managing_attributes")}
{...args}
/>
);
}
6 changes: 5 additions & 1 deletion mwdb/web/src/commons/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export { default as MemberList } from "./MemberList";
export { default as NavDropdown } from "./NavDropdown";
export { default as ObjectLink } from "./ObjectLink";
export { default as PagedList } from "./PagedList";
export { default as ProtectedRoute } from "./ProtectedRoute";
export {
ProtectedRoute,
AdministrativeRoute,
AttributeRoute,
} from "./ProtectedRoute";
export { default as RefString } from "./RefString";
export { default as SortedList } from "./SortedList";
export { default as View } from "./View";
Expand Down
3 changes: 2 additions & 1 deletion mwdb/web/src/components/AttributeDefine.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Component } from "react";
import { withRouter } from "react-router";

import api from "@mwdb-web/commons/api";
import { Alert } from "@mwdb-web/commons/ui";
Expand Down Expand Up @@ -153,4 +154,4 @@ class AttributeDefine extends Component {
}
}

export default AttributeDefine;
export default withRouter(AttributeDefine);

0 comments on commit f431423

Please sign in to comment.