mirror of
https://github.com/moodle/moodle.git
synced 2025-06-02 14:15:11 +02:00
Merge branch 'MDL-52206-master-rebased' of git://github.com/peterRd/moodle
This commit is contained in:
commit
b4675942ce
@ -273,7 +273,8 @@ class backup_module_structure_step extends backup_structure_step {
|
||||
'modulename', 'sectionid', 'sectionnumber', 'idnumber',
|
||||
'added', 'score', 'indent', 'visible', 'visibleoncoursepage',
|
||||
'visibleold', 'groupmode', 'groupingid',
|
||||
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
|
||||
'completion', 'completiongradeitemnumber', 'completionpassgrade',
|
||||
'completionview', 'completionexpected',
|
||||
'availability', 'showdescription'));
|
||||
|
||||
$tags = new backup_nested_element('tags');
|
||||
@ -2806,12 +2807,13 @@ class backup_completion_defaults_structure_step extends backup_structure_step {
|
||||
$cc = new backup_nested_element('course_completion_defaults');
|
||||
|
||||
$defaults = new backup_nested_element('course_completion_default', array('id'), array(
|
||||
'modulename', 'completion', 'completionview', 'completionusegrade', 'completionexpected', 'customrules'
|
||||
'modulename', 'completion', 'completionview', 'completionusegrade', 'completionpassgrade',
|
||||
'completionexpected', 'customrules'
|
||||
));
|
||||
|
||||
// Use module name instead of module id so we can insert into another site later.
|
||||
$sourcesql = "SELECT d.id, m.name as modulename, d.completion, d.completionview, d.completionusegrade,
|
||||
d.completionexpected, d.customrules
|
||||
d.completionpassgrade, d.completionexpected, d.customrules
|
||||
FROM {course_completion_defaults} d join {modules} m on d.module = m.id
|
||||
WHERE d.course = ?";
|
||||
$defaults->set_source_sql($sourcesql, array(backup::VAR_COURSEID));
|
||||
|
@ -25,8 +25,8 @@ Feature: Award badges based on activity completion
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer the first question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionattemptsexhausted | completionpass | completionusegrade |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionattemptsexhausted | completionpassgrade | completionusegrade |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
And quiz "Test quiz name" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
@ -53,7 +53,8 @@ Feature: Award badges based on activity completion
|
||||
Scenario: Student earns a badge using activity completion, but does not get passing grade
|
||||
Given I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "todo"
|
||||
When I am on the "Test quiz name" "quiz activity" page
|
||||
And I press "Re-attempt quiz"
|
||||
|
@ -17,8 +17,9 @@ Feature: Enable Block Completion in a course using activity completion
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro |
|
||||
| page | C1 | page1 | Test page name | Test page description |
|
||||
| activity | course | idnumber | name | intro |
|
||||
| page | C1 | page1 | Test page name | Test page description |
|
||||
| assign | C1 | assign1 | Test assign name | Test page description |
|
||||
|
||||
Scenario: Add the block to a the course and add course completion items
|
||||
Given I log in as "teacher1"
|
||||
@ -65,3 +66,71 @@ Feature: Enable Block Completion in a course using activity completion
|
||||
And I should see "1 of 1" in the "Activity completion" "table_row"
|
||||
And I follow "More details"
|
||||
And I should see "Yes" in the "Activity completion" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Add the block to a the course and add course completion items with passing grade
|
||||
Given I am on the "Test assign name" "assign activity" page logged in as teacher1
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test assign name" "assign activity" page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student" "table_row"
|
||||
And I set the field "Grade out of 100" to "53"
|
||||
And I set the field "Notify students" to "0"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Course completion status" block
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test assign name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I am on the "Test assign name" "assign activity" page logged in as student1
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Status: Pending" in the "Course completion status" "block"
|
||||
And I should see "0 of 1" in the "Activity completion" "table_row"
|
||||
And I trigger cron
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "More details"
|
||||
And I should see "Achieving grade, Achieving passing grade" in the "Activity completion" "table_row"
|
||||
And I should see "Yes" in the "Activity completion" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Add the block to a the course and add course completion items with failing grade.
|
||||
Given I am on the "Test assign name" "assign activity" page logged in as teacher1
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test assign name" "assign activity" page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student" "table_row"
|
||||
And I set the field "Grade out of 100" to "49"
|
||||
And I set the field "Notify students" to "0"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Course completion status" block
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Test assign name | 1 |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I am on the "Test assign name" "assign activity" page logged in as student1
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Status: Pending" in the "Course completion status" "block"
|
||||
And I should see "0 of 1" in the "Activity completion" "table_row"
|
||||
And I trigger cron
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "More details"
|
||||
And I should see "Achieving grade, Achieving passing grade" in the "Activity completion" "table_row"
|
||||
And I should see "Yes" in the "Activity completion" "table_row"
|
||||
|
@ -40,15 +40,20 @@ abstract class activity_custom_completion {
|
||||
/** @var int The user's ID. */
|
||||
protected $userid;
|
||||
|
||||
/** @var array The current state of core completion */
|
||||
protected $completionstate;
|
||||
|
||||
/**
|
||||
* activity_custom_completion constructor.
|
||||
*
|
||||
* @param cm_info $cm
|
||||
* @param int $userid
|
||||
* @param array|null $completionstate The current state of the core completion criteria
|
||||
*/
|
||||
public function __construct(cm_info $cm, int $userid) {
|
||||
public function __construct(cm_info $cm, int $userid, ?array $completionstate = null) {
|
||||
$this->cm = $cm;
|
||||
$this->userid = $userid;
|
||||
$this->completionstate = $completionstate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,7 +137,8 @@ class core_completion_bulkedit_form extends core_completion_edit_base_form {
|
||||
// Completion: Don't let them choose automatic completion without turning
|
||||
// on some conditions.
|
||||
if (array_key_exists('completion', $data) &&
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC && !empty($data['completionusegrade'])) {
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC &&
|
||||
(!empty($data['completionusegrade']) || !empty($data['completionpassgrade']))) {
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
$moduleswithoutgradeitem = [];
|
||||
foreach ($this->cms as $cm) {
|
||||
|
@ -73,7 +73,11 @@ class cm_completion_details {
|
||||
$this->returndetails = $returndetails;
|
||||
$cmcompletionclass = activity_custom_completion::get_cm_completion_class($this->cminfo->modname);
|
||||
if ($cmcompletionclass) {
|
||||
$this->cmcompletion = new $cmcompletionclass($this->cminfo, $this->userid);
|
||||
$this->cmcompletion = new $cmcompletionclass(
|
||||
$this->cminfo,
|
||||
$this->userid,
|
||||
$completioninfo->get_core_completion_state($cminfo, $userid)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,6 +132,13 @@ class cm_completion_details {
|
||||
'status' => $status,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
];
|
||||
|
||||
if (!is_null($this->cminfo->completionpassgrade) && $this->cminfo->completionpassgrade) {
|
||||
$details['completionpassgrade'] = (object)[
|
||||
'status' => $completiondata->passgrade ?? COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->cmcompletion) {
|
||||
|
@ -199,10 +199,19 @@ abstract class core_completion_edit_base_form extends moodleform {
|
||||
|
||||
// Automatic completion once it's graded.
|
||||
if ($this->support_grades()) {
|
||||
$mform->addElement('advcheckbox', 'completionusegrade', get_string('completionusegrade', 'completion'),
|
||||
$group = [];
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionusegrade', get_string('completionusegrade', 'completion'),
|
||||
get_string('completionusegrade_desc', 'completion'));
|
||||
$mform->disabledIf('completionusegrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion');
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion', '', true);
|
||||
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionpassgrade', get_string('completionpassgrade', 'completion'),
|
||||
get_string('completionpassgrade_desc', 'completion'));
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion', '', true);
|
||||
$mform->disabledIf('completionpassgrade', 'completionusegrade', 'notchecked');
|
||||
|
||||
$mform->addGroup($group, 'completionpassgroup', get_string('completionpassgrade', 'completion'), ' ', false);
|
||||
$mform->disabledIf('completionpassgroup', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
|
||||
$autocompletionpossible = true;
|
||||
}
|
||||
|
||||
@ -247,7 +256,7 @@ abstract class core_completion_edit_base_form extends moodleform {
|
||||
// on some conditions.
|
||||
if (array_key_exists('completion', $data) &&
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC) {
|
||||
if (empty($data['completionview']) && empty($data['completionusegrade']) &&
|
||||
if (empty($data['completionview']) && empty($data['completionusegrade']) && empty($data['completionpassgrade']) &&
|
||||
!$this->completion_rule_enabled($data)) {
|
||||
$errors['completion'] = get_string('badautocompletion', 'completion');
|
||||
}
|
||||
|
@ -176,7 +176,13 @@ class manager {
|
||||
}
|
||||
if ($moduledata instanceof cm_info && !is_null($moduledata->completiongradeitemnumber) ||
|
||||
($moduledata instanceof stdClass && !empty($moduledata->completionusegrade))) {
|
||||
$activeruledescriptions[] = get_string('completionusegrade_desc', 'completion');
|
||||
|
||||
$description = 'completionusegrade_desc';
|
||||
if (!empty($moduledata->completionpassgrade)) {
|
||||
$description = 'completionpassgrade_desc';
|
||||
}
|
||||
|
||||
$activeruledescriptions[] = get_string($description, 'completion');
|
||||
}
|
||||
|
||||
// Now, ask the module to provide descriptions for its custom conditional completion rules.
|
||||
@ -351,8 +357,11 @@ class manager {
|
||||
protected function apply_completion_cm(\cm_info $cm, $data, $updateinstance) {
|
||||
global $DB;
|
||||
|
||||
$defaults = ['completion' => COMPLETION_DISABLED, 'completionview' => COMPLETION_VIEW_NOT_REQUIRED,
|
||||
'completionexpected' => 0, 'completiongradeitemnumber' => null];
|
||||
$defaults = [
|
||||
'completion' => COMPLETION_DISABLED, 'completionview' => COMPLETION_VIEW_NOT_REQUIRED,
|
||||
'completionexpected' => 0, 'completiongradeitemnumber' => null,
|
||||
'completionpassgrade' => 0
|
||||
];
|
||||
|
||||
$data += ['completion' => $cm->completion,
|
||||
'completionexpected' => $cm->completionexpected,
|
||||
@ -374,6 +383,8 @@ class manager {
|
||||
$data['completiongradeitemnumber'] = !empty($data['completionusegrade']) ? 0 : null;
|
||||
unset($data['completionusegrade']);
|
||||
} else {
|
||||
// Completion grade item number is classified in mod_edit forms as 'use grade'.
|
||||
$data['completionusegrade'] = is_null($cm->completiongradeitemnumber) ? 0 : 1;
|
||||
$data['completiongradeitemnumber'] = $cm->completiongradeitemnumber;
|
||||
}
|
||||
|
||||
@ -413,7 +424,8 @@ class manager {
|
||||
'completion' => COMPLETION_DISABLED,
|
||||
'completionview' => COMPLETION_VIEW_NOT_REQUIRED,
|
||||
'completionexpected' => 0,
|
||||
'completionusegrade' => 0
|
||||
'completionusegrade' => 0,
|
||||
'completionpassgrade' => 0
|
||||
];
|
||||
|
||||
$data = (array)$data;
|
||||
@ -470,7 +482,7 @@ class manager {
|
||||
public static function get_default_completion($course, $module, $flatten = true) {
|
||||
global $DB, $CFG;
|
||||
if ($data = $DB->get_record('course_completion_defaults', ['course' => $course->id, 'module' => $module->id],
|
||||
'completion, completionview, completionexpected, completionusegrade, customrules')) {
|
||||
'completion, completionview, completionexpected, completionusegrade, completionpassgrade, customrules')) {
|
||||
if ($data->customrules && ($customrules = @json_decode($data->customrules, true))) {
|
||||
if ($flatten) {
|
||||
foreach ($customrules as $key => $value) {
|
||||
|
@ -240,6 +240,10 @@ class completion_criteria_activity extends completion_criteria {
|
||||
if (!is_null($cm->completiongradeitemnumber)) {
|
||||
$details['requirement'][] = get_string('achievinggrade', 'completion');
|
||||
}
|
||||
|
||||
if ($cm->completionpassgrade) {
|
||||
$details['requirement'][] = get_string('achievingpassinggrade', 'completion');
|
||||
}
|
||||
}
|
||||
|
||||
$details['requirement'] = implode(', ', $details['requirement']);
|
||||
|
@ -1,14 +1,10 @@
|
||||
@core @core_completion
|
||||
@core @core_completion @javascript
|
||||
Feature: Allow teachers to bulk edit activity completion rules in a course.
|
||||
In order to avoid editing single activities
|
||||
As a teacher
|
||||
I need to be able to edit the completion rules for a group of activities.
|
||||
|
||||
# Given I am a teacher in a course with completion tracking enabled and activities present.
|
||||
# When I bulk edit activity completion rules for activities of the same kind.
|
||||
# Then the completion rules should be updated for all selected activities.
|
||||
@javascript
|
||||
Scenario: Bulk edit activity completion rules
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
@ -32,6 +28,14 @@ Feature: Allow teachers to bulk edit activity completion rules in a course.
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
|
||||
# Given I am a teacher in a course with completion tracking enabled and activities present.
|
||||
# When I bulk edit activity completion rules for activities of the same kind.
|
||||
# Then the completion rules should be updated for all selected activities.
|
||||
Scenario: Bulk edit activity completion rules
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I navigate to "Course completion" in current page administration
|
||||
And I follow "Bulk edit activity completion"
|
||||
And I click on "Test assignment one" "checkbox"
|
||||
@ -56,3 +60,29 @@ Feature: Allow teachers to bulk edit activity completion rules in a course.
|
||||
And I should see "Student must receive a grade to complete this activity" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
And I should see "Student must submit to this activity to complete it" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
And I should not see "Completion expected on" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
|
||||
# Same conditions as above,
|
||||
# However if completionpassgrade is set, only the completionpassgrade detail should be shown.
|
||||
# It is implied requires grade is selected as it passgrade is dependent on it.
|
||||
Scenario: Bulk edit passing grade completion
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I navigate to "Course completion" in current page administration
|
||||
And I follow "Bulk edit activity completion"
|
||||
And I click on "Test assignment one" "checkbox"
|
||||
And I click on "Test assignment two" "checkbox"
|
||||
And I click on "Edit" "button"
|
||||
And I should see "Completion tracking"
|
||||
And I should see "The changes will affect the following 2 activities or resources:"
|
||||
And I should see "Student must submit to this activity to complete it"
|
||||
And I select "Show activity as complete when conditions are met" from the "completion" singleselect
|
||||
And I click on "completionusegrade" "checkbox"
|
||||
And I click on "completionpassgrade" "checkbox"
|
||||
And I click on "Save changes" "button"
|
||||
Then I should see "Changes saved"
|
||||
And I should see "With conditions" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment one']]" "xpath_element"
|
||||
And I should see "Student must receive a passing grade to complete this activity" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment one']]" "xpath_element"
|
||||
And I should not see "Completion expected on" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment one']]" "xpath_element"
|
||||
And I should see "With conditions" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
And I should see "Student must receive a passing grade to complete this activity" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
And I should not see "Completion expected on" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' row ')][.//*[text() = 'Test assignment two']]" "xpath_element"
|
||||
|
@ -0,0 +1,52 @@
|
||||
@core @core_completion
|
||||
Feature: Students will be marked as completed if they have achieved a passing grade.
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | enablecompletion |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Frist | teacher1@example.com |
|
||||
| student1 | Student | First | student1@example.com |
|
||||
| student2 | Student | Second | student2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And the following "activity" exists:
|
||||
| idnumber | a1 |
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| intro | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| completion | 2 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionusegrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has not completed "Test assignment name" activity
|
||||
And I log out
|
||||
|
||||
Scenario: Passing grade completion
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done"
|
@ -0,0 +1,69 @@
|
||||
@core @core_completion
|
||||
Feature: Students will be marked as completed and pass/fail
|
||||
if they have viewed an activity and achieved a grade.
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | enablecompletion |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Frist | teacher1@example.com |
|
||||
| student1 | Student | First | student1@example.com |
|
||||
| student2 | Student | Second | student2@example.com |
|
||||
| student3 | Student | Third | student3@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| idnumber | a1 |
|
||||
| name | Test assignment name |
|
||||
| intro | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| completion | 2 |
|
||||
| completionview | 1 |
|
||||
| completionusegrade | 1 |
|
||||
| gradepass | 50 |
|
||||
| completionpassgrade | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has not completed "Test assignment name" activity
|
||||
And I log out
|
||||
And I am on the "Test assignment name" "assign activity" page logged in as student2
|
||||
And I log out
|
||||
And I am on the "Test assignment name" "assign activity" page logged in as student1
|
||||
And I log out
|
||||
|
||||
Scenario: Confirm completion (incomplete/pass/fail) are set correctly
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I give the grade "30" to the user "Student Third" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "View" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "View" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "View" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "failed"
|
@ -80,7 +80,7 @@ class core_completion_bulk_update_testcase extends advanced_testcase {
|
||||
'lti-2' => ['lti', ['completion' => COMPLETION_TRACKING_MANUAL]],
|
||||
'page-1' => ['page', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
|
||||
'page-2' => ['page', ['completion' => COMPLETION_TRACKING_MANUAL]],
|
||||
'quiz-1' => ['quiz', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionpass' => 1]],
|
||||
'quiz-1' => ['quiz', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionpassgrade' => 1]],
|
||||
'quiz-2' => ['quiz', ['completion' => COMPLETION_TRACKING_MANUAL]],
|
||||
'resource-1' => ['resource', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
|
||||
'resource-2' => ['resource', ['completion' => COMPLETION_TRACKING_MANUAL]],
|
||||
|
@ -93,6 +93,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
['modname', $modname],
|
||||
['completionview', $completionoptions['completionview'] ?? COMPLETION_VIEW_NOT_REQUIRED],
|
||||
['completiongradeitemnumber', $completionoptions['completionusegrade'] ?? null],
|
||||
['completionpassgrade', $completionoptions['completionpassgrade'] ?? null],
|
||||
]));
|
||||
|
||||
return new cm_completion_details($this->completioninfo, $mockcminfo, 2);
|
||||
@ -192,13 +193,13 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
public function get_details_provider() {
|
||||
return [
|
||||
'No completion tracking' => [
|
||||
COMPLETION_TRACKING_NONE, null, null, []
|
||||
COMPLETION_TRACKING_NONE, null, null, null, []
|
||||
],
|
||||
'Manual completion tracking' => [
|
||||
COMPLETION_TRACKING_MANUAL, null, null, []
|
||||
COMPLETION_TRACKING_MANUAL, null, null, null, []
|
||||
],
|
||||
'Automatic, require view, not viewed' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, null, null, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
@ -206,7 +207,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
],
|
||||
'Automatic, require view, viewed' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, null, null, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
@ -214,7 +215,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
],
|
||||
'Automatic, require grade, incomplete' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_INCOMPLETE, null, [
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
@ -222,7 +223,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
],
|
||||
'Automatic, require grade, complete' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, null, [
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
@ -230,7 +231,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
],
|
||||
'Automatic, require view (complete) and grade (incomplete)' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, null, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
@ -242,7 +243,7 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
],
|
||||
'Automatic, require view (incomplete) and grade (complete)' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, null, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
@ -253,6 +254,62 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
]
|
||||
]
|
||||
],
|
||||
'Automatic, require grade, require pass grade, complete' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
],
|
||||
'completionpassgrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'Automatic, require grade, require pass grade, incomplete' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, null, COMPLETION_COMPLETE, COMPLETION_INCOMPLETE, [
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
],
|
||||
'completionpassgrade' => (object)[
|
||||
'status' => COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'Automatic, require view (complete), require grade(complete), require pass grade(complete)' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_COMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
],
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
],
|
||||
'completionpassgrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
|
||||
],
|
||||
]
|
||||
],
|
||||
'Automatic, require view (incomplete), require grade(complete), require pass grade(complete)' => [
|
||||
COMPLETION_TRACKING_AUTOMATIC, COMPLETION_INCOMPLETE, COMPLETION_COMPLETE, COMPLETION_COMPLETE, [
|
||||
'completionview' => (object)[
|
||||
'status' => COMPLETION_INCOMPLETE,
|
||||
'description' => get_string('detail_desc:view', 'completion'),
|
||||
],
|
||||
'completionusegrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivegrade', 'completion'),
|
||||
],
|
||||
'completionpassgrade' => (object)[
|
||||
'status' => COMPLETION_COMPLETE,
|
||||
'description' => get_string('detail_desc:receivepassgrade', 'completion'),
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -263,13 +320,16 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
* @param int $completion The completion tracking mode.
|
||||
* @param int|null $completionview Completion status of the "view" completion condition.
|
||||
* @param int|null $completiongrade Completion status of the "must receive grade" completion condition.
|
||||
* @param int|null $completionpassgrade Completion status of the "must receive passing grade" completion condition.
|
||||
* @param array $expecteddetails Expected completion details returned by get_details().
|
||||
*/
|
||||
public function test_get_details(int $completion, ?int $completionview, ?int $completiongrade, array $expecteddetails) {
|
||||
public function test_get_details(int $completion, ?int $completionview,
|
||||
?int $completiongrade, ?int $completionpassgrade, array $expecteddetails) {
|
||||
$options = [];
|
||||
$getdatareturn = (object)[
|
||||
'viewed' => $completionview,
|
||||
'completiongrade' => $completiongrade,
|
||||
'passgrade' => $completionpassgrade,
|
||||
];
|
||||
|
||||
if (!is_null($completionview)) {
|
||||
@ -278,13 +338,16 @@ class cm_completion_details_test extends advanced_testcase {
|
||||
if (!is_null($completiongrade)) {
|
||||
$options['completionusegrade'] = true;
|
||||
}
|
||||
if (!is_null($completionpassgrade)) {
|
||||
$options['completionpassgrade'] = true;
|
||||
}
|
||||
|
||||
$cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
|
||||
$this->assertEquals($expecteddetails, $cmcompletion->get_details());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_get_details().
|
||||
* Data provider for test_get_details_custom_order().
|
||||
* @return array[]
|
||||
*/
|
||||
public function get_details_custom_order_provider() {
|
||||
|
@ -122,6 +122,15 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
['course' => $course->id],
|
||||
['availability' => $availability],
|
||||
);
|
||||
$assignautocompletion = $this->getDataGenerator()->create_module('assign',
|
||||
['course' => $course->id], [
|
||||
'showdescription' => true,
|
||||
'completionview' => 1,
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC,
|
||||
'completiongradeitemnumber' => 1,
|
||||
'completionpassgrade' => 1,
|
||||
],
|
||||
);
|
||||
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id),
|
||||
array('completion' => 1, 'visible' => 0));
|
||||
|
||||
@ -151,11 +160,11 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
$result = external_api::clean_returnvalue(
|
||||
core_completion_external::get_activities_completion_status_returns(), $result);
|
||||
|
||||
// We added 5 activities, but only 4 with completion enabled and one of those is hidden.
|
||||
$numberofactivities = 5;
|
||||
// We added 6 activities, but only 4 with completion enabled and one of those is hidden.
|
||||
$numberofactivities = 6;
|
||||
$numberofhidden = 1;
|
||||
$numberofcompletions = $numberofactivities - $numberofhidden;
|
||||
$numberofstatusstudent = 3;
|
||||
$numberofstatusstudent = 4;
|
||||
|
||||
$this->assertCount($numberofstatusstudent, $result['statuses']);
|
||||
|
||||
@ -186,6 +195,26 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
$this->assertEquals('completionview', $details[0]['rulename']);
|
||||
$this->assertEquals(0, $details[0]['rulevalue']['status']);
|
||||
|
||||
} else if ($status['cmid'] == $assignautocompletion->cmid) {
|
||||
$activitiesfound++;
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
|
||||
$this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $status['tracking']);
|
||||
$this->assertFalse($status['valueused']);
|
||||
$this->assertTrue($status['hascompletion']);
|
||||
$this->assertTrue($status['isautomatic']);
|
||||
$this->assertTrue($status['istrackeduser']);
|
||||
$this->assertTrue($status['uservisible']);
|
||||
$details = $status['details'];
|
||||
$this->assertCount(3, $details);
|
||||
$expecteddetails = [
|
||||
'completionview',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
foreach ($expecteddetails as $index => $name) {
|
||||
$this->assertEquals($name, $details[$index]['rulename']);
|
||||
$this->assertEquals(0, $details[$index]['rulevalue']['status']);
|
||||
}
|
||||
} else if ($status['cmid'] == $data->cmid and $status['modname'] == 'data' and $status['instance'] == $data->id) {
|
||||
$activitiesfound++;
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
|
||||
@ -200,7 +229,7 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
$this->assertCount(0, $details);
|
||||
}
|
||||
}
|
||||
$this->assertEquals(3, $activitiesfound);
|
||||
$this->assertEquals(4, $activitiesfound);
|
||||
|
||||
// Teacher should see students status, they are in different groups but the teacher can access all groups.
|
||||
$this->setUser($teacher);
|
||||
@ -248,7 +277,7 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
$activitiesfound++;
|
||||
$this->assertEquals(COMPLETION_COMPLETE, $status['state']);
|
||||
$this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
|
||||
} else if ($status['cmid'] == $forumautocompletion->cmid) {
|
||||
} else if (in_array($status['cmid'], [$forumautocompletion->cmid, $assignautocompletion->cmid])) {
|
||||
$activitiesfound++;
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $status['state']);
|
||||
$this->assertEquals(COMPLETION_TRACKING_AUTOMATIC, $status['tracking']);
|
||||
@ -258,7 +287,7 @@ class core_completion_externallib_testcase extends externallib_advanced_testcase
|
||||
$this->assertEquals(COMPLETION_TRACKING_MANUAL, $status['tracking']);
|
||||
}
|
||||
}
|
||||
$this->assertEquals(4, $activitiesfound);
|
||||
$this->assertEquals(5, $activitiesfound);
|
||||
|
||||
// Change teacher role capabilities (disable access all groups).
|
||||
$context = context_course::instance($course->id);
|
||||
|
@ -4,6 +4,15 @@ information provided here is intended especially for developers.
|
||||
=== 4.0 ===
|
||||
* New method mark_course_completions_activity_criteria() has been added to mark course completions instantly. It is
|
||||
based on cron for completion_criteria_activity.php which is refactored to use it as well.
|
||||
* Modified completion criteria to allow plugins to override core completion logic.
|
||||
* Core now passes an additional parameter to '_get_completion_state'. This is an array representation of the completion results that have already been
|
||||
tested. Currently contains - viewed, usegrade, passgrade. Any plugin that are dependent on these criteria can now check this array instead of retesting it.
|
||||
* Introduced a new plugin function - '_get_completion_aggregation_state', that would indicate the aggregation type/relationship between the plugin and core
|
||||
completion criteria. This callback should either return a COMPLETION_STANDARD_FLOW / COMPLETION_CUSTOM_MODULE_FLOW. The former for default existing core
|
||||
behaviour while the latter enforces the override logic from the plugin. Defaults to COMPLETION_STANDARD_FLOW if not defined. This is useful when plugins
|
||||
need to override the core completion criteria in cases where it may be dependent on them. In these cases, the 'source of truth' would be the response
|
||||
from the plugin's 'get_completion_state' function. e.g. Quiz's completion defines a criteria of 'requires passing grade OR all attempts AND min attempts
|
||||
reached.' In these cases, even if a passing grade has not been achieved, the activity should be marked as completed if the no.of attempts have been reached.
|
||||
|
||||
=== 3.11 ===
|
||||
* New Behat steps for activity completion in the behat_completion class:
|
||||
|
@ -2867,6 +2867,7 @@ class core_course_external extends external_api {
|
||||
'visibleoncoursepage' => new external_value(PARAM_INT, 'If visible on course page', VALUE_OPTIONAL),
|
||||
'visibleold' => new external_value(PARAM_INT, 'Visible old', VALUE_OPTIONAL),
|
||||
'completiongradeitemnumber' => new external_value(PARAM_INT, 'Completion grade item', VALUE_OPTIONAL),
|
||||
'completionpassgrade' => new external_value(PARAM_INT, 'Completion pass grade setting', VALUE_OPTIONAL),
|
||||
'completionview' => new external_value(PARAM_INT, 'Completion view setting', VALUE_OPTIONAL),
|
||||
'completionexpected' => new external_value(PARAM_INT, 'Completion time expected', VALUE_OPTIONAL),
|
||||
'showdescription' => new external_value(PARAM_INT, 'If the description is showed', VALUE_OPTIONAL),
|
||||
|
@ -461,6 +461,7 @@ function get_array_of_activities($courseid) {
|
||||
$mod[$seq]->extra = "";
|
||||
$mod[$seq]->completiongradeitemnumber =
|
||||
$rawmods[$seq]->completiongradeitemnumber;
|
||||
$mod[$seq]->completionpassgrade = $rawmods[$seq]->completionpassgrade;
|
||||
$mod[$seq]->completionview = $rawmods[$seq]->completionview;
|
||||
$mod[$seq]->completionexpected = $rawmods[$seq]->completionexpected;
|
||||
$mod[$seq]->showdescription = $rawmods[$seq]->showdescription;
|
||||
|
@ -72,6 +72,7 @@ function add_moduleinfo($moduleinfo, $course, $mform = null) {
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled()) {
|
||||
$newcm->completion = $moduleinfo->completion;
|
||||
$newcm->completionpassgrade = $moduleinfo->completionpassgrade ?? 0;
|
||||
if ($moduleinfo->completiongradeitemnumber === '') {
|
||||
$newcm->completiongradeitemnumber = null;
|
||||
} else {
|
||||
@ -432,6 +433,8 @@ function set_moduleinfo_defaults($moduleinfo) {
|
||||
if (isset($moduleinfo->completionusegrade) && $moduleinfo->completionusegrade) {
|
||||
$moduleinfo->completiongradeitemnumber = 0;
|
||||
} else if (!isset($moduleinfo->completiongradeitemnumber)) {
|
||||
// If there is no gradeitemnumber set, make sure to disable completionpassgrade.
|
||||
$moduleinfo->completionpassgrade = 0;
|
||||
$moduleinfo->completiongradeitemnumber = null;
|
||||
}
|
||||
|
||||
@ -544,6 +547,7 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
|
||||
// the activity may be locked; if so, these should not be updated.
|
||||
if (!empty($moduleinfo->completionunlocked)) {
|
||||
$cm->completion = $moduleinfo->completion;
|
||||
$cm->completionpassgrade = $moduleinfo->completionpassgrade ?? 0;
|
||||
if ($moduleinfo->completiongradeitemnumber === '') {
|
||||
$cm->completiongradeitemnumber = null;
|
||||
} else {
|
||||
@ -712,6 +716,7 @@ function get_moduleinfo_data($cm, $course) {
|
||||
$data->completionview = $cm->completionview;
|
||||
$data->completionexpected = $cm->completionexpected;
|
||||
$data->completionusegrade = is_null($cm->completiongradeitemnumber) ? 0 : 1;
|
||||
$data->completionpassgrade = $cm->completionpassgrade;
|
||||
$data->completiongradeitemnumber = $cm->completiongradeitemnumber;
|
||||
$data->showdescription = $cm->showdescription;
|
||||
$data->tags = core_tag_tag::get_item_tags_array('core', 'course_modules', $cm->id);
|
||||
|
@ -370,6 +370,15 @@ abstract class moodleform_mod extends moodleform {
|
||||
if ($mform->elementExists('completionusegrade')) {
|
||||
$mform->freeze('completionusegrade');
|
||||
}
|
||||
if ($mform->elementExists('completionpassgrade')) {
|
||||
$mform->freeze('completionpassgrade');
|
||||
|
||||
// Has the completion pass grade completion criteria been set?
|
||||
// If it has then we shouldn't change the gradepass field.
|
||||
if ($mform->exportValue('completionpassgrade')) {
|
||||
$mform->freeze('gradepass');
|
||||
}
|
||||
}
|
||||
if ($mform->elementExists('completiongradeitemnumber')) {
|
||||
$mform->freeze('completiongradeitemnumber');
|
||||
}
|
||||
@ -468,6 +477,28 @@ abstract class moodleform_mod extends moodleform {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['completionpassgrade']) && $data['completionpassgrade']) {
|
||||
// We need to check whether there's a valid gradepass value.
|
||||
// This can either be in completiongradeitemnumber when there are multiple options OR,
|
||||
// The first grade item if completionusegrade is specified.
|
||||
$validategradepass = false;
|
||||
if (isset($data['completiongradeitemnumber'])) {
|
||||
if ($data['completiongradeitemnumber'] == (string)$itemnumber) {
|
||||
$validategradepass = true;
|
||||
}
|
||||
} else if (isset($data['completionusegrade']) && $data['completionusegrade']) {
|
||||
$validategradepass = true;
|
||||
}
|
||||
|
||||
// Confirm gradepass is a valid non-zero value.
|
||||
if ($validategradepass && (!isset($data[$gradepassfieldname]) || grade_floatval($data[$gradepassfieldname]) == 0)) {
|
||||
$errors['completionpassgrade'] = get_string(
|
||||
'activitygradetopassnotset',
|
||||
'completion'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Completion: Don't let them choose automatic completion without turning
|
||||
@ -482,7 +513,7 @@ abstract class moodleform_mod extends moodleform {
|
||||
$rulesenabled = !empty($data['completionview']);
|
||||
|
||||
// Use grade to complete (only one grade item).
|
||||
$rulesenabled = $rulesenabled || !empty($data['completionusegrade']);
|
||||
$rulesenabled = $rulesenabled || !empty($data['completionusegrade']) || !empty($data['completionpassgrade']);
|
||||
|
||||
// Use grade to complete (specific grade item).
|
||||
if (!$rulesenabled && isset($data['completiongradeitemnumber'])) {
|
||||
@ -724,16 +755,28 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->hideIf('completionusegrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion');
|
||||
|
||||
// Complete if the user has reached the pass grade.
|
||||
$mform->addElement(
|
||||
'checkbox',
|
||||
'completionpassgrade', null,
|
||||
get_string('completionpassgrade_desc', 'completion')
|
||||
);
|
||||
$mform->hideIf('completionpassgrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->disabledIf('completionpassgrade', 'completionusegrade', 'notchecked');
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion');
|
||||
|
||||
// The disabledIf logic differs between ratings and other grade items due to different field types.
|
||||
if ($this->_features->rating) {
|
||||
// If using the rating system, there is no grade unless ratings are enabled.
|
||||
$mform->disabledIf('completionusegrade', 'assessed', 'eq', 0);
|
||||
$mform->disabledIf('completionpassgrade', 'assessed', 'eq', 0);
|
||||
} else {
|
||||
// All other field types use the '$gradefieldname' field's modgrade_type.
|
||||
$itemnumbers = array_keys($itemnames);
|
||||
$itemnumber = array_shift($itemnumbers);
|
||||
$gradefieldname = component_gradeitems::get_field_name_for_itemnumber($component, $itemnumber, 'grade');
|
||||
$mform->disabledIf('completionusegrade', "{$gradefieldname}[modgrade_type]", 'eq', 'none');
|
||||
$mform->disabledIf('completionpassgrade', "{$gradefieldname}[modgrade_type]", 'eq', 'none');
|
||||
}
|
||||
} else if (count($itemnames) > 1) {
|
||||
// There are multiple grade items in this activity.
|
||||
@ -752,6 +795,16 @@ abstract class moodleform_mod extends moodleform {
|
||||
$options
|
||||
);
|
||||
$mform->hideIf('completiongradeitemnumber', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
|
||||
// Complete if the user has reached the pass grade.
|
||||
$mform->addElement(
|
||||
'checkbox',
|
||||
'completionpassgrade', null,
|
||||
get_string('completionpassgrade_desc', 'completion')
|
||||
);
|
||||
$mform->hideIf('completionpassgrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->disabledIf('completionpassgrade', 'completiongradeitemnumber', 'eq', '');
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,6 +221,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$moduleinfo->completion = COMPLETION_TRACKING_AUTOMATIC;
|
||||
$moduleinfo->completionview = COMPLETION_VIEW_REQUIRED;
|
||||
$moduleinfo->completiongradeitemnumber = 1;
|
||||
$moduleinfo->completionpassgrade = 0;
|
||||
$moduleinfo->completionexpected = time() + (7 * 24 * 3600);
|
||||
|
||||
// Conditional activity.
|
||||
@ -283,6 +284,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($moduleinfo->completion, $dbcm->completion);
|
||||
$this->assertEquals($moduleinfo->completionview, $dbcm->completionview);
|
||||
$this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber);
|
||||
$this->assertEquals($moduleinfo->completionpassgrade, $dbcm->completionpassgrade);
|
||||
$this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected);
|
||||
$this->assertEquals($moduleinfo->availability, $dbcm->availability);
|
||||
$this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription);
|
||||
@ -504,6 +506,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$moduleinfo->completion = COMPLETION_TRACKING_AUTOMATIC;
|
||||
$moduleinfo->completionview = COMPLETION_VIEW_REQUIRED;
|
||||
$moduleinfo->completiongradeitemnumber = 1;
|
||||
$moduleinfo->completionpassgrade = 0;
|
||||
$moduleinfo->completionexpected = time() + (7 * 24 * 3600);
|
||||
$moduleinfo->completionunlocked = 1;
|
||||
|
||||
@ -561,6 +564,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($moduleinfo->completion, $dbcm->completion);
|
||||
$this->assertEquals($moduleinfo->completionview, $dbcm->completionview);
|
||||
$this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber);
|
||||
$this->assertEquals($moduleinfo->completionpassgrade, $dbcm->completionpassgrade);
|
||||
$this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected);
|
||||
$this->assertEquals($moduleinfo->availability, $dbcm->availability);
|
||||
$this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription);
|
||||
|
@ -2306,14 +2306,17 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$course = self::getDataGenerator()->create_course(['enablecompletion' => 1]);
|
||||
$record = array(
|
||||
'course' => $course->id,
|
||||
'name' => 'First Assignment'
|
||||
);
|
||||
$options = array(
|
||||
'idnumber' => 'ABC',
|
||||
'visible' => 0
|
||||
'visible' => 0,
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC,
|
||||
'completiongradeitemnumber' => 0,
|
||||
'completionpassgrade' => 1,
|
||||
);
|
||||
// Hidden activity.
|
||||
$assign = self::getDataGenerator()->create_module('assign', $record, $options);
|
||||
@ -2370,7 +2373,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
// Test we retrieve all the fields.
|
||||
$this->assertCount(28, $result['cm']);
|
||||
$this->assertCount(29, $result['cm']);
|
||||
$this->assertEquals($record['name'], $result['cm']['name']);
|
||||
$this->assertEquals($options['idnumber'], $result['cm']['idnumber']);
|
||||
$this->assertEquals(100, $result['cm']['grade']);
|
||||
@ -2438,7 +2441,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
// Test we retrieve all the fields.
|
||||
$this->assertCount(26, $result['cm']);
|
||||
$this->assertCount(27, $result['cm']);
|
||||
$this->assertEquals($record['name'], $result['cm']['name']);
|
||||
$this->assertEquals($record['grade'], $result['cm']['grade']);
|
||||
$this->assertEquals($options['idnumber'], $result['cm']['idnumber']);
|
||||
|
@ -112,6 +112,7 @@ class core_course_modlib_testcase extends advanced_testcase {
|
||||
$expecteddata->completionview = $assigncm->completionview;
|
||||
$expecteddata->completionexpected = $assigncm->completionexpected;
|
||||
$expecteddata->completionusegrade = is_null($assigncm->completiongradeitemnumber) ? 0 : 1;
|
||||
$expecteddata->completionpassgrade = $assigncm->completionpassgrade;
|
||||
$expecteddata->completiongradeitemnumber = null;
|
||||
$expecteddata->showdescription = $assigncm->showdescription;
|
||||
$expecteddata->tags = core_tag_tag::get_item_tags_array('core', 'course_modules', $assigncm->id);
|
||||
@ -138,6 +139,7 @@ class core_course_modlib_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
$expecteddata->gradepass = '0.00';
|
||||
$expecteddata->completionpassgrade = $assigncm->completionpassgrade;
|
||||
|
||||
// Unset untestable.
|
||||
unset($expecteddata->cmid);
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
$string['achievinggrade'] = 'Achieving grade';
|
||||
$string['achievingpassinggrade'] = 'Achieving passing grade';
|
||||
$string['activities'] = 'Activities';
|
||||
$string['activitieslabel'] = 'Activities / resources';
|
||||
$string['activityaggregation'] = 'Condition requires';
|
||||
@ -35,6 +36,7 @@ $string['activitiescompletednote'] = 'Note: Activity completion must be set for
|
||||
$string['activitycompletion'] = 'Activity completion';
|
||||
$string['activitycompletionupdated'] = 'Changes saved';
|
||||
$string['activitygradenotrequired'] = 'Grade not required';
|
||||
$string['activitygradetopassnotset'] = 'This activity does not have a valid grade to pass set. It may be set in the Grade section of the activity settings.';
|
||||
$string['affectedactivities'] = 'The changes will affect the following <b>{$a}</b> activities or resources:';
|
||||
$string['aggregationmethod'] = 'Aggregation method';
|
||||
$string['all'] = 'All';
|
||||
@ -106,6 +108,9 @@ $string['completionondate'] = 'Date';
|
||||
$string['completionondatevalue'] = 'Date when course will be marked as complete';
|
||||
$string['completionduration'] = 'Enrolment';
|
||||
$string['completionsettingslocked'] = 'Completion settings locked';
|
||||
$string['completionpassgrade'] = 'Require passing grade';
|
||||
$string['completionpassgrade_desc'] = 'Student must receive a passing grade to complete this activity';
|
||||
$string['completionpassgrade_help'] = 'If enabled, the activity is considered complete when a student receives a passing grade.';
|
||||
$string['completionusegrade'] = 'Require grade';
|
||||
$string['completionusegrade_desc'] = 'Student must receive a grade to complete this activity';
|
||||
$string['completionusegrade_help'] = 'If enabled, the activity is considered complete when a student receives a grade. If a pass grade for the activity is set, then pass and fail icons are displayed in the activity completion report.';
|
||||
@ -141,6 +146,7 @@ $string['deletecompletiondata'] = 'Delete completion data';
|
||||
$string['dependencies'] = 'Dependencies';
|
||||
$string['dependenciescompleted'] = 'Completion of other courses';
|
||||
$string['detail_desc:receivegrade'] = 'Receive a grade';
|
||||
$string['detail_desc:receivepassgrade'] = 'Receive a passing grade';
|
||||
$string['detail_desc:view'] = 'View';
|
||||
$string['hiddenrules'] = 'Some settings specific to <b>{$a}</b> have been hidden. To view unselect other activities';
|
||||
$string['editcoursecompletionsettings'] = 'Edit course completion settings';
|
||||
|
@ -132,6 +132,16 @@ define('COMPLETION_OR', false);
|
||||
*/
|
||||
define('COMPLETION_AND', true);
|
||||
|
||||
/**
|
||||
* When a module implements this, completion state is dependent to the
|
||||
* module's _get_completion_state callback and activity_custom_completion class.
|
||||
*/
|
||||
define('COMPLETION_CUSTOM_MODULE_FLOW', true);
|
||||
/**
|
||||
* Standard flow indicates ALL conditions need to be met for completion to be marked as done.
|
||||
*/
|
||||
define('COMPLETION_STANDARD_FLOW', false);
|
||||
|
||||
/**
|
||||
* Course completion criteria aggregation method.
|
||||
*/
|
||||
@ -686,13 +696,7 @@ class completion_info {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
|
||||
// Check viewed
|
||||
if ($cm->completionview == COMPLETION_VIEW_REQUIRED &&
|
||||
$current->viewed == COMPLETION_NOT_VIEWED) {
|
||||
|
||||
return COMPLETION_INCOMPLETE;
|
||||
}
|
||||
|
||||
$newstate = COMPLETION_COMPLETE;
|
||||
if ($cm instanceof stdClass) {
|
||||
// Modname hopefully is provided in $cm but just in case it isn't, let's grab it.
|
||||
if (!isset($cm->modname)) {
|
||||
@ -705,25 +709,15 @@ class completion_info {
|
||||
}
|
||||
// Make sure we're using a cm_info object.
|
||||
$cminfo = cm_info::create($cm, $userid);
|
||||
|
||||
$newstate = COMPLETION_COMPLETE;
|
||||
|
||||
// Check grade
|
||||
if (!is_null($cminfo->completiongradeitemnumber)) {
|
||||
$newstate = $this->get_grade_completion($cminfo, $userid);
|
||||
if ($newstate == COMPLETION_INCOMPLETE) {
|
||||
return COMPLETION_INCOMPLETE;
|
||||
}
|
||||
}
|
||||
$completionstate = $this->get_core_completion_state($cminfo, $userid);
|
||||
|
||||
if (plugin_supports('mod', $cminfo->modname, FEATURE_COMPLETION_HAS_RULES)) {
|
||||
$response = true;
|
||||
$cmcompletionclass = activity_custom_completion::get_cm_completion_class($cminfo->modname);
|
||||
if ($cmcompletionclass) {
|
||||
/** @var activity_custom_completion $cmcompletion */
|
||||
$cmcompletion = new $cmcompletionclass($cminfo, $userid);
|
||||
if ($cmcompletion->get_overall_completion_state() == COMPLETION_INCOMPLETE) {
|
||||
return COMPLETION_INCOMPLETE;
|
||||
}
|
||||
$cmcompletion = new $cmcompletionclass($cminfo, $userid, $completionstate);
|
||||
$response = $cmcompletion->get_overall_completion_state() != COMPLETION_INCOMPLETE;
|
||||
} else {
|
||||
// Fallback to the get_completion_state callback.
|
||||
$cmcompletionclass = "mod_{$cminfo->modname}\\completion\\custom_completion";
|
||||
@ -736,10 +730,34 @@ class completion_info {
|
||||
debugging("*_get_completion_state() callback functions such as $function have been deprecated and should no " .
|
||||
"longer be used. Please implement the custom completion class $cmcompletionclass which extends " .
|
||||
"\core_completion\activity_custom_completion.", DEBUG_DEVELOPER);
|
||||
if (!$function($this->course, $cminfo, $userid, COMPLETION_AND)) {
|
||||
return COMPLETION_INCOMPLETE;
|
||||
}
|
||||
$response = $function($this->course, $cm, $userid, COMPLETION_AND, $completionstate);
|
||||
}
|
||||
|
||||
// Get the relationship between the core_completion and plugin_completion criteria.
|
||||
$aggregationtype = COMPLETION_STANDARD_FLOW;
|
||||
if ($aggregationfn = component_callback_exists("mod_$cminfo->modname", 'get_completion_aggregation_state')) {
|
||||
$aggregationtype = $aggregationfn();
|
||||
}
|
||||
// If the module aggregates using COMPLETION_STANDARD_FLOW, it requires ALL conditions to be met.
|
||||
// If the aggregation type is COMPLETION_CUSTOM_MODULE_FLOW, completion can be overridden by the plugin.
|
||||
if (!$response && $aggregationtype == COMPLETION_STANDARD_FLOW) {
|
||||
return COMPLETION_INCOMPLETE;
|
||||
} else if ($aggregationtype == COMPLETION_CUSTOM_MODULE_FLOW) {
|
||||
return ($response ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
if ($completionstate) {
|
||||
// We have allowed the plugins to do it's thing and run their own checks.
|
||||
// We have now reached a state where we need to AND all the calculated results.
|
||||
$newstate = array_reduce($completionstate, function($carry, $value) {
|
||||
if ($carry == COMPLETION_INCOMPLETE) {
|
||||
return $carry;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
|
||||
}, COMPLETION_COMPLETE);
|
||||
}
|
||||
|
||||
return $newstate;
|
||||
@ -1120,6 +1138,51 @@ class completion_info {
|
||||
return (object)$cacheddata[$cminfo->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest completion state for each criteria used in the module
|
||||
*
|
||||
* @param cm_info $cm The corresponding module's information
|
||||
* @param int $userid The id for the user we are calculating core completion state
|
||||
* @return array $data The individualised core completion state used in the module.
|
||||
* Consists of the following keys completiongrade, passgrade, viewed
|
||||
*/
|
||||
public function get_core_completion_state(cm_info $cm, int $userid): array {
|
||||
global $DB;
|
||||
$data = [];
|
||||
// Include in the completion info the grade completion, if necessary.
|
||||
if (!is_null($cm->completiongradeitemnumber)) {
|
||||
$newstate = $this->get_grade_completion($cm, $userid);
|
||||
$data['completiongrade'] = $newstate;
|
||||
|
||||
if ($cm->completionpassgrade) {
|
||||
// If we are asking to use pass grade completion but haven't set it properly,
|
||||
// then default to COMPLETION_COMPLETE_PASS.
|
||||
if ($newstate == COMPLETION_COMPLETE) {
|
||||
$newstate = COMPLETION_COMPLETE_PASS;
|
||||
}
|
||||
|
||||
// The activity is using 'passing grade' criteria therefore fail indication should be on this criteria.
|
||||
// The user has received a (failing) grade so 'completiongrade' should properly indicate this.
|
||||
if ($newstate == COMPLETION_COMPLETE_FAIL) {
|
||||
$data['completiongrade'] = COMPLETION_COMPLETE;
|
||||
}
|
||||
|
||||
$data['passgrade'] = $newstate;
|
||||
}
|
||||
}
|
||||
|
||||
// If view is required, try and fetch from the db. In some cases, cache can be invalid.
|
||||
if ($cm->completionview == COMPLETION_VIEW_REQUIRED) {
|
||||
$data['viewed'] = COMPLETION_INCOMPLETE;
|
||||
$record = $DB->get_record('course_modules_completion', array('coursemoduleid' => $cm->id, 'userid' => $userid));
|
||||
if ($record) {
|
||||
$data['viewed'] = ($record->viewed == COMPLETION_VIEWED ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the user's custom completion data on the given course module.
|
||||
*
|
||||
@ -1128,12 +1191,7 @@ class completion_info {
|
||||
* @return array The additional completion data.
|
||||
*/
|
||||
protected function get_other_cm_completion_data(cm_info $cm, int $userid): array {
|
||||
$data = [];
|
||||
|
||||
// Include in the completion info the grade completion, if necessary.
|
||||
if (!is_null($cm->completiongradeitemnumber)) {
|
||||
$data['completiongrade'] = $this->get_grade_completion($cm, $userid);
|
||||
}
|
||||
$data = $this->get_core_completion_state($cm, $userid);
|
||||
|
||||
// Custom activity module completion data.
|
||||
|
||||
@ -1153,7 +1211,7 @@ class completion_info {
|
||||
}
|
||||
|
||||
/** @var activity_custom_completion $customcmcompletion */
|
||||
$customcmcompletion = new $cmcompletionclass($cm, $userid);
|
||||
$customcmcompletion = new $cmcompletionclass($cm, $userid, $data);
|
||||
foreach ($customdata['customcompletionrules'] as $rule => $enabled) {
|
||||
if (!$enabled) {
|
||||
// Skip inactive completion rules.
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20210728" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20211001" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -304,6 +304,7 @@
|
||||
<FIELD NAME="completiongradeitemnumber" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Grade-item number used to track automatic completion, if applicable."/>
|
||||
<FIELD NAME="completionview" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Controls whether a page view is part of the automatic completion requirements for this activity. 0 = view not required 1 = view required"/>
|
||||
<FIELD NAME="completionexpected" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Date at which students are expected to complete this activity. This field is used when displaying student progress."/>
|
||||
<FIELD NAME="completionpassgrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Enable completion check on passing grade."/>
|
||||
<FIELD NAME="showdescription" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Some module types support a 'description' which shows within the module pages. This option controls whether it also displays on the course main page. 0 = does not display (default), 1 = displays"/>
|
||||
<FIELD NAME="availability" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Availability restrictions for viewing this activity, in JSON format. Null if no restrictions."/>
|
||||
<FIELD NAME="deletioninprogress" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@ -3866,6 +3867,7 @@
|
||||
<FIELD NAME="completion" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionview" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionusegrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionpassgrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionexpected" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="customrules" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
|
@ -2892,5 +2892,34 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2021100600.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2021100600.02) {
|
||||
$table = new xmldb_table('course_completion_defaults');
|
||||
|
||||
// Adding fields to table course_completion_defaults.
|
||||
$field = new xmldb_field('completionpassgrade', XMLDB_TYPE_INTEGER, '1', null,
|
||||
XMLDB_NOTNULL, null, '0', 'completionusegrade');
|
||||
|
||||
// Conditionally launch add field for course_completion_defaults.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
upgrade_main_savepoint(true, 2021100600.02);
|
||||
}
|
||||
|
||||
if ($oldversion < 2021100600.03) {
|
||||
$table = new xmldb_table('course_modules');
|
||||
|
||||
// Adding new fields to table course_module table.
|
||||
$field = new xmldb_field('completionpassgrade', XMLDB_TYPE_INTEGER, '1', null,
|
||||
XMLDB_NOTNULL, null, '0', 'completionexpected');
|
||||
// Conditionally launch create table for course_completion_defaults.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
upgrade_main_savepoint(true, 2021100600.03);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -970,6 +970,12 @@ class cm_info implements IteratorAggregate {
|
||||
*/
|
||||
private $completiongradeitemnumber;
|
||||
|
||||
/**
|
||||
* 1 if pass grade completion is enabled, 0 otherwise - from course_modules table
|
||||
* @var int
|
||||
*/
|
||||
private $completionpassgrade;
|
||||
|
||||
/**
|
||||
* 1 if 'on view' completion is enabled, 0 otherwise - from course_modules table
|
||||
* @var int
|
||||
@ -1173,6 +1179,7 @@ class cm_info implements IteratorAggregate {
|
||||
'completion' => false,
|
||||
'completionexpected' => false,
|
||||
'completiongradeitemnumber' => false,
|
||||
'completionpassgrade' => false,
|
||||
'completionview' => false,
|
||||
'conditionscompletion' => false,
|
||||
'conditionsfield' => false,
|
||||
@ -1648,7 +1655,7 @@ class cm_info implements IteratorAggregate {
|
||||
// Standard fields from table course_modules.
|
||||
static $cmfields = array('id', 'course', 'module', 'instance', 'section', 'idnumber', 'added',
|
||||
'score', 'indent', 'visible', 'visibleoncoursepage', 'visibleold', 'groupmode', 'groupingid',
|
||||
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
|
||||
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected', 'completionpassgrade',
|
||||
'showdescription', 'availability', 'deletioninprogress');
|
||||
foreach ($cmfields as $key) {
|
||||
$cmrecord->$key = $this->$key;
|
||||
@ -1867,6 +1874,7 @@ class cm_info implements IteratorAggregate {
|
||||
// availability and completion fields, even if availability or completion
|
||||
// are actually disabled
|
||||
$this->completion = isset($mod->completion) ? $mod->completion : 0;
|
||||
$this->completionpassgrade = isset($mod->completionpassgrade) ? $mod->completionpassgrade : 0;
|
||||
$this->completiongradeitemnumber = isset($mod->completiongradeitemnumber)
|
||||
? $mod->completiongradeitemnumber : null;
|
||||
$this->completionview = isset($mod->completionview)
|
||||
|
@ -176,7 +176,7 @@ abstract class testing_module_generator extends component_generator_base {
|
||||
$easymergefields = array('section', 'added', 'score', 'indent',
|
||||
'visible', 'visibleold', 'groupmode', 'groupingid',
|
||||
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
|
||||
'availability', 'showdescription');
|
||||
'completionpassgrade', 'availability', 'showdescription');
|
||||
foreach ($easymergefields as $key) {
|
||||
if (isset($options[$key])) {
|
||||
$moduleinfo->$key = $options[$key];
|
||||
@ -195,6 +195,7 @@ abstract class testing_module_generator extends component_generator_base {
|
||||
'completion' => 0,
|
||||
'completionview' => 0,
|
||||
'completionexpected' => 0,
|
||||
'completionpassgrade' => 0,
|
||||
'conditiongradegroup' => array(),
|
||||
'conditionfieldgroup' => array(),
|
||||
'conditioncompletiongroup' => array()
|
||||
|
@ -258,6 +258,7 @@ class core_test_generator_testcase extends advanced_testcase {
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC, // "Show activity as complete when conditions are met."
|
||||
'completionview' => 1, // "Student must view this activity to complete it"
|
||||
'completionusegrade' => 1, // "Student must receive a grade to complete this activity"
|
||||
'completionpassgrade' => 1, // "Student must receive a passing grade to complete this activity"
|
||||
);
|
||||
|
||||
// Module supports FEATURE_RATE:
|
||||
@ -327,6 +328,7 @@ class core_test_generator_testcase extends advanced_testcase {
|
||||
$cm3 = $modinfo->cms[$m3->cmid];
|
||||
$this->assertEquals($featurecompletionautomatic['completion'], $cm3->completion);
|
||||
$this->assertEquals($featurecompletionautomatic['completionview'], $cm3->completionview);
|
||||
$this->assertEquals($featurecompletionautomatic['completionpassgrade'], $cm3->completionpassgrade);
|
||||
$this->assertEquals(0, $cm3->completiongradeitemnumber); // Zero instead of default null since 'completionusegrade' was set.
|
||||
$gradingitem = grade_item::fetch(array('courseid'=>$course->id, 'itemtype'=>'mod', 'itemmodule' => 'assign', 'iteminstance' => $m3->id));
|
||||
$this->assertEquals(0, $gradingitem->grademin);
|
||||
|
@ -725,6 +725,7 @@ class core_completionlib_testcase extends advanced_testcase {
|
||||
'completion' => COMPLETION_TRACKING_AUTOMATIC,
|
||||
// Submission grade required.
|
||||
'completiongradeitemnumber' => 0,
|
||||
'completionpassgrade' => 1,
|
||||
]);
|
||||
|
||||
$cmworkshop = cm_info::create(get_coursemodule_from_instance('workshop', $workshop->id));
|
||||
@ -756,8 +757,10 @@ class core_completionlib_testcase extends advanced_testcase {
|
||||
$workshopcompletiondata = $method->invoke($completioninfo, $cmworkshop, $user->id);
|
||||
|
||||
$this->assertArrayHasKey('completiongrade', $workshopcompletiondata);
|
||||
$this->assertArrayHasKey('passgrade', $workshopcompletiondata);
|
||||
$this->assertArrayNotHasKey('customcompletion', $workshopcompletiondata);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $workshopcompletiondata['completiongrade']);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $workshopcompletiondata['passgrade']);
|
||||
|
||||
// Check that fetching data for a module with no completion conditions does not provide any data.
|
||||
$choice2completiondata = $method->invoke($completioninfo, $cmchoice2, $user->id);
|
||||
|
@ -183,6 +183,7 @@ class modinfolib_test extends advanced_testcase {
|
||||
$this->assertEquals($moduledb->indent, $cm->indent);
|
||||
$this->assertEquals($moduledb->completion, $cm->completion);
|
||||
$this->assertEquals($moduledb->completiongradeitemnumber, $cm->completiongradeitemnumber);
|
||||
$this->assertEquals($moduledb->completionpassgrade, $cm->completionpassgrade);
|
||||
$this->assertEquals($moduledb->completionview, $cm->completionview);
|
||||
$this->assertEquals($moduledb->completionexpected, $cm->completionexpected);
|
||||
$this->assertEquals($moduledb->showdescription, $cm->showdescription);
|
||||
|
@ -103,6 +103,9 @@ completely removed from Moodle core too.
|
||||
fixed units), to always include a non-breaking space between the number and unit, and to use
|
||||
consistent rounding (always 1 decimal place by default).
|
||||
* The persistent method get() now returns the correct type for each property defined in the persistent class.
|
||||
* Require pass grade criteria is now part of core.
|
||||
Refer to upgrade.php to see transitioning from similar plugin criteria to core
|
||||
Refer to completion/upgrade.txt for additional information.
|
||||
|
||||
=== 3.11.2 ===
|
||||
* For security reasons, filelib has been updated so all requests now use emulated redirects.
|
||||
|
@ -89,6 +89,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionview',
|
||||
'completionsubmit',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionview',
|
||||
'completionentries',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
177
mod/data/tests/behat/data_activity_completion_pass_grade.feature
Normal file
177
mod/data/tests/behat/data_activity_completion_pass_grade.feature
Normal file
@ -0,0 +1,177 @@
|
||||
@mod @mod_data @core_completion
|
||||
Feature: Completion pass grade
|
||||
View activity completion in the database activity
|
||||
In order to have visibility of database completion requirements
|
||||
As a student
|
||||
I need to be able to view my database completion progress
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| student2 | Vinnie | Student2 | student2@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And the following "activity" exists:
|
||||
| activity | data |
|
||||
| course | C1 |
|
||||
| idnumber | mh1 |
|
||||
| name | Music history |
|
||||
| section | 1 |
|
||||
And I am on the "Music history" "data activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Aggregate type | Average of ratings |
|
||||
| scale[modgrade_type] | Point |
|
||||
| scale[modgrade_point] | 100 |
|
||||
| gradepass | 50 |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
| Require grade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionentriesenabled | 1 |
|
||||
| completionentries | 2 |
|
||||
And I press "Save and display"
|
||||
And I add a "Text input" field to "Music history" database and I fill the form with:
|
||||
| Field name | Instrument types |
|
||||
And I follow "Templates"
|
||||
And I press "Save template"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items as a teacher and confirm all tabs display conditions
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Music history"
|
||||
Then "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "View single"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Search"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Add entry"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Export"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Templates"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Fields"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I follow "Presets"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 2" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
|
||||
@javascript
|
||||
Scenario: View automatic completion items as a failing student
|
||||
Given I am on the "Music history" "data activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add an entry to "Music history" database with:
|
||||
| Instrument types | Drums |
|
||||
And I press "Save and view"
|
||||
# One entry is not enough to mark as complete.
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add an entry to "Music history" database with:
|
||||
| Instrument types | Hurdygurdy |
|
||||
And I press "Save and view"
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
And I am on the "Music history" "data activity" page logged in as teacher1
|
||||
And I follow "View single"
|
||||
And I set the field "rating" to "3"
|
||||
And I log out
|
||||
When I am on the "Music history" "data activity" page logged in as student1
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Vinnie Student1" user has completed "Music history" activity
|
||||
|
||||
@javascript
|
||||
Scenario: View automatic completion items as a passing student
|
||||
Given I am on the "Music history" "data activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add an entry to "Music history" database with:
|
||||
| Instrument types | Drums |
|
||||
And I press "Save and view"
|
||||
# One entry is not enough to mark as complete.
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add an entry to "Music history" database with:
|
||||
| Instrument types | Hurdygurdy |
|
||||
And I press "Save and view"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
And I am on the "Music history" "data activity" page logged in as teacher1
|
||||
And I follow "View single"
|
||||
And I set the field "rating" to "60"
|
||||
And I log out
|
||||
When I am on the "Music history" "data activity" page logged in as student1
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Vinnie Student1" user has completed "Music history" activity
|
@ -112,6 +112,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionreplies',
|
||||
'completionposts',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,151 @@
|
||||
@mod @mod_forum @core_completion
|
||||
Feature: Completion pass grade view activity completion in the forum activity
|
||||
In order to have visibility of forum completion requirements
|
||||
As a student
|
||||
I need to be able to view my forum completion progress
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And the following "activity" exists:
|
||||
| activity | forum |
|
||||
| course | C1 |
|
||||
| idnumber | mh1 |
|
||||
| name | Music history |
|
||||
| section | 1 |
|
||||
And I am on the "Music history" "forum activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Whole forum grading > Type | Point |
|
||||
| Whole forum grading > Grade to pass | 50 |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
| Require grade | Whole forum |
|
||||
| completionpostsenabled | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionposts | 2 |
|
||||
| completiondiscussionsenabled | 1 |
|
||||
| completiondiscussions | 1 |
|
||||
| completionrepliesenabled | 1 |
|
||||
| completionreplies | 1 |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items as a teacher
|
||||
Given I am on the "Music history" "forum activity" page logged in as teacher1
|
||||
Then "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Start discussions: 1" completion condition
|
||||
And "Music history" should have the "Make forum posts: 2" completion condition
|
||||
And "Music history" should have the "Post replies: 1" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
|
||||
@javascript
|
||||
Scenario: View automatic completion items as a failing student
|
||||
Given I am on the "Music history" "forum activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I add a new discussion to "Music history" forum with:
|
||||
| Subject | Fun instruments |
|
||||
| Message | I like drums |
|
||||
And I am on the "Music history" "forum activity" page
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I reply "Fun instruments" post from "Music history" forum with:
|
||||
| Subject | Reply 1 to Fun instruments |
|
||||
| Message | Guitar is also Fun |
|
||||
And I am on the "Music history" "forum activity" page
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
# Grade the student
|
||||
And I am on the "Music history" "forum activity" page logged in as teacher1
|
||||
And I press "Grade users"
|
||||
And I set the field "grade" to "33"
|
||||
And I press "Save"
|
||||
And I press "Close grader"
|
||||
And I log out
|
||||
# All conditions should now be completed.
|
||||
When I am on the "Music history" "forum activity" page logged in as student1
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
|
||||
@javascript
|
||||
Scenario: View automatic completion items as a passing student
|
||||
Given I am on the "Music history" "forum activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I add a new discussion to "Music history" forum with:
|
||||
| Subject | Fun instruments |
|
||||
| Message | I like drums |
|
||||
And I am on the "Music history" "forum activity" page
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I reply "Fun instruments" post from "Music history" forum with:
|
||||
| Subject | Reply 1 to Fun instruments |
|
||||
| Message | Guitar is also Fun |
|
||||
And I am on the "Music history" "forum activity" page
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
# Grade the student
|
||||
And I am on the "Music history" "forum activity" page logged in as teacher1
|
||||
And I press "Grade users"
|
||||
And I set the field "grade" to "60"
|
||||
And I press "Save"
|
||||
And I press "Close grader"
|
||||
And I log out
|
||||
# All conditions should now be completed.
|
||||
When I am on the "Music history" "forum activity" page logged in as student1
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Start discussions: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make forum posts: 2" completion condition of "Music history" is displayed as "done"
|
||||
And the "Post replies: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
@ -84,6 +84,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionview',
|
||||
'completionentries',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,118 @@
|
||||
@mod @mod_glossary @core_completion
|
||||
Feature: Pass grade completion in the glossary activity
|
||||
In order to have visibility of glossary completion requirements
|
||||
As a student
|
||||
I need to be able to view my glossary completion progress
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And the following "activity" exists:
|
||||
| activity | glossary |
|
||||
| course | C1 |
|
||||
| idnumber | mh1 |
|
||||
| name | Music history |
|
||||
| section | 1 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Aggregate type | Average of ratings |
|
||||
| scale[modgrade_type] | Point |
|
||||
| scale[modgrade_point] | 100 |
|
||||
| Ratings > Grade to pass | 50 |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
| Require grade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionentriesenabled | 1 |
|
||||
| completionentries | 1 |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items as a teacher
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Music history"
|
||||
Then "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Make entries: 1" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
|
||||
Scenario: View automatic completion items as a failing student
|
||||
Given I am on the "Music history" "glossary activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
When I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I press "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Blast beats |
|
||||
| Definition | Repeated fast tempo hits combining bass, snare and cymbal |
|
||||
And I press "Save changes"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
And I am on the "Music history" "glossary activity" page logged in as teacher1
|
||||
And I set the field "rating" to "3"
|
||||
And I press "Rate"
|
||||
And I log out
|
||||
When I am on the "Music history" "glossary activity" page logged in as student1
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
|
||||
Scenario: View automatic completion items as a passing student
|
||||
Given I am on the "Music history" "glossary activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
When I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I press "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Blast beats |
|
||||
| Definition | Repeated fast tempo hits combining bass, snare and cymbal |
|
||||
And I press "Save changes"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I set the field "rating" to "60"
|
||||
And I press "Rate"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
@ -0,0 +1,84 @@
|
||||
@mod @mod_h5pactivity @core_h5p @_file_upload @_switch_iframe @javascript @core_completion
|
||||
Feature: Pass grade activity completion information in the h5p activity
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| student2 | Vinnie | Student2 | student2@example.com |
|
||||
| student3 | Vinnie | Student3 | student3@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "H5P" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | Music history |
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
| Require grade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| gradepass | 25 |
|
||||
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Package file" filemanager
|
||||
And I click on "Save and display" "button"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items
|
||||
# Teacher view.
|
||||
Given I am on the "Music history" "h5pactivity activity" page logged in as teacher1
|
||||
# Given I log in as "teacher1"
|
||||
# And I am on "Course 1" course homepage
|
||||
# And I follow "Music history"
|
||||
And "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
And I log out
|
||||
# Student view.
|
||||
When I am on the "Music history" "h5pactivity activity" page logged in as student1
|
||||
# When I log in as "student1"
|
||||
# And I am on "Course 1" course homepage
|
||||
# And I follow "Music history"
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I click on "Check" "button" in the ".h5p-question-buttons" "css_element"
|
||||
And I reload the page
|
||||
And I log out
|
||||
And I am on the "Music history" "h5pactivity activity" page logged in as student2
|
||||
And I switch to "h5p-player" class iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 1 of 4\")]" to "Brasilia"
|
||||
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 2 of 4\")]" to "Washington"
|
||||
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 3 of 4\")]" to "Berlin"
|
||||
And I set the field with xpath "//input[contains(@aria-label,\"Blank input 4 of 4\")]" to "Canberra"
|
||||
And I click on "Check" "button" in the ".h5p-question-buttons" "css_element"
|
||||
And I switch to the main frame
|
||||
And I reload the page
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
And I am on the "Music history" "h5pactivity activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Vinnie Student1" user has completed "Music history" activity
|
||||
And "Vinnie Student2" user has completed "Music history" activity
|
||||
And "Vinnie Student3" user has not completed "Music history" activity
|
@ -103,6 +103,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completiontimespent',
|
||||
'completionendreached',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
105
mod/lesson/tests/behat/lesson_completion_pass_grade.feature
Normal file
105
mod/lesson/tests/behat/lesson_completion_pass_grade.feature
Normal file
@ -0,0 +1,105 @@
|
||||
@mod @mod_lesson @core_completion
|
||||
Feature: Pass grade activity completion in the lesson activity
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| student2 | Vinnie | Student2 | student2@example.com |
|
||||
| student3 | Vinnie | Student3 | student3@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And the following "activity" exists:
|
||||
| activity | lesson |
|
||||
| course | C1 |
|
||||
| idnumber | mh1 |
|
||||
| name | Music history |
|
||||
| section | 1 |
|
||||
| gradepass | 50 |
|
||||
| completion | 2 |
|
||||
| completionview | 1 |
|
||||
| completionusegrade | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionendreached | 1 |
|
||||
| completiontimespentenabled | 1 |
|
||||
| completiontimespent | 1 |
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I follow "Add a question page"
|
||||
And I set the field "Select a question type" to "Numerical"
|
||||
And I press "Add a question page"
|
||||
And I set the following fields to these values:
|
||||
| Page title | Numerical question |
|
||||
| Page contents | What is 1 + 2? |
|
||||
| id_answer_editor_0 | 3 |
|
||||
| id_jumpto_0 | End of lesson |
|
||||
| id_enableotheranswers | 1 |
|
||||
| id_jumpto_6 | Next page |
|
||||
And I press "Save page"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items as a teacher
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Music history"
|
||||
Then "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Spend at least 1 sec on this activity" completion condition
|
||||
And "Music history" should have the "Go through the activity to the end" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
|
||||
Scenario: View automatic completion items as a student
|
||||
Given I am on the "Music history" "lesson activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Spend at least 1 sec on this activity" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Go through the activity to the end" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
When I am on "Course 1" course homepage
|
||||
And I follow "Music history"
|
||||
And I wait "2" seconds
|
||||
And I reload the page
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Spend at least 1 sec on this activity" completion condition of "Music history" is displayed as "done"
|
||||
And the "Go through the activity to the end" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I set the field "Your answer" to "3"
|
||||
And I press "Submit"
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Spend at least 1 sec on this activity" completion condition of "Music history" is displayed as "done"
|
||||
And the "Go through the activity to the end" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
And I am on the "Music history" "lesson activity" page logged in as student2
|
||||
And I wait "2" seconds
|
||||
And I set the field "Your answer" to "0"
|
||||
And I press "Submit"
|
||||
Then the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Spend at least 1 sec on this activity" completion condition of "Music history" is displayed as "done"
|
||||
And the "Go through the activity to the end" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Vinnie Student1" user has completed "Music history" activity
|
||||
And "Vinnie Student2" user has completed "Music history" activity
|
||||
And "Vinnie Student3" user has not completed "Music history" activity
|
84
mod/lti/tests/behat/lti_completion_pass_grade.feature
Normal file
84
mod/lti/tests/behat/lti_completion_pass_grade.feature
Normal file
@ -0,0 +1,84 @@
|
||||
@mod @mod_lti @core_completion @javascript
|
||||
Feature: Pass grade activity completion information in the LTI activity
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Vinnie | Student1 | student1@example.com |
|
||||
| student2 | Vinnie | Student2 | student2@example.com |
|
||||
| student3 | Vinnie | Student3 | student3@example.com |
|
||||
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| lti | Music history | C1 | lti1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
| Enable completion tracking | Yes |
|
||||
| Show activity completion conditions | Yes |
|
||||
And I press "Save and display"
|
||||
And I turn editing mode on
|
||||
When I open "Music history" actions menu
|
||||
And I click on "Edit settings" "link" in the "Music history" activity
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
| Require view | 1 |
|
||||
| Require grade | 1 |
|
||||
| gradepass | 50 |
|
||||
| completionpassgrade | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
|
||||
Scenario: View automatic completion items as a teacher
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Music history"
|
||||
Then "Music history" should have the "View" completion condition
|
||||
And "Music history" should have the "Receive a grade" completion condition
|
||||
And "Music history" should have the "Receive a passing grade" completion condition
|
||||
|
||||
Scenario: View automatic completion items as a student
|
||||
Given I am on the "Music history" "lti activity" page logged in as student1
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "90.00" to the user "Vinnie Student1" for the grade item "Music history"
|
||||
And I give the grade "20.00" to the user "Vinnie Student2" for the grade item "Music history"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I am on the "Music history" "lti activity" page logged in as student1
|
||||
Then the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
Then the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
When I am on the "Music history" "lti activity" page logged in as student2
|
||||
Then the "Receive a grade" completion condition of "Music history" is displayed as "done"
|
||||
Then the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
When I am on the "Music history" "lti activity" page logged in as student3
|
||||
Then the "Receive a grade" completion condition of "Music history" is displayed as "todo"
|
||||
Then the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
|
||||
And the "View" completion condition of "Music history" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Vinnie Student1" user has completed "Music history" activity
|
||||
And "Vinnie Student2" user has completed "Music history" activity
|
||||
And "Vinnie Student3" user has not completed "Music history" activity
|
@ -49,7 +49,7 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
'questionsperpage', 'navmethod', 'shuffleanswers',
|
||||
'sumgrades', 'grade', 'timecreated',
|
||||
'timemodified', 'password', 'subnet', 'browsersecurity',
|
||||
'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted', 'completionpass',
|
||||
'delay1', 'delay2', 'showuserpicture', 'showblocks', 'completionattemptsexhausted',
|
||||
'completionminattempts', 'allowofflineattempts'));
|
||||
|
||||
// Define elements for access rule subplugin settings.
|
||||
|
@ -292,6 +292,12 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
|
||||
$DB->insert_record('quizaccess_seb_quizsettings', $sebsettings);
|
||||
}
|
||||
|
||||
// If we are dealing with a backup from < 4.0 then we need to move completionpass to core.
|
||||
if (!empty($data->completionpass)) {
|
||||
$params = ['id' => $this->task->get_moduleid()];
|
||||
$DB->set_field('course_modules', 'completionpassgrade', $data->completionpass, $params);
|
||||
}
|
||||
}
|
||||
|
||||
protected function process_quiz_question_instance($data) {
|
||||
|
@ -48,23 +48,14 @@ class custom_completion extends activity_custom_completion {
|
||||
|
||||
$completionpassorattempts = $this->cm->customdata['customcompletionrules']['completionpassorattemptsexhausted'];
|
||||
|
||||
if (empty($completionpassorattempts['completionpass'])) {
|
||||
if (empty($completionpassorattempts['completionpassgrade'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for passing grade.
|
||||
$item = grade_item::fetch([
|
||||
'courseid' => $this->cm->get_course()->id,
|
||||
'itemtype' => 'mod',
|
||||
'itemmodule' => 'quiz',
|
||||
'iteminstance' => $this->cm->instance,
|
||||
'outcomeid' => null
|
||||
]);
|
||||
if ($item) {
|
||||
$grades = grade_grade::fetch_users_grades($item, [$this->userid], false);
|
||||
if (!empty($grades[$this->userid]) && $grades[$this->userid]->is_passed($item)) {
|
||||
return true;
|
||||
}
|
||||
if ($this->completionstate &&
|
||||
isset($this->completionstate['passgrade']) &&
|
||||
$this->completionstate['passgrade'] == COMPLETION_COMPLETE_PASS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If a passing grade is required and exhausting all available attempts is not accepted for completion,
|
||||
@ -146,18 +137,15 @@ class custom_completion extends activity_custom_completion {
|
||||
*/
|
||||
public function get_custom_rule_descriptions(): array {
|
||||
$minattempts = $this->cm->customdata['customcompletionrules']['completionminattempts'] ?? 0;
|
||||
$description['completionminattempts'] = get_string('completiondetail:minattempts', 'mod_quiz', $minattempts);
|
||||
|
||||
// Completion pass grade is now part of core. Only show the following if it's combined with min attempts.
|
||||
$completionpassorattempts = $this->cm->customdata['customcompletionrules']['completionpassorattemptsexhausted'] ?? [];
|
||||
if (!empty($completionpassorattempts['completionattemptsexhausted'])) {
|
||||
$passorallattemptslabel = get_string('completiondetail:passorexhaust', 'mod_quiz');
|
||||
} else {
|
||||
$passorallattemptslabel = get_string('completiondetail:passgrade', 'mod_quiz');
|
||||
$description['completionpassorattemptsexhausted'] = get_string('completiondetail:passorexhaust', 'mod_quiz');
|
||||
}
|
||||
|
||||
return [
|
||||
'completionpassorattemptsexhausted' => $passorallattemptslabel,
|
||||
'completionminattempts' => get_string('completiondetail:minattempts', 'mod_quiz', $minattempts),
|
||||
];
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,6 +158,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionview',
|
||||
'completionminattempts',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
'completionpassorattemptsexhausted',
|
||||
];
|
||||
}
|
||||
|
@ -131,9 +131,12 @@ class mod_quiz_external extends external_api {
|
||||
'reviewspecificfeedback', 'reviewgeneralfeedback', 'reviewrightanswer',
|
||||
'reviewoverallfeedback', 'questionsperpage', 'navmethod',
|
||||
'browsersecurity', 'delay1', 'delay2', 'showuserpicture', 'showblocks',
|
||||
'completionattemptsexhausted', 'completionpass', 'overduehandling',
|
||||
'completionattemptsexhausted', 'overduehandling',
|
||||
'graceperiod', 'canredoquestions', 'allowofflineattempts');
|
||||
$viewablefields = array_merge($viewablefields, $additionalfields);
|
||||
|
||||
// Any course module fields that previously existed in quiz.
|
||||
$quizdetails['completionpass'] = $quizobj->get_cm()->completionpassgrade;
|
||||
}
|
||||
|
||||
// Fields only for managers.
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20200615" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20200630" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -45,7 +45,6 @@
|
||||
<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"/>
|
||||
<FIELD NAME="completionminattempts" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="allowofflineattempts" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether to allow the quiz to be attempted offline in the mobile app"/>
|
||||
</FIELDS>
|
||||
|
@ -60,5 +60,45 @@ function xmldb_quiz_upgrade($oldversion) {
|
||||
upgrade_mod_savepoint(true, 2020061501, 'quiz');
|
||||
}
|
||||
|
||||
if ($oldversion < 2021052503) {
|
||||
$table = new xmldb_table('quiz');
|
||||
$field = new xmldb_field('completionpass');
|
||||
|
||||
if ($dbman->field_exists($table, $field)) {
|
||||
$sql = "SELECT q.id " .
|
||||
"FROM {quiz} q " .
|
||||
"INNER JOIN {course_modules} cm ON cm.instance = q.id " .
|
||||
"INNER JOIN {modules} m ON m.id = cm.module " .
|
||||
"WHERE m.name = :name AND q.completionpass = :completionpass";
|
||||
|
||||
/** @var moodle_recordset $records */
|
||||
$records = $DB->get_recordset_sql($sql, ['name' => 'quiz', 'completionpass' => 1], 0, 1000);
|
||||
while ($records->valid()) {
|
||||
foreach ($records as $record) {
|
||||
$ids[] = $record->id;
|
||||
}
|
||||
|
||||
if ($ids) {
|
||||
list($insql, $params) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
|
||||
$DB->set_field_select('course_modules', 'completionpassgrade', 1, "instance $insql", $params);
|
||||
|
||||
// Reset the value so it doesn't get picked on the next run. The field will be dropped later.
|
||||
$DB->set_field_select('quiz', 'completionpass', 0, "id $insql", $params);
|
||||
|
||||
// Get the next batch of records.
|
||||
$records = $DB->get_recordset_sql($sql, ['name' => 'quiz', 'completionpass' => 1], 0, 1000);
|
||||
}
|
||||
}
|
||||
$records->close();
|
||||
|
||||
// We have completed our checks. Drop the field.
|
||||
if ($dbman->field_exists($table, $field)) {
|
||||
$dbman->drop_field($table, $field);
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_mod_savepoint(true, 2021052503, 'quiz');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ function quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $user
|
||||
|
||||
debugging('quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', DEBUG_DEVELOPER);
|
||||
|
||||
if (!$quiz->completionpass) {
|
||||
if (!$cm->completionpassgrade) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ function quiz_get_completion_state($course, $cm, $userid, $type) {
|
||||
// No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state().
|
||||
|
||||
$quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
|
||||
if (!$quiz->completionattemptsexhausted && !$quiz->completionpass && !$quiz->completionminattempts) {
|
||||
if (!$quiz->completionattemptsexhausted && !$cm->completionpassgrade && !$quiz->completionminattempts) {
|
||||
return $type;
|
||||
}
|
||||
|
||||
|
@ -2,3 +2,8 @@ numattemptsmade,mod_quiz
|
||||
reviewofattempt,mod_quiz
|
||||
reviewofpreview,mod_quiz
|
||||
settingsoverrides,mod_quiz
|
||||
completionpass,mod_quiz
|
||||
completionpassdesc,mod_quiz
|
||||
completionpass_help,mod_quiz
|
||||
completiondetail:passgrade,mod_quiz
|
||||
gradetopassnotset,mod_quiz
|
||||
|
@ -181,15 +181,11 @@ $string['commentorgrade'] = 'Make comment or override grade';
|
||||
$string['comments'] = 'Comments';
|
||||
$string['completedon'] = 'Completed on';
|
||||
$string['completiondetail:minattempts'] = 'Make attempts: {$a}';
|
||||
$string['completiondetail:passgrade'] = 'Receive a pass grade';
|
||||
$string['completiondetail:passorexhaust'] = 'Receive a pass grade or complete all available attempts';
|
||||
$string['completionminattempts'] = 'Minimum number of attempts:';
|
||||
$string['completionminattemptsdesc'] = 'Minimum number of attempts required: {$a}';
|
||||
$string['completionminattemptsgroup'] = 'Require attempts';
|
||||
$string['completionminattemptserror'] = 'Minimum number of attempts must be lower or equal to attempts allowed.';
|
||||
$string['completionpass'] = 'Require passing grade';
|
||||
$string['completionpassdesc'] = 'Student must achieve a passing grade to complete this activity';
|
||||
$string['completionpass_help'] = 'If enabled, this activity is considered complete when the student receives a pass grade (as specified in the Grade section of the quiz settings) or higher.';
|
||||
$string['completionpassorattemptsexhausteddesc'] = 'Student must achieve a passing grade, or exhaust all available attempts to complete this activity';
|
||||
$string['completionattemptsexhausted'] = 'Or all available attempts completed';
|
||||
$string['completionattemptsexhausted_help'] = 'Mark quiz complete when the student has exhausted the maximum number of attempts.';
|
||||
@ -421,7 +417,6 @@ $string['grademethod_help'] = 'When multiple attempts are allowed, the following
|
||||
* Last attempt (all other attempts are ignored)';
|
||||
$string['gradesdeleted'] = 'Quiz grades deleted';
|
||||
$string['gradesofar'] = '{$a->method}: {$a->mygrade} / {$a->quizgrade}.';
|
||||
$string['gradetopassnotset'] = 'This quiz does not yet have a grade to pass set. It may be set in the Grade section of the quiz settings.';
|
||||
$string['gradetopassmustbeset'] = 'Grade to pass cannot be zero as this quiz has its completion method set to require passing grade. Please set a non-zero value.';
|
||||
$string['gradetopassoutof'] = 'Grade to pass: {$a->grade} out of {$a->maxgrade}';
|
||||
$string['gradingdetails'] = 'Marks for this submission: {$a->raw}/{$a->max}.';
|
||||
@ -1037,3 +1032,10 @@ $string['settingsoverrides'] = 'Settings overrides';
|
||||
|
||||
// Deprecated since Moodle 3.11.
|
||||
$string['completionattemptsexhausteddesc'] = 'Complete if all available attempts are exhausted';
|
||||
|
||||
// Deprecated since Moodle 4.0.
|
||||
$string['completionpass'] = 'Require passing grade';
|
||||
$string['completionpassdesc'] = 'Student must achieve a passing grade to complete this activity';
|
||||
$string['completionpass_help'] = 'If enabled, this activity is considered complete when the student receives a pass grade (as specified in the Grade section of the quiz settings) or higher.';
|
||||
$string['completiondetail:passgrade'] = 'Receive a pass grade';
|
||||
$string['gradetopassnotset'] = 'This quiz does not yet have a grade to pass set. It may be set in the Grade section of the quiz settings.';
|
||||
|
@ -1129,9 +1129,9 @@ function quiz_process_options($quiz) {
|
||||
|
||||
// Ensure that disabled checkboxes in completion settings are set to 0.
|
||||
if (empty($quiz->completionusegrade)) {
|
||||
$quiz->completionpass = 0;
|
||||
$quiz->completionpassgrade = 0;
|
||||
}
|
||||
if (empty($quiz->completionpass)) {
|
||||
if (empty($quiz->completionpassgrade)) {
|
||||
$quiz->completionattemptsexhausted = 0;
|
||||
}
|
||||
if (empty($quiz->completionminattemptsenabled)) {
|
||||
@ -1908,6 +1908,15 @@ function quiz_get_navigation_options() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aggregation state for the module.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function quiz_get_completion_aggregation_state() {
|
||||
return COMPLETION_CUSTOM_MODULE_FLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the module has any update that affects the current user since a given time.
|
||||
*
|
||||
@ -2092,7 +2101,7 @@ function quiz_get_coursemodule_info($coursemodule) {
|
||||
global $DB;
|
||||
|
||||
$dbparams = ['id' => $coursemodule->instance];
|
||||
$fields = 'id, name, intro, introformat, completionattemptsexhausted, completionpass, completionminattempts,
|
||||
$fields = 'id, name, intro, introformat, completionattemptsexhausted, completionminattempts,
|
||||
timeopen, timeclose';
|
||||
if (!$quiz = $DB->get_record('quiz', $dbparams, $fields)) {
|
||||
return false;
|
||||
@ -2108,9 +2117,9 @@ function quiz_get_coursemodule_info($coursemodule) {
|
||||
|
||||
// Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'.
|
||||
if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) {
|
||||
if ($quiz->completionpass || $quiz->completionattemptsexhausted) {
|
||||
if ($quiz->completionattemptsexhausted) {
|
||||
$result->customdata['customcompletionrules']['completionpassorattemptsexhausted'] = [
|
||||
'completionpass' => $quiz->completionpass,
|
||||
'completionpassgrade' => $coursemodule->completionpassgrade,
|
||||
'completionattemptsexhausted' => $quiz->completionattemptsexhausted,
|
||||
];
|
||||
} else {
|
||||
@ -2206,16 +2215,11 @@ function mod_quiz_get_completion_active_rule_descriptions($cm) {
|
||||
if (!empty($rules['completionpassorattemptsexhausted'])) {
|
||||
if (!empty($rules['completionpassorattemptsexhausted']['completionattemptsexhausted'])) {
|
||||
$descriptions[] = get_string('completionpassorattemptsexhausteddesc', 'quiz');
|
||||
} else if (!empty($rules['completionpassorattemptsexhausted']['completionpass'])) {
|
||||
$descriptions[] = get_string('completionpassdesc', 'quiz',
|
||||
format_time($rules['completionpassorattemptsexhausted']['completionpass']));
|
||||
}
|
||||
} else {
|
||||
// Fallback.
|
||||
if (!empty($rules['completionattemptsexhausted'])) {
|
||||
$descriptions[] = get_string('completionpassorattemptsexhausteddesc', 'quiz');
|
||||
} else if (!empty($rules['completionpass'])) {
|
||||
$descriptions[] = get_string('completionpassdesc', 'quiz', format_time($rules['completionpass']));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1877,7 +1877,7 @@ function quiz_attempt_submitted_handler($event) {
|
||||
// Update completion state.
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled($cm) &&
|
||||
($quiz->completionattemptsexhausted || $quiz->completionpass || $quiz->completionminattempts)) {
|
||||
($quiz->completionattemptsexhausted || $quiz->completionminattempts)) {
|
||||
$completion->update_state($cm, COMPLETION_COMPLETE, $event->userid);
|
||||
}
|
||||
return quiz_send_notification_messages($course, $quiz, $attempt,
|
||||
|
@ -527,19 +527,6 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('completion', $data) && $data['completion'] == COMPLETION_TRACKING_AUTOMATIC) {
|
||||
$completionpass = isset($data['completionpass']) ? $data['completionpass'] : $this->current->completionpass;
|
||||
|
||||
// Show an error if require passing grade was selected and the grade to pass was set to 0.
|
||||
if ($completionpass && (empty($data['gradepass']) || grade_floatval($data['gradepass']) == 0)) {
|
||||
if (isset($data['completionpass'])) {
|
||||
$errors['completionpassgroup'] = get_string('gradetopassnotset', 'quiz');
|
||||
} else {
|
||||
$errors['gradepass'] = get_string('gradetopassmustbeset', 'quiz');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data['completionminattempts'])) {
|
||||
if ($data['attempts'] > 0 && $data['completionminattempts'] > $data['attempts']) {
|
||||
$errors['completionminattemptsgroup'] = get_string('completionminattemptserror', 'quiz');
|
||||
@ -615,17 +602,11 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
$mform = $this->_form;
|
||||
$items = array();
|
||||
|
||||
$group = array();
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionpass', null, get_string('completionpass', 'quiz'),
|
||||
array('group' => 'cpass'));
|
||||
$mform->disabledIf('completionpass', 'completionusegrade', 'notchecked');
|
||||
$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';
|
||||
$mform->addElement('advcheckbox', 'completionattemptsexhausted', null,
|
||||
get_string('completionattemptsexhausted', 'quiz'),
|
||||
array('group' => 'cattempts'));
|
||||
$mform->disabledIf('completionattemptsexhausted', 'completionpassgrade', 'notchecked');
|
||||
$items[] = 'completionattemptsexhausted';
|
||||
|
||||
$group = array();
|
||||
$group[] = $mform->createElement('checkbox', 'completionminattemptsenabled', '',
|
||||
@ -648,7 +629,6 @@ class mod_quiz_mod_form extends moodleform_mod {
|
||||
*/
|
||||
public function completion_rule_enabled($data) {
|
||||
return !empty($data['completionattemptsexhausted']) ||
|
||||
!empty($data['completionpass']) ||
|
||||
!empty($data['completionminattemptsenabled']);
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ Feature: Set a quiz to be marked complete when the student uses all attempts all
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer the first question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionusegrade | completionpass | completionattemptsexhausted |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionusegrade | completionpassgrade | completionattemptsexhausted |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 2 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
And quiz "Test quiz name" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
@ -37,7 +37,8 @@ Feature: Set a quiz to be marked complete when the student uses all attempts all
|
||||
Scenario: student1 uses up both attempts without passing
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And I follow "Test quiz name"
|
||||
And I press "Re-attempt quiz"
|
||||
@ -45,10 +46,12 @@ Feature: Set a quiz to be marked complete when the student uses all attempts all
|
||||
And I press "Finish attempt ..."
|
||||
And I press "Submit all and finish"
|
||||
And I am on "Course 1" course homepage
|
||||
Then the "Receive a grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
Then the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "done"
|
||||
And I follow "Test quiz name"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
|
@ -25,8 +25,8 @@ Feature: Set a quiz to be marked complete when the student passes
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | First question | Answer the first question |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionusegrade | completionpass | completionview |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 4 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
| activity | name | course | idnumber | attempts | gradepass | completion | completionusegrade | completionpassgrade | completionview |
|
||||
| quiz | Test quiz name | C1 | quiz1 | 4 | 5.00 | 2 | 1 | 1 | 1 |
|
||||
And quiz "Test quiz name" contains the following questions:
|
||||
| question | page |
|
||||
| First question | 1 |
|
||||
@ -35,18 +35,18 @@ Feature: Set a quiz to be marked complete when the student passes
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "Receive a pass grade" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And user "student1" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
And I follow "Test quiz name"
|
||||
Then the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a pass grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "done"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a pass grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
|
@ -35,7 +35,7 @@ Feature: View activity completion in the quiz activity
|
||||
| completion | 2 |
|
||||
| completionview | 1 |
|
||||
| completionusegrade | 1 |
|
||||
| completionpass | 1 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionattemptsexhausted | 1 |
|
||||
| completionminattemptsenabled | 1 |
|
||||
| completionminattempts | 1 |
|
||||
@ -50,6 +50,7 @@ Feature: View activity completion in the quiz activity
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Make attempts: 1" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And user "student1" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
@ -58,7 +59,8 @@ Feature: View activity completion in the quiz activity
|
||||
And I follow "Test quiz name"
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Make attempts: 1" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "failed"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "todo"
|
||||
And I press "Re-attempt quiz"
|
||||
And I set the field "True" to "1"
|
||||
@ -68,4 +70,5 @@ Feature: View activity completion in the quiz activity
|
||||
And the "View" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Make attempts: 1" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test quiz name" is displayed as "done"
|
||||
And the "Receive a pass grade or complete all available attempts" completion condition of "Test quiz name" is displayed as "done"
|
||||
|
@ -20,6 +20,7 @@ namespace mod_quiz;
|
||||
|
||||
use advanced_testcase;
|
||||
use cm_info;
|
||||
use core_completion\cm_completion_details;
|
||||
use grade_item;
|
||||
use mod_quiz\completion\custom_completion;
|
||||
use question_engine;
|
||||
@ -127,11 +128,8 @@ class custom_completion_test extends advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test checking the completion state of a quiz.
|
||||
* Test checking the completion state of a quiz base on core's completionpassgrade criteria.
|
||||
* The quiz requires a passing grade to be completed.
|
||||
*
|
||||
* @covers ::get_state
|
||||
* @covers ::get_custom_rule_descriptions
|
||||
*/
|
||||
public function test_completionpass() {
|
||||
list($students, $quiz, $cm) = $this->setup_quiz_for_testing_completion([
|
||||
@ -139,7 +137,7 @@ class custom_completion_test extends advanced_testcase {
|
||||
'qtype' => 'numerical',
|
||||
'quizoptions' => [
|
||||
'completionusegrade' => 1,
|
||||
'completionpass' => 1
|
||||
'completionpassgrade' => 1
|
||||
]
|
||||
]);
|
||||
|
||||
@ -153,13 +151,14 @@ class custom_completion_test extends advanced_testcase {
|
||||
'tosubmit' => [1 => ['answer' => '3.14']]
|
||||
]);
|
||||
|
||||
$completioninfo = new \completion_info($cm->get_course());
|
||||
$completiondetails = new cm_completion_details($completioninfo, $cm, (int) $passstudent->id);
|
||||
|
||||
// Check the results.
|
||||
$customcompletion = new custom_completion($cm, (int) $passstudent->id);
|
||||
$this->assertArrayHasKey('completionpassorattemptsexhausted', $cm->customdata['customcompletionrules']);
|
||||
$this->assertEquals(COMPLETION_COMPLETE, $customcompletion->get_state('completionpassorattemptsexhausted'));
|
||||
$this->assertEquals(COMPLETION_COMPLETE_PASS, $completiondetails->get_details()['completionpassgrade']->status);
|
||||
$this->assertEquals(
|
||||
'Receive a pass grade',
|
||||
$customcompletion->get_custom_rule_descriptions()['completionpassorattemptsexhausted']
|
||||
'Receive a passing grade',
|
||||
$completiondetails->get_details()['completionpassgrade']->description
|
||||
);
|
||||
|
||||
// Do a failing attempt.
|
||||
@ -170,13 +169,13 @@ class custom_completion_test extends advanced_testcase {
|
||||
'tosubmit' => [1 => ['answer' => '0']]
|
||||
]);
|
||||
|
||||
$completiondetails = new cm_completion_details($completioninfo, $cm, (int) $failstudent->id);
|
||||
|
||||
// Check the results.
|
||||
$customcompletion = new custom_completion($cm, (int) $failstudent->id);
|
||||
$this->assertArrayHasKey('completionpassorattemptsexhausted', $cm->customdata['customcompletionrules']);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $customcompletion->get_state('completionpassorattemptsexhausted'));
|
||||
$this->assertEquals(COMPLETION_COMPLETE_FAIL, $completiondetails->get_details()['completionpassgrade']->status);
|
||||
$this->assertEquals(
|
||||
'Receive a pass grade',
|
||||
$customcompletion->get_custom_rule_descriptions()['completionpassorattemptsexhausted']
|
||||
'Receive a passing grade',
|
||||
$completiondetails->get_details()['completionpassgrade']->description
|
||||
);
|
||||
}
|
||||
|
||||
@ -194,7 +193,7 @@ class custom_completion_test extends advanced_testcase {
|
||||
'quizoptions' => [
|
||||
'attempts' => 2,
|
||||
'completionusegrade' => 1,
|
||||
'completionpass' => 1,
|
||||
'completionpassgrade' => 1,
|
||||
'completionattemptsexhausted' => 1
|
||||
]
|
||||
]);
|
||||
@ -209,8 +208,11 @@ class custom_completion_test extends advanced_testcase {
|
||||
'tosubmit' => [1 => ['answer' => '3.14']]
|
||||
]);
|
||||
|
||||
$completioninfo = new \completion_info($cm->get_course());
|
||||
|
||||
// Check the results. Quiz is completed by $passstudent because of passing grade.
|
||||
$customcompletion = new custom_completion($cm, (int) $passstudent->id);
|
||||
$studentid = (int) $passstudent->id;
|
||||
$customcompletion = new custom_completion($cm, $studentid, $completioninfo->get_core_completion_state($cm, $studentid));
|
||||
$this->assertArrayHasKey('completionpassorattemptsexhausted', $cm->customdata['customcompletionrules']);
|
||||
$this->assertEquals(COMPLETION_COMPLETE, $customcompletion->get_state('completionpassorattemptsexhausted'));
|
||||
$this->assertEquals(
|
||||
@ -227,7 +229,8 @@ class custom_completion_test extends advanced_testcase {
|
||||
]);
|
||||
|
||||
// Check the results. Quiz is not completed by $exhauststudent yet because of failing grade and of remaining attempts.
|
||||
$customcompletion = new custom_completion($cm, (int) $exhauststudent->id);
|
||||
$studentid = (int) $exhauststudent->id;
|
||||
$customcompletion = new custom_completion($cm, $studentid, $completioninfo->get_core_completion_state($cm, $studentid));
|
||||
$this->assertArrayHasKey('completionpassorattemptsexhausted', $cm->customdata['customcompletionrules']);
|
||||
$this->assertEquals(COMPLETION_INCOMPLETE, $customcompletion->get_state('completionpassorattemptsexhausted'));
|
||||
$this->assertEquals(
|
||||
@ -244,7 +247,7 @@ class custom_completion_test extends advanced_testcase {
|
||||
]);
|
||||
|
||||
// Check the results. Quiz is completed by $exhauststudent because there are no remaining attempts.
|
||||
$customcompletion = new custom_completion($cm, (int) $exhauststudent->id);
|
||||
$customcompletion = new custom_completion($cm, $studentid, $completioninfo->get_core_completion_state($cm, $studentid));
|
||||
$this->assertArrayHasKey('completionpassorattemptsexhausted', $cm->customdata['customcompletionrules']);
|
||||
$this->assertEquals(COMPLETION_COMPLETE, $customcompletion->get_state('completionpassorattemptsexhausted'));
|
||||
$this->assertEquals(
|
||||
|
@ -228,6 +228,7 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
|
||||
$quiz1->groupingid = 0;
|
||||
$quiz1->hasquestions = 0;
|
||||
$quiz1->hasfeedback = 0;
|
||||
$quiz1->completionpass = 0;
|
||||
$quiz1->autosaveperiod = get_config('quiz', 'autosaveperiod');
|
||||
$quiz1->introfiles = [];
|
||||
|
||||
@ -239,6 +240,7 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase {
|
||||
$quiz2->groupingid = 0;
|
||||
$quiz2->hasquestions = 0;
|
||||
$quiz2->hasfeedback = 0;
|
||||
$quiz2->completionpass = 0;
|
||||
$quiz2->autosaveperiod = get_config('quiz', 'autosaveperiod');
|
||||
$quiz2->introfiles = [];
|
||||
|
||||
|
@ -226,7 +226,7 @@ class mod_quiz_lib_testcase extends advanced_testcase {
|
||||
'qtype' => 'numerical',
|
||||
'quizoptions' => [
|
||||
'completionusegrade' => 1,
|
||||
'completionpass' => 1
|
||||
'completionpassgrade' => 1
|
||||
]
|
||||
]);
|
||||
|
||||
@ -273,7 +273,7 @@ class mod_quiz_lib_testcase extends advanced_testcase {
|
||||
'quizoptions' => [
|
||||
'attempts' => 2,
|
||||
'completionusegrade' => 1,
|
||||
'completionpass' => 1,
|
||||
'completionpassgrade' => 1,
|
||||
'completionattemptsexhausted' => 1
|
||||
]
|
||||
]);
|
||||
@ -383,7 +383,7 @@ class mod_quiz_lib_testcase extends advanced_testcase {
|
||||
'quizoptions' => [
|
||||
'attempts' => 2,
|
||||
'completionusegrade' => 1,
|
||||
'completionpass' => 1,
|
||||
'completionpassgrade' => 1,
|
||||
'completionminattemptsenabled' => 1,
|
||||
'completionminattempts' => 2
|
||||
]
|
||||
@ -1140,8 +1140,8 @@ class mod_quiz_lib_testcase extends advanced_testcase {
|
||||
'course' => $course->id,
|
||||
'completion' => 2,
|
||||
'completionusegrade' => 1,
|
||||
'completionpassgrade' => 1,
|
||||
'completionattemptsexhausted' => 1,
|
||||
'completionpass' => 1
|
||||
]);
|
||||
$quiz2 = $this->getDataGenerator()->create_module('quiz', [
|
||||
'course' => $course->id,
|
||||
@ -1157,7 +1157,6 @@ class mod_quiz_lib_testcase extends advanced_testcase {
|
||||
$moddefaults = new stdClass();
|
||||
$moddefaults->customdata = ['customcompletionrules' => [
|
||||
'completionattemptsexhausted' => 1,
|
||||
'completionpass' => 1
|
||||
]];
|
||||
$moddefaults->completion = 2;
|
||||
|
||||
|
@ -6,6 +6,8 @@ This files describes API changes in the quiz code.
|
||||
- process_finish() in mod/quiz/attemptlib.php
|
||||
- quiz_send_confirmation() in mod/quiz/locallib.php
|
||||
- quiz_send_notification_messages() in mod/quiz/locallib.php
|
||||
* The completionpass criteria has been moved to core as 'completionpassgrade'. Refer to completion/upgrade.txt for
|
||||
further information.
|
||||
|
||||
=== 3.11 ===
|
||||
|
||||
|
@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021052502;
|
||||
$plugin->version = 2021052503;
|
||||
$plugin->requires = 2021052500;
|
||||
$plugin->component = 'mod_quiz';
|
||||
|
@ -210,6 +210,7 @@ class custom_completion extends activity_custom_completion {
|
||||
'completionstatusallscos',
|
||||
'completionstatusrequired',
|
||||
'completionusegrade',
|
||||
'completionpassgrade',
|
||||
'completionscorerequired',
|
||||
];
|
||||
}
|
||||
|
@ -275,6 +275,9 @@ class mod_scorm_mod_form extends moodleform_mod {
|
||||
|
||||
$this->standard_coursemodule_elements();
|
||||
|
||||
// A SCORM module should define this within itself and is not needed here.
|
||||
$mform->removeElement('completionpassgrade');
|
||||
|
||||
// Buttons.
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
This files describes API changes in /mod/* - activity modules,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.0 ===
|
||||
* A new API function introduced to handle custom completion logic. Refer to completion/upgrade.txt for additional information.
|
||||
|
||||
=== 3.9 ===
|
||||
|
||||
* The callback get_shortcuts() is now deprecated. Please use get_course_content_items and get_all_content_items instead.
|
||||
|
@ -32,6 +32,7 @@ require_once($CFG->dirroot . '/course/moodleform_mod.php');
|
||||
require_once(__DIR__ . '/locallib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
use core_grades\component_gradeitems;
|
||||
/**
|
||||
* Module settings form for Workshop instances
|
||||
*/
|
||||
@ -462,6 +463,23 @@ class mod_workshop_mod_form extends moodleform_mod {
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do a custom completion validation because workshop grade items identifiers divert from standard.
|
||||
// Refer to validation defined in moodleform_mod.php.
|
||||
if (isset($data['completionpassgrade']) && $data['completionpassgrade'] &&
|
||||
isset($data['completiongradeitemnumber'])) {
|
||||
$itemnames = component_gradeitems::get_itemname_mapping_for_component('mod_workshop');
|
||||
$gradepassfield = $itemnames[(int) $data['completiongradeitemnumber']] . 'gradepass';
|
||||
if (!isset($data[$gradepassfield]) || grade_floatval($data[$gradepassfield]) == 0) {
|
||||
$errors['completionpassgrade'] = get_string(
|
||||
'activitygradetopassnotset',
|
||||
'completion'
|
||||
);
|
||||
} else {
|
||||
// We have validated grade pass. Unset any errors.
|
||||
unset($errors['completionpassgrade']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$data['submissiontypetextavailable'] && !$data['submissiontypefileavailable']) {
|
||||
// One submission type must be available.
|
||||
$errors['submissiontypes'] = get_string('nosubmissiontype', 'workshop');
|
||||
|
145
mod/workshop/tests/behat/workshop_completion_pass_grade.feature
Normal file
145
mod/workshop/tests/behat/workshop_completion_pass_grade.feature
Normal file
@ -0,0 +1,145 @@
|
||||
@mod @mod_workshop @core_completion @javascript
|
||||
Feature: Workshop submission and assessment with pass grade activity completion
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Sam1 | Student1 | student1@example.com |
|
||||
| student2 | Sam2 | Student2 | student2@example.com |
|
||||
| student3 | Sam3 | Student3 | student3@example.com |
|
||||
| student4 | Sam4 | Student4 | student3@example.com |
|
||||
| teacher1 | Terry1 | Teacher1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | enablecompletion |
|
||||
| Course1 | c1 | 1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | c1 | student |
|
||||
| student2 | c1 | student |
|
||||
| student3 | c1 | student |
|
||||
| student4 | c1 | student |
|
||||
| teacher1 | c1 | editingteacher |
|
||||
And the following "activity" exists:
|
||||
| activity | workshop |
|
||||
| name | TestWorkshop |
|
||||
| intro | Test workshop description |
|
||||
| course | c1 |
|
||||
| idnumber | workshop1 |
|
||||
| submissiontypetext | 2 |
|
||||
| submissiontypefile | 1 |
|
||||
| completion | 2 |
|
||||
| completiongradeitemnumber | 0 |
|
||||
| submissiongradepass | 40 |
|
||||
| gradinggradepass | 60 |
|
||||
| completionpassgrade | 1 |
|
||||
# teacher1 sets up assessment form and changes the phase to submission
|
||||
When I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
|
||||
And I edit assessment form in workshop "TestWorkshop" as:"
|
||||
| id_description__idx_0_editor | Aspect1 |
|
||||
| id_description__idx_1_editor | Aspect2 |
|
||||
| id_description__idx_2_editor | |
|
||||
And I change phase in workshop "TestWorkshop" to "Submission phase"
|
||||
And I log out
|
||||
# student1 submits
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as student1
|
||||
And I add a submission in workshop "TestWorkshop" as:"
|
||||
| Title | Submission1 |
|
||||
| Submission content | Some content |
|
||||
And I log out
|
||||
# student2 submits
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as student2
|
||||
And I add a submission in workshop "TestWorkshop" as:"
|
||||
| Title | Submission2 |
|
||||
| Submission content | Some content |
|
||||
And I log out
|
||||
# student3 submits
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as student3
|
||||
And I add a submission in workshop "TestWorkshop" as:"
|
||||
| Title | Submission3 |
|
||||
| Submission content | Some content |
|
||||
And I log out
|
||||
# teacher1 allocates reviewers and changes the phase to assessment
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
|
||||
And I allocate submissions in workshop "TestWorkshop" as:"
|
||||
| Participant | Reviewer |
|
||||
| Sam1 Student1 | Sam2 Student2 |
|
||||
| Sam2 Student2 | Sam1 Student1 |
|
||||
| Sam3 Student3 | Sam1 Student1 |
|
||||
| Sam2 Student2 | Sam4 Student4 |
|
||||
And I follow "TestWorkshop"
|
||||
And I change phase in workshop "TestWorkshop" to "Assessment phase"
|
||||
And I log out
|
||||
# student1 assesses work of student2 and student3
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as student1
|
||||
And I assess submission "Sam2" in workshop "TestWorkshop" as:"
|
||||
| grade__idx_0 | 5 / 10 |
|
||||
| peercomment__idx_0 | You can do better |
|
||||
| grade__idx_1 | 10 / 10 |
|
||||
| peercomment__idx_1 | Amazing |
|
||||
| Feedback for the author | Good work |
|
||||
And I am on "Course1" course homepage
|
||||
And I assess submission "Sam3" in workshop "TestWorkshop" as:"
|
||||
| grade__idx_0 | 9 / 10 |
|
||||
| peercomment__idx_0 | Well done |
|
||||
| grade__idx_1 | 8 / 10 |
|
||||
| peercomment__idx_1 | Very good |
|
||||
| Feedback for the author | No comments |
|
||||
And I log out
|
||||
# student2 assesses work of student1
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as student2
|
||||
And I assess submission "Sam1" in workshop "TestWorkshop" as:"
|
||||
| grade__idx_0 | 6 / 10 |
|
||||
| peercomment__idx_0 | |
|
||||
| grade__idx_1 | 7 / 10 |
|
||||
| peercomment__idx_1 | |
|
||||
| Feedback for the author | Keep it up |
|
||||
And I log out
|
||||
# teacher1 makes sure he can see all peer grades
|
||||
And I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
|
||||
And I click on "//table/tbody/tr[td[contains(concat(' ', normalize-space(@class), ' '), ' participant ') and contains(.,'Sam2')]]/td[contains(concat(' ', normalize-space(@class), ' '), ' receivedgrade ') and contains(.,'Sam1')]/descendant::a[@class='grade']" "xpath_element"
|
||||
# teacher1 assesses the work on submission1 and assesses the assessment of peer
|
||||
And I set the following fields to these values:
|
||||
| Override grade for assessment | 11 |
|
||||
| Feedback for the reviewer | |
|
||||
And I press "Save and close"
|
||||
And I change phase in workshop "TestWorkshop" to "Grading evaluation phase"
|
||||
And I follow "Submission1"
|
||||
And I press "Assess"
|
||||
And I set the following fields to these values:
|
||||
| grade__idx_0 | 1 / 10 |
|
||||
| peercomment__idx_0 | Extremely bad |
|
||||
| grade__idx_1 | 2 / 10 |
|
||||
| peercomment__idx_1 | Very bad |
|
||||
| Feedback for the author | Your peers overestimate you |
|
||||
And I press "Save and close"
|
||||
And I press "Re-calculate grades"
|
||||
And I change phase in workshop "TestWorkshop" to "Closed"
|
||||
And I log out
|
||||
|
||||
Scenario: Add and assess submissions in workshop with javascript enabled
|
||||
And I log in as "student1"
|
||||
And I am on "Course1" course homepage
|
||||
And the "Receive a grade" completion condition of "TestWorkshop" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "TestWorkshop" is displayed as "failed"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course1" course homepage
|
||||
And the "Receive a grade" completion condition of "TestWorkshop" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "TestWorkshop" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course1" course homepage
|
||||
And the "Receive a grade" completion condition of "TestWorkshop" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "TestWorkshop" is displayed as "done"
|
||||
And I log out
|
||||
And I log in as "student4"
|
||||
And I am on "Course1" course homepage
|
||||
And the "Receive a grade" completion condition of "TestWorkshop" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "TestWorkshop" is displayed as "todo"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course1" course homepage
|
||||
And "Sam1 Student1" user has completed "TestWorkshop" activity
|
||||
And "Sam2 Student2" user has completed "TestWorkshop" activity
|
||||
And "Sam3 Student3" user has completed "TestWorkshop" activity
|
||||
And "Sam4 Student4" user has not completed "TestWorkshop" activity
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2021100600.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2021100600.03; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.0dev+ (Build: 20211006)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user