feat(auth): проверка устройств на входе — запрос доступа и превью камеры

Отключаемый модуль (instance_settings.device_check, дефолт выключен):
запрос доступа к камере/микрофону на LoginPage и в карточке "Как вас
зовут?" (JoinPage), живое зеркальное превью и кнопки вкл/выкл камеры и
микрофона там же. На JoinPage кнопки определяют, с чем гость войдёт в
конференцию (RoomPage.LiveKitRoom audio/video вместо жёстких false) —
на LoginPage только пре-авторизуют разрешение, без UI (карточка ведёт
в лобби, применить выбор некуда). Вход в комнату по умолчанию, как и
раньше, с выключенными микрофоном/камерой.

Публичный GET /api/v1/public/settings отдаёт флаг модуля обеим
страницам до аутентификации.
This commit is contained in:
2026-08-09 18:09:10 +03:00
parent ba01548088
commit 7ee68b17ee
19 changed files with 713 additions and 7 deletions

View File

@@ -0,0 +1,43 @@
"""Тесты публичного эндпоинта настроек клиента (`/api/v1/public/settings`, сессия 33)."""
import httpx
import pytest_asyncio
from sqlalchemy.ext.asyncio import AsyncSession
from services.instance_settings import InstanceSettingsService, SettingsUpdateIn
@pytest_asyncio.fixture(autouse=True)
async def _reset_device_check(db_session: AsyncSession) -> None:
"""Сбросить `device_check_enabled` перед каждым тестом — общая dev-БД не изолирована
от ручных правок администратора (та же дисциплина, что и `_reset_registration_gating`
в `test_auth.py`); `db_session` не коммитится в реальную БД, см. `conftest.py`."""
await InstanceSettingsService(db_session).update(SettingsUpdateIn(device_check_enabled=False))
async def test_public_settings_disabled_by_default(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
response = await client.get("/api/v1/public/settings")
assert response.status_code == 200, response.text
assert response.json() == {"device_check_enabled": False}
async def test_public_settings_reflects_enabled(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
await InstanceSettingsService(db_session).update(SettingsUpdateIn(device_check_enabled=True))
await db_session.commit()
response = await client.get("/api/v1/public/settings")
assert response.status_code == 200, response.text
assert response.json() == {"device_check_enabled": True}
async def test_public_settings_requires_no_auth(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
"""Эндпоинт публичный — работает без заголовка `Authorization`, как и обязан
(обе страницы, которым он нужен, доступны до входа в систему)."""
response = await client.get("/api/v1/public/settings")
assert response.status_code == 200, response.text