Настройка «Эталон mail-домена» теперь хранит список доменов вместо
одного — email при регистрации принимается, если совпадает с любым из
них. Старое значение в БД ({"domain": str|None}) читается прозрачно
(обратная совместимость без Alembic-миграции) и переписывается в новую
форму ({"domains": [...]}) при первом же сохранении настроек. В админке
добавление/удаление доменов — списком чипов; на экране регистрации
подсказка о несовпадении домена перечисляет все эталонные варианты.
82 lines
3.3 KiB
TypeScript
82 lines
3.3 KiB
TypeScript
/**
|
||
* API-функции аутентификации.
|
||
*/
|
||
import { apiRequest } from '@/api/client'
|
||
|
||
export interface RegisterPayload {
|
||
email: string
|
||
name_user: string
|
||
password: string
|
||
/** Выбранная команда — только если выбор команды включён в настройках инстанса. */
|
||
team_id?: string | null
|
||
}
|
||
|
||
/** Команда, доступная для выбора на экране регистрации. */
|
||
export interface RegistrationTeamOption {
|
||
id: string
|
||
name: string
|
||
}
|
||
|
||
/** Параметры экрана регистрации — зависят от настройки инстанса `registration_team_choice`. */
|
||
export interface RegistrationOptions {
|
||
team_choice_enabled: boolean
|
||
teams: RegistrationTeamOption[]
|
||
/** Эталонные домены почты при включённой верификации (email подходит под любой), иначе пуст. */
|
||
email_domains: string[]
|
||
}
|
||
|
||
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')
|
||
}
|