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.
"""
@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):
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()
dot_application = ApplicationFactory(user=self.other_user, authorization_grant_type='password')
@@ -4744,7 +4748,14 @@ class TestOauthInstructorAPILevelsAccess(SharedModuleStoreTestCase, LoginEnrollm
"send-to": ["myself"],
"subject": "This is subject",
"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'

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.views.serializer import (
AccessSerializer, BlockDueDateSerializer, RoleNameSerializer, ShowStudentExtensionSerializer, UserSerializer,
SendEmailSerializer, StudentAttemptsSerializer
SendEmailSerializer, StudentAttemptsSerializer, ListInstructorTaskInputSerializer
)
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
@@ -2373,9 +2373,8 @@ class InstructorTasks(DeveloperErrorViewMixin, APIView):
return _list_instructor_tasks(request=request, course_id=course_id)
@require_POST
@ensure_csrf_cookie
def list_instructor_tasks(request, course_id):
@method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True), name='dispatch')
class ListInstructorTasks(APIView):
"""
List instructor tasks.
@@ -2385,21 +2384,44 @@ def list_instructor_tasks(request, course_id):
- `problem_location_str` and `unique_student_identifier` lists task
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)
@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.
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)
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 serialize_data is not None:
problem_location_str = strip_if_string(serialize_data.get('problem_location_str', False))
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:
student = get_student_from_identifier(student)

View File

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

View File

@@ -61,6 +61,43 @@ class AccessSerializer(serializers.Serializer):
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):
"""
Serializer for validating and processing the student identifier.