first commit
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled

This commit is contained in:
2026-07-23 02:38:05 +03:00
commit 8757bec8ac
335 changed files with 61527 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
"""Проверка права входа в конференцию (статус/пароль) и генерация ответа join.
Заменяет `services/room_access.py`: комнаты больше не конкурируют за
время («правило часа» удалено вместе с бронированием, ADR-001, п.5), но
пароль закрытой конференции по-прежнему проверяется здесь же — для обычного
пользователя и гостя одинаково.
"""
import json
from core.config import get_settings
from core.security import verify_password
from models.conference import Conference
from schemas.conferences import JoinOut
from services.livekit_tokens import create_room_access_token
class ConferenceEndedError(Exception):
"""Конференция завершена (терминальный статус) — повторный вход невозможен."""
class PasswordRequiredError(Exception):
"""Конференция закрыта паролем; пароль не передан."""
class InvalidPasswordError(Exception):
"""Указанный пароль не совпадает с паролем закрытой конференции."""
def ensure_joinable(conference: Conference, *, password: str | None) -> None:
"""Проверить, что в конференцию можно войти прямо сейчас.
Бросает `ConferenceEndedError` для терминального статуса `ended`
(история и саммари остаются, но повторный вход невозможен — ADR-001,
п.2), либо `PasswordRequiredError`/`InvalidPasswordError` для закрытой
паролем конференции. Ничего не бросает для открытой конференции в
статусе `scheduled`/`active`.
"""
if conference.status == "ended":
raise ConferenceEndedError
if not conference.is_closed:
return
if conference.password_hash is None or password is None:
raise PasswordRequiredError
if not verify_password(password, conference.password_hash):
raise InvalidPasswordError
def build_join(
conference: Conference,
*,
identity: str,
name: str,
chat_enabled: bool,
avatar_url: str | None = None,
) -> JoinOut:
"""Построить ответ join: LiveKit access-токен для входа в комнату конференции.
Имя LiveKit-комнаты всегда равно `conference.slug` (ADR-001, п.4).
`chat_enabled` — снятый вызывающей стороной тоггл `instance_settings`:
читается здесь параметром, а не заново из БД, чтобы не плодить
отдельный запрос настроек на каждый join. `avatar_url` прокидывается
в метаданные токена как JSON
`{"avatar_url": ...}`; `None` (гость либо пользователь без аватара) —
метаданные не выставляются вовсе.
"""
settings = get_settings()
metadata = json.dumps({"avatar_url": avatar_url}) if avatar_url else None
token = create_room_access_token(
room_name=conference.slug, identity=identity, name=name, metadata=metadata
)
return JoinOut(
livekit_url=settings.livekit_public_url,
token=token,
room_name=conference.slug,
conference_id=conference.id,
chat_enabled=chat_enabled,
)