Skip to content
Snippets Groups Projects
Commit fc7ad00a authored by Nico Vermaas's avatar Nico Vermaas
Browse files

Merge branch 'dev-nico' into 'master'

Dev nico

See merge request astron-sdc/esap-gui!54
parents 8b86a4e6 9df28f7c
No related branches found
No related tags found
2 merge requests!57Master,!54Dev nico
Pipeline #16787 passed
...@@ -19,6 +19,8 @@ build-esap-gui: ...@@ -19,6 +19,8 @@ build-esap-gui:
expire_in: 1 hour expire_in: 1 hour
paths: paths:
- build - build
only:
- master
deploy-esap-gui: deploy-esap-gui:
stage: deploy stage: deploy
......
import React, { useContext, useState } from "react"; import React, { useContext, useState } from "react";
import { useHistory } from "react-router-dom";
import { Button, Modal } from "react-bootstrap"; import { Button, Modal } from "react-bootstrap";
import { GlobalContext } from "../../contexts/GlobalContext"; import { GlobalContext } from "../../contexts/GlobalContext";
import { BasketContext } from "../../contexts/BasketContext"; import { BasketContext } from "../../contexts/BasketContext";
import { getTrashIcon, getOKIcon } from "../../utils/styling"; import { getTrashIcon, getOKIcon } from "../../utils/styling";
import { saveBasket } from "./SaveBasketButton"
export default function EmptyBasketButton(props) { export default function EmptyBasketButton(props) {
const { api_host, isAuthenticated } = useContext(GlobalContext); const { api_host, isAuthenticated, isTokenValid, loginAgain } = useContext(GlobalContext);
const basketContext = useContext(BasketContext); const basketContext = useContext(BasketContext);
const { setHasChanged } = useContext(BasketContext); const { setHasChanged } = useContext(BasketContext);
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const handleClose = () => setShow(false); const handleClose = () => setShow(false);
const handleShow = () => setShow(true); const handleShow = () => setShow(true);
function emptyBasket(){ let history = useHistory()
function emptyBasket(basketContext , api_host, isTokenValid, loginAgain, history){
basketContext.setDatasets([]) basketContext.setDatasets([])
setHasChanged(true) setHasChanged(true)
setShow(false) setShow(false)
saveBasket(basketContext , api_host, isTokenValid, loginAgain, history)
} }
...@@ -39,7 +43,9 @@ export default function EmptyBasketButton(props) { ...@@ -39,7 +43,9 @@ export default function EmptyBasketButton(props) {
</Modal.Header> </Modal.Header>
<Modal.Body>Are you sure you want to empty the shopping basket?</Modal.Body> <Modal.Body>Are you sure you want to empty the shopping basket?</Modal.Body>
<Modal.Footer> <Modal.Footer>
<Button variant="success" onClick={emptyBasket}> <Button variant="success"
onClick={() => emptyBasket(basketContext, api_host, isTokenValid, loginAgain, history)}
>
{getOKIcon()}{' '}OK {getOKIcon()}{' '}OK
</Button> </Button>
<Button variant="warning" onClick={handleClose}> <Button variant="warning" onClick={handleClose}>
......
...@@ -13,9 +13,8 @@ function ResponseToDatasets(response) { ...@@ -13,9 +13,8 @@ function ResponseToDatasets(response) {
let datasets = shopping_cart.map((item) => { let datasets = shopping_cart.map((item) => {
// make item_data an object instead of a string // make item_data an object instead of a string
console.log('itemdata = '+item.item_data) //console.log('itemdata = '+item.item_data)
let o = JSON.parse(item.item_data) let o = JSON.parse(item.item_data)
//alert(o)
return o return o
//return item.item_data //return item.item_data
...@@ -23,6 +22,8 @@ function ResponseToDatasets(response) { ...@@ -23,6 +22,8 @@ function ResponseToDatasets(response) {
return datasets return datasets
} }
export function loadBasket(basketContext, api_host, isAuthenticated){ export function loadBasket(basketContext, api_host, isAuthenticated){
//alert('loadBasket: authenticated = '+isAuthenticated) //alert('loadBasket: authenticated = '+isAuthenticated)
if (!isAuthenticated) { if (!isAuthenticated) {
......
import React, { useContext } from "react"; import React, { useContext } from "react";
import { useHistory } from "react-router-dom";
import { Button } from "react-bootstrap"; import { Button } from "react-bootstrap";
import { GlobalContext } from "../../contexts/GlobalContext"; import { GlobalContext } from "../../contexts/GlobalContext";
import { BasketContext } from "../../contexts/BasketContext"; import { BasketContext } from "../../contexts/BasketContext";
import axios from "axios"; import axios from "axios";
import { getShoppingIcon } from "../../utils/styling"; import { getShoppingIcon } from "../../utils/styling";
export default function SaveBasketButton(props) {
const { api_host, isAuthenticated } = useContext(GlobalContext);
const basketContext = useContext(BasketContext);
const { hasChanged, setHasChanged } = useContext(BasketContext);
function saveBasket(basketData){
const payload = {shopping_cart: basketData};
console.log(payload);
export function saveBasket(basketContext, api_host, isTokenValid, loginAgain, history){
const payload = {shopping_cart: basketContext.datasets};
console.log('saveBasket()')
const profileUrl = api_host + "accounts/user-profiles/"; const profileUrl = api_host + "accounts/user-profiles/";
// check if he token is still valid
let token_is_valid = isTokenValid()
console.log('token valid: '+token_is_valid)
// if the token is not valid, then refresh it by logging in again
if (token_is_valid < 0) {
console.log('token no longer valid, retrying login...')
loginAgain(history)
//saveBasket(basketContext, api_host, isTokenValid, history)
return
}
axios axios
.get(profileUrl, { .get(profileUrl, {
withCredentials: true, withCredentials: true,
//headers : {"Access-Control-Allow-Origin": "*"} })
}) .then((response) => {
.then((response) => { // build the userProfileUrl based on the user_name in the original id_token
console.log(response.data) console.log(response.data)
const userProfileUrl = profileUrl + response.data.results[0].user_name + "/"; const userProfileUrl = profileUrl + response.data.results[0].user_name + "/";
axios // send the payload to the userProfile
.patch(userProfileUrl, payload, {withCredentials: true}) axios
.then((response) => { .patch(userProfileUrl, payload, {withCredentials: true})
console.log("patch", response); .then((response) => {
basketContext.setHasChanged(false) console.log("patch", response);
}) basketContext.setHasChanged(false)
.catch((error) => { })
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error); console.log(error);
alert(error) });
}); }
})
.catch((error) => { export default function SaveBasketButton(props) {
console.log(error); const { api_host, isAuthenticated, isTokenValid, loginAgain } = useContext(GlobalContext);
//alert(error) const basketContext = useContext(BasketContext);
}); const { hasChanged, setHasChanged } = useContext(BasketContext);
}
// fake authentication when in 'development' mode. let history = useHistory()
//let authenticated = isAuthenticated || (process.env.NODE_ENV === "development")
let authenticated = isAuthenticated
if (authenticated) { // only show the 'save basket' button when a user is logged in and something in the basket has changed
if (isAuthenticated) {
if (hasChanged) { if (hasChanged) {
return ( return (
<Button <Button
type="button" type="button"
variant="primary" variant="primary"
onClick={() => saveBasket(basketContext.datasets)} onClick={() => saveBasket(basketContext , api_host, isTokenValid, loginAgain, history)}
{...props}> {...props}>
{getShoppingIcon("save_cart")} Save Basket</Button> {getShoppingIcon("save_cart")} Save Basket</Button>
) )
...@@ -60,11 +74,7 @@ export default function SaveBasketButton(props) { ...@@ -60,11 +74,7 @@ export default function SaveBasketButton(props) {
} }
} }
else{ else{
return (<> return null
<Button variant="warning" disabled {...props}>
Log In to Enable Data Selection
</Button>
</>
);
} }
} }
...@@ -11,8 +11,8 @@ function setProfileState(api_host, ...@@ -11,8 +11,8 @@ function setProfileState(api_host,
setIdToken, setIdToken,
setAccessToken, setAccessToken,
setTokenExpiration, setTokenExpiration,
setSecondsLeft,
setIsAuthenticated){ setIsAuthenticated){
const profileUrl = api_host + "accounts/user-profiles/"; const profileUrl = api_host + "accounts/user-profiles/";
axios axios
.get(profileUrl, {withCredentials: true}) .get(profileUrl, {withCredentials: true})
...@@ -30,12 +30,13 @@ function setProfileState(api_host, ...@@ -30,12 +30,13 @@ function setProfileState(api_host,
}) })
.catch((error) => { .catch((error) => {
alert('GlobalContext.setProfileState:' + error) console.log('GlobalContext.setProfileState:' + error)
// when the token is no longer valid, .get with credentials will fail // when the token is no longer valid, .get with credentials will fail
// mark the user as being logged out // mark the user as being logged out
localStorage.removeItem('esap_logged_in') localStorage.removeItem('esap_logged_in')
setIsAuthenticated(false); setIsAuthenticated(false);
setLoggedInUserName(""); setLoggedInUserName("");
}); });
} }
...@@ -53,32 +54,30 @@ export function GlobalContextProvider({ children }) { ...@@ -53,32 +54,30 @@ export function GlobalContextProvider({ children }) {
const [idToken, setIdToken] = useState([]); const [idToken, setIdToken] = useState([]);
const [accessToken, setAccessToken] = useState([]); const [accessToken, setAccessToken] = useState([]);
const [tokenExpiration, setTokenExpiration] = useState([]); const [tokenExpiration, setTokenExpiration] = useState([]);
const [secondsLeft, setSecondsLeft] = useState(undefined)
useEffect(() => {
axios
.get(api_host + "query/archives-uri")
.then((response) => setArchives(response.data.results));
}, [api_host]);
useEffect(() => { useEffect(() => {
axios axios
.get(api_host + "query/configuration?name=navbar") .get(api_host + "query/archives-uri")
.then((response) => { .then((response) => setArchives(response.data.results));
console.log("navbar response", response.data.configuration); }, [api_host]);
setNavbar(response.data.configuration);
}); useEffect(() => {
}, [api_host]); axios
.get(api_host + "query/configuration?name=navbar")
.then((response) => {
console.log("navbar response", response.data.configuration);
setNavbar(response.data.configuration);
});
}, [api_host]);
// Zheng: "!!!!! Still need to look at sessionid and stuff" // Zheng: "!!!!! Still need to look at sessionid and stuff"
const [sessionid, setSessionid] = useState(getCookie("sessionid")); const [sessionid, setSessionid] = useState(getCookie("sessionid"));
console.log("waah", sessionid, getCookie("sessionid"), document.cookie); console.log("waah", sessionid, getCookie("sessionid"), document.cookie);
const [isAuthenticated, setIsAuthenticated] = useState( const [isAuthenticated, setIsAuthenticated] = useState(sessionid ? true : false);
sessionid ? true : false
);
const handleLogin = ({ history }) => { const handleLogin = ({ history }) => {
console.log('handleLogin()')
setIsAuthenticated(true); setIsAuthenticated(true);
setSessionid(getCookie("sessionid")); setSessionid(getCookie("sessionid"));
history.replace("/"); history.replace("/");
...@@ -88,17 +87,29 @@ export function GlobalContextProvider({ children }) { ...@@ -88,17 +87,29 @@ export function GlobalContextProvider({ children }) {
setIdToken, setIdToken,
setAccessToken, setAccessToken,
setTokenExpiration, setTokenExpiration,
setSecondsLeft,
setIsAuthenticated); setIsAuthenticated);
return null; return null;
}; };
// used when token expiration is detected before or during an axios fetch
const loginAgain = (history) => {
console.log('loginAgain()')
const loginUrl = api_host + "oidc/authenticate"
console.log('history = '+history)
//history.replace("/login");
window.location = loginUrl
//alert('history push')
//history.push("/login");
}
const handleLogout = ({ history }) => { const handleLogout = ({ history }) => {
setIsAuthenticated(false); console.log('handleLogout()')
setSessionid(null); setIsAuthenticated(false);
history.replace("/"); setSessionid(null);
setLoggedInUserName(""); history.replace("/");
localStorage.removeItem('esap_logged_in') setLoggedInUserName("");
localStorage.removeItem('esap_logged_in')
return null; return null;
}; };
...@@ -112,6 +123,15 @@ export function GlobalContextProvider({ children }) { ...@@ -112,6 +123,15 @@ export function GlobalContextProvider({ children }) {
} }
} }
// compare the tokenExpiration timestamp with the current time
// to determine if the token is still valid.
const isTokenValid = () => {
let expiration = Date.parse(tokenExpiration)
let now = Date.parse(new Date())
let valid = (expiration - now) > 0
return (expiration - now)/1000
}
const handleError = (event) => { const handleError = (event) => {
setIsAuthenticated(false); setIsAuthenticated(false);
setSessionid(null); setSessionid(null);
...@@ -140,9 +160,9 @@ export function GlobalContextProvider({ children }) { ...@@ -140,9 +160,9 @@ export function GlobalContextProvider({ children }) {
idToken, idToken,
accessToken, accessToken,
tokenExpiration, tokenExpiration,
secondsLeft, refreshLogin,
setSecondsLeft, isTokenValid,
refreshLogin loginAgain
}} }}
> >
{children} {children}
......
...@@ -16,7 +16,7 @@ export function QueryContextProvider({ children }) { ...@@ -16,7 +16,7 @@ export function QueryContextProvider({ children }) {
const [collection, setCollection] = useState(); const [collection, setCollection] = useState();
const [config, setConfig] = useState(); const [config, setConfig] = useState();
const [configName, setConfigName] = useState(defaultConf); const [configName, setConfigName] = useState(defaultConf);
const { api_host } = useContext(GlobalContext); const { api_host, loginAgain } = useContext(GlobalContext);
const [preview, setPreview] = useState(false); const [preview, setPreview] = useState(false);
const [ds9, setDS9] = useState(false); const [ds9, setDS9] = useState(false);
...@@ -61,6 +61,11 @@ export function QueryContextProvider({ children }) { ...@@ -61,6 +61,11 @@ export function QueryContextProvider({ children }) {
let description = ". Configuration not loaded. Is ESAP-API online? " + api_host let description = ". Configuration not loaded. Is ESAP-API online? " + api_host
console.log(error.toString() + description) console.log(error.toString() + description)
//alert(description) //alert(description)
// frantic attempt to solve cors errors by trying to trigger a login
//const loginUrl = api_host + "oidc/authenticate"
//alert('(QueryContext) token expired, attempting login: '+loginUrl)
//window.location = loginUrl
loginAgain()
return false return false
}); });
...@@ -95,9 +100,13 @@ export function QueryContextProvider({ children }) { ...@@ -95,9 +100,13 @@ export function QueryContextProvider({ children }) {
setConfig(config); setConfig(config);
}) })
.catch((error) => { .catch((error) => {
let description = ". Configuration not loaded. Is ESAP-API online? " + api_host let description = ". Configuration not loaded. Is ESAP-API online? " + api_host
console.log(error.toString() + description) console.log(error.toString() + description)
//alert(description) alert(description)
//const loginUrl = api_host + "oidc/authenticate"
// window.location = loginUrl
loginAgain()
}); });
return true return true
......
...@@ -87,7 +87,7 @@ export default function Routes() { ...@@ -87,7 +87,7 @@ export default function Routes() {
</Switch> </Switch>
<footer><small>esap-gui version 23 aug 2021 - 15:00</small></footer> <footer><small>esap-gui version 27 aug 2021 - 11:00</small></footer>
</Router> </Router>
); );
} }
import React, { useContext, useState, useRef, useEffect } from "react";
import { GlobalContext } from "../contexts/GlobalContext";
export function ShowTimeLeft() {
const { tokenExpiration } = useContext(GlobalContext);
const [timer, setTimer] = useState(undefined)
const [secondsLeft, setSecondsLeft] = useState(undefined)
useEffect(() => {
setTimer(setInterval(() => showTimeLeft(), 10000))
// this function is automatically called when the component unmounts
return function cleanup() {
clearInterval(timer);
}
},[]
);
function showTimeLeft() {
//console.log({tokenExpiration})
alert(tokenExpiration)
//let expiration = new Date(tokenExpiration)
setSecondsLeft(1)
}
alert('showtimeleft')
return (<h5>{secondsLeft}</h5>)
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment