From f2c84e9cbf73e9e4f627442d7c02eda3ee47fdb3 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Thu, 18 Jun 2026 08:27:56 +0330 Subject: [PATCH] live sessions name changed --- .../management/commands/assign_professors.py | 25 ---- .../tests/test_live_session_subjects.py | 133 ++++++++++++++++++ apps/course/views/course.py | 23 +-- apps/course/views/live_session.py | 33 ++--- 4 files changed, 144 insertions(+), 70 deletions(-) create mode 100644 apps/course/tests/test_live_session_subjects.py diff --git a/apps/course/management/commands/assign_professors.py b/apps/course/management/commands/assign_professors.py index 8d435de..e69de29 100644 --- a/apps/course/management/commands/assign_professors.py +++ b/apps/course/management/commands/assign_professors.py @@ -1,25 +0,0 @@ -from django.core.management.base import BaseCommand -from apps.course.models import Course -from apps.account.models import ProfessorUser -import random - -class Command(BaseCommand): - help = 'Assign at least one professor to every course (if missing)' - - def handle(self, *args, **options): - # Gather all active professors - professors = list(ProfessorUser.objects.filter(is_active=True)) - if not professors: - self.stdout.write(self.style.ERROR('No active professors found.')) - return - - updated = 0 - for course in Course.objects.all(): - if course.professors.exists(): - continue # already has a professor - professor = random.choice(professors) - course.professors.add(professor) - updated += 1 - self.stdout.write(f'Added professor {professor.id} to course {course.id}') - - self.stdout.write(self.style.SUCCESS(f'Finished. Updated {updated} course(s).')) diff --git a/apps/course/tests/test_live_session_subjects.py b/apps/course/tests/test_live_session_subjects.py new file mode 100644 index 0000000..2bfd229 --- /dev/null +++ b/apps/course/tests/test_live_session_subjects.py @@ -0,0 +1,133 @@ +import tempfile +from unittest import mock + +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 +from apps.course.models import Course, CourseCategory, CourseLiveSession +from apps.course.views.course import get_course_slug_value + + +@override_settings( + PLUGNMEET_SERVER_URL='https://meet.example.com', + PLUGNMEET_API_KEY='test-key', + PLUGNMEET_API_SECRET='test-secret', + MEDIA_ROOT=tempfile.gettempdir(), + ONLINE_CLASS_FRONTEND_DOMAIN='http://testserver', +) +class CourseLiveSessionSubjectTests(APITestCase): + def setUp(self): + Language.objects.update_or_create( + id=69, + defaults={ + 'code': 'en', + 'name': 'English', + 'status': True, + 'countries': [], + }, + ) + self.professor = ProfessorUser.objects.create( + email='subject-prof@example.com', + fullname='Subject Professor', + experience_years=5, + ) + self.category = CourseCategory.objects.create(name='Category', slug='category') + thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg') + self.course = Course.objects.create( + title=[{'title': 'Sample Course', 'language_code': 'en'}], + slug=[{'title': 'sample-course', 'language_code': 'en'}], + category=self.category, + thumbnail=thumbnail, + video_type=Course.VedioTypeChoices.YOUTUBE_LINK, + video_link='https://example.com/video', + is_online=True, + online_link='https://example.com/live', + level=[{'title': 'beginner', 'language_code': 'en'}], + duration=10, + lessons_count=2, + description=[{'title': 'Description', 'language_code': 'en'}], + short_description=[{'title': 'Short', 'language_code': 'en'}], + status=[{'title': 'ongoing', 'language_code': 'en'}], + is_free=True, + ) + self.course.professors.add(self.professor) + + @mock.patch('apps.course.views.live_session.PlugNMeetClient') + def test_room_create_uses_incremental_subject(self, mock_client_cls): + mock_client_cls.return_value.create_room.return_value = {'status': 'success'} + CourseLiveSession.objects.create( + course=self.course, + room_id='room-old', + subject='Live Session 1', + started_at=timezone.now(), + ended_at=timezone.now(), + ) + + self.client.force_authenticate(user=self.professor) + url = reverse( + 'course-live-session-room-create', + kwargs={'slug': get_course_slug_value(self.course)}, + ) + response = self.client.post(url, {}, format='json') + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + session = CourseLiveSession.objects.filter( + course=self.course, + ended_at__isnull=True, + ).latest('id') + self.assertEqual(session.subject, 'Live Session 2') + + @mock.patch('apps.course.views.course.PlugNMeetClient') + def test_validate_professor_create_uses_incremental_subject(self, mock_client_cls): + mock_client = mock_client_cls.return_value + mock_client.create_room.return_value = {'status': 'success'} + mock_client.get_join_token.return_value = {'token': 'teacher-access-token'} + CourseLiveSession.objects.create( + course=self.course, + room_id='room-old', + subject='Live Session 1', + started_at=timezone.now(), + ended_at=timezone.now(), + ) + + self.client.force_authenticate(user=self.professor) + url = reverse( + 'course-online-validate', + kwargs={'slug': get_course_slug_value(self.course)}, + ) + response = self.client.get(url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + session = CourseLiveSession.objects.filter( + course=self.course, + ended_at__isnull=True, + ).latest('id') + self.assertEqual(session.subject, 'Live Session 2') + + def test_set_recording_title_updates_session_subject(self): + session = CourseLiveSession.objects.create( + course=self.course, + room_id='room-active', + subject='Live Session 1', + started_at=timezone.now(), + ) + + response = self.client.post( + reverse('course-live-session-set-recording-title'), + { + 'room_id': session.room_id, + 'title': 'machine learning', + }, + format='json', + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + session.refresh_from_db() + self.assertEqual(session.recording_title, 'machine learning') + self.assertEqual(session.subject, 'machine learning') diff --git a/apps/course/views/course.py b/apps/course/views/course.py index 5007f79..8ee0b4e 100644 --- a/apps/course/views/course.py +++ b/apps/course/views/course.py @@ -758,27 +758,8 @@ class CourseOnlineClassTokenValidateAPIView(GenericAPIView): @staticmethod def _get_live_session_subject(course: Course) -> str: - title = "" - course_title = course.title - if isinstance(course_title, list): - for tr in course_title: - if isinstance(tr, dict) and tr.get('language_code') == 'en': - val = tr.get('title') or tr.get('text') or tr.get('value') or tr.get('name') - if val: - title = str(val).strip() - break - if not title: - for tr in course_title: - if isinstance(tr, dict) and tr.get('language_code') == 'ru': - val = tr.get('title') or tr.get('text') or tr.get('value') or tr.get('name') - if val: - title = str(val).strip() - break - if not title: - title = extract_text_from_json(course_title) - if not title: - title = "Course" - return f"{title} Live Session" + next_session_number = course.live_sessions.count() + 1 + return f"Live Session {next_session_number}" def _build_live_room_metadata(self, subject: str) -> dict: return { diff --git a/apps/course/views/live_session.py b/apps/course/views/live_session.py index 3691f8d..eb37b7b 100644 --- a/apps/course/views/live_session.py +++ b/apps/course/views/live_session.py @@ -25,28 +25,8 @@ logger = logging.getLogger(__name__) def get_live_session_subject(course): - title = "" - course_title = course.title - if isinstance(course_title, list): - for tr in course_title: - if isinstance(tr, dict) and tr.get('language_code') == 'en': - val = tr.get('title') or tr.get('text') or tr.get('value') or tr.get('name') - if val: - title = str(val).strip() - break - if not title: - for tr in course_title: - if isinstance(tr, dict) and tr.get('language_code') == 'ru': - val = tr.get('title') or tr.get('text') or tr.get('value') or tr.get('name') - if val: - title = str(val).strip() - break - if not title: - from apps.course.models.course import extract_text_from_json - title = extract_text_from_json(course_title) - if not title: - title = "Course" - return f"{title} Live Session" + next_session_number = course.live_sessions.count() + 1 + return f"Live Session {next_session_number}" def get_plugnmeet_webhook_url() -> str: @@ -1300,13 +1280,18 @@ class CourseLiveSessionSetRecordingTitleAPIView(GenericAPIView): if not room_id or not title: raise AppAPIException({'message': 'room_id and title are required.'}, status_code=status.HTTP_400_BAD_REQUEST) + title = title.strip() + if not title: + raise AppAPIException({'message': 'title cannot be empty.'}, status_code=status.HTTP_400_BAD_REQUEST) + try: session = CourseLiveSession.objects.get(room_id=room_id, ended_at__isnull=True) except CourseLiveSession.DoesNotExist: raise AppAPIException({'message': 'Active session not found.'}, status_code=status.HTTP_404_NOT_FOUND) - session.recording_title = title.strip() - session.save(update_fields=['recording_title', 'updated_at']) + session.recording_title = title + session.subject = title + session.save(update_fields=['recording_title', 'subject', 'updated_at']) sync_session_recording_titles(session) logger.info(f"[LiveSession Title] Set recording title for room_id={room_id} to '{title}'")