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

Разбор исходника: src/actions/authentication.js

Файл: authentication.js на develop (85 строк)

Статус: не менялся между develop → нашей веткой

Тестируется: actions/authentication.test.js

Связан с: reducers/authentication.js — обрабатывает действия, отправляемые отсюда

1. Импорт (строка 1)

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

Две утилиты из rest.js:

2. Константы action types (строки 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';

Три строковые константы для использования редьюсером (reducers/authentication.js). switch(type) в редьюсере сопоставляет эти строки.

USER_LOGOUT был здесь раньше — удалён в коммите 7c60c2fbb (июль 2019).

3. Action creators (строки 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 — чистые функции, возвращающие простые объекты. Синхронные «сообщения» для редьюсера.

CreatorСигнатураЧто делает редьюсер
userLoginBegin()() → { type: BEGIN }Сброс: { loading: true, error: null, user: null }
userLoginSuccess(u, v, b, a)(obj, str, str, str?) → { type, payload }Записывает все 4 поля в state
userLoginFailure(e)(str) → { type, payload: { error } }Сохраняет ошибку, очищает user

4. catchError (строка 28)

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

Каррированная функция. Первый вызов захватывает dispatch, второй — error. Используется в .catch() обоих thunk'ов.

loadUserStatus() вызывает catchError(dispatch)({ message: undefined }) — передаёт { message: undefined } потому что сам обрабатывает ошибку редиректом.

5. loadUserStatus — проверка сессии (строки 30–63)

export const loadUserStatus = () => (dispatch) => {
    dispatch(userLoginBegin());
    return fetch(
        getServiceURL('userStatus'),
        { method: 'GET', credentials: 'include' },
    )
        .then(handleHTTPErrors)
        .then((response) => response.json())
        .then(({ userData, systemData, alertMessage }) => {
            dispatch(userLoginSuccess(
                userData,
                systemData.version,
                systemData.buildTimestamp,
                alertMessage,
            ));
        })
        .catch(() => {
            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 });
        });
};

Назначение: «Кто я?» — вызывается при старте приложения и после логина.

(a) Диспатчит USER_LOGIN_BEGIN.

(b) GET /rs/userStatus — отправляет сессионную куку. Попадает в UserStatusRest.kt:111.

(c–e) Успех: парсит JSON, диспатчит SUCCESS.

(f) Ошибка: 401 → редирект на /react/public/login?url=.... catchError(dispatch)({ message: undefined }) — очищает ошибку.

6. login — аутентификация (строки 65–85)

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

Назначение: отправить учётные данные. При успехе — узнать кто залогинился.

(a) Диспатчит BEGIN.

(b) POST /rsPublic/login. Сервер ставит JSESSIONID. Попадает в LoginPageRest.kt:93.

(c) stayLoggedIn: keepSignedIn — флажок «оставаться в системе». Сервер ставит куку stayLoggedIn на 30 дней (CookieService.kt:201).

(d–e) Успех → loadUserStatus()(dispatch). Именно поэтому тест ожидает 3 действия: BEGIN (login) + BEGIN (loadUserStatus) + SUCCESS.

(f) Ошибка → catchErrorFAILURE.

Поток действий

ЗАПУСК:
  ProjectForge.jsx → dispatch(loadUserStatus())
    └─ GET /rs/userStatus
         ├─ 200 → SUCCESS(userData, systemData, alertMessage)
         └─ 401 → редирект на /react/public/login

ЛОГИН:
  login(username, password, keepSignedIn)
    ├─ dispatch(BEGIN)
    ├─ POST /rsPublic/login
    ├─ сервер ставит JSESSIONID (+ stayLoggedIn если keepSignedIn)
    ├─ 200 → loadUserStatus()(dispatch) → BEGIN → SUCCESS
    └─ 401/ошибка → catchError → FAILURE

Связанные доки: комментарий к authentication.test.js | комментарий к reducers/authentication.js