diff --git a/frontend/src/FrontDesk.jsx b/frontend/src/FrontDesk.jsx
index 119f708872..832d805f19 100644
--- a/frontend/src/FrontDesk.jsx
+++ b/frontend/src/FrontDesk.jsx
@@ -52,7 +52,6 @@ export default function FrontDesk() {
};
useEffect(() => {
- getAllNotifications();
checkLoginStatus();
const intervalId = setInterval(() => {
checkLoginStatus();
@@ -61,6 +60,12 @@ export default function FrontDesk() {
return () => clearInterval(intervalId);
}, []);
+ useEffect(() => {
+ if (isLoggedIn) {
+ getAllNotifications();
+ }
+ }, [isLoggedIn]);
+
if (loading) return ;
if (isLoggedIn) {
diff --git a/frontend/src/UnAuthenticatedSwitch.jsx b/frontend/src/UnAuthenticatedSwitch.jsx
index 701de7d5a0..60a4e1fcd7 100644
--- a/frontend/src/UnAuthenticatedSwitch.jsx
+++ b/frontend/src/UnAuthenticatedSwitch.jsx
@@ -1,15 +1,15 @@
import React from "react";
-import { Routes, Route } from "react-router-dom";
+import { Routes, Route, Navigate, useLocation } from "react-router-dom";
import Login from "./pages/Login";
import Footer from "./components/Footer";
import AlertBanner from "./components/AlertBanner";
import UnAuthenticatedAppHeader from "./components/UnAuthenticatedAppHeader";
-import NotFound from "./pages/errorPages/NotFound";
import Unauthorized from "./pages/errorPages/Unauthorized";
import Citation from "./pages/Citation";
export default function UnAuthenticatedSwitch({ showAlert, setShowAlert }) {
const [header, setHeader] = React.useState(true);
+ const location = useLocation();
return (
@@ -41,10 +41,13 @@ export default function UnAuthenticatedSwitch({ showAlert, setShowAlert }) {
element={}
/>
} />
- } />
+
} />
} />
- } />
+ }
+ />
diff --git a/frontend/src/locale/de.json b/frontend/src/locale/de.json
index 93e7f03f4e..3b51bf689f 100644
--- a/frontend/src/locale/de.json
+++ b/frontend/src/locale/de.json
@@ -246,5 +246,6 @@
"SESSION_LOGIN_MODAL_CONTENT" : "Sie wurden vom System abgemeldet.",
"SESSION_EXTEND" : "Verlängern",
"SESSION_LOGIN" : "Anmelden",
- "SESSION_CLOSE" : "Schließen"
+ "SESSION_CLOSE" : "Schließen",
+ "LOADING" : "Laden"
}
\ No newline at end of file
diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json
index cd6257bc34..f28cd0e2e9 100644
--- a/frontend/src/locale/en.json
+++ b/frontend/src/locale/en.json
@@ -246,5 +246,6 @@
"SESSION_LOGIN_MODAL_CONTENT" : "You've been logged out of the system.",
"SESSION_EXTEND" : "Extend",
"SESSION_LOGIN" : "Login",
- "SESSION_CLOSE" : "Close"
+ "SESSION_CLOSE" : "Close",
+ "LOADING" : "Loading"
}
\ No newline at end of file
diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json
index bd5a0f4c0b..f597525ad6 100644
--- a/frontend/src/locale/es.json
+++ b/frontend/src/locale/es.json
@@ -239,11 +239,12 @@
"CITATION_CITATION_DETAILS_2": "J. Levenson, S. Gero, J. Van Oast y J. Holmberg. 2015. Flukebook: herramientas de análisis de identificación fotográfica basadas en la nube para la investigación de mamíferos marinos. Disponible en: https://www.flukebook.org",
"CITATION_FORWARD": "Reenviar la cita de cualquier publicación / informe que haya utilizado los datos / herramientas proporcionados por Wild Me para su inclusión en nuestra lista de referencias enviándola a info@wildme.org.",
"CITATION_DISCLAIMER": "No responsabilizar a Wild Me ni a los proveedores de datos originales por errores en los datos. Aunque hemos hecho todo lo posible por garantizar la calidad de la base de datos, no podemos garantizar la exactitud de estos conjuntos de datos.",
- "MAP_IS_LOADING" : "El mapa se está cargando",
- "SESSION_WARNING_CONTENT" : "Tu sesión está a punto de expirar.",
- "SESSION_WARNING_TITLE" : "Advertencia de tiempo de sesión",
- "SESSION_LOGIN_MODAL_CONTENT" : "Has sido desconectado del sistema.",
- "SESSION_EXTEND" : "Extender",
- "SESSION_LOGIN" : "Iniciar sesión",
- "SESSION_CLOSE" : "Cerrar"
+ "MAP_IS_LOADING": "El mapa se está cargando",
+ "SESSION_WARNING_CONTENT": "Tu sesión está a punto de expirar.",
+ "SESSION_WARNING_TITLE": "Advertencia de tiempo de sesión",
+ "SESSION_LOGIN_MODAL_CONTENT": "Has sido desconectado del sistema.",
+ "SESSION_EXTEND": "Extender",
+ "SESSION_LOGIN": "Iniciar sesión",
+ "SESSION_CLOSE": "Cerrar",
+ "LOADING": "Cargando"
}
\ No newline at end of file
diff --git a/frontend/src/locale/fr.json b/frontend/src/locale/fr.json
index 86a86dd04d..86e511aa71 100644
--- a/frontend/src/locale/fr.json
+++ b/frontend/src/locale/fr.json
@@ -245,5 +245,6 @@
"SESSION_LOGIN_MODAL_CONTENT" : "Vous avez été déconnecté du système.",
"SESSION_EXTEND" : "Prolonger",
"SESSION_LOGIN" : "Connexion",
- "SESSION_CLOSE" : "Fermer"
+ "SESSION_CLOSE" : "Fermer",
+ "LOADING" : "Chargement"
}
\ No newline at end of file
diff --git a/frontend/src/locale/it.json b/frontend/src/locale/it.json
index 0c185cdcdf..a8c9fda1b1 100644
--- a/frontend/src/locale/it.json
+++ b/frontend/src/locale/it.json
@@ -245,5 +245,6 @@
"SESSION_LOGIN_MODAL_CONTENT" : "Sei stato disconnesso dal sistema.",
"SESSION_EXTEND" : "Estendi",
"SESSION_LOGIN" : "Accedi",
- "SESSION_CLOSE" : "Chiudi"
+ "SESSION_CLOSE" : "Chiudi",
+ "LOADING" : "Caricamento"
}
\ No newline at end of file
diff --git a/frontend/src/models/auth/useLogin.js b/frontend/src/models/auth/useLogin.js
index 511806440e..da71e4acfe 100644
--- a/frontend/src/models/auth/useLogin.js
+++ b/frontend/src/models/auth/useLogin.js
@@ -1,42 +1,44 @@
-import { useState } from 'react';
-import axios from 'axios';
-import { get } from 'lodash-es';
-import { useIntl } from 'react-intl';
+import { useState } from "react";
+import axios from "axios";
+import { get } from "lodash-es";
+import { useIntl } from "react-intl";
+import { useLocation } from "react-router-dom";
export default function useLogin() {
const intl = useIntl();
+ const location = useLocation();
const errorMessage = intl.formatMessage({
- id: 'LOGIN_INVALID_EMAIL_OR_PASSWORD',
+ id: "LOGIN_INVALID_EMAIL_OR_PASSWORD",
});
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
- const authenticate = async (username, password, nextLocation) => {
+ const authenticate = async (username, password) => {
try {
setLoading(true);
const response = await axios.request({
url: `/api/v3/login`,
- method: 'post',
+ method: "post",
data: {
username,
password,
},
});
- const successful = get(response, 'data.success', false);
+ // use .startsWith("/") to prevent open redirects
+ const successful = get(response, "data.success", false);
+
+ const nextLocation = get(response, "data.redirectUrl", null)
+ || (new URLSearchParams(location.search).get("redirect")?.startsWith("/")
+ ? `${new URL(process.env.PUBLIC_URL).pathname}${new URLSearchParams(location.search).get("redirect")}${location.hash}`
+ : null);
if (successful) {
- let url = `${process.env.PUBLIC_URL}/home`;
- if (nextLocation) {
- url = nextLocation?.pathname;
- url = nextLocation?.search
- ? url + nextLocation.search
- : url;
- url = nextLocation?.hash ? url + nextLocation.hash : url;
- }
+ let url = nextLocation || `${process.env.PUBLIC_URL}/home`;
window.location.href = url;
+
// Fun quirk - a reload is required if there is a hash in the URL.
// https://stackoverflow.com/questions/10612438/javascript-reload-the-page-with-hash-value
if (nextLocation?.hash) window.location.reload();
@@ -46,7 +48,7 @@ export default function useLogin() {
} catch (loginError) {
setLoading(false);
setError(errorMessage);
- console.error('Error logging in');
+ console.error("Error logging in");
console.error(loginError);
}
};
diff --git a/frontend/src/pages/Login.jsx b/frontend/src/pages/Login.jsx
index 8f260b6eaf..c5c2359101 100644
--- a/frontend/src/pages/Login.jsx
+++ b/frontend/src/pages/Login.jsx
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { Container, Row, Col, Form, InputGroup } from "react-bootstrap";
import { useState } from "react";
import BrutalismButton from "../components/BrutalismButton";
-import { useIntl } from "react-intl";
+import { FormattedMessage, useIntl } from "react-intl";
import useLogin from "../models/auth/useLogin";
import useDocumentTitle from "../hooks/useDocumentTitle";
import WildmeLogo from "../components/svg/WildmeLogo";
@@ -194,14 +194,21 @@ function LoginPage() {
type="submit"
onClick={handleSubmit}
color={theme.primaryColors.primary500}
- // color='#00ACCE'
- // borderColor='#00ACCE'
borderColor={theme.primaryColors.primary500}
disabled={actionDisabled}
>
{intl.formatMessage({
id: "LOGIN_SIGN_IN",
})}
+
+ {loading && (
+
+
+
+ )}
{show && error && (
diff --git a/src/main/java/org/ecocean/api/Login.java b/src/main/java/org/ecocean/api/Login.java
index 46c8715b85..b9fe39acba 100644
--- a/src/main/java/org/ecocean/api/Login.java
+++ b/src/main/java/org/ecocean/api/Login.java
@@ -16,6 +16,8 @@
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.util.SavedRequest;
+import org.apache.shiro.web.util.WebUtils;
import org.apache.shiro.SecurityUtils;
import org.ecocean.servlet.ServletUtilities;
@@ -72,6 +74,15 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
success = true;
results = user.infoJSONObject(context, true);
results.put("success", true);
+
+ //check for redirect URL
+ SavedRequest saved=WebUtils.getAndClearSavedRequest(request);
+ if(saved!=null) {
+ results.put("redirectUrl",saved.getRequestUrl());
+ }
+
+
+
} catch (UnknownAccountException ex) {
// username not found
ex.printStackTrace();