Commit 5157b6da by Chris Dodge

Do the pagination before doing serialization, also refactor out the API endpoint…

Do the pagination before doing serialization, also refactor out the API endpoint which is for instructor only access
parent 1bb60c89
......@@ -793,20 +793,23 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
)
attempt_data = {
'exam_id': proctored_exam.id,
'user_id': self.student_taking_exam.id,
'external_id': proctored_exam.external_id
}
response = self.client.post(
reverse('edx_proctoring.proctored_exam.attempt.collection'),
attempt_data
)
url = reverse('edx_proctoring.proctored_exam.attempt', kwargs={'course_id': proctored_exam.course_id})
url = reverse('edx_proctoring.proctored_exam.attempts.course', kwargs={'course_id': proctored_exam.course_id})
self.assertEqual(response.status_code, 200)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content)
self.assertEqual(len(response_data['proctored_exam_attempts']), 1)
attempt = response_data['proctored_exam_attempts'][0]
self.assertEqual(attempt['proctored_exam']['id'], proctored_exam.id)
self.assertEqual(attempt['user']['id'], self.user.id)
url = '{url}?page={invalid_page_no}'.format(url=url, invalid_page_no=9999)
# url with the invalid page # still gives us the first page result.
response = self.client.get(url)
......@@ -835,7 +838,7 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
reverse('edx_proctoring.proctored_exam.attempt.collection'),
attempt_data
)
url = reverse('edx_proctoring.proctored_exam.attempt', kwargs={'course_id': proctored_exam.course_id})
url = reverse('edx_proctoring.proctored_exam.attempts.course', kwargs={'course_id': proctored_exam.course_id})
self.user.is_staff = False
self.user.save()
......@@ -878,7 +881,7 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
self.client.login_user(self.user)
response = self.client.get(
reverse(
'edx_proctoring.proctored_exam.attempt.search',
'edx_proctoring.proctored_exam.attempts.search',
kwargs={
'course_id': proctored_exam.course_id,
'search_by': 'tester'
......@@ -889,6 +892,13 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response_data = json.loads(response.content)
self.assertEqual(len(response_data['proctored_exam_attempts']), 2)
attempt = response_data['proctored_exam_attempts'][0]
self.assertEqual(attempt['proctored_exam']['id'], proctored_exam.id)
self.assertEqual(attempt['user']['id'], self.second_user.id)
attempt = response_data['proctored_exam_attempts'][1]
self.assertEqual(attempt['proctored_exam']['id'], proctored_exam.id)
self.assertEqual(attempt['user']['id'], self.user.id)
def test_stop_others_attempt(self):
"""
......
......@@ -37,14 +37,14 @@ urlpatterns = patterns( # pylint: disable=invalid-name
),
url(
r'edx_proctoring/v1/proctored_exam/attempt/course_id/{}$'.format(settings.COURSE_ID_PATTERN),
views.StudentProctoredExamAttemptCollection.as_view(),
name='edx_proctoring.proctored_exam.attempt'
views.StudentProctoredExamAttemptsByCourse.as_view(),
name='edx_proctoring.proctored_exam.attempts.course'
),
url(
r'edx_proctoring/v1/proctored_exam/attempt/course_id/{}/search/(?P<search_by>.+)$'.format(
settings.COURSE_ID_PATTERN),
views.StudentProctoredExamAttemptCollection.as_view(),
name='edx_proctoring.proctored_exam.attempt.search'
views.StudentProctoredExamAttemptsByCourse.as_view(),
name='edx_proctoring.proctored_exam.attempts.search'
),
url(
r'edx_proctoring/v1/proctored_exam/attempt$',
......
......@@ -27,9 +27,7 @@ from edx_proctoring.api import (
get_allowances_for_course,
get_all_exams_for_course,
get_exam_attempt_by_id,
get_all_exam_attempts,
remove_exam_attempt,
get_filtered_exam_attempts,
update_attempt_status
)
from edx_proctoring.exceptions import (
......@@ -39,8 +37,8 @@ from edx_proctoring.exceptions import (
ProctoredExamPermissionDenied,
StudentExamAttemptDoesNotExistsException,
)
from edx_proctoring.serializers import ProctoredExamSerializer
from edx_proctoring.models import ProctoredExamStudentAttemptStatus
from edx_proctoring.serializers import ProctoredExamSerializer, ProctoredExamStudentAttemptSerializer
from edx_proctoring.models import ProctoredExamStudentAttemptStatus, ProctoredExamStudentAttempt
from .utils import AuthenticatedAPIView
......@@ -438,53 +436,10 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView):
return the status of the exam attempt
"""
def get(self, request, course_id=None, search_by=None): # pylint: disable=unused-argument
def get(self, request): # pylint: disable=unused-argument
"""
HTTP GET Handler. Returns the status of the exam attempt.
"""
if course_id is not None:
#
# This code path is only for authenticated global staff users
#
if not request.user.is_staff:
return Response(
status=status.HTTP_403_FORBIDDEN,
data={"detail": "Must be a Staff User to Perform this request."}
)
if search_by is not None:
exam_attempts = get_filtered_exam_attempts(course_id, search_by)
attempt_url = reverse('edx_proctoring.proctored_exam.attempt.search', args=[course_id, search_by])
else:
exam_attempts = get_all_exam_attempts(course_id)
attempt_url = reverse('edx_proctoring.proctored_exam.attempt', args=[course_id])
paginator = Paginator(exam_attempts, ATTEMPTS_PER_PAGE)
page = request.GET.get('page')
try:
exam_attempts_page = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
exam_attempts_page = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
exam_attempts_page = paginator.page(paginator.num_pages)
data = {
'proctored_exam_attempts': exam_attempts_page.object_list,
'pagination_info': {
'has_previous': exam_attempts_page.has_previous(),
'has_next': exam_attempts_page.has_next(),
'current_page': exam_attempts_page.number,
'total_pages': exam_attempts_page.paginator.num_pages,
},
'attempt_url': attempt_url
}
return Response(
data=data,
status=status.HTTP_200_OK
)
exams = get_active_exams_for_user(request.user.id)
......@@ -583,6 +538,57 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView):
)
class StudentProctoredExamAttemptsByCourse(AuthenticatedAPIView):
"""
This endpoint is called by the Instructor Dashboard to get
paginated attempts in a course
A search parameter is optional
"""
@method_decorator(require_staff)
def get(self, request, course_id, search_by=None): # pylint: disable=unused-argument
"""
HTTP GET Handler. Returns the status of the exam attempt.
"""
if search_by is not None:
exam_attempts = ProctoredExamStudentAttempt.objects.get_filtered_exam_attempts(course_id, search_by)
attempt_url = reverse('edx_proctoring.proctored_exam.attempts.search', args=[course_id, search_by])
else:
exam_attempts = ProctoredExamStudentAttempt.objects.get_all_exam_attempts(course_id)
attempt_url = reverse('edx_proctoring.proctored_exam.attempts.course', args=[course_id])
paginator = Paginator(exam_attempts, ATTEMPTS_PER_PAGE)
page = request.GET.get('page')
try:
exam_attempts_page = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
exam_attempts_page = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
exam_attempts_page = paginator.page(paginator.num_pages)
data = {
'proctored_exam_attempts': [
ProctoredExamStudentAttemptSerializer(attempt).data for
attempt in exam_attempts_page.object_list
],
'pagination_info': {
'has_previous': exam_attempts_page.has_previous(),
'has_next': exam_attempts_page.has_next(),
'current_page': exam_attempts_page.number,
'total_pages': exam_attempts_page.paginator.num_pages,
},
'attempt_url': attempt_url
}
return Response(
data=data,
status=status.HTTP_200_OK
)
class ExamAllowanceView(AuthenticatedAPIView):
"""
Endpoint for the Exam Allowance
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment