From 28f99a9de29556b6e0309e6337101f039b36409f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr>
Date: Tue, 12 Mar 2024 18:48:04 +0100
Subject: [PATCH] Call SSO login with a redirect url and open it after login

---
 src/router/index.js | 15 ++++++---
 src/store/index.js  | 76 +++++++++++++++++++++++++++++++++++----------
 2 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/src/router/index.js b/src/router/index.js
index ee401ccc..ab3b4f44 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -130,11 +130,16 @@ const routes = [
           query['feature_type_slug'] = slug_type_signal; // set feature_type slug in query
         }
         const offset = await featureAPI.getFeaturePosition(slug, slug_signal, query);
-        next({ 
-          name: 'details-signalement-filtre', 
-          params: { slug }, 
-          query: { ...query, offset } 
-        });        
+        if (offset) {
+          next({ 
+            name: 'details-signalement-filtre', 
+            params: { slug }, 
+            query: { ...query, offset } 
+          });        
+        } else {
+          store.commit('DISPLAY_MESSAGE', { comment: 'Désolé, une erreur est survenue pendant la recherche du signalement', level: 'negative' });
+          next({ path: '/' });
+        }
       } catch (error) {
         console.error('error', error);
         store.commit('DISPLAY_MESSAGE', { comment: `Désolé, une erreur est survenue pendant la recherche du signalement   -   ${error}`, level: 'negative' });
diff --git a/src/store/index.js b/src/store/index.js
index 0ec31562..becf00ef 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -183,33 +183,71 @@ export default new Vuex.Store({
         });
       }
     },
-
+    /**
+     * Action to retrieve user information.
+     * - If a token is present in the URL, it indicates a Single Sign-On (SSO) attempt, 
+     * in which case it logs out the user (if logged in) and connects via SSO with the token.
+     * Otherwise, it fetches user information from the Django API endpoint:
+     * - If no user is logged AND if the login should be done through SSO with a redirect,
+     * it naviguates to the login plateform, afterwards the user will be redirected with the token and the original url to open in geocontrib
+     * - Else it displays a message that the user is not logged but can still access the app as an anonymous user.
+     */
     async GET_USER_INFO({ state, commit, dispatch }) {
-      const token = new URLSearchParams(window.location.search).get('token');
-      if (token && this.state.configuration.VUE_APP_LOGIN_URL) {
-        // if user was previously connected through SSO, make sure he's logout before connecting through SSO, in case user changed
+      // Extract token from URL query parameters
+      const searchParams = new URLSearchParams(window.location.search);
+      const token = searchParams.get('token');
+      const url_redirect = searchParams.get('url_redirect');
+      // Check if token exists and SSO login URL is configured
+      if (token && state.configuration.VUE_APP_LOGIN_URL) {
+        // If user was previously connected through SSO, ensure they are logged out before reconnecting through SSO, in case user changed
         await dispatch('LOGOUT');
-        dispatch('CONNECT_SSO_WITH_TOKEN', token);
+        dispatch('CONNECT_SSO_WITH_TOKEN', { token, url_redirect });
       } else if (!state.user) {
+        // If user infos are not set, try to fetch them
         axios
-          .get(`${this.state.configuration.VUE_APP_DJANGO_API_BASE}user_info/`)
+          .get(`${state.configuration.VUE_APP_DJANGO_API_BASE}user_info/`)
           .then((response) => {
+            // Update the user state with received user data
             if (response && response.status === 200) {
               const user = response.data.user;
               commit('SET_USER', user);
             }
           })
-          .catch((err) => {
-            console.error(err);
-            commit('DISPLAY_MESSAGE', {
-              comment: `Vous n'êtes pas connecté actuellement.
-                Vous pouvez accéder à l'application en tant qu'utilisateur anonyme`
-            });
+          .catch(() => {
+            // If the instance is set to accept login with redirection
+            if (state.configuration.VUE_APP_SSO_LOGIN_URL_WITH_REDIRECT) {
+              commit('DISPLAY_MESSAGE', {
+                comment: 'Vous allez être redirigé vers la plateforme de connexion.'
+              });
+              // Prepare the url to redirect with vue-router that prefix the url with DOMAIN+BASE_URL
+              let urlRedirect = window.location.href;
+              let substringToRemove = state.configuration.BASE_URL;
+              // Find the index of the string to remove
+              let index = urlRedirect.indexOf(substringToRemove);
+              // If found, keep only the remaining part after the substring to remove
+              if (index !== -1) {
+                urlRedirect = urlRedirect.substring(index + substringToRemove.length);
+              }
+              // Call the SSO login plateform with url to redirect after login
+              window.open(`${state.configuration.VUE_APP_SSO_LOGIN_URL_WITH_REDIRECT}/?url_redirect=${urlRedirect}`, '_self');
+            } else {
+              // If the user is not logged in, display an info message
+              commit('DISPLAY_MESSAGE', {
+                comment: `Vous n'êtes pas connecté actuellement.
+                  Vous pouvez accéder à l'application en tant qu'utilisateur anonyme`
+              });
+            }
           });
       }
     },
-
-    async CONNECT_SSO_WITH_TOKEN({ state, commit, dispatch }, token) {
+    /**
+     * Action to connect user through SSO with a token.
+     * If the app was opened with a token in the url, it attempts a login,
+     * if the login is succesfull, it set the user in the state
+     * and retrieve information that would have been retrieved in GET_USER_INFO when logged.
+     * If the url contained a url to redirect, it calls the router to open this page.
+     */
+    async CONNECT_SSO_WITH_TOKEN({ state, commit, dispatch }, { token, url_redirect }) {
       axios
         .get(`${state.configuration.VUE_APP_DJANGO_API_BASE}login-token/?token=${token}`)
         .then((response) => {
@@ -219,15 +257,21 @@ export default new Vuex.Store({
             dispatch('GET_USER_LEVEL_PROJECTS');
             dispatch('GET_USER_LEVEL_PERMISSIONS');
             commit('DISPLAY_MESSAGE', {
-              comment: `Vous êtes maintenant connecté ${ user.first_name} ${ user.last_name}`, level: 'positive'
+              comment: `Vous êtes maintenant connecté ${user.first_name} ${user.last_name}`,
+              level: 'positive'
             });
             dispatch('projects/GET_PROJECTS');
+            if (url_redirect) {
+              // catch error from the router, because of second redirection to feature when call with a feature's id
+              router.push(url_redirect).catch((e) => e);
+            }
           }
         })
         .catch((err) => {
           console.error(err);
           commit('DISPLAY_MESSAGE', {
-            comment: 'La connexion a échoué.', level: 'negative'
+            comment: 'La connexion a échoué.',
+            level: 'negative'
           });
         });
     },
-- 
GitLab