frontend/app/index.jsx (259 lines of code) (raw):

import React from "react"; import { render } from "react-dom"; import { BrowserRouter, Link, Route, Switch, Redirect, withRouter, } from "react-router-dom"; import RootComponent from "./RootComponent.jsx"; import Raven from "raven-js"; import SearchComponent from "./SearchComponent"; import OAuthCallbackComponent from "./OAuthCallbackComponent.jsx"; import ByProjectComponent from "./ByProjectComponent"; import LoadingIndicator from "./LoadingIndicator.jsx"; import { authenticatedFetch } from "./auth"; import { ThemeProvider } from "@material-ui/core/styles"; import { createMuiTheme } from "@material-ui/core"; import LoginComponentNew from "./LoginComponentNew"; import DuplicateComponent from "./DuplicateComponent"; class App extends React.Component { constructor(props) { super(props); this.state = { isLoggedIn: false, currentUsername: "", isAdmin: false, loading: true, loginDetail: null, redirectingTo: null, clientId: "", resource: "", oAuthUri: "", tokenUri: "", startup: true, scope: "" }; this.returnToRoot = this.returnToRoot.bind(this); this.theme = createMuiTheme({ palette: { type: "dark", primary: { main: "#f5f5f5", //same as "whitesmoke" }, }, typography: { fontFamily: `'DejaVu Sans Mono', monospace`, fontSize: 14, }, overrides: { MuiMenuItem: { root: { backgroundColor: "#000000", color: "#f5f5f5", "&$selected": { color: "#000000", backgroundColor: "#f5f5f5ff", }, }, }, MuiListItem: { root: { backgroundColor: "#000000", color: "#f5f5f5", "&$selected": { color: "#000000", backgroundColor: "#f5f5f5ff", }, }, }, }, }); const currentUri = new URL(window.location.href); this.redirectUri = currentUri.protocol + "//" + currentUri.host + "/oauth2/callback"; authenticatedFetch("/system/publicdsn").then(async (response) => { if (response.status === 200) { try { const responseJson = await response.json(); Raven.config(responseJson.publicDsn).install(); console.log("Sentry initialised for " + responseJson.publicDsn); } catch (error) { console.error("Could not intialise sentry", error); } } else { const responseBody = await response.text(); console.error("Could not get public DSN from backend: ", responseBody); } }); } returnToRoot() { this.props.history.push("/"); } setStatePromise(newstate) { return new Promise((resolve, reject) => this.setState(newstate, () => resolve()) ); } checkLogin() { return new Promise((resolve, reject) => this.setState({ loading: true, haveChecked: true }, async () => { const response = await authenticatedFetch("/api/isLoggedIn"); if (response.status === 200) { const responseJson = await response.json(); this.setState( { isLoggedIn: true, loading: false, currentUsername: responseJson.uid, isAdmin: responseJson.isAdmin, }, () => resolve() ); } else if (response.status === 403 || response.status === 401) { try { const responseJson = await response.json(); this.setState({ isLoggedIn: false, loading: false, loginDetail: responseJson.detail, }); } catch (e) { const responseText = await response.text(); console.error( "Permission denied but response invalid: ", responseText ); this.setState({ isLoggedIn: false, loading: false, loginDetail: "Permission denied, but response was invalid", }); } } else { const serverError = await response.text(); this.setState( { isLoggedIn: false, loginDetail: serverError, loading: false, currentUsername: "", }, () => resolve() ); } }) ); } async loadOauthData() { const response = await fetch("/meta/oauth/config.json"); switch (response.status) { case 200: console.log("got response data"); try { const content = await response.json(); return this.setStatePromise({ clientId: content.clientId, oAuthUri: content.oAuthUri, tokenUri: content.tokenUri, scope: content.scope, startup: false, }); } catch (err) { console.error("Could not load oauth config: ", err); return this.setStatePromise({ loginDetail: "Could not load auth configuration, please contact multimediatech", startup: false, }); } case 404: await response.text(); //consume body and discard it return this.setStatePromise({ startup: false, lastError: "Metadata not found on server, please contact administrator", }); default: await response.text(); //consume body and discard it return this.setStatePromise({ startup: false, lastError: "Server returned a " + response.status + " error trying to access metadata", }); } } async componentDidMount() { await this.loadOauthData(); await this.checkLogin(); if (!this.state.loading && !this.state.isLoggedIn) { this.setState({ redirectingTo: "/" }); } } render() { return ( <ThemeProvider theme={this.theme}> {this.state.loading || this.state.startup ? ( <LoadingIndicator /> ) : ( <div> <h1 style={{ marginTop: 0 }} onClick={this.returnToRoot} className="clickable" > VaultDoor </h1> <Switch> <Route path="/byproject" component={ByProjectComponent} /> <Route path="/search" component={SearchComponent} /> <Route path="/duplicates" component={DuplicateComponent} /> <Route exact path="/oauth2/callback" render={(props) => ( <OAuthCallbackComponent {...props} oAuthUri={this.state.oAuthUri} tokenUri={this.state.tokenUri} clientId={this.state.clientId} redirectUri={this.redirectUri} scope={this.state.scope} /> )} /> <Route exact path="/" component={() => ( <RootComponent currentUsername={this.state.currentUsername} isLoggedIn={this.state.isLoggedIn} loginErrorDetail={this.state.loginDetail} isAdmin={this.state.isAdmin} oAuthUri={this.state.oAuthUri} tokenUri={this.state.tokenUri} clientId={this.state.clientId} scope={this.state.scope} /> )} /> </Switch> <LoginComponentNew /> </div> )} </ThemeProvider> ); } } const AppWithRouter = withRouter(App); render( <BrowserRouter root="/"> <AppWithRouter /> </BrowserRouter>, document.getElementById("app") );