Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jeff/tmp #1871

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ client error are correctly passed through to the client.
LMS: Improve performance of page load and thread list load for
discussion tab

Studio: Added feature to allow instructors to specify wait time between attempts
of the same quiz. In a problem's settings, instructors can specify how many
seconds student's are locked out of submitting another attempt of the same quiz.
The timer starts as soon as they submit an attempt for grading. Note that this
does not prevent a student from starting to work on another quiz attempt. It only
prevents the students from submitting a bunch of attempts in rapid succession.

LMS: The wiki markup cheatsheet dialog is now accessible to screen readers.
(LMS-1303)

Expand Down
2 changes: 2 additions & 0 deletions cms/djangoapps/contentstore/features/problem-editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
PROBLEM_WEIGHT = "Problem Weight"
RANDOMIZATION = 'Randomization'
SHOW_ANSWER = "Show Answer"
TIMER_BETWEEN_ATTEMPTS = "Timer Between Attempts"


@step('I have created a Blank Common Problem$')
Expand Down Expand Up @@ -45,6 +46,7 @@ def i_see_advanced_settings_with_values(step):
[PROBLEM_WEIGHT, "", False],
[RANDOMIZATION, "Never", False],
[SHOW_ANSWER, "Finished", False],
[TIMER_BETWEEN_ATTEMPTS, "0", False]
])


Expand Down
37 changes: 37 additions & 0 deletions common/lib/xmodule/xmodule/capa_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ class CapaFields(object):
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)
seed = Integer(help="Random seed for this student", scope=Scope.user_state)

last_submission_time = Date(help="Last submission time", scope=Scope.user_state)
submission_wait_seconds = Integer(
display_name="Timer Between Attempts",
help="Seconds a student must wait between submissions for a problem with multiple attempts.",
scope=Scope.settings,
default=0)

weight = Float(
display_name="Problem Weight",
help=("Defines the number of points each problem is worth. "
Expand Down Expand Up @@ -303,6 +311,12 @@ def set_state_from_lcp(self):
self.student_answers = lcp_state['student_answers']
self.seed = lcp_state['seed']

def set_last_submission_time(self):
"""
Set the module's last submission time (when the problem was checked)
"""
self.last_submission_time = datetime.datetime.now(UTC())

def get_score(self):
"""
Access the problem's score
Expand Down Expand Up @@ -925,17 +939,28 @@ def check_problem(self, data):
if self.lcp.is_queued():
current_time = datetime.datetime.now(UTC())
prev_submit_time = self.lcp.get_recentmost_queuetime()

waittime_between_requests = self.system.xqueue['waittime']
if (current_time - prev_submit_time).total_seconds() < waittime_between_requests:
msg = u'You must wait at least {wait} seconds between submissions'.format(
wait=waittime_between_requests)
return {'success': msg, 'html': ''} # Prompts a modal dialog in ajax callback

# Wait time between resets
current_time = datetime.datetime.now(UTC())
if self.last_submission_time is not None:
if (current_time - self.last_submission_time).total_seconds() < self.submission_wait_seconds:
seconds_left = int(self.submission_wait_seconds - (current_time - self.last_submission_time).total_seconds()) + 1
msg = u'You must wait at least {w} between submissions. {s} remaining.'.format(
w=self.pretty_print_seconds(self.submission_wait_seconds), s=self.pretty_print_seconds(seconds_left))
return {'success': msg, 'html': ''} # Prompts a modal dialog in ajax callback

try:
correct_map = self.lcp.grade_answers(answers)
self.attempts = self.attempts + 1
self.lcp.done = True
self.set_state_from_lcp()
self.set_last_submission_time()

except (StudentInputError, ResponseError, LoncapaProblemError) as inst:
log.warning("StudentInputError in capa_module:problem_check",
Expand Down Expand Up @@ -994,6 +1019,18 @@ def check_problem(self, data):
'contents': html,
}

def pretty_print_seconds(self, num_seconds):
"""
Returns time formatted nicely.
"""
if(num_seconds < 60):
plural = "s" if num_seconds > 1 else ""
return "%i second%s" % (num_seconds, plural)
elif(num_seconds < 60*60):
return "%i min, %i sec" % (int(num_seconds / 60), num_seconds % 60)
else:
return "%i hrs, %i min, %i sec" % (int(num_seconds / 3600), int((num_seconds % 3600) / 60), (num_seconds % 60))

def rescore_problem(self):
"""
Checks whether the existing answers to a problem are correct.
Expand Down
Loading