Отключаемый в админке модуль `virtual_background` (дефолт — выключен, чтобы
обновление не меняло продукт у тех, кто ничего не просил). Флаг едет клиенту
двумя путями: на публичные страницы входа — через `GET /public/settings`,
участнику комнаты — в join-ответе (`JoinOut`), потому что значение нужно на
руках ДО первого рендера комнаты, а `/admin/settings` доступен только админу.
Свои картинки пользователя (`/users/me/backgrounds`, GET/POST/DELETE):
файлы на диске (`backgrounds/{user_id}/{id}.{ext}`), в БД только путь — как у
аватаров, «чтобы не грузили БД». Лимит в 10 штук проверяется на сервере под
блокировкой строки пользователя: две одновременные загрузки иначе обе увидели
бы «уже девять» и обе прошли бы. Удаление сносит и запись, и файл; чужую
картинку по её id удалить нельзя — владелец в условии запроса.
Валидация загрузки (допустимые форматы, магические байты, реальный размер)
выделена из `services/avatars.py` в общий `services/images.py`: правила у
аватара и фона одни и те же, а разъехавшись, они дали бы дыру ровно там, ради
чего проверка и написана. Публичный API аватаров не изменился.
Сжимает картинку клиент (Pillow на бэкенде нет), но серверная валидация
остаётся полноценной — запрос может прийти и мимо интерфейса.
Новый ключ настройки вписан в `_MANAGED_KEYS` тестов: без этого включённый
в общей dev-БД модуль ронял чужие тесты, которые считают себя изолированными.
60 lines
2.7 KiB
Python
60 lines
2.7 KiB
Python
"""Тесты публичного эндпоинта настроек клиента (`/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_public_flags(db_session: AsyncSession) -> None:
|
||
"""Сбросить публичные тогглы перед каждым тестом — общая dev-БД не изолирована
|
||
от ручных правок администратора (та же дисциплина, что и `_reset_registration_gating`
|
||
в `test_auth.py`); `db_session` не коммитится в реальную БД, см. `conftest.py`."""
|
||
await InstanceSettingsService(db_session).update(
|
||
SettingsUpdateIn(device_check_enabled=False, virtual_background_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, "virtual_background_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"] is True
|
||
|
||
|
||
async def test_public_settings_reflects_virtual_background_enabled(
|
||
client: httpx.AsyncClient, db_session: AsyncSession
|
||
) -> None:
|
||
"""Замена фона нужна и на публичном превью входа (`JoinPage`) — до аутентификации."""
|
||
await InstanceSettingsService(db_session).update(
|
||
SettingsUpdateIn(virtual_background_enabled=True)
|
||
)
|
||
await db_session.commit()
|
||
|
||
response = await client.get("/api/v1/public/settings")
|
||
assert response.status_code == 200, response.text
|
||
assert response.json()["virtual_background_enabled"] is 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
|