uchill/backend/apps/video/jitsi_views.py

240 lines
9.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
API views для работы с Jitsi Meet.
"""
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.conf import settings
from .jitsi_service import JitsiService
from .models import VideoRoom
from apps.schedule.models import Lesson
from apps.users.utils import format_datetime_for_user
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def create_jitsi_room(request):
"""
Создание Jitsi комнаты для занятия.
POST /api/video/jitsi/create-room/
Body: {
"lesson_id": 123
}
Returns:
{
"room_name": "uuid",
"room_url": "http://jitsi.../room",
"jwt_token": "token",
"video_room_id": 1
}
"""
lesson_id = request.data.get('lesson_id')
if not lesson_id:
return Response(
{'error': 'lesson_id обязателен'},
status=status.HTTP_400_BAD_REQUEST
)
try:
lesson = Lesson.objects.get(id=lesson_id)
except Lesson.DoesNotExist:
return Response(
{'error': 'Занятие не найдено'},
status=status.HTTP_404_NOT_FOUND
)
# Проверка прав доступа
user = request.user
if user != lesson.mentor and (not hasattr(user, 'client_profile') or user.client_profile != lesson.client):
return Response(
{'error': 'Нет доступа к этому занятию'},
status=status.HTTP_403_FORBIDDEN
)
# Проверка времени - блокируем доступ через 10 минут после фактического окончания
from django.utils import timezone
from datetime import timedelta
if lesson.end_time:
now = timezone.now()
# Используем фактическое время завершения, если оно есть, иначе запланированное
actual_end_time = lesson.completed_at if (lesson.status == 'completed' and lesson.completed_at) else lesson.end_time
allowed_end_time = actual_end_time + timedelta(minutes=10)
if now > allowed_end_time:
return Response(
{'error': 'Доступ к видеокомнате закрыт. Время занятия истекло более 10 минут назад.'},
status=status.HTTP_403_FORBIDDEN
)
# Проверяем, есть ли уже VideoRoom для этого занятия
try:
video_room = VideoRoom.objects.get(lesson=lesson)
room_name = str(video_room.room_id) # Преобразуем UUID в строку
except VideoRoom.DoesNotExist:
# Создаем новую комнату
room_name = str(JitsiService.generate_room_name()) # Преобразуем UUID в строку
# Получаем User объект клиента
client_user = lesson.client.user if hasattr(lesson.client, 'user') else lesson.client
video_room = VideoRoom.objects.create(
lesson=lesson,
mentor=lesson.mentor,
client=client_user,
room_id=room_name,
is_recording=True,
max_participants=2
)
# Определяем роль пользователя
is_moderator = user == lesson.mentor
user_role = 'mentor' if is_moderator else 'client'
# Получаем данные пользователя
user_name = user.get_full_name() or user.email
user_email = user.email
avatar_url = request.build_absolute_uri(user.avatar.url) if user.avatar else None
# Генерируем JWT токен
jwt_token = JitsiService.generate_jwt_token(
room_name=room_name,
user_id=user.id,
user_name=user_name,
user_email=user_email,
is_moderator=is_moderator,
avatar_url=avatar_url,
expires_in_minutes=180 # 3 часа
)
# Получаем config overrides
config_overrides = JitsiService.get_default_config_overrides(user_role)
# Генерируем URL комнаты
room_url = JitsiService.get_room_url(
room_name=room_name,
jwt_token=jwt_token,
config_overrides=config_overrides
)
return Response({
'room_name': str(room_name), # Преобразуем UUID в строку
'room_url': room_url,
'jwt_token': jwt_token,
'video_room_id': video_room.id,
'is_moderator': is_moderator,
'lesson': {
'id': lesson.id,
'title': lesson.title,
'start_time': format_datetime_for_user(lesson.start_time, request.user.timezone) if lesson.start_time else None,
'end_time': format_datetime_for_user(lesson.end_time, request.user.timezone) if lesson.end_time else None,
}
})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_jitsi_config(request):
"""
Получение конфигурации Jitsi для фронтенда.
GET /api/video/jitsi/config/
Returns:
{
"jitsi_url": "http://127.0.0.1:8443",
"domain": "meet.jitsi",
"app_name": "Платформа"
}
"""
return Response({
'jitsi_url': getattr(settings, 'JITSI_PUBLIC_URL', 'http://127.0.0.1:8443'),
'domain': getattr(settings, 'JITSI_XMPP_DOMAIN', 'meet.jitsi'),
'app_name': getattr(settings, 'JITSI_APP_NAME', 'Платформа'),
})
@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def delete_jitsi_room_by_lesson(request, lesson_id):
"""
Удаление Jitsi видеокомнаты по ID занятия.
DELETE /api/video/jitsi/rooms/lesson/{lesson_id}/
Проверяет, что прошло минимум 10 минут после окончания занятия.
Только ментор может удалять видеокомнату.
"""
from django.utils import timezone
from datetime import timedelta
try:
lesson = Lesson.objects.get(id=lesson_id)
except Lesson.DoesNotExist:
return Response(
{'error': 'Занятие не найдено'},
status=status.HTTP_404_NOT_FOUND
)
# Проверка прав доступа - только ментор может удалять
user = request.user
if user != lesson.mentor:
return Response(
{'error': 'Только ментор может удалять видеокомнату'},
status=status.HTTP_403_FORBIDDEN
)
# Проверка времени - можно удалять только через 10 минут после фактического окончания
if lesson.end_time:
now = timezone.now()
# Используем фактическое время завершения, если оно есть, иначе запланированное
actual_end_time = lesson.completed_at if (lesson.status == 'completed' and lesson.completed_at) else lesson.end_time
allowed_delete_time = actual_end_time + timedelta(minutes=10)
if now < allowed_delete_time:
minutes_remaining = int((allowed_delete_time - now).total_seconds() / 60)
return Response(
{
'error': f'Видеокомнату можно удалить только через 10 минут после окончания занятия. Осталось {minutes_remaining} минут.'
},
status=status.HTTP_400_BAD_REQUEST
)
else:
return Response(
{'error': 'Время окончания занятия не указано'},
status=status.HTTP_400_BAD_REQUEST
)
# Проверяем, есть ли VideoRoom для этого занятия
try:
video_room = VideoRoom.objects.get(lesson=lesson)
# Удаляем комнату из SFU сервера (если используется)
from .services import get_sfu_client, SFUClientError
sfu_client = get_sfu_client()
try:
sfu_client.delete_room(str(video_room.room_id))
except SFUClientError as e:
# Логируем ошибку, но продолжаем удаление из Django
import logging
logger = logging.getLogger(__name__)
logger.warning(f'Не удалось удалить комнату из SFU сервера: {e}')
# Удаляем комнату из базы данных
video_room.delete()
return Response(
{'message': 'Видеокомната успешно удалена'},
status=status.HTTP_200_OK
)
except VideoRoom.DoesNotExist:
return Response(
{'error': 'Видеокомната для этого занятия не найдена'},
status=status.HTTP_404_NOT_FOUND
)