Commit 4ca93ade by rabiaiftikhar

EDUCATOR-1648 give proctored exam student attempts and prcotored exam allowances…

EDUCATOR-1648 give proctored exam student attempts and prcotored exam allowances access to course staff
parent 580c32ad
...@@ -353,12 +353,12 @@ def add_allowance_for_user(exam_id, user_info, key, value): ...@@ -353,12 +353,12 @@ def add_allowance_for_user(exam_id, user_info, key, value):
emit_event(exam, 'allowance.{action}'.format(action=action), override_data=data) emit_event(exam, 'allowance.{action}'.format(action=action), override_data=data)
def get_allowances_for_course(course_id, timed_exams_only=False): def get_allowances_for_course(course_id):
""" """
Get all the allowances for the course. Get all the allowances for the course.
""" """
student_allowances = ProctoredExamStudentAllowance.get_allowances_for_course( student_allowances = ProctoredExamStudentAllowance.get_allowances_for_course(
course_id, timed_exams_only=timed_exams_only course_id
) )
return [ProctoredExamStudentAllowanceSerializer(allowance).data for allowance in student_allowances] return [ProctoredExamStudentAllowanceSerializer(allowance).data for allowance in student_allowances]
......
...@@ -394,27 +394,20 @@ class ProctoredExamStudentAttemptManager(models.Manager): ...@@ -394,27 +394,20 @@ class ProctoredExamStudentAttemptManager(models.Manager):
exam_attempt_obj = None exam_attempt_obj = None
return exam_attempt_obj return exam_attempt_obj
def get_all_exam_attempts(self, course_id, timed_exams_only=False): def get_all_exam_attempts(self, course_id):
""" """
Returns the Student Exam Attempts for the given course_id. Returns the Student Exam Attempts for the given course_id.
""" """
filtered_query = Q(proctored_exam__course_id=course_id) filtered_query = Q(proctored_exam__course_id=course_id)
if timed_exams_only:
filtered_query = filtered_query & Q(proctored_exam__is_proctored=False)
return self.filter(filtered_query).order_by('-created') return self.filter(filtered_query).order_by('-created')
def get_filtered_exam_attempts(self, course_id, search_by, timed_exams_only=False): def get_filtered_exam_attempts(self, course_id, search_by):
""" """
Returns the Student Exam Attempts for the given course_id filtered by search_by. Returns the Student Exam Attempts for the given course_id filtered by search_by.
""" """
filtered_query = Q(proctored_exam__course_id=course_id) & ( filtered_query = Q(proctored_exam__course_id=course_id) & (
Q(user__username__contains=search_by) | Q(user__email__contains=search_by) Q(user__username__contains=search_by) | Q(user__email__contains=search_by)
) )
if timed_exams_only:
filtered_query = filtered_query & Q(proctored_exam__is_proctored=False)
return self.filter(filtered_query).order_by('-created') # pylint: disable=no-member return self.filter(filtered_query).order_by('-created') # pylint: disable=no-member
def get_proctored_exam_attempts(self, course_id, username): def get_proctored_exam_attempts(self, course_id, username):
...@@ -720,14 +713,11 @@ class ProctoredExamStudentAllowance(TimeStampedModel): ...@@ -720,14 +713,11 @@ class ProctoredExamStudentAllowance(TimeStampedModel):
verbose_name = 'proctored allowance' verbose_name = 'proctored allowance'
@classmethod @classmethod
def get_allowances_for_course(cls, course_id, timed_exams_only=False): def get_allowances_for_course(cls, course_id):
""" """
Returns all the allowances for a course. Returns all the allowances for a course.
""" """
filtered_query = Q(proctored_exam__course_id=course_id) filtered_query = Q(proctored_exam__course_id=course_id)
if timed_exams_only:
filtered_query = filtered_query & Q(proctored_exam__is_proctored=False)
return cls.objects.filter(filtered_query) return cls.objects.filter(filtered_query)
@classmethod @classmethod
......
...@@ -409,7 +409,7 @@ class ProctoredExamApiTests(ProctoredExamTestCase): ...@@ -409,7 +409,7 @@ class ProctoredExamApiTests(ProctoredExamTestCase):
Test to get all the allowances for a course. Test to get all the allowances for a course.
""" """
allowance = self._add_allowance_for_user() allowance = self._add_allowance_for_user()
course_allowances = get_allowances_for_course(self.course_id, False) course_allowances = get_allowances_for_course(self.course_id)
self.assertEqual(len(course_allowances), 1) self.assertEqual(len(course_allowances), 1)
self.assertEqual(course_allowances[0]['proctored_exam']['course_id'], allowance.proctored_exam.course_id) self.assertEqual(course_allowances[0]['proctored_exam']['course_id'], allowance.proctored_exam.course_id)
......
...@@ -1190,11 +1190,10 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1190,11 +1190,10 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response_data = json.loads(response.content) response_data = json.loads(response.content)
self.assertEqual(len(response_data['proctored_exam_attempts']), 1) self.assertEqual(len(response_data['proctored_exam_attempts']), 1)
def test_exam_attempts_not_staff(self): def test_exam_attempts_not_global_staff(self):
""" """
Test to get the exam attempts in a course as a not Test to get both timed and proctored exam attempts
staff user but still we get the timed exams attempts in a course as a course staff
but not the proctored exam attempts
""" """
# Create an timed_exam. # Create an timed_exam.
timed_exam = ProctoredExam.objects.create( timed_exam = ProctoredExam.objects.create(
...@@ -1241,11 +1240,15 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1241,11 +1240,15 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content) response_data = json.loads(response.content)
# we should only get the timed exam attempt in this case # assert that both timed and proctored exam attempts are in response data
# so the len should be 1 # so the len should be 2
self.assertEqual(len(response_data['proctored_exam_attempts']), 1) self.assertEqual(len(response_data['proctored_exam_attempts']), 2)
self.assertEqual( self.assertEqual(
response_data['proctored_exam_attempts'][0]['proctored_exam']['is_proctored'], response_data['proctored_exam_attempts'][0]['proctored_exam']['is_proctored'],
proctored_exam.is_proctored
)
self.assertEqual(
response_data['proctored_exam_attempts'][1]['proctored_exam']['is_proctored'],
timed_exam.is_proctored timed_exam.is_proctored
) )
...@@ -2317,9 +2320,9 @@ class TestExamAllowanceView(LoggedInTestCase): ...@@ -2317,9 +2320,9 @@ class TestExamAllowanceView(LoggedInTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content) response_data = json.loads(response.content)
# we should only get the timed exam allowance # assert that both timed and proctored exams allowance are in response data
# We are not logged in as a global user # so the len should be 2
self.assertEqual(len(response_data), 1) self.assertEqual(len(response_data), 2)
self.assertEqual(response_data[0]['proctored_exam']['course_id'], timed_exam.course_id) self.assertEqual(response_data[0]['proctored_exam']['course_id'], timed_exam.course_id)
self.assertEqual(response_data[0]['proctored_exam']['content_id'], timed_exam.content_id) self.assertEqual(response_data[0]['proctored_exam']['content_id'], timed_exam.content_id)
self.assertEqual(response_data[0]['key'], allowance_data['key']) self.assertEqual(response_data[0]['key'], allowance_data['key'])
......
...@@ -611,18 +611,16 @@ class StudentProctoredExamAttemptsByCourse(AuthenticatedAPIView): ...@@ -611,18 +611,16 @@ class StudentProctoredExamAttemptsByCourse(AuthenticatedAPIView):
def get(self, request, course_id, search_by=None): # pylint: disable=unused-argument def get(self, request, course_id, search_by=None): # pylint: disable=unused-argument
""" """
HTTP GET Handler. Returns the status of the exam attempt. HTTP GET Handler. Returns the status of the exam attempt.
Course and Global staff can view both timed and proctored exam attempts.
""" """
# course staff only views attempts of timed exams. edx staff can view both timed and proctored attempts.
time_exams_only = not request.user.is_staff
if search_by is not None: if search_by is not None:
exam_attempts = ProctoredExamStudentAttempt.objects.get_filtered_exam_attempts( exam_attempts = ProctoredExamStudentAttempt.objects.get_filtered_exam_attempts(
course_id, search_by, time_exams_only course_id, search_by
) )
attempt_url = reverse('edx_proctoring.proctored_exam.attempts.search', args=[course_id, search_by]) attempt_url = reverse('edx_proctoring.proctored_exam.attempts.search', args=[course_id, search_by])
else: else:
exam_attempts = ProctoredExamStudentAttempt.objects.get_all_exam_attempts( exam_attempts = ProctoredExamStudentAttempt.objects.get_all_exam_attempts(
course_id, time_exams_only course_id
) )
attempt_url = reverse('edx_proctoring.proctored_exam.attempts.course', args=[course_id]) attempt_url = reverse('edx_proctoring.proctored_exam.attempts.course', args=[course_id])
...@@ -701,13 +699,10 @@ class ExamAllowanceView(AuthenticatedAPIView): ...@@ -701,13 +699,10 @@ class ExamAllowanceView(AuthenticatedAPIView):
def get(self, request, course_id): # pylint: disable=unused-argument def get(self, request, course_id): # pylint: disable=unused-argument
""" """
HTTP GET handler. Get all allowances for a course. HTTP GET handler. Get all allowances for a course.
Course and Global staff can view both timed and proctored exam allowances.
""" """
# course staff only views attempts of timed exams. edx staff can view both timed and proctored attempts.
time_exams_only = not request.user.is_staff
result_set = get_allowances_for_course( result_set = get_allowances_for_course(
course_id=course_id, course_id=course_id
timed_exams_only=time_exams_only
) )
return Response(result_set) return Response(result_set)
......
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