feat: upgrading list_instructor_tasks to DRF ( 10th ) (#35332)

* feat: upgrading simple api to drf compatible.
This commit is contained in:
Awais Qureshi
2024-09-18 15:54:01 +05:00
committed by GitHub
parent 50ceed3b46
commit 3de0dbd9ea
4 changed files with 88 additions and 18 deletions

View File

@@ -4704,15 +4704,19 @@ class TestOauthInstructorAPILevelsAccess(SharedModuleStoreTestCase, LoginEnrollm
Test endpoints using Oauth2 authentication. Test endpoints using Oauth2 authentication.
""" """
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.course = CourseFactory.create(
entrance_exam_id='i4x://{}/{}/chapter/Entrance_exam'.format('test_org', 'test_course')
)
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.course = CourseFactory.create(
org='test_org',
course='test_course',
run='test_run',
entrance_exam_id='i4x://{}/{}/chapter/Entrance_exam'.format('test_org', 'test_course')
)
self.problem_location = msk_from_problem_urlname(
self.course.id,
'robot-some-problem-urlname'
)
self.problem_urlname = str(self.problem_location)
self.other_user = UserFactory() self.other_user = UserFactory()
dot_application = ApplicationFactory(user=self.other_user, authorization_grant_type='password') dot_application = ApplicationFactory(user=self.other_user, authorization_grant_type='password')
@@ -4744,7 +4748,14 @@ class TestOauthInstructorAPILevelsAccess(SharedModuleStoreTestCase, LoginEnrollm
"send-to": ["myself"], "send-to": ["myself"],
"subject": "This is subject", "subject": "This is subject",
"message": "message" "message": "message"
}, 'data_researcher') }, 'data_researcher'),
('list_instructor_tasks',
{
'problem_location_str': self.problem_urlname,
'unique_student_identifier': self.other_user.email
},
'data_researcher'),
('list_instructor_tasks', {}, 'data_researcher')
] ]
self.fake_jwt = ('wyJUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJjaGFuZ2UtbWUiLCJleHAiOjE3MjU4OTA2NzIsImdyY' self.fake_jwt = ('wyJUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJjaGFuZ2UtbWUiLCJleHAiOjE3MjU4OTA2NzIsImdyY'

View File

@@ -108,7 +108,7 @@ from lms.djangoapps.instructor_task.data import InstructorTaskTypes
from lms.djangoapps.instructor_task.models import ReportStore from lms.djangoapps.instructor_task.models import ReportStore
from lms.djangoapps.instructor.views.serializer import ( from lms.djangoapps.instructor.views.serializer import (
AccessSerializer, BlockDueDateSerializer, RoleNameSerializer, ShowStudentExtensionSerializer, UserSerializer, AccessSerializer, BlockDueDateSerializer, RoleNameSerializer, ShowStudentExtensionSerializer, UserSerializer,
SendEmailSerializer, StudentAttemptsSerializer SendEmailSerializer, StudentAttemptsSerializer, ListInstructorTaskInputSerializer
) )
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview 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 from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, is_course_cohorted
@@ -2373,9 +2373,8 @@ class InstructorTasks(DeveloperErrorViewMixin, APIView):
return _list_instructor_tasks(request=request, course_id=course_id) return _list_instructor_tasks(request=request, course_id=course_id)
@require_POST @method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
@ensure_csrf_cookie class ListInstructorTasks(APIView):
def list_instructor_tasks(request, course_id):
""" """
List instructor tasks. List instructor tasks.
@@ -2385,21 +2384,44 @@ def list_instructor_tasks(request, course_id):
- `problem_location_str` and `unique_student_identifier` lists task - `problem_location_str` and `unique_student_identifier` lists task
history for problem AND student (intersection) history for problem AND student (intersection)
""" """
return _list_instructor_tasks(request=request, course_id=course_id) permission_classes = (IsAuthenticated, permissions.InstructorPermission)
permission_name = permissions.SHOW_TASKS
serializer_class = ListInstructorTaskInputSerializer
@method_decorator(ensure_csrf_cookie)
def post(self, request, course_id):
"""
List instructor tasks.
"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return _list_instructor_tasks(
request=request, course_id=course_id, serialize_data=serializer.validated_data
)
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_course_permission(permissions.SHOW_TASKS) @require_course_permission(permissions.SHOW_TASKS)
def _list_instructor_tasks(request, course_id): def _list_instructor_tasks(request, course_id, serialize_data=None):
""" """
List instructor tasks. List instructor tasks.
Internal function with common code for both DRF and and tradition views. Internal function with common code for both DRF and and tradition views.
""" """
# This method is also used by other APIs with the GET method.
# The query_params attribute is utilized for GET requests,
# where parameters are passed as query strings.
course_id = CourseKey.from_string(course_id) course_id = CourseKey.from_string(course_id)
params = getattr(request, 'query_params', request.POST) if serialize_data is not None:
problem_location_str = strip_if_string(params.get('problem_location_str', False)) problem_location_str = strip_if_string(serialize_data.get('problem_location_str', False))
student = params.get('unique_student_identifier', None) student = serialize_data.get('unique_student_identifier', None)
else:
params = getattr(request, 'query_params', request.POST)
problem_location_str = strip_if_string(params.get('problem_location_str', False))
student = params.get('unique_student_identifier', None)
if student is not None: if student is not None:
student = get_student_from_identifier(student) student = get_student_from_identifier(student)

View File

@@ -44,7 +44,7 @@ urlpatterns = [
name='list_entrance_exam_instructor_tasks'), 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.mark_student_can_skip_entrance_exam,
name='mark_student_can_skip_entrance_exam'), name='mark_student_can_skip_entrance_exam'),
path('list_instructor_tasks', api.list_instructor_tasks, name='list_instructor_tasks'), 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'), path('list_background_email_tasks', api.list_background_email_tasks, name='list_background_email_tasks'),
path('list_email_content', api.ListEmailContent.as_view(), name='list_email_content'), path('list_email_content', api.ListEmailContent.as_view(), name='list_email_content'),
path('list_forum_members', api.list_forum_members, name='list_forum_members'), path('list_forum_members', api.list_forum_members, name='list_forum_members'),

View File

@@ -61,6 +61,43 @@ class AccessSerializer(serializers.Serializer):
return user return user
class ListInstructorTaskInputSerializer(serializers.Serializer): # pylint: disable=abstract-method
"""
Serializer for handling the input data for the problem response report generation API.
Attributes:
unique_student_identifier (str): The email or username of the student.
This field is optional, but if provided, the `problem_location_str`
must also be provided.
problem_location_str (str): The string representing the location of the problem within the course.
This field is optional, unless `unique_student_identifier` is provided.
"""
unique_student_identifier = serializers.CharField(
max_length=255,
help_text="Email or username of student",
required=False
)
problem_location_str = serializers.CharField(
help_text="Problem location",
required=False
)
def validate(self, data):
"""
Validate the data to ensure that if unique_student_identifier is provided,
problem_location_str must also be provided.
"""
unique_student_identifier = data.get('unique_student_identifier')
problem_location_str = data.get('problem_location_str')
if unique_student_identifier and not problem_location_str:
raise serializers.ValidationError(
"unique_student_identifier must accompany problem_location_str"
)
return data
class ShowStudentExtensionSerializer(serializers.Serializer): class ShowStudentExtensionSerializer(serializers.Serializer):
""" """
Serializer for validating and processing the student identifier. Serializer for validating and processing the student identifier.