Files
vidconf/frontend/src/api/auth.ts
Max Ronzhin 4f82ebe17a
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
feat(auth): согласие на обработку персональных данных при регистрации
Отключаемый модуль (instance_settings.consent_policy): галочка + ссылка на
публичную страницу регламента на форме регистрации, редактируемый в админке
текст с типовым шаблоном по умолчанию (плейсхолдеры под организацию, не
проходил юридическую проверку), версия текста растёт при каждой правке.
Факт согласия хранится в users (consent_version, consent_given_at) — второй
эшелон проверки на сервере, как и для отключаемых модулей ранее. Дефолт
(выключено) сохраняет поведение существующих инсталляций, у уже
зарегистрированных пользователей согласие не запрашивается.
2026-08-04 22:20:00 +03:00

90 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* API-функции аутентификации.
*/
import { apiRequest } from '@/api/client'
export interface RegisterPayload {
email: string
name_user: string
password: string
/** Выбранная команда — только если выбор команды включён в настройках инстанса. */
team_id?: string | null
/** Согласие на обработку персональных данных — обязано быть `true`, если `consent_required`. */
consent_accepted?: boolean
}
/** Команда, доступная для выбора на экране регистрации. */
export interface RegistrationTeamOption {
id: string
name: string
}
/** Параметры экрана регистрации — зависят от настройки инстанса `registration_team_choice`. */
export interface RegistrationOptions {
team_choice_enabled: boolean
teams: RegistrationTeamOption[]
/** Эталонные домены почты при включённой верификации (email подходит под любой), иначе пуст. */
email_domains: string[]
/** Обязательна ли галочка согласия на обработку персональных данных на форме регистрации. */
consent_required: boolean
/** Текст регламента — отдаётся всегда, независимо от `consent_required` (нужен и странице регламента). */
consent_text: string
/** Номер редакции текста, с которой согласится пользователь при регистрации. */
consent_version: number
}
export interface CurrentUser {
id: string
email: string
name_user: string
role: string
/** URL загруженного аватара, `null` — показывается заглушка с инициалами (см. `Avatar`). */
avatar_url: string | null
team_id: string | null
team_name: string | null
}
export interface TokenResponse {
access_token: string
token_type: string
}
/** Регистрация нового пользователя. 409 — если email уже занят. */
export async function register(payload: RegisterPayload): Promise<void> {
await apiRequest('/auth/register', { method: 'POST', body: payload, skipAuthRefresh: true })
}
/**
* Параметры экрана регистрации — публичный эндпоинт, доступен без авторизации.
* Если выбор команды отключён в настройках инстанса, `teams` пуст.
*/
export async function getRegistrationOptions(): Promise<RegistrationOptions> {
return apiRequest<RegistrationOptions>('/auth/registration-options', { skipAuthRefresh: true })
}
/** Подтверждение почты по токену из письма. 400 — если ссылка просрочена/недействительна. */
export async function verifyEmail(token: string): Promise<void> {
await apiRequest('/auth/verify-email', { method: 'POST', body: { token }, skipAuthRefresh: true })
}
/**
* Вход по логину/паролю. Backend ждёт OAuth2-form-data (username=email).
* Refresh-токен приходит httpOnly cookie — тело ответа содержит только access.
*/
export async function login(email: string, password: string): Promise<TokenResponse> {
const form = new URLSearchParams()
form.set('username', email)
form.set('password', password)
return apiRequest<TokenResponse>('/auth/token', { method: 'POST', body: form, skipAuthRefresh: true })
}
/** Явный выход — инвалидирует refresh-сессию на backend. */
export async function logout(): Promise<void> {
await apiRequest('/auth/logout', { method: 'POST' })
}
/** Текущий пользователь по access-токену. */
export async function getMe(): Promise<CurrentUser> {
return apiRequest<CurrentUser>('/users/me')
}