Commit 14044ea0 by Joe Blaylock

Merge pull request #70 from Stanford-Online/jbau/timed-exam-hack

HACK capa timed-test on capa_base.py
parents cc34a0f0 846ab440
...@@ -160,6 +160,9 @@ class CapaFields(object): ...@@ -160,6 +160,9 @@ class CapaFields(object):
student_answers = Dict(help=_("Dictionary with the current student responses"), scope=Scope.user_state) student_answers = Dict(help=_("Dictionary with the current student responses"), scope=Scope.user_state)
done = Boolean(help=_("Whether the student has answered the problem"), scope=Scope.user_state) done = Boolean(help=_("Whether the student has answered the problem"), scope=Scope.user_state)
seed = Integer(help=_("Random seed for this student"), scope=Scope.user_state) seed = Integer(help=_("Random seed for this student"), scope=Scope.user_state)
minutes_allowed = Integer(help=_("EXPERIMENTAL FEATURE: DO NOT USE. Number of minutes allowed to finish this assessment. Set 0 for no time-limit"),
default=0, scope=Scope.settings)
time_started = Date(help=_("time student started this assessment"), scope=Scope.user_state)
last_submission_time = Date(help=_("Last submission time"), scope=Scope.user_state) last_submission_time = Date(help=_("Last submission time"), scope=Scope.user_state)
submission_wait_seconds = Integer( submission_wait_seconds = Integer(
display_name=_("Timer Between Attempts"), display_name=_("Timer Between Attempts"),
...@@ -346,6 +349,12 @@ class CapaMixin(CapaFields): ...@@ -346,6 +349,12 @@ class CapaMixin(CapaFields):
self.student_answers = lcp_state['student_answers'] self.student_answers = lcp_state['student_answers']
self.seed = lcp_state['seed'] self.seed = lcp_state['seed']
def set_time_started(self):
"""
Sets the time when the student started the module.
"""
self.time_started = datetime.datetime.now(UTC())
def set_last_submission_time(self): def set_last_submission_time(self):
""" """
Set the module's last submission time (when the problem was checked) Set the module's last submission time (when the problem was checked)
...@@ -616,6 +625,21 @@ class CapaMixin(CapaFields): ...@@ -616,6 +625,21 @@ class CapaMixin(CapaFields):
check_button = False check_button = False
check_button_checking = False check_button_checking = False
problem_is_timed = self.minutes_allowed > 0
if problem_is_timed and not self.time_started:
self.set_time_started()
end_time_to_display = (self.time_started + datetime.timedelta(minutes=self.minutes_allowed)
if problem_is_timed
else None)
# because we use self.due and not self.close_date below, this is not the actual end_time, but the
# end_time we want to display to the user
if self.due and end_time_to_display:
end_time_to_display = min(self.due, end_time_to_display)
content = { content = {
'name': self.display_name_with_default, 'name': self.display_name_with_default,
'html': html, 'html': html,
...@@ -625,6 +649,9 @@ class CapaMixin(CapaFields): ...@@ -625,6 +649,9 @@ class CapaMixin(CapaFields):
context = { context = {
'problem': content, 'problem': content,
'id': self.location.to_deprecated_string(), 'id': self.location.to_deprecated_string(),
'problem_is_timed': problem_is_timed,
'start_time': self.time_started,
'end_time_to_display': end_time_to_display,
'check_button': check_button, 'check_button': check_button,
'check_button_checking': check_button_checking, 'check_button_checking': check_button_checking,
'reset_button': self.should_show_reset_button(), 'reset_button': self.should_show_reset_button(),
...@@ -652,6 +679,17 @@ class CapaMixin(CapaFields): ...@@ -652,6 +679,17 @@ class CapaMixin(CapaFields):
return html return html
def exceeded_time_limit(self):
"""
Has student used up allotted time, if set
"""
if self.minutes_allowed <= 0 or not self.time_started:
return False
now = datetime.datetime.now(UTC())
# built in hardcoded grace period of 5 min
time_limit_end = self.time_started + datetime.timedelta(minutes=(self.minutes_allowed + 5))
return now > time_limit_end
def is_past_due(self): def is_past_due(self):
""" """
Is it now past this problem's due date, including grace period? Is it now past this problem's due date, including grace period?
...@@ -667,6 +705,8 @@ class CapaMixin(CapaFields): ...@@ -667,6 +705,8 @@ class CapaMixin(CapaFields):
return True return True
if self.is_past_due(): if self.is_past_due():
return True return True
if self.exceeded_time_limit():
return True
return False return False
......
<%! from django.utils.translation import ugettext as _ %> <%!
from django.utils.translation import ugettext as _
from xmodule.util.date_utils import get_time_display
from django.conf import settings
%>
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<h2 class="problem-header"> <h2 class="problem-header">
...@@ -7,6 +11,20 @@ ...@@ -7,6 +11,20 @@
<div class="problem-progress"></div> <div class="problem-progress"></div>
% if problem_is_timed:
<div class="time_limit">
<p>
${_("At {start_time}, you started this exam.").format(
start_time=get_time_display(start_time, coerce_tz=settings.TIME_ZONE))}
<br />
<b>
${_("By {end_time}, you must manually click the 'Final Submit' button below!").format(
end_time=get_time_display(end_time_to_display, coerce_tz=settings.TIME_ZONE))}
</b>
</p>
</div>
% endif
<div class="problem" role="application"> <div class="problem" role="application">
${ problem['html'] } ${ problem['html'] }
......
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