⚠️ Draft documentation
Work in progress — some sections may be incomplete, typos possible. Last updated: 2026-05-10.
EN | DE | RU | FR | ES
FR

Parcours du code source : src/actions/authentication.js

Fichier : authentication.js sur develop (85 lignes)

Statut : inchangé entre develop → notre branche

Testé par : actions/authentication.test.js

En rapport avec : reducers/authentication.js — traite les actions dispatchées ici

1. Imports (ligne 1)

import { getServiceURL, handleHTTPErrors } from '../utilities/rest';

Deux utilitaires provenant de rest.js :

Aucune autre dépendance. Le fichier est autonome hormis ces deux helpers.

2. Constantes de types d'actions (lignes 3–5)

export const USER_LOGIN_BEGIN   = 'USER_LOGIN_BEGIN';
export const USER_LOGIN_SUCCESS = 'USER_LOGIN_SUCCESS';
export const USER_LOGIN_FAILURE = 'USER_LOGIN_FAILURE';

Trois constantes de chaîne exportées pour être utilisées par le reducer (reducers/authentication.js). Le switch(type) du reducer correspond à ces chaînes exactes.

Pourquoi des chaînes et non des symboles ? Convention Redux — les chaînes sont sérialisables, débogables dans Redux DevTools, et fonctionnent entre les modules sans nécessiter de références partagées.

Note : USER_LOGOUT se trouvait ici auparavant — supprimé dans le commit 7c60c2fbb (juil. 2019) lorsque la déconnexion a été simplifiée pour ne plus faire que dispatch USER_LOGIN_BEGIN (réinitialise l'état).

3. Fonctions créatrices d'actions (Action Creators) (lignes 7–26)

export const userLoginBegin = () => ({
    type: USER_LOGIN_BEGIN,
});

export const userLoginSuccess = (user, version, buildTimestamp, alertMessage) => ({
    type: USER_LOGIN_SUCCESS,
    payload: { user, version, buildTimestamp, alertMessage },
});

export const userLoginFailure = (error) => ({
    type: USER_LOGIN_FAILURE,
    payload: { error },
});

Action creators — des fonctions pures retournant des objets simples. Ce sont les « messages » synchrones envoyés au reducer.

CréateurSignatureAction du reducer
userLoginBegin() () → { type: BEGIN } Réinitialise à { loading: true, error: null, user: null } — spinner lancé, anciennes données effacées
userLoginSuccess(user, version, buildTimestamp, alertMessage) (obj, str, str, str?) → { type, payload } Écrit les quatre champs dans l'état — user, version, buildTimestamp, alertMessage. loading → false
userLoginFailure(error) (str) → { type, payload: { error } } Stocke le message d'erreur, efface user, loading → false

Ces fonctions sont appelées depuis les thunks ci-dessous — jamais dispatchées directement par les composants.

4. Helper catchError (ligne 28)

const catchError = (dispatch) => (error) => dispatch(userLoginFailure(error.message));

Fonction curryfiée : catchError(dispatch)(error).

Utilisé dans les chaînes .catch() de login() et loadUserStatus() :

5. loadUserStatus — vérification de session (lignes 30–63)

export const loadUserStatus = () => (dispatch) => {
    dispatch(userLoginBegin());                                    // (a)

    return fetch(                                                   // (b)
        getServiceURL('userStatus'),
        { method: 'GET', credentials: 'include' },
    )
        .then(handleHTTPErrors)                                    // (c)
        .then((response) => response.json())                       // (d)
        .then(({ userData, systemData, alertMessage }) => {        // (e)
            dispatch(userLoginSuccess(
                userData,
                systemData.version,
                systemData.buildTimestamp,
                alertMessage,
            ));
        })
        .catch(() => {                                             // (f)
            const { pathname, search } = window.location;
            const href = pathname + search;
            if (!pathname.startsWith('/react/public/login')
                && !pathname.startsWith('/react/public/datatransfer/')) {
                window.location.href =
                    `/react/public/login?url=${encodeURIComponent(href)}`;
            }
            catchError(dispatch)({ message: undefined });
        });
};

Rôle : « Qui suis-je ? » — appelé au démarrage de l'application et après la connexion pour vérifier si l'utilisateur a une session valide.

(a) Dispatch USER_LOGIN_BEGIN — spinner lancé, ancien état effacé.

(b) GET /rs/userStatus — envoie le cookie de session (credentials: 'include'). Appelle UserStatusRest.kt:111.

(c) handleHTTPErrors — si status ≠ 2xx, lève Error('Fetch failed: Error {status}'). Passe au .catch().

(d) Analyse la réponse JSON. Structure attendue : { userData: {...}, systemData: {version, buildTimestamp}, alertMessage?: string }.

(e) Déstructure et dispatch USER_LOGIN_SUCCESS avec tous les champs. Le reducer les écrit dans l'état.

(f) Session invalide ou expirée. Deux cas :

Dispatch : catchError(dispatch)({ message: undefined })error.message sera undefined. Le reducer stocke { error: undefined } — efface efficacement toute erreur précédente.

Cet appel est effectué :

6. login — authentification (lignes 65–85)

export const login = (username, password, keepSignedIn) => (dispatch) => {
    dispatch(userLoginBegin());                                    // (a)

    return fetch(                                                   // (b)
        getServiceURL('/rsPublic/login'),
        {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                username,
                password,
                stayLoggedIn: keepSignedIn,                        // (c)
            }),
            credentials: 'include',
        },
    )
        .then(handleHTTPErrors)                                    // (d)
        .then(() => loadUserStatus()(dispatch))                    // (e)
        .catch(catchError(dispatch));                              // (f)
};

Rôle : Envoyer les identifiants au serveur. En cas de succès, interroger la session pour récupérer les données utilisateur.

(a) Dispatch USER_LOGIN_BEGIN — spinner lancé.

(b) POST /rsPublic/login avec un corps JSON. Appelle LoginPageRest.kt:93LoginService.authenticate(). Le serveur définit le cookie JSESSIONID en cas de succès.

(c) stayLoggedIn: keepSignedIn — le flag « se souvenir de moi ». Quand true, le serveur définit en plus un cookie stayLoggedIn (CookieService.kt:201) valable 30 jours. À la prochaine visite, ce cookie renouvelle automatiquement la session sans mot de passe.

(d) handleHTTPErrors — si la connexion échoue (401, 403, etc.), lève une erreur et passe au .catch().

(e) En cas de succès (200) : enchaîne avec loadUserStatus(). La connexion n'authentifie que — il faut quand même savoir qui s'est connecté. loadUserStatus()(dispatch) invoque le thunk manuellement (il retourne (dispatch) => {...}, donc on l'appelle avec dispatch). C'est pourquoi le test attend 3 actions : BEGIN (login) + BEGIN (loadUserStatus) + SUCCESS (loadUserStatus).

(f) En cas d'échec : catchError(dispatch) dispatch USER_LOGIN_FAILURE avec le message d'erreur — ex. 'Fetch failed: Error 401' pour un mot de passe incorrect.

Résumé : flux d'actions

DÉMARRAGE DE L'APP :
  ProjectForge.jsx → dispatch(loadUserStatus())
    └─ GET /rs/userStatus
         ├─ 200 → SUCCESS(userData, systemData, alertMessage)
         └─ 401 → redirige vers /react/public/login

CONNEXION :
  login(username, password, keepSignedIn)
    ├─ dispatch(BEGIN)
    ├─ POST /rsPublic/login
    ├─ le serveur définit JSESSIONID (+ cookie stayLoggedIn si keepSignedIn)
    ├─ 200 → loadUserStatus()(dispatch)
    │   └─ GET /rs/userStatus → BEGIN → SUCCESS
    └─ 401/erreur → catchError → FAILURE

APRÈS CONNEXION :
  L'utilisateur revient à la page initiale. ProjectForge.jsx est remonté.
  loadUserStatus() s'exécute à nouveau — cette fois JSESSIONID est valide → SUCCESS

Documentation associée : commentaire sur le diff de authentication.test.js | commentaire sur le diff de reducers/authentication.js