feat(auth): согласие на обработку персональных данных при регистрации
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled

Отключаемый модуль (instance_settings.consent_policy): галочка + ссылка на
публичную страницу регламента на форме регистрации, редактируемый в админке
текст с типовым шаблоном по умолчанию (плейсхолдеры под организацию, не
проходил юридическую проверку), версия текста растёт при каждой правке.
Факт согласия хранится в users (consent_version, consent_given_at) — второй
эшелон проверки на сервере, как и для отключаемых модулей ранее. Дефолт
(выключено) сохраняет поведение существующих инсталляций, у уже
зарегистрированных пользователей согласие не запрашивается.
This commit is contained in:
2026-08-04 22:20:00 +03:00
parent 0e029a2bf8
commit 4f82ebe17a
19 changed files with 615 additions and 9 deletions

View File

@@ -48,6 +48,7 @@ from services.instance_settings import (
BootstrapOverrides,
InstanceSettingsService,
InvalidAiLevelError,
InvalidConsentPolicyError,
InvalidContactEmailError,
InvalidEmailDomainError,
InvalidTimezoneError,
@@ -73,6 +74,7 @@ _MANAGED_KEYS = (
"registration_email_domain",
"contact_email",
"media_limits",
"consent_policy",
)
@@ -130,6 +132,7 @@ async def test_ensure_bootstrapped_imports_yaml_defaults(
"registration_email_domain",
"contact_email",
"media_limits",
"consent_policy",
}
cfg = await service.get()
assert cfg.transcriber.provider == "faster_whisper_cpu"
@@ -149,6 +152,13 @@ async def test_ensure_bootstrapped_imports_yaml_defaults(
# потолку `StageGrid` (5×5).
assert cfg.media_limits.publish_quality_cap == "off"
assert cfg.media_limits.stage_max_tiles == 25
# Согласие на обработку персональных данных выключено по умолчанию
# (дефолт сохраняет поведение существующих инсталляций), но дефолтный
# текст-шаблон уже на месте — публичная страница регламента осмысленна
# даже при выключенном модуле.
assert cfg.consent_required is False
assert cfg.consent_policy_text != ""
assert cfg.consent_policy_version == 1
async def test_ensure_bootstrapped_is_idempotent_and_keeps_admin_edits(
@@ -351,6 +361,61 @@ async def test_registration_team_choice_toggle(
assert reloaded.registration_team_choice is True
async def test_consent_policy_toggle_without_text_change_keeps_version(
db_session: AsyncSession, clean_instance_settings: None
) -> None:
"""Включение флага без правки текста не увеличивает версию."""
service = InstanceSettingsService(db_session)
await service.ensure_bootstrapped(PLUGINS_YAML)
baseline = await service.get()
assert baseline.consent_required is False
cfg = await service.update(SettingsUpdateIn(consent_required=True))
assert cfg.consent_required is True
assert cfg.consent_policy_version == baseline.consent_policy_version
reloaded = await service.get()
assert reloaded.consent_required is True
assert reloaded.consent_policy_version == baseline.consent_policy_version
async def test_consent_policy_text_change_bumps_version(
db_session: AsyncSession, clean_instance_settings: None
) -> None:
"""Правка текста регламента увеличивает версию — иначе «версия согласия» в БД бессмысленна."""
service = InstanceSettingsService(db_session)
await service.ensure_bootstrapped(PLUGINS_YAML)
baseline = await service.get()
cfg = await service.update(SettingsUpdateIn(consent_policy_text="Новый текст регламента"))
assert cfg.consent_policy_text == "Новый текст регламента"
assert cfg.consent_policy_version == baseline.consent_policy_version + 1
# Повторное сохранение ТОГО ЖЕ текста версию больше не двигает.
cfg2 = await service.update(SettingsUpdateIn(consent_policy_text="Новый текст регламента"))
assert cfg2.consent_policy_version == cfg.consent_policy_version
reloaded = await service.get()
assert reloaded.consent_policy_version == cfg.consent_policy_version
async def test_consent_policy_enable_with_empty_text_rejected(
db_session: AsyncSession, clean_instance_settings: None
) -> None:
"""Нельзя включить обязательное согласие, если текст регламента пуст."""
service = InstanceSettingsService(db_session)
await service.ensure_bootstrapped(PLUGINS_YAML)
with pytest.raises(InvalidConsentPolicyError):
await service.update(
SettingsUpdateIn(consent_required=True, consent_policy_text=" ")
)
cfg = await service.get()
assert cfg.consent_required is False
async def test_registration_email_domain_enable_without_domain_rejected(
db_session: AsyncSession, clean_instance_settings: None
) -> None: