From 0457d95f2a053f73a001fda959248df857a73267 Mon Sep 17 00:00:00 2001 From: awais qureshi Date: Tue, 10 Sep 2024 18:23:50 +0500 Subject: [PATCH 1/5] feat!: upgrading simple api with DRF. --- lms/djangoapps/instructor/views/api.py | 83 +++++++++---------- lms/djangoapps/instructor/views/api_urls.py | 2 +- lms/djangoapps/instructor/views/serializer.py | 28 ++++--- 3 files changed, 58 insertions(+), 55 deletions(-) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index c6db96b3ca60..d8aef8721cbe 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -108,7 +108,7 @@ from lms.djangoapps.instructor_task.models import ReportStore from lms.djangoapps.instructor.views.serializer import ( AccessSerializer, RoleNameSerializer, ShowStudentExtensionSerializer, - UserSerializer, SendEmailSerializer + UserSerializer, SendEmailSerializer, UniqueStudentIdentifierSerializer ) from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, is_course_cohorted @@ -1702,60 +1702,57 @@ def post(self, request, course_id): return JsonResponse({"status": success_status}) -@require_POST -@ensure_csrf_cookie -@cache_control(no_cache=True, no_store=True, must_revalidate=True) -@require_course_permission(permissions.VIEW_ENROLLMENTS) -@require_post_params( - unique_student_identifier="email or username of student for whom to get enrollment status" -) -def get_student_enrollment_status(request, course_id): +@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch') +class GetStudentEnrollmentStatus(APIView): """ Get the enrollment status of a student. - Limited to staff access. - - Takes query parameter unique_student_identifier """ + permission_classes = (IsAuthenticated, permissions.InstructorPermission) + permission_name = permissions.VIEW_ENROLLMENTS - error = '' - user = None - mode = None - is_active = None + @method_decorator(ensure_csrf_cookie) + def post(self, request, course_id): + """ + Permission: Limited to staff access. + Takes query parameter unique_student_identifier + """ + error = '' + user = None + mode = None + is_active = None - course_id = CourseKey.from_string(course_id) - unique_student_identifier = request.POST.get('unique_student_identifier') + course_id = CourseKey.from_string(course_id) + unique_student_identifier = request.data.get("unique_student_identifier") - try: - user = get_student_from_identifier(unique_student_identifier) + serializer_data = UniqueStudentIdentifierSerializer(data=request.data) + if not serializer_data.is_valid(): + return HttpResponseBadRequest(reason=serializer_data.errors) + + user = serializer_data.validated_data.get('unique_student_identifier') mode, is_active = CourseEnrollment.enrollment_mode_for_user(user, course_id) - except User.DoesNotExist: - # The student could have been invited to enroll without having - # registered. We'll also look at CourseEnrollmentAllowed - # records, so let the lack of a User slide. - pass - enrollment_status = _('Enrollment status for {student}: unknown').format(student=unique_student_identifier) + enrollment_status = _('Enrollment status for {student}: unknown').format(student=unique_student_identifier) - if user and mode: - if is_active: - enrollment_status = _('Enrollment status for {student}: active').format(student=user) - else: - enrollment_status = _('Enrollment status for {student}: inactive').format(student=user) - else: - email = user.email if user else unique_student_identifier - allowed = CourseEnrollmentAllowed.may_enroll_and_unenrolled(course_id) - if allowed and email in [cea.email for cea in allowed]: - enrollment_status = _('Enrollment status for {student}: pending').format(student=email) + if user and mode: + if is_active: + enrollment_status = _('Enrollment status for {student}: active').format(student=user) + else: + enrollment_status = _('Enrollment status for {student}: inactive').format(student=user) else: - enrollment_status = _('Enrollment status for {student}: never enrolled').format(student=email) + email = user.email if user else unique_student_identifier + allowed = CourseEnrollmentAllowed.may_enroll_and_unenrolled(course_id) + if allowed and email in [cea.email for cea in allowed]: + enrollment_status = _('Enrollment status for {student}: pending').format(student=email) + else: + enrollment_status = _('Enrollment status for {student}: never enrolled').format(student=email) - response_payload = { - 'course_id': str(course_id), - 'error': error, - 'enrollment_status': enrollment_status - } + response_payload = { + 'course_id': str(course_id), + 'error': error, + 'enrollment_status': enrollment_status + } - return JsonResponse(response_payload) + return JsonResponse(response_payload) class StudentProgressUrlSerializer(serializers.Serializer): diff --git a/lms/djangoapps/instructor/views/api_urls.py b/lms/djangoapps/instructor/views/api_urls.py index d4719b90b4b0..4c151fcc624f 100644 --- a/lms/djangoapps/instructor/views/api_urls.py +++ b/lms/djangoapps/instructor/views/api_urls.py @@ -32,7 +32,7 @@ path('get_issued_certificates/', api.get_issued_certificates, name='get_issued_certificates'), path('get_students_who_may_enroll', api.GetStudentsWhoMayEnroll.as_view(), name='get_students_who_may_enroll'), path('get_anon_ids', api.GetAnonIds.as_view(), name='get_anon_ids'), - path('get_student_enrollment_status', api.get_student_enrollment_status, name="get_student_enrollment_status"), + path('get_student_enrollment_status', api.GetStudentEnrollmentStatus.as_view(), name="get_student_enrollment_status"), path('get_student_progress_url', api.StudentProgressUrl.as_view(), name='get_student_progress_url'), path('reset_student_attempts', api.reset_student_attempts, name='reset_student_attempts'), path('rescore_problem', api.rescore_problem, name='rescore_problem'), diff --git a/lms/djangoapps/instructor/views/serializer.py b/lms/djangoapps/instructor/views/serializer.py index ff79124d026d..06bb6f078fc0 100644 --- a/lms/djangoapps/instructor/views/serializer.py +++ b/lms/djangoapps/instructor/views/serializer.py @@ -31,23 +31,14 @@ class Meta: fields = ['username', 'email', 'first_name', 'last_name'] -class AccessSerializer(serializers.Serializer): +class UniqueStudentIdentifierSerializer(serializers.Serializer): """ - Serializer for managing user access changes. - This serializer validates and processes the data required to modify - user access within a system. + Serializer for identifying unique_student. """ unique_student_identifier = serializers.CharField( max_length=255, help_text="Email or username of user to change access" ) - rolename = serializers.CharField( - help_text="Role name to assign to the user" - ) - action = serializers.ChoiceField( - choices=['allow', 'revoke'], - help_text="Action to perform on the user's access" - ) def validate_unique_student_identifier(self, value): """ @@ -61,6 +52,21 @@ def validate_unique_student_identifier(self, value): return user +class AccessSerializer(UniqueStudentIdentifierSerializer): + """ + Serializer for managing user access changes. + This serializer validates and processes the data required to modify + user access within a system. + """ + rolename = serializers.CharField( + help_text="Role name to assign to the user" + ) + action = serializers.ChoiceField( + choices=['allow', 'revoke'], + help_text="Action to perform on the user's access" + ) + + class ShowStudentExtensionSerializer(serializers.Serializer): """ Serializer for validating and processing the student identifier. From fbdafd015ddede2f79ba53ec290fa8fa9be5544e Mon Sep 17 00:00:00 2001 From: awais qureshi Date: Tue, 10 Sep 2024 18:40:39 +0500 Subject: [PATCH 2/5] feat!: upgrading simple api with DRF. --- lms/djangoapps/instructor/views/api.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index d8aef8721cbe..c89a95a4940a 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -1717,7 +1717,6 @@ def post(self, request, course_id): Takes query parameter unique_student_identifier """ error = '' - user = None mode = None is_active = None @@ -1729,9 +1728,8 @@ def post(self, request, course_id): return HttpResponseBadRequest(reason=serializer_data.errors) user = serializer_data.validated_data.get('unique_student_identifier') - mode, is_active = CourseEnrollment.enrollment_mode_for_user(user, course_id) - - enrollment_status = _('Enrollment status for {student}: unknown').format(student=unique_student_identifier) + if user: + mode, is_active = CourseEnrollment.enrollment_mode_for_user(user, course_id) if user and mode: if is_active: From 02b3ca0c41eb8c863b7cf1413fb6d8aaee6698d2 Mon Sep 17 00:00:00 2001 From: awais qureshi Date: Tue, 10 Sep 2024 18:53:32 +0500 Subject: [PATCH 3/5] feat!: upgrading simple api with DRF. --- lms/djangoapps/instructor/views/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index ac6d7ad32b52..1e5537fb8384 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -108,7 +108,7 @@ from lms.djangoapps.instructor_task.models import ReportStore from lms.djangoapps.instructor.views.serializer import ( AccessSerializer, RoleNameSerializer, ShowStudentExtensionSerializer, - UniqueStudentIdentifierSerializer, UserSerializer, SendEmailSerializer, + UniqueStudentIdentifierSerializer, UserSerializer, SendEmailSerializer, StudentAttemptsSerializer ) from openedx.core.djangoapps.content.course_overviews.models import CourseOverview From 1e83b413c80ed42534ae60b76173a8731a213f2b Mon Sep 17 00:00:00 2001 From: Awais Qureshi Date: Tue, 10 Sep 2024 19:18:33 +0500 Subject: [PATCH 4/5] chore: Update api_urls.py --- lms/djangoapps/instructor/views/api_urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/instructor/views/api_urls.py b/lms/djangoapps/instructor/views/api_urls.py index 8102b1acdbe5..07691c900f59 100644 --- a/lms/djangoapps/instructor/views/api_urls.py +++ b/lms/djangoapps/instructor/views/api_urls.py @@ -32,7 +32,8 @@ path('get_issued_certificates/', api.get_issued_certificates, name='get_issued_certificates'), path('get_students_who_may_enroll', api.GetStudentsWhoMayEnroll.as_view(), name='get_students_who_may_enroll'), path('get_anon_ids', api.GetAnonIds.as_view(), name='get_anon_ids'), - path('get_student_enrollment_status', api.GetStudentEnrollmentStatus.as_view(), name="get_student_enrollment_status"), + path('get_student_enrollment_status', api.GetStudentEnrollmentStatus.as_view(), + name="get_student_enrollment_status"), path('get_student_progress_url', api.StudentProgressUrl.as_view(), name='get_student_progress_url'), path('reset_student_attempts', api.ResetStudentAttempts.as_view(), name='reset_student_attempts'), path('rescore_problem', api.rescore_problem, name='rescore_problem'), From ccb203a55feedcd27b102c795745b605563f5ddb Mon Sep 17 00:00:00 2001 From: awais qureshi Date: Tue, 10 Sep 2024 23:26:41 +0500 Subject: [PATCH 5/5] feat!: upgrading simple api with DRF. --- lms/djangoapps/instructor/views/api_urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/djangoapps/instructor/views/api_urls.py b/lms/djangoapps/instructor/views/api_urls.py index 07691c900f59..5178c0a6a99e 100644 --- a/lms/djangoapps/instructor/views/api_urls.py +++ b/lms/djangoapps/instructor/views/api_urls.py @@ -32,7 +32,7 @@ path('get_issued_certificates/', api.get_issued_certificates, name='get_issued_certificates'), path('get_students_who_may_enroll', api.GetStudentsWhoMayEnroll.as_view(), name='get_students_who_may_enroll'), path('get_anon_ids', api.GetAnonIds.as_view(), name='get_anon_ids'), - path('get_student_enrollment_status', api.GetStudentEnrollmentStatus.as_view(), + path('get_student_enrollment_status', api.GetStudentEnrollmentStatus.as_view(), name="get_student_enrollment_status"), path('get_student_progress_url', api.StudentProgressUrl.as_view(), name='get_student_progress_url'), path('reset_student_attempts', api.ResetStudentAttempts.as_view(), name='reset_student_attempts'),