Merge branch 'MDL-79726-main' of https://github.com/sarjona/moodle

This commit is contained in:
Jun Pataleta 2023-12-04 12:09:26 +08:00
commit e756edf18d
No known key found for this signature in database
GPG Key ID: F83510526D99E2C7
5 changed files with 239 additions and 3 deletions

View File

@ -193,6 +193,32 @@ class cm_completion_details {
return (int)$this->completiondata->completionstate;
}
/**
* Returns whether the overall completion state of this course module should be marked as complete or not.
* This is based on the completion settings of the course module, so when the course module requires a passing grade,
* it will only be marked as complete when the user has passed the course module. Otherwise, it will be marked as complete
* even when the user has failed the course module.
*
* @return bool True when the module can be marked as completed.
*/
public function is_overall_complete(): bool {
$completionstates = [];
if ($this->is_manual()) {
$completionstates = [COMPLETION_COMPLETE];
} else if ($this->is_automatic()) {
// Successfull completion states depend on the completion settings.
if (isset($this->completiondata->passgrade)) {
// Passing grade is required. Don't mark it as complete when state is COMPLETION_COMPLETE_FAIL.
$completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS];
} else {
// Any grade is required. Mark it as complete even when state is COMPLETION_COMPLETE_FAIL.
$completionstates = [COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS, COMPLETION_COMPLETE_FAIL];
}
}
return in_array($this->get_overall_completion(), $completionstates);
}
/**
* Whether this activity module has completion enabled.
*

View File

@ -223,6 +223,141 @@ class cm_completion_details_test extends advanced_testcase {
$this->assertEquals($state, $cmcompletion->get_overall_completion());
}
/**
* Data provider for test_is_overall_complete().
* @return array[]
*/
public static function is_overall_complete_provider(): array {
return [
'Automatic, require view, not viewed' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_INCOMPLETE,
'completionview' => COMPLETION_INCOMPLETE,
'completiongrade' => null,
'completionpassgrade' => null,
],
'Automatic, require view, viewed' => [
'expected' => true,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_COMPLETE,
'completionview' => COMPLETION_COMPLETE,
'completiongrade' => null,
'completionpassgrade' => null,
],
'Automatic, require grade, not graded' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_INCOMPLETE,
'completionview' => null,
'completiongrade' => COMPLETION_INCOMPLETE,
'completionpassgrade' => null,
],
'Automatic, require grade, graded with fail' => [
'expected' => true,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_COMPLETE_FAIL,
'completionview' => null,
'completiongrade' => COMPLETION_COMPLETE_FAIL,
'completionpassgrade' => null,
],
'Automatic, require grade, graded with passing' => [
'expected' => true,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_COMPLETE_PASS,
'completionview' => null,
'completiongrade' => COMPLETION_COMPLETE_PASS,
'completionpassgrade' => null,
],
'Automatic, require passgrade, not graded' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_INCOMPLETE,
'completionview' => null,
'completiongrade' => null,
'completionpassgrade' => COMPLETION_INCOMPLETE,
],
'Automatic, require passgrade, graded with fail' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_COMPLETE_FAIL,
'completionview' => null,
'completiongrade' => null,
'completionpassgrade' => COMPLETION_COMPLETE_FAIL,
],
'Automatic, require passgrade, graded with passing' => [
'expected' => true,
'completion' => COMPLETION_TRACKING_AUTOMATIC,
'completionstate' => COMPLETION_COMPLETE_PASS,
'completionview' => null,
'completiongrade' => null,
'completionpassgrade' => COMPLETION_COMPLETE_PASS,
],
'Manual, incomplete' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_MANUAL,
'completionstate' => COMPLETION_INCOMPLETE,
],
'Manual, complete' => [
'expected' => true,
'completion' => COMPLETION_TRACKING_MANUAL,
'completionstate' => COMPLETION_COMPLETE,
],
'None, incomplete' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_NONE,
'completionstate' => COMPLETION_INCOMPLETE,
],
'None, complete' => [
'expected' => false,
'completion' => COMPLETION_TRACKING_NONE,
'completionstate' => COMPLETION_COMPLETE,
],
];
}
/**
* Test for is_overall_complete().
*
* @covers ::is_overall_complete
* @dataProvider is_overall_complete_provider
* @param bool $expected Expected result returned by is_overall_complete().
* @param int $completion The completion tracking mode.
* @param int $completionstate The overall completion state.
* @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.
*/
public function test_is_overall_complete(
bool $expected,
int $completion,
int $completionstate,
?int $completionview = null,
?int $completiongrade = null,
?int $completionpassgrade = null,
): void {
$options = [];
$getdatareturn = (object)[
'completionstate' => $completionstate,
'viewed' => $completionview,
'completiongrade' => $completiongrade,
'passgrade' => $completionpassgrade,
];
if (!is_null($completionview)) {
$options['completionview'] = true;
}
if (!is_null($completiongrade)) {
$options['completionusegrade'] = true;
}
if (!is_null($completionpassgrade)) {
$options['completionpassgrade'] = true;
}
$cmcompletion = $this->setup_data($completion, $options, $getdatareturn);
$this->assertEquals($expected, $cmcompletion->is_overall_complete());
}
/**
* Data provider for test_get_details().
* @return array[]

View File

@ -1,6 +1,10 @@
This file describes API changes in /completion/* - completion,
information provided here is intended especially for developers.
=== 4.4 ===
* A new method, cm_completion_details::is_overall_complete() has been added to calculate whether a module should be considered or
not completed, based on their completion options and the current value for the overall complete state.
=== 4.3 ===
* A trait class, core_completion/form/form_trait has been added to reuse code for adding and validation completion settings to any
form.

View File

@ -57,6 +57,7 @@ class activity_completion implements renderable, templatable {
global $CFG;
$overallcompletion = $this->cmcompletion->get_overall_completion();
$isoverallcomplete = $this->cmcompletion->is_overall_complete();
$overrideby = $this->get_overrideby();
$course = $this->cminfo->get_course();
@ -77,8 +78,8 @@ class activity_completion implements renderable, templatable {
'ismanual' => $this->cmcompletion->is_manual(),
'showmanualcompletion' => $this->cmcompletion->show_manual_completion(),
'istrackeduser' => $this->cmcompletion->is_tracked_user(),
'overallcomplete' => $overallcompletion == COMPLETION_COMPLETE,
'overallincomplete' => $overallcompletion == COMPLETION_INCOMPLETE,
'overallcomplete' => $isoverallcomplete,
'overallincomplete' => !$isoverallcomplete,
'withavailability' => $withavailability ?? false,
'overrideby' => $overrideby,
'completiondetails' => $this->get_completion_details($overrideby),

View File

@ -56,7 +56,7 @@ Feature: Course page activities completion
And I am on the "Course 1" course page
And "Completion" "button" should exist in the "Activity sample" "activity"
Scenario: Student should see the automatic completion criterias statuses of activities
Scenario: Student should see the automatic completion criterias statuses of activities with completion view
Given the following "activity" exists:
| activity | assign |
| name | Activity sample |
@ -71,6 +71,76 @@ Feature: Course page activities completion
And "To do" "button" should not exist in the "Activity sample" "activity"
And the "View" item should exist in the "Done" dropdown of the "Activity sample" "activity"
Scenario: Student should see the automatic completion criterias statuses of activities with completion grade
Given the following "activities" exist:
| activity | name | course | idnumber | gradepass | completion | completionusegrade |
| quiz | Activity sample 1 | C1 | quiz1 | 5.00 | 2 | 1 |
| quiz | Activity sample 2 | C1 | quiz2 | 5.00 | 2 | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Activity sample 1" contains the following questions:
| question | page |
| First question | 1 |
And quiz "Activity sample 2" contains the following questions:
| question | page |
| First question | 1 |
When I am on the "C1" "Course" page logged in as "student1"
Then the "Receive a grade" item should exist in the "To do" dropdown of the "Activity sample 1" "activity"
And the "Receive a grade" item should exist in the "To do" dropdown of the "Activity sample 2" "activity"
# Pass grade.
And user "student1" has attempted "Activity sample 1" with responses:
| slot | response |
| 1 | True |
# Fail grade.
And user "student1" has attempted "Activity sample 2" with responses:
| slot | response |
| 1 | False |
# After receiving a grade, the completion criteria dropdown should display "Done" instead of "To do", regardless of pass/fail.
And I am on the "Course 1" course page
And "To do" "button" should not exist in the "Activity sample 1" "activity"
And the "Receive a grade" item should exist in the "Done" dropdown of the "Activity sample 1" "activity"
And "To do" "button" should not exist in the "Activity sample 2" "activity"
And the "Receive a grade" item should exist in the "Done" dropdown of the "Activity sample 2" "activity"
Scenario: Student should see the automatic completion criterias statuses of activities with completion passgrade
Given the following "activities" exist:
| activity | name | course | idnumber | gradepass | completion | completionusegrade | completionpassgrade |
| quiz | Activity sample 1 | C1 | quiz1 | 5.00 | 2 | 1 | 1 |
| quiz | Activity sample 2 | C1 | quiz2 | 5.00 | 2 | 1 | 1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
And quiz "Activity sample 1" contains the following questions:
| question | page |
| First question | 1 |
And quiz "Activity sample 2" contains the following questions:
| question | page |
| First question | 1 |
When I am on the "C1" "Course" page logged in as "student1"
Then the "Receive a grade" item should exist in the "To do" dropdown of the "Activity sample 1" "activity"
And the "Receive a grade" item should exist in the "To do" dropdown of the "Activity sample 2" "activity"
# Pass grade.
And user "student1" has attempted "Activity sample 1" with responses:
| slot | response |
| 1 | True |
# Fail grade.
And user "student1" has attempted "Activity sample 2" with responses:
| slot | response |
| 1 | False |
# After receiving a grade, the completion criteria dropdown should display "Done" only for the passing grade.
And I am on the "Course 1" course page
And "To do" "button" should not exist in the "Activity sample 1" "activity"
And the "Receive a grade" item should exist in the "Done" dropdown of the "Activity sample 1" "activity"
But "To do" "button" should exist in the "Activity sample 2" "activity"
And the "Receive a grade" item should exist in the "To do" dropdown of the "Activity sample 2" "activity"
Scenario: Teacher can edit activity completion using completion dialog link
Given the following "activity" exists:
| activity | assign |