Skip to content

Commit

Permalink
feat: [BD-26] Timer bar on non-sequence pages (#894)
Browse files Browse the repository at this point in the history
* feat: change url for ProctoredExamAttempt API

* test: add test for ProctoredExamAttempt API

* feat: additionally leave the old URL format for ProctoredExamAttemptView
  • Loading branch information
UvgenGen authored Jul 2, 2021
1 parent 16b1ec6 commit 7caef68
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 15 deletions.
62 changes: 50 additions & 12 deletions edx_proctoring/tests/test_mfe_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import json
from itertools import product
from urllib.parse import urlencode

import ddt
from mock import patch
Expand Down Expand Up @@ -39,9 +40,11 @@ def setUp(self):
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': self.content_id
}
) + '?is_learning_mfe=true'
) + '?' + urlencode({
'content_id': self.content_id,
'is_learning_mfe': True,
})
self.expected_exam_url = '{}/course/{}/{}'.format(
settings.LEARNING_MICROFRONTEND_URL, self.course_id, self.content_id
)
Expand Down Expand Up @@ -103,6 +106,31 @@ def test_get_started_proctored_exam_attempts_data(self):
self.assertEqual(exam_data['attempt']['exam_url_path'], self.expected_exam_url)
self.assertEqual(exam_data['type'], 'proctored')

def test_get_exam_attempts_data_by_course_id(self):
"""
Tests the get exam attempts data by course id.
"""
self._create_started_exam_attempt(is_proctored=True)

url = reverse(
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
}
) + '?' + urlencode({
'is_learning_mfe': True,
})

response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content.decode('utf-8'))
exam_data = response_data['exam']

# if exam started the prerequisites are not checked
assert 'prerequisite_status' not in exam_data
assert not exam_data
assert 'active_attempt' in response_data and response_data['active_attempt']

def test_get_started_timed_exam_attempts_data(self):
"""
Tests the get timed exam attempts data by course id and usage key endpoint for started exam.
Expand All @@ -113,9 +141,11 @@ def test_get_started_timed_exam_attempts_data(self):
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': self.content_id_timed
}
) + '?is_learning_mfe=true'
) + '?' + urlencode({
'content_id': self.content_id_timed,
'is_learning_mfe': True,
})

response = self.client.get(url)
self.assertEqual(response.status_code, 200)
Expand Down Expand Up @@ -167,9 +197,11 @@ def test_no_exam_data_returned_for_non_exam_sequence(self):
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': 'block-v1:test+course+1+type@sequential+block@unit'
}
) + '?is_learning_mfe=true'
) + '?' + urlencode({
'content_id': 'block-v1:test+course+1+type@sequential+block@unit',
'is_learning_mfe': True,
})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response_data = json.loads(response.content.decode('utf-8'))
Expand All @@ -194,9 +226,11 @@ def test_prerequisites_are_not_checked_if_exam_is_not_proctored(self, content_id
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': content_id
}
) + '?is_learning_mfe=true'
) + '?' + urlencode({
'content_id': content_id,
'is_learning_mfe': True,
})

response = self.client.get(url)
self.assertEqual(response.status_code, 200)
Expand Down Expand Up @@ -267,9 +301,11 @@ def test_exam_data_contains_link_to_onboarding_exam_if_attempt_in_onboarding_err
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': self.content_id
}
) + '?is_learning_mfe={is_learning_mfe}'.format(is_learning_mfe=is_learning_mfe)
) + '?' + urlencode({
'content_id': self.content_id,
'is_learning_mfe': is_learning_mfe,
})
response = self.client.get(url)
response_data = json.loads(response.content.decode('utf-8'))
exam = response_data['exam']
Expand All @@ -287,9 +323,11 @@ def test_exam_data_does_not_fail_if_onboarding_errors_and_no_onboarding_exam(sel
'edx_proctoring:proctored_exam.exam_attempts',
kwargs={
'course_id': self.course_id,
'content_id': self.content_id
}
) + '?is_learning_mfe=true'
) + '?' + urlencode({
'content_id': self.content_id,
'is_learning_mfe': True,
})
with patch('edx_proctoring.models.ProctoredExam.objects.filter', return_value=ProctoredExam.objects.none()):
response = self.client.get(url)
response_data = json.loads(response.content.decode('utf-8'))
Expand Down
9 changes: 8 additions & 1 deletion edx_proctoring/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,18 @@
views.UserRetirement.as_view(),
name='user_retirement_api'
),
url(
r'edx_proctoring/v1/proctored_exam/attempt/course_id/{}$'.format(
settings.COURSE_ID_PATTERN),
views.ProctoredExamAttemptView.as_view(),
name='proctored_exam.exam_attempts'
),
# TODO: remove url after updating frontend-lib-special-exams
url(
r'edx_proctoring/v1/proctored_exam/attempt/course_id/{}/content_id/{}$'.format(
settings.COURSE_ID_PATTERN, CONTENT_ID_PATTERN),
views.ProctoredExamAttemptView.as_view(),
name='proctored_exam.exam_attempts'
name='proctored_exam.exam_attempts_old'
),
url(
r'edx_proctoring/v1/proctored_exam/settings/exam_id/(?P<exam_id>\d+)/$',
Expand Down
15 changes: 13 additions & 2 deletions edx_proctoring/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,13 @@ def handle_exception(self, exc):
class ProctoredExamAttemptView(ProctoredAPIView):
"""
Endpoint for getting timed or proctored exam and its attempt data.
/edx_proctoring/v1/proctored_exam/attempt/course_id/{course_id}/content_id/{content_id}
/edx_proctoring/v1/proctored_exam/attempt/course_id/{course_id}
Supports:
HTTP GET:
** Scenarios **
?content_id=123
returns an existing exam
?is_learning_mfe=true
returns attempt data with `exam_url_path` built for the learning mfe
Expand All @@ -213,7 +215,7 @@ class ProctoredExamAttemptView(ProctoredAPIView):
'active_attempt': { ... },
}
"""
def get(self, request, course_id, content_id):
def get(self, request, course_id, content_id=None):
"""
HTTP GET handler. Returns exam with attempt and active attempt
"""
Expand All @@ -222,6 +224,7 @@ def get(self, request, course_id, content_id):
active_exam = {}

is_learning_mfe = request.GET.get('is_learning_mfe') in ['1', 'true', 'True']
content_id = request.GET.get('content_id', content_id)

active_exams = get_active_exams_for_user(request.user.id)
if active_exams:
Expand All @@ -235,6 +238,14 @@ def get(self, request, course_id, content_id):
active_attempt.get('id'),
is_learning_mfe=is_learning_mfe
)

if not content_id:
response_dict = {
'exam': {},
'active_attempt': active_attempt_data,
}
return Response(data=response_dict, status=status.HTTP_200_OK)

if active_exam and active_exam.get('course_id') == course_id and active_exam.get('content_id') == content_id:
exam = active_exam
exam.update({'attempt': active_attempt_data})
Expand Down

0 comments on commit 7caef68

Please sign in to comment.