diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 51fc514c4879..4d3e413f5a2a 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -3455,6 +3455,15 @@ def test_list_entrance_exam_instructor_with_invalid_exam_key(self): }) assert response.status_code == 400 + def test_skip_entrance_exam_student_with_invalid_student(self): + """ Test skip entrance exam api for non existing user. """ + # create a re-score entrance exam task + url = reverse('mark_student_can_skip_entrance_exam', kwargs={'course_id': str(self.course.id)}) + response = self.client.post(url, { + 'unique_student_identifier': 'test', + }) + assert response.status_code == 400 + def test_skip_entrance_exam_student(self): """ Test skip entrance exam api for student. """ # create a re-score entrance exam task diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 5ac663d38418..94184f6d9373 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -3203,28 +3203,40 @@ def enable_certificate_generation(request, course_id=None): return redirect(_instructor_dash_url(course_key, section='certificates')) -@ensure_csrf_cookie -@cache_control(no_cache=True, no_store=True, must_revalidate=True) -@require_course_permission(permissions.ALLOW_STUDENT_TO_BYPASS_ENTRANCE_EXAM) -@require_POST -def mark_student_can_skip_entrance_exam(request, course_id): +@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch') +class MarkStudentCanSkipEntranceExam(APIView): """ Mark a student to skip entrance exam. - Takes `unique_student_identifier` as required POST parameter. """ - course_id = CourseKey.from_string(course_id) - student_identifier = request.POST.get('unique_student_identifier') - student = get_student_from_identifier(student_identifier) + permission_classes = (IsAuthenticated, permissions.InstructorPermission) + permission_name = permissions.ALLOW_STUDENT_TO_BYPASS_ENTRANCE_EXAM - __, created = EntranceExamConfiguration.objects.get_or_create(user=student, course_id=course_id) - if created: - message = _('This student (%s) will skip the entrance exam.') % student_identifier - else: - message = _('This student (%s) is already allowed to skip the entrance exam.') % student_identifier - response_payload = { - 'message': message, - } - return JsonResponse(response_payload) + @method_decorator(ensure_csrf_cookie) + def post(self, request, course_id): + """ + Takes `unique_student_identifier` as required POST parameter. + """ + course_id = CourseKey.from_string(course_id) + student_identifier = request.data.get("unique_student_identifier") + + serializer_data = UniqueStudentIdentifierSerializer(data=request.data) + if not serializer_data.is_valid(): + return HttpResponseBadRequest(reason=serializer_data.errors) + + student = serializer_data.validated_data.get('unique_student_identifier') + if not student: + response_payload = f'Could not find student matching : {student_identifier}' + return JsonResponse({'error': response_payload}, status=400) + + __, created = EntranceExamConfiguration.objects.get_or_create(user=student, course_id=course_id) + if created: + message = _('This student (%s) will skip the entrance exam.') % student_identifier + else: + message = _('This student (%s) is already allowed to skip the entrance exam.') % student_identifier + response_payload = { + 'message': message, + } + return JsonResponse(response_payload) @transaction.non_atomic_requests diff --git a/lms/djangoapps/instructor/views/api_urls.py b/lms/djangoapps/instructor/views/api_urls.py index 3e4a9c1f3274..5976411a9756 100644 --- a/lms/djangoapps/instructor/views/api_urls.py +++ b/lms/djangoapps/instructor/views/api_urls.py @@ -43,7 +43,7 @@ path('rescore_entrance_exam', api.rescore_entrance_exam, name='rescore_entrance_exam'), path('list_entrance_exam_instructor_tasks', api.ListEntranceExamInstructorTasks.as_view(), name='list_entrance_exam_instructor_tasks'), - path('mark_student_can_skip_entrance_exam', api.mark_student_can_skip_entrance_exam, + path('mark_student_can_skip_entrance_exam', api.MarkStudentCanSkipEntranceExam.as_view(), name='mark_student_can_skip_entrance_exam'), path('list_instructor_tasks', api.ListInstructorTasks.as_view(), name='list_instructor_tasks'), path('list_background_email_tasks', api.list_background_email_tasks, name='list_background_email_tasks'),