Commit 66b468e7 by Chris Dodge

Declining a proctoring exam makes it open book and not eligibl for credit

parent ce90c0eb
...@@ -29,7 +29,7 @@ from edx_proctoring.urls import urlpatterns ...@@ -29,7 +29,7 @@ from edx_proctoring.urls import urlpatterns
from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD from edx_proctoring.backends.tests.test_review_payload import TEST_REVIEW_PAYLOAD
from edx_proctoring.backends.tests.test_software_secure import mock_response_content from edx_proctoring.backends.tests.test_software_secure import mock_response_content
from edx_proctoring.tests.test_services import MockCreditService from edx_proctoring.tests.test_services import MockCreditService
from edx_proctoring.runtime import set_runtime_service from edx_proctoring.runtime import set_runtime_service, get_runtime_service
class ProctoredExamsApiTests(LoggedInTestCase): class ProctoredExamsApiTests(LoggedInTestCase):
...@@ -42,6 +42,7 @@ class ProctoredExamsApiTests(LoggedInTestCase): ...@@ -42,6 +42,7 @@ class ProctoredExamsApiTests(LoggedInTestCase):
Build out test harnessing Build out test harnessing
""" """
super(ProctoredExamsApiTests, self).setUp() super(ProctoredExamsApiTests, self).setUp()
set_runtime_service('credit', MockCreditService())
def test_no_anonymous_access(self): def test_no_anonymous_access(self):
""" """
...@@ -950,6 +951,42 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -950,6 +951,42 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_declined_attempt(self):
"""
Makes sure that a declined proctored attempt means that he/she fails credit requirement.
"""
# Create an exam.
proctored_exam = ProctoredExam.objects.create(
course_id='a/b/c',
content_id='test_content',
exam_name='Test Exam',
external_id='123aXqe3',
is_proctored=True,
time_limit_mins=90
)
attempt_data = {
'exam_id': proctored_exam.id,
'start_clock': False,
'attempt_proctored': False
}
# create a exam attempt
response = self.client.post(
reverse('edx_proctoring.proctored_exam.attempt.collection'),
attempt_data
)
self.assertEqual(response.status_code, 200)
# make sure we failed the requirement status
credit_service = get_runtime_service('credit')
credit_status = credit_service.get_credit_state(self.user.id, proctored_exam.course_id)
self.assertEqual(len(credit_status['credit_requirement_status']), 1)
self.assertEqual(
credit_status['credit_requirement_status'][0]['status'],
'failed'
)
def test_exam_callback(self): def test_exam_callback(self):
""" """
Start an exam (create an exam attempt) Start an exam (create an exam attempt)
......
...@@ -30,7 +30,8 @@ from edx_proctoring.api import ( ...@@ -30,7 +30,8 @@ from edx_proctoring.api import (
get_all_exam_attempts, get_all_exam_attempts,
remove_exam_attempt, remove_exam_attempt,
get_filtered_exam_attempts, get_filtered_exam_attempts,
update_exam_attempt update_exam_attempt,
update_attempt_status
) )
from edx_proctoring.exceptions import ( from edx_proctoring.exceptions import (
ProctoredBaseException, ProctoredBaseException,
...@@ -40,6 +41,7 @@ from edx_proctoring.exceptions import ( ...@@ -40,6 +41,7 @@ from edx_proctoring.exceptions import (
StudentExamAttemptDoesNotExistsException, StudentExamAttemptDoesNotExistsException,
) )
from edx_proctoring.serializers import ProctoredExamSerializer from edx_proctoring.serializers import ProctoredExamSerializer
from edx_proctoring.models import ProctoredExamStudentAttemptStatus
from .utils import AuthenticatedAPIView from .utils import AuthenticatedAPIView
...@@ -528,7 +530,17 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView): ...@@ -528,7 +530,17 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView):
taking_as_proctored=attempt_proctored taking_as_proctored=attempt_proctored
) )
if start_immediately: exam = get_exam_by_id(exam_id)
# if use elected not to take as proctored exam, then
# use must take as open book, and loose credit eligibility
if exam['is_proctored'] and not attempt_proctored:
update_attempt_status(
exam_id,
request.user.id,
ProctoredExamStudentAttemptStatus.declined
)
elif start_immediately:
start_exam_attempt(exam_id, request.user.id) start_exam_attempt(exam_id, request.user.id)
return Response({'exam_attempt_id': exam_attempt_id}) return Response({'exam_attempt_id': exam_attempt_id})
......
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