mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 04:30:15 +01:00
Merge branch 'MDL-37993-quiz-completion-pass-attempts' of git://github.com/MorrisR2/moodle
This commit is contained in:
commit
9b3b730c62
@ -49,7 +49,7 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
'questionsperpage', 'navmethod', 'shufflequestions', 'shuffleanswers',
|
||||
'sumgrades', 'grade', 'timecreated',
|
||||
'timemodified', 'password', 'subnet', 'browsersecurity',
|
||||
'delay1', 'delay2', 'showuserpicture', 'showblocks'));
|
||||
'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted', 'completionpass'));
|
||||
|
||||
// Define elements for access rule subplugin settings.
|
||||
$this->add_subplugin_structure('quizaccess', $quiz, true);
|
||||
|
@ -44,6 +44,8 @@
|
||||
<FIELD NAME="delay2" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Delay that must be left between the second and subsequent attempt, in seconds."/>
|
||||
<FIELD NAME="showuserpicture" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Option to show the user's picture during the attempt and on the review page."/>
|
||||
<FIELD NAME="showblocks" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether blocks should be shown on the attempt.php and review.php pages."/>
|
||||
<FIELD NAME="completionattemptsexhausted" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionpass" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
@ -776,6 +776,33 @@ function xmldb_quiz_upgrade($oldversion) {
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2014052800) {
|
||||
|
||||
// Define field completionattemptsexhausted to be added to quiz.
|
||||
$table = new xmldb_table('quiz');
|
||||
$field = new xmldb_field('completionattemptsexhausted', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'showblocks');
|
||||
|
||||
// Conditionally launch add field completionattemptsexhausted.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
// Quiz savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2014052800, 'quiz');
|
||||
}
|
||||
|
||||
if ($oldversion < 2014052801) {
|
||||
// Define field completionpass to be added to quiz.
|
||||
$table = new xmldb_table('quiz');
|
||||
$field = new xmldb_field('completionpass', XMLDB_TYPE_INTEGER, '1', null, null, null, 0, 'completionattemptsexhausted');
|
||||
|
||||
// Conditionally launch add field completionpass.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Quiz savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2014052801, 'quiz');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,10 @@ $string['comment'] = 'Comment';
|
||||
$string['commentorgrade'] = 'Make comment or override grade';
|
||||
$string['comments'] = 'Comments';
|
||||
$string['completedon'] = 'Completed on';
|
||||
$string['completionpass'] = 'Require passing grade';
|
||||
$string['completionpass_help'] = 'If enabled, this activity is considered complete when the student receives a passing grade, with the pass grade set in the gradebook.';
|
||||
$string['completionattemptsexhausted'] = 'Or all available attempts completed';
|
||||
$string['completionattemptsexhausted_help'] = 'Mark quiz complete when the student has exhausted the maximum number of attempts.';
|
||||
$string['configadaptive'] = 'If you choose Yes for this option then the student will be allowed multiple responses to a question even within the same attempt at the quiz.';
|
||||
$string['configattemptsallowed'] = 'Restriction on the number of attempts students are allowed at the quiz.';
|
||||
$string['configdecimaldigits'] = 'Number of digits that should be shown after the decimal point when displaying grades.';
|
||||
|
@ -1560,6 +1560,7 @@ function quiz_supports($feature) {
|
||||
case FEATURE_GROUPMEMBERSONLY: return true;
|
||||
case FEATURE_MOD_INTRO: return true;
|
||||
case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
|
||||
case FEATURE_COMPLETION_HAS_RULES: return true;
|
||||
case FEATURE_GRADE_HAS_GRADE: return true;
|
||||
case FEATURE_GRADE_OUTCOMES: return true;
|
||||
case FEATURE_BACKUP_MOODLE2: return true;
|
||||
@ -1790,3 +1791,52 @@ function quiz_get_navigation_options() {
|
||||
QUIZ_NAVMETHOD_SEQ => get_string('navmethod_seq', 'quiz')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains the automatic completion state for this quiz on any conditions
|
||||
* in quiz settings, such as if all attempts are used or a certain grade is achieved.
|
||||
*
|
||||
* @param object $course Course
|
||||
* @param object $cm Course-module
|
||||
* @param int $userid User ID
|
||||
* @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
|
||||
* @return bool True if completed, false if not. (If no conditions, then return
|
||||
* value depends on comparison type)
|
||||
*/
|
||||
function quiz_get_completion_state($course, $cm, $userid, $type) {
|
||||
global $DB;
|
||||
global $CFG;
|
||||
|
||||
$quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
|
||||
if (!$quiz->completionattemptsexhausted && !$quiz->completionpass) {
|
||||
return $type;
|
||||
}
|
||||
|
||||
// Check if the user has used up all attempts.
|
||||
if ($quiz->completionattemptsexhausted) {
|
||||
$attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true);
|
||||
if ($attempts) {
|
||||
$lastfinishedattempt = end($attempts);
|
||||
$context = context_module::instance($cm->id);
|
||||
$quizobj = quiz::create($quiz->id, $userid);
|
||||
$accessmanager = new quiz_access_manager($quizobj, time(),
|
||||
has_capability('mod/quiz:ignoretimelimits', $context, $userid, false));
|
||||
if ($accessmanager->is_finished(count($attempts), $lastfinishedattempt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for passing grade.
|
||||
if ($quiz->completionpass) {
|
||||
require_once($CFG->libdir . '/gradelib.php');
|
||||
$item = grade_item::fetch(array('courseid' => $course->id, 'itemtype' => 'mod',
|
||||
'itemmodule' => 'quiz', 'iteminstance' => $cm->instance));
|
||||
if ($item) {
|
||||
$grades = grade_grade::fetch_users_grades($item, array($userid), false);
|
||||
return $grades[$userid]->is_passed($item);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1641,6 +1641,11 @@ function quiz_attempt_submitted_handler($event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Update completion state.
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled($cm) && ($quiz->completionattemptsexhausted || $quiz->completionpass)) {
|
||||
$completion->update_state($cm, COMPLETION_COMPLETE, $event->userid);
|
||||
}
|
||||
return quiz_send_notification_messages($course, $quiz, $attempt,
|
||||
context_module::instance($cm->id), $cm);
|
||||
}
|
||||
|
@ -585,4 +585,37 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display module-specific activity completion rules.
|
||||
* Part of the API defined by moodleform_mod
|
||||
* @return array Array of string IDs of added items, empty array if none
|
||||
*/
|
||||
public function add_completion_rules() {
|
||||
$mform = $this->_form;
|
||||
$items = array();
|
||||
|
||||
$group = array();
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionpass', null, get_string('completionpass', 'quiz'),
|
||||
array('group' => 'cpass'));
|
||||
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionattemptsexhausted', null,
|
||||
get_string('completionattemptsexhausted', 'quiz'),
|
||||
array('group' => 'cattempts'));
|
||||
$mform->disabledIf('completionattemptsexhausted', 'completionpass', 'notchecked');
|
||||
$mform->addGroup($group, 'completionpassgroup', get_string('completionpass', 'quiz'), '', false);
|
||||
$mform->addHelpButton('completionpassgroup', 'completionpass', 'quiz');
|
||||
$items[] = 'completionpassgroup';
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during validation. Indicates whether a module-specific completion rule is selected.
|
||||
*
|
||||
* @param array $data Input data (not yet validated)
|
||||
* @return bool True if one or more rules is enabled, false if none are.
|
||||
*/
|
||||
public function completion_rule_enabled($data) {
|
||||
return !empty($data['completionattemptsexhausted']) || !empty($data['completionpass']);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
@mod @mod_quiz
|
||||
Feature: Set a quiz to be marked complete when the student uses all attempts allowed
|
||||
In order to ensure a student has learned the material before being marked complete
|
||||
As a teacher
|
||||
I need to set a quiz to complete when the student receives a passing grade, or completed_fail if they use all attempts without passing
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@asd.com |
|
||||
| teacher1 | Teacher | 1 | teacher1@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I set the following administration settings values:
|
||||
| Enable completion tracking | 1 |
|
||||
And I expand "Grades" node
|
||||
And I follow "Grade item settings"
|
||||
And I set the field "Advanced grade item options" to "hiddenuntil"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
|
||||
Scenario: student1 uses up both attempts without passing
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
And I press "Save changes"
|
||||
And I add a "Quiz" to section "1" and I fill the form with:
|
||||
| Name | Test quiz name |
|
||||
| Description | Test quiz description |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Attempts allowed | 2 |
|
||||
| Require passing grade | 1 |
|
||||
| Or all available attempts completed | 1 |
|
||||
And I add a "True/False" question to the "Test quiz name" quiz with:
|
||||
| Question name | First question |
|
||||
| Question text | Answer the first question |
|
||||
| General feedback | Thank you, this is the general feedback |
|
||||
| Correct answer | True |
|
||||
| Feedback for the response 'True'. | So you think it is true |
|
||||
| Feedback for the response 'False'. | So you think it is false |
|
||||
And I follow "Course 1"
|
||||
And I follow "Grades"
|
||||
And I follow "Simple view"
|
||||
And I follow "Edit quiz Test quiz name"
|
||||
Then I should see "Edit grade item"
|
||||
And I set the field "gradepass" to "5"
|
||||
And I press "Save changes"
|
||||
And I should see "Simple view"
|
||||
Then I log out
|
||||
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I follow "Test quiz name"
|
||||
And I press "Attempt quiz now"
|
||||
And I should see "Question 1"
|
||||
And I should see "Answer the first question"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Next"
|
||||
And I should see "Answer saved"
|
||||
And I press "Submit all and finish"
|
||||
And I follow "C1"
|
||||
And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I follow "Test quiz name"
|
||||
And I press "Re-attempt quiz"
|
||||
Then I should see "Question 1"
|
||||
And I should see "Answer the first question"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Next"
|
||||
And I should see "Answer saved"
|
||||
And I press "Submit all and finish"
|
||||
And I follow "C1"
|
||||
And "//img[contains(@alt, 'Completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Activity completion"
|
||||
Then "//img[contains(@title,'Test quiz name') and @alt='Completed']" "xpath_element" should exist in the "Student 1" "table_row"
|
||||
|
@ -0,0 +1,87 @@
|
||||
@mod @mod_quiz
|
||||
Feature: Set a quiz to be marked complete when the student passes
|
||||
In order to ensure a student has learned the material before being marked complete
|
||||
As a teacher
|
||||
I need to set a quiz to complete when the student recieves a passing grade
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@asd.com |
|
||||
| teacher1 | Teacher | 1 | teacher1@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I set the following administration settings values:
|
||||
| Enable completion tracking | 1 |
|
||||
And I expand "Grades" node
|
||||
And I follow "Grade item settings"
|
||||
And I set the field "Advanced grade item options" to "hiddenuntil"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
|
||||
Scenario: student1 passes on the first try
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
And I press "Save changes"
|
||||
And I add a "Quiz" to section "1" and I fill the form with:
|
||||
| Name | Test quiz name |
|
||||
| Description | Test quiz description |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Attempts allowed | 4 |
|
||||
| Require passing grade | 1 |
|
||||
And I add a "True/False" question to the "Test quiz name" quiz with:
|
||||
| Question name | First question |
|
||||
| Question text | Answer the first question |
|
||||
| General feedback | Thank you, this is the general feedback |
|
||||
| Correct answer | True |
|
||||
| Feedback for the response 'True'. | So you think it is true |
|
||||
| Feedback for the response 'False'. | So you think it is false |
|
||||
And I follow "Course 1"
|
||||
And I follow "Grades"
|
||||
And I select "Simple view" from "jump"
|
||||
And I press "Go"
|
||||
And I follow "Edit quiz Test quiz name"
|
||||
Then I should see "Edit grade item"
|
||||
And I set the field "gradepass" to "5"
|
||||
And I press "Save changes"
|
||||
Then I should see "Simple view"
|
||||
And I log out
|
||||
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I follow "Test quiz name"
|
||||
And I press "Attempt quiz now"
|
||||
Then I should see "Question 1"
|
||||
And I should see "Answer the first question"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Next"
|
||||
And I should see "Answer saved"
|
||||
And I press "Submit all and finish"
|
||||
And I follow "C1"
|
||||
And "//img[contains(@alt, 'Not completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I follow "Test quiz name"
|
||||
And I press "Re-attempt quiz"
|
||||
Then I should see "Question 1"
|
||||
And I should see "Answer the first question"
|
||||
And I set the field "True" to "1"
|
||||
And I press "Next"
|
||||
And I should see "Answer saved"
|
||||
And I press "Submit all and finish"
|
||||
And I follow "C1"
|
||||
And "//img[contains(@alt, 'Completed: Test quiz name')]" "xpath_element" should exist in the "li.modtype_quiz" "css_element"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Activity completion"
|
||||
Then "//img[contains(@title,'Test quiz name') and @alt='Completed']" "xpath_element" should exist in the "Student 1" "table_row"
|
@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014051200; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2014052801; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'mod_quiz'; // Full name of the plugin (used for diagnostics).
|
||||
$plugin->cron = 60;
|
||||
|
Loading…
x
Reference in New Issue
Block a user