Commit cfe4923d by chrisndodge

Merge pull request #9 from edx/muhhshoaib/PHX-42-change-the-timed-exam-entrance-html-file

PHX-42 added the html for the entrance timed exam.
parents 120755b9 8a40531b
......@@ -19,6 +19,7 @@ from edx_proctoring.models import (
)
from edx_proctoring.serializers import ProctoredExamSerializer, ProctoredExamStudentAttemptSerializer, \
ProctoredExamStudentAllowanceSerializer
from edx_proctoring.utils import humanized_time
def create_exam(course_id, content_id, exam_name, time_limit_mins,
......@@ -252,7 +253,9 @@ def get_student_view(user_id, course_id, content_id, context):
if student_view_template:
template = loader.get_template(student_view_template)
django_context = Context(context)
total_time = humanized_time(context['default_time_limit_mins'])
django_context.update({
'total_time': total_time,
'exam_id': exam_id,
'enter_exam_endpoint': reverse('edx_proctoring.proctored_exam.attempt'),
})
......
{% load i18n %}
<div class="sequence" >
<div class="gated-sequence">
All done!
{% trans "All done!" %}
</div>
</div>
{% include 'proctoring/seq_timed_exam_footer.html' %}
{% load i18n %}
<div class="sequence" data-exam-id="{{exam_id}}">
<div class="gated-sequence">
This is a timed exam. Would you like to <a class='start-timed-exam' data-ajax-url="{{enter_exam_endpoint}}">enter</a> it?
</div>
<h3>
{% blocktrans %}
{{ display_name }} is a Timed Exam ({{total_time}})
{% endblocktrans %}
</h3>
<p>
{% trans "This exam has a time limit associated with it." %}
<strong>
{% trans "In order to successfully pass this exam you will have to answer the following questions and problems in the time allotted." %}
</strong>
{% blocktrans %}
Once you proceed, you'll start both the exam and the {{total_time|lower}} given to you.
{% endblocktrans %}
</p>
<div class="gated-sequence">
<a class='start-timed-exam' data-ajax-url="{{enter_exam_endpoint}}" data-exam-id="{{exam_id}}">
{% blocktrans %}
I'm ready! Start this timed exam.
{% endblocktrans %}
<i class="fa fa-arrow-circle-right"></i>
</a>
</div>
</div>
{% include 'proctoring/seq_timed_exam_footer.html' %}
<script type="text/javascript">
$('.start-timed-exam').click(
function(event) {
var target = $(event.target);
var action_url = target.data('ajax-url');
var exam_id = target.parent().parent().data('exam-id');
var action_url = $(this).data('ajax-url');
var exam_id = $(this).data('exam-id');
$.post(
action_url,
{
"exam_id": exam_id,
"exam_id": exam_id
},
function(data) {
// reload the page, because we've unlocked it
......
{% load i18n %}
<div class="sequence">
<div class="gated-sequence">
You have run out of time!
{% trans "You have run out of time!" %}
</div>
</div>
{% include 'proctoring/seq_timed_exam_footer.html' %}
\ No newline at end of file
{% load i18n %}
<div class="footer-sequence">
<h4> {% trans "What if i need more time " %}? </h4>
<p>{% trans "edX ocassionally grants more time for students with disabilities and difficult conditions. " %}
{% blocktrans %}
Please see <a href="#">
our frequently asked questions about timed exams and more policies.
</a>
{% endblocktrans %}
</p>
</div>
\ No newline at end of file
......@@ -3,11 +3,29 @@ All tests for the models.py
"""
from datetime import datetime
import pytz
from edx_proctoring.api import create_exam, update_exam, get_exam_by_id, get_exam_by_content_id, \
add_allowance_for_user, remove_allowance_for_user, start_exam_attempt, stop_exam_attempt, get_active_exams_for_user
from edx_proctoring.exceptions import ProctoredExamAlreadyExists, ProctoredExamNotFoundException, \
StudentExamAttemptAlreadyExistsException, StudentExamAttemptDoesNotExistsException
from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAllowance, ProctoredExamStudentAttempt
from edx_proctoring.api import (
create_exam,
update_exam,
get_exam_by_id,
get_exam_by_content_id,
add_allowance_for_user,
remove_allowance_for_user,
start_exam_attempt,
stop_exam_attempt,
get_active_exams_for_user,
get_exam_attempt
)
from edx_proctoring.exceptions import (
ProctoredExamAlreadyExists,
ProctoredExamNotFoundException,
StudentExamAttemptAlreadyExistsException,
StudentExamAttemptDoesNotExistsException
)
from edx_proctoring.models import (
ProctoredExam,
ProctoredExamStudentAllowance,
ProctoredExamStudentAttempt
)
from .utils import (
LoggedInTestCase
......@@ -176,6 +194,16 @@ class ProctoredExamApiTests(LoggedInTestCase):
attempt_id = start_exam_attempt(self.proctored_exam_id, self.user_id, self.external_id)
self.assertGreater(attempt_id, 0)
def test_get_exam_attempt(self):
"""
Test to get the already made exam attempt.
"""
self._create_student_exam_attempt()
exam_attempt = get_exam_attempt(self.proctored_exam_id, self.user_id)
self.assertEqual(exam_attempt['proctored_exam_id'], self.proctored_exam_id)
self.assertEqual(exam_attempt['user_id'], self.user_id)
def test_restart_exam_attempt(self):
"""
Start an exam attempt that has already been started.
......
"""
File that contains tests for the util methods.
"""
import unittest
from edx_proctoring.utils import humanized_time
class TestHumanizedTime(unittest.TestCase):
"""
Class to test the humanized_time utility function
"""
def test_humanized_time(self):
"""
tests the humanized_time utility function against different values.
"""
human_time = humanized_time(0)
self.assertEqual(human_time, "0 Minutes")
human_time = humanized_time(1)
self.assertEqual(human_time, "1 Minute")
human_time = humanized_time(10)
self.assertEqual(human_time, "10 Minutes")
human_time = humanized_time(60)
self.assertEqual(human_time, "1 Hour")
human_time = humanized_time(61)
self.assertEqual(human_time, "1 Hour and 1 Minute")
human_time = humanized_time(62)
self.assertEqual(human_time, "1 Hour and 2 Minutes")
human_time = humanized_time(120)
self.assertEqual(human_time, "2 Hours")
human_time = humanized_time(121)
self.assertEqual(human_time, "2 Hours and 1 Minute")
human_time = humanized_time(150)
self.assertEqual(human_time, "2 Hours and 30 Minutes")
human_time = humanized_time(180)
self.assertEqual(human_time, "3 Hours")
......@@ -49,26 +49,6 @@ class ProctoredExamsApiTests(LoggedInTestCase):
self.assertEqual(response.status_code, 403)
class StudentProctoredExamAttempt(LoggedInTestCase):
"""
Tests for StudentProctoredExamAttempt
"""
def setUp(self):
super(StudentProctoredExamAttempt, self).setUp()
self.user.is_staff = True
self.user.save()
self.client.login_user(self.user)
def test_get_exam_attempt(self):
"""
Test Case for retrieving student proctored exam attempt status.
"""
response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt')
)
self.assertEqual(response.status_code, 200)
class ProctoredExamViewTests(LoggedInTestCase):
"""
Tests for the ProctoredExamView
......@@ -476,6 +456,81 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
response_data = json.loads(response.content)
self.assertEqual(response_data['detail'], 'Error. Trying to stop an exam that is not in progress.')
def test_get_exam_attempt(self):
"""
Test Case for retrieving student proctored exam attempt status.
"""
# Create an exam.
proctored_exam = ProctoredExam.objects.create(
course_id='a/b/c',
content_id='test_content',
exam_name='Test Exam',
external_id='123aXqe3',
time_limit_mins=90
)
response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt')
)
self.assertEqual(response.status_code, 200)
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'),
attempt_data
)
self.assertEqual(response.status_code, 200)
response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt')
)
self.assertEqual(response.status_code, 200)
def test_get_expired_exam_attempt(self):
"""
Test to get the exam the time for which has finished.
"""
# Create an exam.
proctored_exam = ProctoredExam.objects.create(
course_id='a/b/c',
content_id='test_content',
exam_name='Test Exam',
external_id='123aXqe3',
time_limit_mins=90
)
response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt')
)
self.assertEqual(response.status_code, 200)
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'),
attempt_data
)
self.assertEqual(response.status_code, 200)
ProctoredExamStudentAttempt.objects.filter(
proctored_exam_id=proctored_exam.id,
user_id=self.user.id,
external_id=proctored_exam.external_id,
).update(
started_at=datetime.now(pytz.UTC).replace(year=2013)
)
response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt')
)
self.assertEqual(response.status_code, 200)
class TestExamAllowanceView(LoggedInTestCase):
"""
......
......@@ -2,6 +2,7 @@
Helpers for the HTTP APIs
"""
from django.utils.translation import ugettext as _
from rest_framework.views import APIView
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
......@@ -13,3 +14,45 @@ class AuthenticatedAPIView(APIView):
"""
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,)
def humanized_time(time_in_minutes):
"""
Converts the given value in minutes to a more human readable format
1 -> 1 Minute
2 -> 2 Minutes
60 -> 1 hour
90 -> 1 hour and 30 Minutes
120 -> 2 hours
"""
hours = int(time_in_minutes / 60)
minutes = time_in_minutes % 60
template = ""
hours_present = False
if hours == 0:
hours_present = False
elif hours == 1:
template = _("{num_of_hours} Hour")
hours_present = True
elif hours >= 2:
template = _("{num_of_hours} Hours")
hours_present = True
if minutes == 0:
if not hours_present:
template = _("{num_of_minutes} Minutes")
elif minutes == 1:
if hours_present:
template += _(" and {num_of_minutes} Minute")
else:
template += _("{num_of_minutes} Minute")
elif minutes >= 2:
if hours_present:
template += _(" and {num_of_minutes} Minutes")
else:
template += _("{num_of_minutes} Minutes")
human_time = template.format(num_of_hours=hours, num_of_minutes=minutes)
return human_time
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