You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.6 KiB
201 lines
6.6 KiB
import hashlib
|
|
import hmac
|
|
import json
|
|
import tempfile
|
|
from datetime import timedelta
|
|
from unittest import mock
|
|
|
|
from django.core.management import call_command
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from django.test import override_settings
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
from dj_language.models import Language
|
|
from rest_framework import status
|
|
from rest_framework.test import APITestCase
|
|
|
|
from apps.account.models import ProfessorUser, StudentUser
|
|
from apps.course.models import (
|
|
Course,
|
|
CourseCategory,
|
|
CourseLiveSession,
|
|
LiveSessionUser,
|
|
)
|
|
|
|
|
|
@override_settings(
|
|
PLUGNMEET_API_SECRET='test-secret',
|
|
MEDIA_ROOT=tempfile.gettempdir(),
|
|
)
|
|
class PlugNMeetWebhookLiveSessionTests(APITestCase):
|
|
def setUp(self):
|
|
Language.objects.update_or_create(
|
|
id=69,
|
|
defaults={
|
|
'name': 'English',
|
|
'code': 'en',
|
|
'status': True,
|
|
'countries': ['US'],
|
|
},
|
|
)
|
|
self.professor = ProfessorUser.objects.create(
|
|
email='webhook-prof@example.com',
|
|
fullname='Webhook Professor',
|
|
experience_years=8,
|
|
)
|
|
self.student = StudentUser.objects.create(
|
|
email='webhook-student@example.com',
|
|
fullname='Webhook Student',
|
|
)
|
|
self.category = CourseCategory.objects.create(
|
|
name='Webhook Category',
|
|
slug='webhook-category',
|
|
)
|
|
thumbnail = SimpleUploadedFile(
|
|
'thumb.jpg',
|
|
b'filecontent',
|
|
content_type='image/jpeg',
|
|
)
|
|
self.course = Course.objects.create(
|
|
title='Webhook Course',
|
|
slug='webhook-course',
|
|
category=self.category,
|
|
professor=self.professor,
|
|
thumbnail=thumbnail,
|
|
video_type=Course.VedioTypeChoices.YOUTUBE_LINK,
|
|
video_link='https://example.com/video',
|
|
is_online=True,
|
|
online_link='https://example.com/live',
|
|
level=Course.LevelChoices.BEGINNER,
|
|
duration=10,
|
|
lessons_count=1,
|
|
description='Description',
|
|
short_description='Short',
|
|
status=Course.StatusChoices.ONGOING,
|
|
is_free=True,
|
|
)
|
|
self.session = CourseLiveSession.objects.create(
|
|
course=self.course,
|
|
room_id='room-16-1781160705',
|
|
subject='Webhook Course Live Session',
|
|
started_at=timezone.now(),
|
|
)
|
|
LiveSessionUser.objects.create(
|
|
session=self.session,
|
|
user=self.student,
|
|
role='participant',
|
|
entered_at=timezone.now(),
|
|
is_online=True,
|
|
)
|
|
|
|
def _post_webhook(self, payload: dict):
|
|
body = json.dumps(payload, ensure_ascii=False).encode('utf-8')
|
|
signature = hmac.new(
|
|
b'test-secret',
|
|
body,
|
|
hashlib.sha256,
|
|
).hexdigest()
|
|
url = reverse('plugnmeet-webhook')
|
|
return self.client.post(
|
|
url,
|
|
data=body,
|
|
content_type='application/webhook+json',
|
|
HTTP_HASH_TOKEN=signature,
|
|
)
|
|
|
|
def test_room_finished_with_room_name_closes_live_session(self):
|
|
response = self._post_webhook(
|
|
{
|
|
'event': 'room_finished',
|
|
'room': {
|
|
'name': self.session.room_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.session.refresh_from_db()
|
|
self.assertIsNotNone(self.session.ended_at)
|
|
self.assertFalse(
|
|
LiveSessionUser.objects.get(session=self.session, user=self.student).is_online
|
|
)
|
|
|
|
def test_session_ended_event_closes_live_session(self):
|
|
second_session = CourseLiveSession.objects.create(
|
|
course=self.course,
|
|
room_id='room-16-1781160999',
|
|
subject='Second Live Session',
|
|
started_at=timezone.now(),
|
|
)
|
|
|
|
response = self._post_webhook(
|
|
{
|
|
'event': 'session_ended',
|
|
'room': {
|
|
'name': second_session.room_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
second_session.refresh_from_db()
|
|
self.assertIsNotNone(second_session.ended_at)
|
|
|
|
def test_last_moderator_leave_schedules_auto_close(self):
|
|
LiveSessionUser.objects.create(
|
|
session=self.session,
|
|
user=self.professor,
|
|
role='moderator',
|
|
entered_at=timezone.now(),
|
|
is_online=True,
|
|
)
|
|
|
|
response = self._post_webhook(
|
|
{
|
|
'event': 'participant_left',
|
|
'room': {
|
|
'name': self.session.room_id,
|
|
},
|
|
'participant': {
|
|
'identity': str(self.professor.id),
|
|
},
|
|
}
|
|
)
|
|
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
self.session.refresh_from_db()
|
|
self.assertIsNotNone(self.session.last_moderator_left_at)
|
|
self.assertIsNotNone(self.session.auto_close_after_moderator_exit_at)
|
|
|
|
@mock.patch('apps.course.management.commands.auto_close_professorless_live_sessions.PlugNMeetClient')
|
|
def test_auto_close_command_closes_professorless_session(self, mock_client_cls):
|
|
LiveSessionUser.objects.create(
|
|
session=self.session,
|
|
user=self.professor,
|
|
role='moderator',
|
|
entered_at=timezone.now() - timedelta(minutes=20),
|
|
exited_at=timezone.now() - timedelta(minutes=15),
|
|
is_online=False,
|
|
)
|
|
self.session.last_moderator_left_at = timezone.now() - timedelta(minutes=15)
|
|
self.session.auto_close_after_moderator_exit_at = timezone.now() - timedelta(minutes=5)
|
|
self.session.save(
|
|
update_fields=[
|
|
'last_moderator_left_at',
|
|
'auto_close_after_moderator_exit_at',
|
|
'updated_at',
|
|
]
|
|
)
|
|
|
|
mock_client = mock_client_cls.return_value
|
|
mock_client.end_room.return_value = {'status': True, 'msg': 'room ended successfully'}
|
|
|
|
call_command('auto_close_professorless_live_sessions')
|
|
|
|
self.session.refresh_from_db()
|
|
self.assertIsNotNone(self.session.ended_at)
|
|
self.assertIsNone(self.session.last_moderator_left_at)
|
|
self.assertIsNone(self.session.auto_close_after_moderator_exit_at)
|
|
self.assertFalse(
|
|
LiveSessionUser.objects.get(session=self.session, user=self.student).is_online
|
|
)
|