canvas-lms/app/helpers/quizzes_helper.rb

614 lines
19 KiB
Ruby
Raw Normal View History

2011-02-01 09:57:29 +08:00
#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module QuizzesHelper
def needs_unpublished_warning?(quiz=@quiz, user=@current_user)
if quiz.feature_enabled?(:draft_state)
return false unless can_publish(quiz)
show_unpublished_changes = true
else
return false unless can_read(quiz)
show_unpublished_changes = can_publish(quiz)
end
!quiz.available? || (show_unpublished_changes && quiz.unpublished_changes?)
end
def can_read(quiz, user=@current_user)
can_do(quiz, user, :read)
end
def can_publish(quiz, user=@current_user)
can_do(quiz, user, :update) || can_do(quiz, user, :manage)
end
def unpublished_quiz_warning
I18n.t("#quizzes.warnings.unpublished_quiz",
'*This quiz is unpublished* Only teachers can see the quiz until ' +
'it is published.',
:wrapper => '<strong class=unpublished_quiz_warning>\1</strong>')
end
def unpublished_changes_warning
I18n.t("#quizzes.warnings.unpublished_changes",
'*You have made unpublished changes to this quiz.* '+
'These changes will not appear for students until you publish or ' +
'republish the quiz.',
:wrapper => '<strong class=unpublished_quiz_warning>\1</strong>')
end
def draft_state_unsaved_changes_warning
I18n.t("#quizzes.warnings.draft_state_unsaved_changes",
'*You have made changes to the questions in this quiz.* '+
'These changes will not appear for students until you ' +
'save the quiz.',
:wrapper => '<strong class=unsaved_quiz_warning>\1</strong>')
end
def quiz_published_state_warning(quiz=@quiz)
if !quiz.available?
unpublished_quiz_warning
else
if quiz.feature_enabled? :draft_state
draft_state_unsaved_changes_warning
else
unpublished_changes_warning
end
end
end
def display_save_button?(quiz=@quiz)
quiz.available? && quiz.feature_enabled?(:draft_state) && can_publish(quiz)
end
def render_score(score, precision=2)
if score.nil?
'_'
else
score.to_f.round(precision).to_s
end
end
def render_quiz_type(quiz_type)
case quiz_type
when "practice_quiz"
I18n.t('#quizzes.practice_quiz', "Practice Quiz")
when "assignment"
I18n.t('#quizzes.graded_quiz', "Graded Quiz")
when "graded_survey"
I18n.t('#quizzes.graded_survey', "Graded Survey")
when "survey"
I18n.t('#quizzes.ungraded_survey', "Ungraded Survey")
end
end
def render_score_to_keep(quiz_scoring_policy)
case quiz_scoring_policy
when "keep_highest"
I18n.t('#quizzes.keep_highest', 'Highest')
when "keep_latest"
I18n.t('#quizzes.keep_latest', 'Latest')
end
end
Controlling visibility of student quiz scores Teachers can now control when, and for how long, students get to see the correct answers to their quiz submissions. The patchset introduces two new columns to Quiz and a CSS rework of the quiz options form. See linked references for more info. Quiz#show_correct_answers should no longer be directly accessed, use Quiz#show_correct_answers? instead. == Test plan CAs stands for Correct Answers. - Create a quiz with 3 questions - Take the quiz as a student, and: - get 2/3 of the questions answered correctly - submit it Case A - Showing CAs the moment the submission goes in: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Leave both date fields empty - Save quiz - Refresh student view - You should see the CAs Case B - Showing CAs after some date: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show Correct Answers At" to 3-days from now - Refresh student view: - You should not see the CAs - Edit the quiz, and: - Set the date to 3-days back - Refresh student view: - You should see the CAs Case C - Hiding CAs after some date: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Hide Correct Answers At" to 3-days from now - Refresh student view: - You should see the CAs - You should see an alert that tells you the CAs will be hidden at the date you chose earlier - Edit the quiz, and: - Set the date to 3-days-back - Refresh student view: - You should no longer see the CAs - Alert should read that the answers stopped being visible as of the date you chose earlier Case D - Creating a time-frame for showing CAs: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show Correct Answers At" to yesterday - Set the "Hide Correct Answers At" to 3-days from now - Refresh student view: - You should see the CAs - You should see an alert that tells you the CAs will be visible between yesterday and 3 days from now - Edit the quiz, and: - Set the "Show At" date to tomorrow - Refresh student view: - You should no longer see the CAs - Alert should still tell you that the CAs will be visible starting tomorrow until 3 days from now Case E - Choosing a bad range - Edit the quiz and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show at" to tomorrow - Set the "Hide at" to today, or tomorrow - You should see an error-box == Notes and really wild things - http://docs.kodoware.com/canvas/cnvs-8103-take2 - http://docs.kodoware.com/canvas/cnvs-8103 (legacy changes) refs CNVS-8103, CNVS-9386 Change-Id: Ib241ee5f143b87164105b7541aadac00f38f79ad Reviewed-on: https://gerrit.instructure.com/25505 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> Product-Review: Derek DeVries <ddevries@instructure.com>
2013-10-23 05:10:44 +08:00
def render_show_correct_answers(quiz)
if !quiz.show_correct_answers
return I18n.t('#options.no', 'No')
end
show_at = quiz.show_correct_answers_at
hide_at = quiz.hide_correct_answers_at
if show_at && hide_at
I18n.t('#quizzes.show_and_hide_correct_answers', 'From %{from} to %{to}', {
from: datetime_string(quiz.show_correct_answers_at),
to: datetime_string(quiz.hide_correct_answers_at)
})
elsif show_at
I18n.t('#quizzes.show_correct_answers_after', 'After %{date}', {
date: datetime_string(quiz.show_correct_answers_at)
})
elsif hide_at
I18n.t('#quizzes.show_correct_answers_until', 'Until %{date}', {
date: datetime_string(quiz.hide_correct_answers_at)
})
else
I18n.t('#quizzes.show_correct_answers_immediately', 'Immediately')
end
end
def render_correct_answer_protection(quiz)
show_at = quiz.show_correct_answers_at
hide_at = quiz.hide_correct_answers_at
now = Time.now
# Some labels will be used in more than one case, so we'll pre-define them.
labels = {}
if hide_at
labels[:available_until] = I18n.t('#quizzes.correct_answers_shown_until',
'Correct answers are available until %{date}.', {
date: datetime_string(quiz.hide_correct_answers_at)
})
end
if !quiz.show_correct_answers
I18n.t('#quizzes.correct_answers_protected',
'Correct answers are hidden.')
elsif hide_at.present? && hide_at < now
I18n.t('#quizzes.correct_answers_no_longer_available',
'Correct answers are no longer available.')
elsif show_at.present? && hide_at.present?
# If the answers are currently visible, there's no need to show the range
# of availability.
if now > show_at
labels[:available_until]
else
I18n.t('#quizzes.correct_answers_shown_between',
'Correct answers will be available %{from} - %{to}.', {
from: datetime_string(show_at),
to: datetime_string(hide_at)
})
end
elsif show_at.present?
I18n.t('#quizzes.correct_answers_shown_after',
'Correct answers will be available on %{date}.', {
date: datetime_string(show_at)
})
elsif hide_at.present?
labels[:available_until]
end
end
def render_show_responses(quiz_hide_results)
# "Let Students See Their Quiz Responses?"
case quiz_hide_results
when "always"
I18n.t('#options.no', "No")
when "until_after_last_attempt"
I18n.t('#quizzes.after_last_attempt', "After Last Attempt")
when nil
I18n.t('#quizzes.always', "Always")
end
end
def submitted_students_title(quiz, students, logged_out)
length = students.length + logged_out.length
if quiz.survey?
submitted_students_survey_title(length)
else
submitted_students_quiz_title(length)
end
end
def submitted_students_quiz_title(student_count)
I18n.t('#quizzes.headers.submitted_students_quiz_title',
{ :zero => "Students who have taken the quiz",
:one => "Students who have taken the quiz (%{count})",
:other => "Students who have taken the quiz (%{count})" },
{ :count => student_count })
end
def submitted_students_survey_title(student_count)
I18n.t('#quizzes.headers.submitted_students_survey_title',
{ :zero => "Students who have taken the survey",
:one => "Students who have taken the survey (%{count})",
:other => "Students who have taken the survey (%{count})" },
{ :count => student_count })
end
def no_submitted_students_msg(quiz)
if quiz.survey?
t('#quizzes.messages.no_submitted_students_survey', "No Students have taken the survey yet")
else
t('#quizzes.messages.no_submitted_students_quiz', "No Students have taken the quiz yet")
end
end
def unsubmitted_students_title(quiz, students)
if quiz.survey?
unsubmitted_students_survey_title(students.length)
else
unsubmitted_students_quiz_title(students.length)
end
end
def unsubmitted_students_quiz_title(student_count)
I18n.t('#quizzes.headers.unsubmitted_students_quiz_title',
{ :zero => "Student who haven't taken the quiz",
:one => "Students who haven't taken the quiz (%{count})",
:other => "Students who haven't taken the quiz (%{count})" },
{ :count => student_count })
end
def unsubmitted_students_survey_title(student_count)
I18n.t('#quizzes.headers.unsubmitted_students_survey_title',
{ :zero => "Student who haven't taken the survey",
:one => "Students who haven't taken the survey (%{count})",
:other => "Students who haven't taken the survey (%{count})" },
{ :count => student_count })
end
def no_unsubmitted_students_msg(quiz)
if quiz.survey?
t('#quizzes.messages.no_unsubmitted_students_survey', "All Students have taken the survey")
else
t('#quizzes.messages.no_unsubmitted_students_quiz', "All Students have taken the quiz")
end
end
QuestionType = Struct.new(:question_type,
:entry_type,
:display_answers,
:answer_type,
:multiple_sets,
:unsupported)
2011-02-01 09:57:29 +08:00
def answer_type(question)
return QuestionType.new unless question
2011-02-01 09:57:29 +08:00
@answer_types_lookup ||= {
"multiple_choice_question" => QuestionType.new(
"multiple_choice_question",
"radio",
"multiple",
"select_answer",
false,
false
),
"true_false_question" => QuestionType.new(
"true_false_question",
"radio",
"multiple",
"select_answer",
false,
false
),
"short_answer_question" => QuestionType.new(
"short_answer_question",
"text_box",
"single",
"select_answer",
false,
false
),
"essay_question" => QuestionType.new(
"essay_question",
"textarea",
"single",
"text_answer",
false,
false
),
"file_upload_question" => QuestionType.new(
"file_upload_question",
"file",
"single",
"file_answer",
false,
false
),
"matching_question" => QuestionType.new(
"matching_question",
"matching",
"multiple",
"matching_answer",
false,
false
),
"missing_word_question" => QuestionType.new(
"missing_word_question",
"select",
"multiple",
"select_answer",
false,
false
),
"numerical_question" => QuestionType.new(
"numerical_question",
"numerical_text_box",
"single",
"numerical_answer",
false,
false
),
"calculated_question" => QuestionType.new(
"calculated_question",
"numerical_text_box",
"single",
"numerical_answer",
false,
false
),
"multiple_answers_question" => QuestionType.new(
"multiple_answers_question",
"checkbox",
"multiple",
"select_answer",
false,
false
),
"fill_in_multiple_blanks_question" => QuestionType.new(
"fill_in_multiple_blanks_question",
"text_box",
"multiple",
"select_answer",
true,
false
),
"multiple_dropdowns_question" => QuestionType.new(
"multiple_dropdowns_question",
"select",
"none",
"select_answer",
true,
false
),
"other" => QuestionType.new(
"text_only_question",
"none",
"none",
"none",
false,
false
)
2011-02-01 09:57:29 +08:00
}
res = @answer_types_lookup[question[:question_type]] || @answer_types_lookup["other"]
if res.question_type == "text_only_question"
res.unsupported = question[:question_type] != "text_only_question"
end
res
end
# Build the question-level comments. Lists in the order of :correct_comments, :incorrect_comments, :neutral_comments.
# ==== Arguments
# * <tt>user_answer</tt> - The user_answer hash.
# * <tt>question</tt> - The question hash.
def question_comment(user_answer, question)
correct_text = (hash_get(user_answer, :correct) == true) ? comment_get(question, :correct_comments) : nil
incorrect_text = (hash_get(user_answer, :correct) == false) ? comment_get(question, :incorrect_comments) : nil
neutral_text = (hash_get(question, :neutral_comments).present?) ? comment_get(question, :neutral_comments) : nil
text = []
text << content_tag(:p, correct_text, {:class => 'correct_comments'}) if correct_text.present?
text << content_tag(:p, incorrect_text, {:class => 'incorrect_comments'}) if incorrect_text.present?
text << content_tag(:p, neutral_text, {:class => 'neutral_comments'}) if neutral_text.present?
if text.empty?
''
else
content_tag(:div, text.join('').html_safe, {:class => 'quiz_comment'})
end
end
def comment_get(hash, field)
if html = hash_get(hash, "#{field}_html".to_sym)
raw(html)
else
hash_get(hash, field)
end
end
def fill_in_multiple_blanks_question(options)
question = hash_get(options, :question)
answers = hash_get(options, :answers).dup
answer_list = hash_get(options, :answer_list)
res = user_content hash_get(question, :question_text)
readonly_markup = hash_get(options, :editable) ? " />" : 'readonly="readonly" />'
label_attr = "aria-label='#{I18n.t('#quizzes.labels.multiple_blanks_question', "Fill in the blank, read surrounding text")}'"
index = 0
res.gsub! %r{<input.*?name=['"](question_.*?)['"].*?/>} do |match|
a = h(answer_list[index])
index += 1
# If given answer list, insert the values into the text inputs for displaying user's answers.
if answer_list && !answer_list.empty?
don't display correct answers when quiz set to not show. Fixes #10235 fixes #10154 Address the case when a quiz is set to not show the correct answers when reviewing the results. This adds question-level arrows that show if it was correct, incorrect, or partial. This also addresses: * incorrectly showing answer feedback on a survey * making the text inputs be readonly when viewing results * survey results style issues with borders and header area * hides 'Some questions not yet graded' when an essay question is used on a survey * hide question points on a survey * shows "You Answered" as grey arrow on survey results Testing Notes: ============= * Setup a quiz with the option "Let Students See their Quiz Responses" and ensure "Show Which Answers Were Correct" is unchecked and save the quiz. * Take the quiz. * The answer arrows should all be on the question level (not on the individual answers). * The "red box" around incorrect answers should not appear. * The arrows should include the following * "Correct!" - When fully correct. Full points received. * "Partial" - Shows as red/incorrect. Partial points were awarded. * "Unanswered" - shows for questions that don't have an easy way to show what the user enetered. * "Incorrect" - when wrong and no points were awarded. * When the option to show correct answers is checked on the quiz, it should still show the "Correct Answer" arrow and put red error boxes around incorrect answers. * When viewing the quiz in edit mode and checking "Show Question Details" it should show the "Correct Answer" arrow regardless of the checked quiz option. (Teacher view) Change-Id: I0083d383fcd28c906e1810615769586e7ecd48a7 Reviewed-on: https://gerrit.instructure.com/13293 Reviewed-by: Zach Wily <zach@instructure.com> Tested-by: Zach Wily <zach@instructure.com>
2012-08-29 05:59:20 +08:00
# Replace the {{question_BLAH}} template text with the user's answer text.
Quiz Submission Questions API - Update This patch provides support for answering Quiz Questions via the API. closes CNVS-9844, CNVS-10225 TEST PLAN ---- ---- Testing this will be a bit rough because there are many variations and validations to cover. I'll spare the validations that are covered by specs from the test plan. Create a quiz with a question of *each* type except "Text" and "File Upload". There's a script that creates a quiz with its questions automatically for you if you don't want to keep doing this manually. See references. > Answering Questions Now you need to answer each question via the API. Most of them vary in formats, but they are fully specified in the API documentation page (along with examples). See DOCUMENTATION for more info. > Flagging Questions Flagging, and unflagging, a question is the same regardless of its type, see the "EXAMPLE REQUESTS" section. > Access Validations Here are some generic, non-question based validations to verify. You should NOT be able to answer a question if: - the quiz submission has been turned in - the quiz submission is overdue - the Access Code for the quiz is invalid - the IP filter of the Quiz prohibits you from taking the quiz - the quiz submission :validation_token is incorrectly specified (ie, other students shouldn't be able to answer your questions) - you don't specify the latest :attempt, so if the Quiz has multiple attempts, and this is your 2nd take, you specify an :attempt of 1, 3, or anything but 2 should fail - NEW: turn quiz into an OQAAT quiz with the "Can't go back" flag on; the API should not reject all requests to modify any of the questions with a 501 error saying that type of quizzes is not supported yet (support will come in CNVS-10224) > Grading Also, when you're done answering the questions, take a look at the grades and make sure everything gets graded just like it does when using the UI directly. > Verifying results in the browser While taking a quiz in the canvas UI, the scripts perform backups in the background that would overwrite any changes you do via the API. If you want to verify the changes you make via the API from the UI, you must append "?backup=false" to the take quiz page URL, something like this: http://localhost:3000/courses/1/quizzes/1/take?backup=false Setting that flag will (for now) disable the backup behaviour and should make things tick. EXAMPLE REQUESTS ------- -------- Don't forget to set the 'Content-Type' header to 'application/json'! > Answering a Multiple-Choice question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id { "attempt": 1, "validation_token": "1babd0...", "answer": 10 } > Flagging a question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id/flag { "attempt": 1, "validation_token": "1babd0..." } > Unflagging a question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id/unflag { "attempt": 1, "validation_token": "1babd0..." } DOCUMENTATION ------------- Run `bundle exec rake doc:api` and check out the Quiz Submission Questions page. There's an Appendix that contains example requests for each question type, as well as the errors produced by each handler. LINKS ----- - bootstrap script: https://gist.github.com/amireh/e7e8f835ffbf1d053e4c - direct link to the API documentation page: http://canvas.docs.kodoware.com/quiz_submission_questions.html Change-Id: I9a958323ece8854bc21a24c2affd8dc3972e46d5 Reviewed-on: https://gerrit.instructure.com/27206 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com>
2013-12-10 17:15:01 +08:00
match = match.sub(/\{\{question_.*?\}\}/, a.to_s).
don't display correct answers when quiz set to not show. Fixes #10235 fixes #10154 Address the case when a quiz is set to not show the correct answers when reviewing the results. This adds question-level arrows that show if it was correct, incorrect, or partial. This also addresses: * incorrectly showing answer feedback on a survey * making the text inputs be readonly when viewing results * survey results style issues with borders and header area * hides 'Some questions not yet graded' when an essay question is used on a survey * hide question points on a survey * shows "You Answered" as grey arrow on survey results Testing Notes: ============= * Setup a quiz with the option "Let Students See their Quiz Responses" and ensure "Show Which Answers Were Correct" is unchecked and save the quiz. * Take the quiz. * The answer arrows should all be on the question level (not on the individual answers). * The "red box" around incorrect answers should not appear. * The arrows should include the following * "Correct!" - When fully correct. Full points received. * "Partial" - Shows as red/incorrect. Partial points were awarded. * "Unanswered" - shows for questions that don't have an easy way to show what the user enetered. * "Incorrect" - when wrong and no points were awarded. * When the option to show correct answers is checked on the quiz, it should still show the "Correct Answer" arrow and put red error boxes around incorrect answers. * When viewing the quiz in edit mode and checking "Show Question Details" it should show the "Correct Answer" arrow regardless of the checked quiz option. (Teacher view) Change-Id: I0083d383fcd28c906e1810615769586e7ecd48a7 Reviewed-on: https://gerrit.instructure.com/13293 Reviewed-by: Zach Wily <zach@instructure.com> Tested-by: Zach Wily <zach@instructure.com>
2012-08-29 05:59:20 +08:00
# Match on "/>" but only when at the end of the string and insert "readonly" if set to be readonly
sub(/\/\>\Z/, readonly_markup)
end
# add labelling to input element regardless
match.sub(/\/\>\Z/, "#{label_attr} />")
end
unless answer_list && !answer_list.empty?
answers.delete_if { |k, v| !k.match /^question_#{hash_get(question, :id)}/ }
answers.each { |k, v| res.sub! /\{\{#{k}\}\}/, h(v) }
res.gsub! /\{\{question_[^}]+\}\}/, ""
end
res
end
def multiple_dropdowns_question(options)
question = hash_get(options, :question)
answers = hash_get(options, :answers)
answer_list = hash_get(options, :answer_list)
res = user_content hash_get(question, :question_text)
index = 0
res.gsub %r{<select.*?name=['"](question_.*?)['"].*?>.*?</select>} do |match|
if answer_list && !answer_list.empty?
a = answer_list[index]
index += 1
else
a = hash_get(answers, $1)
end
match.sub(%r{(<option.*?value=['"]#{ERB::Util.h(a)}['"])}, '\\1 selected')
end
end
def duration_in_minutes(duration_seconds)
if duration_seconds < 60
duration_minutes = 0
else
duration_minutes = (duration_seconds / 60).round
end
I18n.t("quizzes.helpers.duration_in_minutes",
{ :zero => "less than 1 minute",
:one => "1 minute",
:other => "%{count} minutes" },
:count => duration_minutes)
end
def score_out_of_points_possible(score, points_possible, options={})
options.reverse_merge!({ :precision => 2 })
score_html = \
if options[:id] or options[:class] or options[:style] then
content_tag('span',
render_score(score, options[:precision]),
options.slice(:class, :id, :style))
else
render_score(score, options[:precision])
end
I18n.t("quizzes.helpers.score_out_of_points_possible", "%{score} out of %{points_possible}",
:score => score_html,
:points_possible => render_score(points_possible, options[:precision]))
end
def link_to_take_quiz(link_body, opts={})
opts = opts.with_indifferent_access
class_array = (opts['class'] || "").split(" ")
class_array << 'element_toggler' if @quiz.cant_go_back?
opts['class'] = class_array.compact.join(" ")
opts['aria-controls'] = 'js-sequential-warning-dialogue' if @quiz.cant_go_back?
opts['data-method'] = 'post' unless @quiz.cant_go_back?
link_to(link_body, take_quiz_url, opts)
end
def take_quiz_url
user_id = @current_user && @current_user.id
course_quiz_take_path(@context, @quiz, user_id: user_id)
end
def link_to_take_or_retake_poll(opts={})
if @submission && !@submission.settings_only?
link_to_retake_poll(opts)
else
link_to_take_poll(opts)
end
end
def link_to_take_poll(opts={})
link_to_take_quiz(take_poll_message, opts)
end
def link_to_retake_poll(opts={})
link_to_take_quiz(retake_poll_message, opts)
end
def link_to_resume_poll(opts = {})
link_to_take_quiz(resume_poll_message, opts)
end
def take_poll_message(quiz=@quiz)
quiz.survey? ?
t('#quizzes.links.take_the_survey', 'Take the Survey') :
t('#quizzes.links.take_the_quiz', 'Take the Quiz')
end
def retake_poll_message(quiz=@quiz)
quiz.survey? ?
t('#quizzes.links.take_the_survey_again', 'Take the Survey Again') :
t('#quizzes.links.take_the_quiz_again', 'Take the Quiz Again')
end
def resume_poll_message(quiz=@quiz)
quiz.survey? ?
t('#quizzes.links.resume_survey', 'Resume Survey') :
t('#quizzes.links.resume_quiz', 'Resume Quiz')
end
def attachment_id_for(question)
attach = attachment_for(question)
attach[:id] if attach.present?
end
def attachment_for(question)
key = "question_#{question[:id]}"
@attachments[@stored_params[key].try(:first).to_i]
end
def score_to_keep_message(quiz=@quiz)
quiz.scoring_policy == "keep_highest" ?
t('#quizzes.links.will_keep_highest_score', "Will keep the highest of all your scores") :
t('#quizzes.links.will_keep_latest_score', "Will keep the latest of all your scores")
end
def quiz_edit_text(quiz=@quiz)
if quiz.survey?
I18n.t('titles.edit_survey', 'Edit Survey')
else
I18n.t('titles.edit_quiz', 'Edit Quiz')
end
end
def quiz_delete_text(quiz=@quiz)
if quiz.survey?
I18n.t('titles.delete_survey', 'Delete Survey')
else
I18n.t('titles.delete_quiz', 'Delete Quiz')
end
end
def submission_has_regrade?(submission)
submission && submission.score_before_regrade.present?
end
def score_affected_by_regrade?(submission)
submission && submission.score_before_regrade != submission.kept_score
end
def answer_title(selected_answer, correct_answer, show_correct_answers)
titles = []
if selected_answer
titles << I18n.t(:selected_answer, "You selected this answer.")
end
if correct_answer && show_correct_answers
titles << I18n.t(:correct_answer, "This was the correct answer.")
end
title = "title=\"#{titles.join(' ')}\"" if titles.length > 0
end
Controlling visibility of student quiz scores Teachers can now control when, and for how long, students get to see the correct answers to their quiz submissions. The patchset introduces two new columns to Quiz and a CSS rework of the quiz options form. See linked references for more info. Quiz#show_correct_answers should no longer be directly accessed, use Quiz#show_correct_answers? instead. == Test plan CAs stands for Correct Answers. - Create a quiz with 3 questions - Take the quiz as a student, and: - get 2/3 of the questions answered correctly - submit it Case A - Showing CAs the moment the submission goes in: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Leave both date fields empty - Save quiz - Refresh student view - You should see the CAs Case B - Showing CAs after some date: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show Correct Answers At" to 3-days from now - Refresh student view: - You should not see the CAs - Edit the quiz, and: - Set the date to 3-days back - Refresh student view: - You should see the CAs Case C - Hiding CAs after some date: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Hide Correct Answers At" to 3-days from now - Refresh student view: - You should see the CAs - You should see an alert that tells you the CAs will be hidden at the date you chose earlier - Edit the quiz, and: - Set the date to 3-days-back - Refresh student view: - You should no longer see the CAs - Alert should read that the answers stopped being visible as of the date you chose earlier Case D - Creating a time-frame for showing CAs: - Edit the quiz, and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show Correct Answers At" to yesterday - Set the "Hide Correct Answers At" to 3-days from now - Refresh student view: - You should see the CAs - You should see an alert that tells you the CAs will be visible between yesterday and 3 days from now - Edit the quiz, and: - Set the "Show At" date to tomorrow - Refresh student view: - You should no longer see the CAs - Alert should still tell you that the CAs will be visible starting tomorrow until 3 days from now Case E - Choosing a bad range - Edit the quiz and: - Tick the 'Let Students See Their Score Points' checkbox - Set the "Show at" to tomorrow - Set the "Hide at" to today, or tomorrow - You should see an error-box == Notes and really wild things - http://docs.kodoware.com/canvas/cnvs-8103-take2 - http://docs.kodoware.com/canvas/cnvs-8103 (legacy changes) refs CNVS-8103, CNVS-9386 Change-Id: Ib241ee5f143b87164105b7541aadac00f38f79ad Reviewed-on: https://gerrit.instructure.com/25505 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> Product-Review: Derek DeVries <ddevries@instructure.com>
2013-10-23 05:10:44 +08:00
def show_correct_answers?(quiz=@quiz, user=@current_user, submission=@submission)
@quiz && @quiz.try_rescue(:show_correct_answers?, @current_user, @submission)
end
def correct_answers_protected?(quiz=@quiz, user=@current_user, submission=@submission)
if !quiz
false
elsif !show_correct_answers?(quiz, user, submission)
true
elsif quiz.hide_correct_answers_at.present?
!quiz.grants_right?(user, nil, :grade)
end
end
def point_value_for_input(user_answer, question)
return user_answer[:points] unless user_answer[:correct] == 'undefined'
if ["assignment", "practice_quiz"].include?(@quiz.quiz_type)
"--"
else
question[:points_possible] || 0
end
end
2011-02-01 09:57:29 +08:00
end