from django.core.files.uploadedfile import SimpleUploadedFile from rest_framework import status from rest_framework.test import APITestCase from apps.account.models import ProfessorUser, StudentUser from apps.course.models.course import Course, CourseCategory from apps.course.models.lesson import CourseChapter, CourseLesson, Lesson from apps.quiz.models.quiz import Quiz, Question class CourseAccessGuardsTests(APITestCase): def setUp(self): self.professor = ProfessorUser.objects.create( email='prof-guard@example.com', fullname='Professor Guard', experience_years=5, ) self.outsider = StudentUser.objects.create( email='outsider@example.com', fullname='Outsider Student', ) self.category = CourseCategory.objects.create( name='Guard Category', slug='guard-category', ) thumbnail = SimpleUploadedFile('guard.jpg', b'filecontent', content_type='image/jpeg') self.course = Course.objects.create( title='Guard Course', slug='guard-course', category=self.category, professor=self.professor, thumbnail=thumbnail, video_type=Course.VedioTypeChoices.YOUTUBE_LINK, video_link='https://example.com/video', is_online=False, level=Course.LevelChoices.BEGINNER, duration=10, lessons_count=0, description='Description', short_description='Short description', status=Course.StatusChoices.ONGOING, is_free=True, ) self.chapter = CourseChapter.objects.create( course=self.course, title='Chapter 1', priority=1, is_active=True, ) lesson = Lesson.objects.create( title='Lesson 1', content_type=Lesson.ContentTypeChoices.VIDEO_FILE, duration=5, ) self.course_lesson = CourseLesson.objects.create( course=self.course, chapter=self.chapter, lesson=lesson, priority=1, is_active=True, ) self.quiz = Quiz.objects.create( lesson=self.course_lesson, course=self.course, title='Guard Quiz', description='Quiz description', each_question_timing=30, status=True, ) self.question = Question.objects.create( quiz=self.quiz, question='What is 2+2?', option1='4', option2='3', option3='2', option4='1', correct_answer=1, priority=1, ) def test_lesson_list_marks_lessons_and_quizzes_inactive_without_course_access(self): self.client.force_authenticate(user=self.outsider) response = self.client.get(f'/api/courses/{self.course.slug}/lessons/') self.assertEqual(response.status_code, status.HTTP_200_OK) lesson_data = response.data['results'][0] self.assertFalse(lesson_data['permission']) self.assertFalse(lesson_data['is_active']) self.assertFalse(lesson_data['quizs'][0]['permission']) def test_lesson_list_v2_marks_chapter_inactive_without_course_access(self): self.client.force_authenticate(user=self.outsider) response = self.client.get(f'/api/courses/v2/{self.course.slug}/lessons/') self.assertEqual(response.status_code, status.HTTP_200_OK) chapter_data = response.data['results'][0] self.assertFalse(chapter_data['is_active']) self.assertFalse(chapter_data['lessons'][0]['is_active']) def test_quiz_detail_rejects_users_without_course_access(self): self.client.force_authenticate(user=self.outsider) response = self.client.get(f'/api/quiz/{self.quiz.id}/') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_quiz_submit_rejects_users_without_course_access(self): self.client.force_authenticate(user=self.outsider) payload = { 'quiz': self.quiz.id, 'started_at': '2026-06-02T10:00:00Z', 'ended_at': '2026-06-02T10:01:00Z', 'total_timing': 60, 'question_score': 1, 'timing_score': 1, 'total_score': 2, 'answers': [ { 'question': self.question.id, 'option_num': 1, 'at_time': '2026-06-02T10:00:30Z', 'answer_timing': 30, } ], } response = self.client.post('/api/quiz/submit-quiz/', payload, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('quiz', response.data)