Commit eaf8a896 by Eric Fischer

Merge pull request #281 from edx/efischer/delete_state

Pass requesting user on delete_student_attempt
parents a7dc8756 5e00da60
...@@ -962,9 +962,9 @@ def send_proctoring_attempt_status_email(exam_attempt_obj, course_name): ...@@ -962,9 +962,9 @@ def send_proctoring_attempt_status_email(exam_attempt_obj, course_name):
email.send() email.send()
def remove_exam_attempt(attempt_id): def remove_exam_attempt(attempt_id, requesting_user):
""" """
Removes an exam attempt given the attempt id. Removes an exam attempt given the attempt id. requesting_user is passed through to the instructor_service.
""" """
log_msg = ( log_msg = (
...@@ -991,7 +991,7 @@ def remove_exam_attempt(attempt_id): ...@@ -991,7 +991,7 @@ def remove_exam_attempt(attempt_id):
instructor_service = get_runtime_service('instructor') instructor_service = get_runtime_service('instructor')
if instructor_service: if instructor_service:
instructor_service.delete_student_attempt(username, course_id, content_id) instructor_service.delete_student_attempt(username, course_id, content_id, requesting_user=requesting_user)
# see if the status transition this changes credit requirement status # see if the status transition this changes credit requirement status
if ProctoredExamStudentAttemptStatus.needs_credit_status_update(to_status): if ProctoredExamStudentAttemptStatus.needs_credit_status_update(to_status):
......
...@@ -649,7 +649,7 @@ class SoftwareSecureTests(TestCase): ...@@ -649,7 +649,7 @@ class SoftwareSecureTests(TestCase):
) )
# now delete the attempt, which puts it into the archive table # now delete the attempt, which puts it into the archive table
remove_exam_attempt(attempt_id) remove_exam_attempt(attempt_id, requesting_user=self.user)
# now process the report # now process the report
provider.on_review_callback(json.loads(test_payload)) provider.on_review_callback(json.loads(test_payload))
...@@ -873,7 +873,7 @@ class SoftwareSecureTests(TestCase): ...@@ -873,7 +873,7 @@ class SoftwareSecureTests(TestCase):
self.assertEqual(attempt['status'], attempt['status']) self.assertEqual(attempt['status'], attempt['status'])
# now delete the attempt, which puts it into the archive table # now delete the attempt, which puts it into the archive table
remove_exam_attempt(attempt_id) remove_exam_attempt(attempt_id, requesting_user=self.user)
review = ProctoredExamSoftwareSecureReview.objects.get(attempt_code=attempt['attempt_code']) review = ProctoredExamSoftwareSecureReview.objects.get(attempt_code=attempt['attempt_code'])
......
...@@ -827,13 +827,21 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -827,13 +827,21 @@ class ProctoredExamApiTests(LoggedInTestCase):
Calling the api remove function removes the attempt. Calling the api remove function removes the attempt.
""" """
with self.assertRaises(StudentExamAttemptDoesNotExistsException): with self.assertRaises(StudentExamAttemptDoesNotExistsException):
remove_exam_attempt(9999) remove_exam_attempt(9999, requesting_user=self.user)
proctored_exam_student_attempt = self._create_unstarted_exam_attempt() proctored_exam_student_attempt = self._create_unstarted_exam_attempt()
remove_exam_attempt(proctored_exam_student_attempt.id) remove_exam_attempt(proctored_exam_student_attempt.id, requesting_user=self.user)
with self.assertRaises(StudentExamAttemptDoesNotExistsException): with self.assertRaises(StudentExamAttemptDoesNotExistsException):
remove_exam_attempt(proctored_exam_student_attempt.id) remove_exam_attempt(proctored_exam_student_attempt.id, requesting_user=self.user)
def test_remove_no_user(self):
"""
Attempting to remove an exam attempt without providing a requesting user will fail.
"""
proctored_exam_student_attempt = self._create_unstarted_exam_attempt()
with self.assertRaises(UserNotFoundException):
remove_exam_attempt(proctored_exam_student_attempt.id, requesting_user={})
@ddt.data( @ddt.data(
(ProctoredExamStudentAttemptStatus.verified, 'satisfied'), (ProctoredExamStudentAttemptStatus.verified, 'satisfied'),
...@@ -868,7 +876,7 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -868,7 +876,7 @@ class ProctoredExamApiTests(LoggedInTestCase):
) )
# now remove exam attempt which calls the credit service method 'remove_credit_requirement_status' # now remove exam attempt which calls the credit service method 'remove_credit_requirement_status'
remove_exam_attempt(exam_attempt.proctored_exam_id) remove_exam_attempt(exam_attempt.proctored_exam_id, requesting_user=self.user)
# make sure the credit requirement status is no longer there # make sure the credit requirement status is no longer there
credit_status = credit_service.get_credit_state(self.user.id, exam_attempt.proctored_exam.course_id) credit_status = credit_service.get_credit_state(self.user.id, exam_attempt.proctored_exam.course_id)
......
...@@ -10,6 +10,7 @@ from datetime import datetime, timedelta ...@@ -10,6 +10,7 @@ from datetime import datetime, timedelta
from edx_proctoring.services import ( from edx_proctoring.services import (
ProctoringService ProctoringService
) )
from edx_proctoring.exceptions import UserNotFoundException
from edx_proctoring import api as edx_proctoring_api from edx_proctoring import api as edx_proctoring_api
import types import types
...@@ -111,10 +112,14 @@ class MockInstructorService(object): ...@@ -111,10 +112,14 @@ class MockInstructorService(object):
""" """
self.is_user_course_staff = is_user_course_staff self.is_user_course_staff = is_user_course_staff
def delete_student_attempt(self, student_identifier, course_id, content_id): # pylint: disable=unused-argument # pylint: disable=unused-argument
def delete_student_attempt(self, student_identifier, course_id, content_id, requesting_user):
""" """
Mock implementation Mock implementation
""" """
# Ensure that this method was called with a real user object
if not hasattr(requesting_user, 'id'):
raise UserNotFoundException
return True return True
def is_course_staff(self, user, course_id): def is_course_staff(self, user, course_id):
......
...@@ -464,7 +464,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -464,7 +464,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
) )
raise StudentExamAttemptDoesNotExistsException(err_msg) raise StudentExamAttemptDoesNotExistsException(err_msg)
remove_exam_attempt(attempt_id) remove_exam_attempt(attempt_id, request.user)
return Response() return Response()
except ProctoredBaseException, ex: except ProctoredBaseException, ex:
......
...@@ -34,7 +34,7 @@ def load_requirements(*requirements_paths): ...@@ -34,7 +34,7 @@ def load_requirements(*requirements_paths):
setup( setup(
name='edx-proctoring', name='edx-proctoring',
version='0.12.13', version='0.12.14',
description='Proctoring subsystem for Open edX', description='Proctoring subsystem for Open edX',
long_description=open('README.md').read(), long_description=open('README.md').read(),
author='edX', author='edX',
......
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