""" 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 )