feat(auth): несколько эталонных mail-доменов для верификации регистрации
Настройка «Эталон mail-домена» теперь хранит список доменов вместо
одного — email при регистрации принимается, если совпадает с любым из
них. Старое значение в БД ({"domain": str|None}) читается прозрачно
(обратная совместимость без Alembic-миграции) и переписывается в новую
форму ({"domains": [...]}) при первом же сохранении настроек. В админке
добавление/удаление доменов — списком чипов; на экране регистрации
подсказка о несовпадении домена перечисляет все эталонные варианты.
This commit is contained in:
@@ -6,19 +6,21 @@ import { AuthLayout } from '@/components/auth/AuthLayout'
|
||||
import { getRegistrationOptions, register } from '@/api/auth'
|
||||
import { ApiError, errorDetail } from '@/api/client'
|
||||
|
||||
/** Текст предупреждения о несовпадении домена почты с эталонным. */
|
||||
function domainMismatchMessage(domain: string): string {
|
||||
return `Укажите рабочую почту — регистрация доступна только для домена @${domain}`
|
||||
/** Текст предупреждения о несовпадении домена почты с эталонными. */
|
||||
function domainMismatchMessage(domains: string[]): string {
|
||||
const list = domains.map((domain) => `@${domain}`).join(' или ')
|
||||
return `Укажите рабочую почту — регистрация доступна только для домена ${list}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Экран регистрации (см. design/mockups/auth.html, блок «регистрация»).
|
||||
* Поле «Команда» показывается только если выбор команды включён в
|
||||
* настройках инстанса (`GET /auth/registration-options`, публичный эндпоинт).
|
||||
* Поле «Рабочая почта» дополнительно сверяется с эталонным доменом
|
||||
* (`registration-options.email_domain`), если в админке включена
|
||||
* верификация по домену — проверка идёт по blur и при сабмите, backend
|
||||
* при включённой верификации и чужом домене отвечает 400 `invalid_email_domain`.
|
||||
* Поле «Рабочая почта» дополнительно сверяется с эталонными доменами
|
||||
* (`registration-options.email_domains` — подходит совпадение с ЛЮБЫМ),
|
||||
* если в админке включена верификация по домену — проверка идёт по blur и
|
||||
* при сабмите, backend при включённой верификации и чужом домене отвечает
|
||||
* 400 `invalid_email_domain`.
|
||||
* После успешной регистрации показывает состояние «подтвердите почту»
|
||||
* (письмо со ссылкой backend в dev-режиме печатает в консоль).
|
||||
*/
|
||||
@@ -38,16 +40,16 @@ export function RegisterPage() {
|
||||
})
|
||||
const teamChoiceEnabled = registrationOptions?.team_choice_enabled ?? false
|
||||
const teams = registrationOptions?.teams ?? []
|
||||
const expectedEmailDomain = registrationOptions?.email_domain ?? null
|
||||
const expectedEmailDomains = registrationOptions?.email_domains ?? []
|
||||
|
||||
/** Домен после «@» не совпадает (без учёта регистра) с эталонным — `null`, если сверять не с чем. */
|
||||
/** Домен после «@» не совпадает (без учёта регистра) ни с одним эталонным — `null`, если сверять не с чем. */
|
||||
function checkEmailDomain(value: string): string | null {
|
||||
if (!expectedEmailDomain) return null
|
||||
if (expectedEmailDomains.length === 0) return null
|
||||
const atIndex = value.lastIndexOf('@')
|
||||
if (atIndex === -1) return null
|
||||
const domain = value.slice(atIndex + 1).trim().toLowerCase()
|
||||
if (domain !== expectedEmailDomain.toLowerCase()) {
|
||||
return domainMismatchMessage(expectedEmailDomain)
|
||||
if (!expectedEmailDomains.some((expected) => domain === expected.toLowerCase())) {
|
||||
return domainMismatchMessage(expectedEmailDomains)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -68,7 +70,7 @@ export function RegisterPage() {
|
||||
if (err instanceof ApiError && err.status === 409) {
|
||||
setError('Пользователь с таким email уже зарегистрирован')
|
||||
} else if (err instanceof ApiError && err.status === 400 && errorDetail(err) === 'invalid_email_domain') {
|
||||
setEmailDomainError(expectedEmailDomain ? domainMismatchMessage(expectedEmailDomain) : 'Регистрация с этим доменом почты недоступна')
|
||||
setEmailDomainError(expectedEmailDomains.length > 0 ? domainMismatchMessage(expectedEmailDomains) : 'Регистрация с этим доменом почты недоступна')
|
||||
} else {
|
||||
setError('Не удалось зарегистрироваться. Проверьте данные и попробуйте снова')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user