MDL-83896 mod_lesson: Add course overview integration

- Implement course overview integration
- Redirect index.php to course overview
This commit is contained in:
Mikel Martín
2025-07-03 15:05:21 +02:00
parent 15f8c92d9e
commit ce3eb175af
7 changed files with 646 additions and 96 deletions
@@ -121,7 +121,7 @@ final class overviewfactory_test extends \advanced_testcase {
],
'lesson' => [
'resourcetype' => 'lesson',
'expected' => resourceoverview::class,
'expected' => \mod_lesson\courseformat\overview::class,
],
'lti' => [
'resourcetype' => 'lti',
@@ -75,7 +75,7 @@ final class missingoverviewnotice_test extends \advanced_testcase {
'h5pactivity' => ['modname' => 'h5pactivity', 'expectempty' => true],
'imscp' => ['modname' => 'imscp', 'expectempty' => false],
'label' => ['modname' => 'label', 'expectempty' => false],
'lesson' => ['modname' => 'lesson', 'expectempty' => false],
'lesson' => ['modname' => 'lesson', 'expectempty' => true],
'lti' => ['modname' => 'lti', 'expectempty' => false],
'page' => ['modname' => 'page', 'expectempty' => false],
'qbank' => ['modname' => 'qbank', 'expectempty' => false],
@@ -0,0 +1,166 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_lesson\courseformat;
use core\output\action_link;
use core\output\local\properties\button;
use core\output\local\properties\text_align;
use core\url;
use core_courseformat\output\local\overview\overviewdialog;
use lesson;
use core_calendar\output\humandate;
use core_courseformat\local\overview\overviewitem;
use cm_info;
/**
* Class overview
*
* @package mod_lesson
* @copyright 2025 Mikel Martín <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class overview extends \core_courseformat\activityoverviewbase {
/** @var array $deadlines user's deadline for all lessons in the course. */
private array $deadlines;
/** @var lesson $lesson the lesson instance. */
private lesson $lesson;
/**
* Constructor.
*
* @param cm_info $cm the course module instance.
* @param \core\output\renderer_helper $rendererhelper the renderer helper.
* @param \core_string_manager $stringmanager the string manager.
*/
public function __construct(
cm_info $cm,
/** @var \core\output\renderer_helper $rendererhelper the renderer helper */
protected readonly \core\output\renderer_helper $rendererhelper,
/** @var \core_string_manager $sm the string manager */
protected readonly \core_string_manager $stringmanager,
) {
global $CFG;
require_once($CFG->dirroot . '/mod/lesson/locallib.php');
parent::__construct($cm);
$this->lesson = new lesson($this->cm->get_instance_record());
$this->deadlines = lesson_get_user_deadline($this->cm->get_course()->id);
}
#[\Override]
public function get_due_date_overview(): ?overviewitem {
$duedate = null;
if (isset($this->deadlines[$this->lesson->id])) {
$duedate = $this->deadlines[$this->lesson->id]->userdeadline;
}
return new overviewitem(
name: $this->stringmanager->get_string('duedate', 'mod_lesson'),
value: $duedate,
content: $duedate ? humandate::create_from_timestamp($duedate) : '-',
);
}
#[\Override]
public function get_actions_overview(): ?overviewitem {
if (!has_capability('mod/lesson:manage', $this->context)) {
return null;
}
$content = new action_link(
url: new url('/mod/lesson/report.php', ['id' => $this->cm->id, 'action' => 'reportoverview']),
text: $this->stringmanager->get_string('view', 'mod_lesson'),
attributes: ['class' => button::SECONDARY_OUTLINE->classes()],
);
return new overviewitem(
name: $this->stringmanager->get_string('actions'),
value: '',
content: $content,
);
}
#[\Override]
public function get_extra_overview_items(): array {
return [
'attemptedstudents' => $this->get_extra_attemptedstudents_overview(),
'totalattempts' => $this->get_extra_totalattempts_overview(),
];
}
/**
* Get the extra overview for attempted students.
*
* @return overviewitem|null The overview item (or null if the user cannot manage lesson activity).
*/
protected function get_extra_attemptedstudents_overview(): ?overviewitem {
if (!has_capability('mod/lesson:manage', $this->context)) {
return null;
}
$attemptedusers = $this->lesson->count_submitted_participants();
$totalusers = $this->lesson->count_all_participants();
return new overviewitem(
name: $this->stringmanager->get_string('studentswhoattempted', 'mod_lesson'),
value: $attemptedusers,
content: $this->stringmanager->get_string(
'count_of_total',
'core',
['count' => $attemptedusers, 'total' => $totalusers]
),
);
}
/**
* Get the extra overview for attempted students.
*
* @return overviewitem|null The overview item (or null if the user cannot manage lesson activity).
*/
protected function get_extra_totalattempts_overview(): ?overviewitem {
if (!has_capability('mod/lesson:manage', $this->context)) {
return null;
}
$totalattempts = $this->lesson->count_all_submissions();
if ($this->lesson->retake) {
$attemptedusers = $this->lesson->count_submitted_participants();
$overviewdialog = new overviewdialog(
buttoncontent: $totalattempts,
description: $this->stringmanager->get_string('retakesallowedinfo', 'mod_lesson'),
definition: ['buttonclasses' => button::SECONDARY_OUTLINE->classes() . ' dropdown-toggle'],
);
$averageattempts = $totalattempts ? round($totalattempts / $attemptedusers) : 0;
$overviewdialog->add_item(
$this->stringmanager->get_string('averageattempts', 'mod_lesson'),
$averageattempts
);
}
// If the lesson does not allow retakes, do not show the dialog, only the total attepmts number.
// And also, set the value to null, that will hide the whole column if every lesson does not allow retakes.
return new overviewitem(
name: $this->stringmanager->get_string('totalattepmts', 'mod_lesson'),
value: !empty($overviewdialog) ? $totalattempts : null,
content: $overviewdialog ?? $totalattempts,
textalign: text_align::CENTER,
);
}
}
+2 -94
View File
@@ -23,100 +23,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
**/
/** Include required files */
require_once("../../config.php");
require_once($CFG->dirroot.'/mod/lesson/locallib.php');
$id = required_param('id', PARAM_INT); // course
$courseid = required_param('id', PARAM_INT);
$PAGE->set_url('/mod/lesson/index.php', array('id'=>$id));
if (!$course = $DB->get_record("course", array("id" => $id))) {
throw new \moodle_exception('invalidcourseid');
}
require_login($course);
$PAGE->set_pagelayout('incourse');
// Trigger instances list viewed event.
$params = array(
'context' => context_course::instance($course->id)
);
$event = \mod_lesson\event\course_module_instance_list_viewed::create($params);
$event->add_record_snapshot('course', $course);
$event->trigger();
/// Get all required strings
$strlessons = get_string("modulenameplural", "lesson");
$strlesson = get_string("modulename", "lesson");
/// Print the header
$PAGE->navbar->add($strlessons);
$PAGE->set_title("$course->shortname: $strlessons");
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading($strlessons, 2);
/// Get all the appropriate data
if (! $lessons = get_all_instances_in_course("lesson", $course)) {
notice(get_string('thereareno', 'moodle', $strlessons), "../../course/view.php?id=$course->id");
die;
}
$usesections = course_format_uses_sections($course->format);
/// Print the list of instances (your module will probably extend this)
$timenow = time();
$strname = get_string("name");
$strgrade = get_string("gradenoun");
$strdeadline = get_string("deadline", "lesson");
$strnodeadline = get_string("nodeadline", "lesson");
$table = new html_table();
if ($usesections) {
$strsectionname = course_get_format($course)->get_generic_section_name();
$table->head = array ($strsectionname, $strname, $strgrade, $strdeadline);
$table->align = array ("center", "left", "center", "center");
} else {
$table->head = array ($strname, $strgrade, $strdeadline);
$table->align = array ("left", "center", "center");
}
// Get all deadlines.
$deadlines = lesson_get_user_deadline($course->id);
foreach ($lessons as $lesson) {
$cm = get_coursemodule_from_instance('lesson', $lesson->id);
$context = context_module::instance($cm->id);
$class = $lesson->visible ? null : array('class' => 'dimmed'); // Hidden modules are dimmed.
$link = html_writer::link(new moodle_url('view.php', array('id' => $cm->id)), format_string($lesson->name, true), $class);
$deadline = $deadlines[$lesson->id]->userdeadline;
if ($deadline == 0) {
$due = $strnodeadline;
} else if ($deadline > $timenow) {
$due = userdate($deadline);
} else {
$due = html_writer::tag('span', userdate($deadline), array('class' => 'text-danger'));
}
if ($usesections) {
if (has_capability('mod/lesson:manage', $context)) {
$grade_value = $lesson->grade;
} else {
// it's a student, show their grade
$grade_value = 0;
if ($return = lesson_get_user_grades($lesson, $USER->id)) {
$grade_value = $return[$USER->id]->rawgrade;
}
}
$table->data[] = array (get_section_name($course, $lesson->section), $link, $grade_value, $due);
} else {
$table->data[] = array ($link, $lesson->grade, $due);
}
}
echo html_writer::table($table);
echo $OUTPUT->footer();
\core_courseformat\activityoverviewbase::redirect_to_overview_page($courseid, 'lesson');
+7
View File
@@ -61,6 +61,7 @@ $string['addtruefalse'] = 'Create a True/false question page';
$string['allotheranswers'] = 'All other answers';
$string['allotheranswersjump'] = 'All other answers jump';
$string['allotheranswersscore'] = 'All other answers score';
$string['allowedattempts'] = 'Allowed attempts per student';
$string['allowofflineattempts'] = 'Allow lesson to be attempted offline using the mobile app';
$string['allowofflineattempts_help'] = 'If enabled, a mobile app user can download the lesson and attempt it offline.
All the possible answers and correct responses will be downloaded as well.
@@ -79,6 +80,7 @@ $string['attempts'] = 'Attempts';
$string['attemptsdeleted'] = 'Deleted attempts';
$string['attemptsremaining'] = 'You have {$a} attempt(s) remaining';
$string['available'] = 'Available from';
$string['averageattempts'] = 'Average attempts per student';
$string['averagescore'] = 'Average score';
$string['averagetime'] = 'Average time';
$string['branch'] = 'Content';
@@ -175,6 +177,7 @@ $string['displayscorewithessays'] = '<p>You earned {$a->score} out of {$a->tempm
<p>Your {$a->essayquestions} essay question(s) will be graded and added into your final score at a later date.</p>
<p>Your current grade without the essay question(s) is {$a->score} out of {$a->grade}.</p>';
$string['displayscorewithoutessays'] = 'Your score is {$a->score} (out of {$a->grade}).';
$string['duedate'] = 'Due date';
$string['duplicatepagenamed'] = 'Duplicate page: {$a}';
$string['edit'] = 'Edit';
$string['editbranchtable'] = 'Editing a content page';
@@ -522,6 +525,7 @@ $string['reports'] = 'Reports';
$string['response'] = 'Response';
$string['retakesallowed'] = 'Allow multiple attempts';
$string['retakesallowed_help'] = 'Allow students to attempt the lesson more than once.';
$string['retakesallowedinfo'] = 'This Lesson allows students to do multiple attempts.';
$string['returnto'] = 'Return to {$a}';
$string['returntocourse'] = 'Return to the course';
$string['reverttodefaults'] = 'Revert to lesson defaults';
@@ -560,6 +564,7 @@ $string['studentname'] = '{$a} Name';
$string['studentoneminwarning'] = 'Warning: You have 1 minute or less to finish the lesson.';
$string['studentoutoftimeforreview'] = 'Attention: You ran out of time for reviewing this lesson';
$string['studentresponse'] = '{$a}\'s response';
$string['studentswhoattempted'] = 'Students who attempted';
$string['submit'] = 'Submit';
$string['submitname'] = 'Submit name';
$string['teacherjumpwarning'] = 'A {$a->cluster} jump or an {$a->unseen} jump is being used in this lesson. The next page jump will be used instead. Log in as a student to test these jumps.';
@@ -577,6 +582,7 @@ $string['timeremaining'] = 'Time remaining';
$string['timespenterror'] = 'Spend at least {$a} minutes in the lesson';
$string['timespentminutes'] = 'Time spent (minutes)';
$string['timetaken'] = 'Time taken';
$string['totalattepmts'] = 'Total attempts';
$string['totalpagesviewedheader'] = 'Number of pages viewed';
$string['true'] = 'True';
$string['truefalse'] = 'True/false';
@@ -593,6 +599,7 @@ $string['usepassword'] = 'Password protected lesson';
$string['usepassword_help'] = 'If enabled, a password is required in order to access the lesson.';
$string['useroverrides'] = 'User overrides';
$string['usersnone'] = 'No students have access to this lesson';
$string['view'] = 'View';
$string['viewessayanswers'] = 'View essay answers';
$string['viewgrades'] = 'View grades';
$string['viewreports'] = 'View {$a->attempts} completed {$a->student} attempts';
@@ -0,0 +1,103 @@
@mod @mod_lesson
Feature: Testing overview_report in mod_lesson
In order to list all lessons in a course
As a user
I need to be able to see the lesson overview
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Username | 1 |
| student2 | Username | 2 |
| student3 | Username | 3 |
| teacher1 | Teacher | T |
And the following "courses" exist:
| fullname | shortname | groupmode |
| Course 1 | C1 | 1 |
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 | retake | deadline |
| lesson | Lesson 1 | C1 | lesson1 | 1 | ##tomorrow## |
| lesson | Lesson 2 | C1 | lesson2 | 0 | 0 |
And the following "mod_lesson > pages" exist:
| lesson | qtype | title | content |
| lesson1 | truefalse | Question 1 | The number 10 is greater than 5 |
And the following "mod_lesson > answers" exist:
| page | answer | jumpto | score |
| Question 1 | True | End of lesson | 1 |
| Question 1 | False | End of lesson | 0 |
And the following "mod_lesson > submissions" exist:
| lesson | user | grade |
| Lesson 1 | student1 | 50 |
| Lesson 1 | student1 | 60 |
| Lesson 1 | student1 | 100 |
| Lesson 1 | student2 | 90 |
@javascript
Scenario: Teacher can see the lesson relevant information in the lesson overview
When I am on the "Course 1" "course > activities > lesson" page logged in as "teacher1"
Then the following should exist in the "Table listing all Lesson activities" table:
| Name | Students who attempted | Total attempts | Due date |
| Lesson 1 | 2 of 3 | 4 | Tomorrow |
| Lesson 2 | 0 of 3 | 0 | - |
And I click on "4" "button" in the "Lesson 1" "table_row"
And I should see "This Lesson allows students to do multiple attempts."
And I should see "Average attempts per student: 2"
And I press the escape key
And "0" "button" should not exist in the "Lesson 2" "table_row"
And I click on "View" "link" in the "Lesson 1" "table_row"
And I should see "Reports" in the "page-header" "region"
Scenario: Teacher can see the lesson overview with all lessons with retakes disabled
Given the following "courses" exist:
| fullname | shortname |
| Course 2 | C2 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C2 | student |
| teacher1 | C2 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber | retake |
| lesson | Lesson 1 | C2 | lesson1 | 0 |
| lesson | Lesson 2 | C2 | lesson2 | 0 |
When I am on the "Course 2" "course > activities > lesson" page logged in as "teacher1"
Then I should not see "Total attempts" in the "lesson_overview_collapsible" "region"
And the following should exist in the "Table listing all Lesson activities" table:
| Name | Students who attempted | Due date |
| Lesson 1 | 0 of 1 | - |
| Lesson 2 | 0 of 1 | - |
Scenario: Students can see the lesson relevant information in the lesson overview
When I am on the "Course 1" "course > activities > lesson" page logged in as "student1"
Then I should not see "Actions" in the "lesson_overview_collapsible" "region"
And I should not see "Students who attempted" in the "lesson_overview_collapsible" "region"
And I should not see "Total attempts" in the "lesson_overview_collapsible" "region"
And the following should exist in the "Table listing all Lesson activities" table:
| Name | Due date |
| Lesson 1 | Tomorrow |
| Lesson 2 | - |
Scenario: The lesson index redirect to the activities overview
When I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add the "Activities" block
And I click on "Lessons" "link" in the "Activities" "block"
Then I should see "An overview of all activities in the course, with dates and other information."
And I should see "Name" in the "lesson_overview_collapsible" "region"
And I should see "Students who attempted" in the "lesson_overview_collapsible" "region"
And I should see "Total attempts" in the "lesson_overview_collapsible" "region"
And I should see "Actions" in the "lesson_overview_collapsible" "region"
Scenario: The lesson overview report should generate log events
Given I am on the "Course 1" "course > activities > lesson" page logged in as "teacher1"
When I am on the "Course 1" "course" page logged in as "teacher1"
And I navigate to "Reports" in current page administration
And I click on "Logs" "link"
And I click on "Get these logs" "button"
Then I should see "Course activities overview page viewed"
And I should see "viewed the instance list for the module 'lesson'"
@@ -0,0 +1,366 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_lesson\courseformat;
use core_courseformat\local\overview\overviewfactory;
use lesson;
/**
* Tests for Lesson overview.
*
* @package mod_lesson
* @category test
* @copyright 2025 Mikel Martín <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class overview_test extends \advanced_testcase {
/**
* Helper function to create lesson pages with multichoice questions.
*
* @param lesson $lesson The lesson object.
* @param int $count The number of multichoice questions to create.
*/
private function create_lesson_pages(lesson $lesson, int $count): void {
/** @var \mod_lesson_generator $lessongenerator */
$lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
for ($i = 0; $i < $count; $i++) {
$lessongenerator->create_page([
'title' => 'Multichoice question' . ($i + 1),
'content' => 'Question content',
'qtype' => 'multichoice',
'lessonid' => $lesson->id,
]);
$lessongenerator->create_answer(['page' => 'Multichoice question' . ($i + 1), 'answer' => 'A', 'score' => 1]);
$lessongenerator->create_answer(['page' => 'Multichoice question' . ($i + 1), 'answer' => 'B']);
}
$lessongenerator->finish_generate_answer();
}
/**
* Test get_due_date_overview.
*
* @covers ::get_due_date_overview
* @dataProvider provider_test_get_due_date_overview
*
* @param int|null $timeincrement the time increment in seconds to add to the current time for the deadline.
* @return void
*/
public function test_get_due_date_overview(?int $timeincrement): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$deadline = $timeincrement ? $this->mock_clock_with_frozen()->time() + $timeincrement : 0;
$lesson = $this->getDataGenerator()->create_module(
'lesson',
[
'course' => $course->id,
'deadline' => $deadline,
],
);
$this->setUser($student);
$cm = get_fast_modinfo($course)->get_cm($lesson->cmid);
$item = overviewfactory::create($cm)->get_due_date_overview();
$this->assertEquals(get_string('duedate', 'lesson'), $item->get_name());
$this->assertEquals($deadline, $item->get_value());
}
/**
* Provider for test_get_due_date_overview.
*
* @return array
*/
public static function provider_test_get_due_date_overview(): array {
return [
'no_due' => [
'timeincrement' => null,
],
'past_due' => [
'timeincrement' => -1 * (4 * DAYSECS),
],
'future_due' => [
'timeincrement' => (4 * DAYSECS),
],
];
}
/**
* Test get_actions_overview.
*
* @covers ::get_actions_overview
* @dataProvider provider_test_get_actions_overview
*
* @param string $role
* @param array|null $expected
* @return void
*/
public function test_get_actions_overview(
string $role,
?array $expected
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$currentuser = $this->getDataGenerator()->create_and_enrol($course, $role);
$lesson = $this->getDataGenerator()->create_module( 'lesson', ['course' => $course->id]);
$this->setUser($currentuser);
$cm = get_fast_modinfo($course)->get_cm($lesson->cmid);
$item = overviewfactory::create($cm)->get_actions_overview();
if ($expected === null) {
$this->assertNull($item);
return;
}
$this->assertEquals(
$expected,
['name' => $item->get_name(), 'value' => $item->get_value()]
);
}
/**
* Data provider for test_get_actions_overview.
*
* @return array
*/
public static function provider_test_get_actions_overview(): array {
return [
'Student' => [
'role' => 'student',
'expected' => null,
],
'Teacher' => [
'role' => 'editingteacher',
'expected' => [
'name' => get_string('actions'),
'value' => '',
],
],
];
}
/**
* Test get_extra_totalattempts_overview.
*
* @covers ::get_extra_totalattempts_overview
* @dataProvider provider_test_get_extra_totalattempts_overview
*
* @param string $role
* @param bool $hasentries
* @param bool $hasretakes
* @param array|null $expected
* @return void
*/
public function test_get_extra_totalattempts_overview(
string $role,
bool $hasentries,
bool $hasretakes,
?array $expected
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$currentuser = $this->getDataGenerator()->create_and_enrol($course, $role);
$lessonmodule = $this->getDataGenerator()->create_module(
'lesson',
['course' => $course, 'retake' => $hasretakes]
);
$cm = get_fast_modinfo($course)->get_cm($lessonmodule->cmid);
$lesson = new lesson($lessonmodule);
/** @var \mod_lesson_generator $lessongenerator */
$lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
$this->create_lesson_pages($lesson, 2);
if ($hasentries) {
$lessongenerator->create_submission([
'lessonid' => $lesson->id,
'userid' => $student1->id,
'grade' => 100,
]);
$lessongenerator->create_submission([
'lessonid' => $lesson->id,
'userid' => $currentuser->id,
'grade' => 100,
]);
}
$this->setUser($currentuser);
$overview = overviewfactory::create($cm);
$reflection = new \ReflectionClass($overview);
$method = $reflection->getMethod('get_extra_totalattempts_overview');
$method->setAccessible(true);
$item = $method->invoke($overview);
if ($expected === null) {
$this->assertNull($item);
return;
}
$this->assertEquals(
$expected,
['name' => $item->get_name(), 'value' => $item->get_value()]
);
}
/**
* Data provider for test_get_extra_totalattempts_overview.
*
* @return array
*/
public static function provider_test_get_extra_totalattempts_overview(): array {
return [
'Teacher (with attempts)' => [
'role' => 'editingteacher',
'hasentries' => true,
'hasretakes' => true,
'expected' => [
'name' => get_string('totalattepmts', 'mod_lesson'),
'value' => 2,
],
],
'Teacher (with attempts without retakes)' => [
'role' => 'editingteacher',
'hasentries' => true,
'hasretakes' => false,
'expected' => [
'name' => get_string('totalattepmts', 'mod_lesson'),
'value' => null,
],
],
'Teacher (without attempts)' => [
'role' => 'editingteacher',
'hasentries' => false,
'hasretakes' => true,
'expected' => [
'name' => get_string('totalattepmts', 'mod_lesson'),
'value' => 0,
],
],
'Student' => [
'role' => 'student',
'hasentries' => true,
'hasretakes' => true,
'expected' => null,
],
];
}
/**
* Test get_extra_attemptedstudents_overview.
*
* @covers ::get_extra_attemptedstudents_overview
* @dataProvider provider_test_get_extra_attemptedstudents_overview
*
* @param string $role
* @param bool $hasentries
* @param array|null $expected
* @return void
*/
public function test_get_extra_attemptedstudents_overview(
string $role,
bool $hasentries,
?array $expected
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$currentuser = $this->getDataGenerator()->create_and_enrol($course, $role);
$lessonmodule = $this->getDataGenerator()->create_module('lesson', ['course' => $course]);
$cm = get_fast_modinfo($course)->get_cm($lessonmodule->cmid);
$lesson = new lesson($lessonmodule);
/** @var \mod_lesson_generator $lessongenerator */
$lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
$this->create_lesson_pages($lesson, 2);
if ($hasentries) {
$lessongenerator->create_submission([
'lessonid' => $lesson->id,
'userid' => $student1->id,
'grade' => 100,
]);
$lessongenerator->create_submission([
'lessonid' => $lesson->id,
'userid' => $currentuser->id,
'grade' => 100,
]);
}
$this->setUser($currentuser);
$overview = overviewfactory::create($cm);
$reflection = new \ReflectionClass($overview);
$method = $reflection->getMethod('get_extra_attemptedstudents_overview');
$method->setAccessible(true);
$item = $method->invoke($overview);
if ($expected === null) {
$this->assertNull($item);
return;
}
$this->assertEquals(
$expected,
['name' => $item->get_name(), 'value' => (int)$item->get_value()]
);
}
/**
* Data provider for test_get_extra_attemptedstudents_overview.
*
* @return array
*/
public static function provider_test_get_extra_attemptedstudents_overview(): array {
return [
'Teacher (with attempts)' => [
'role' => 'editingteacher',
'hasentries' => true,
'expected' => [
'name' => get_string('studentswhoattempted', 'mod_lesson'),
'value' => 2,
],
],
'Teacher (without attempts)' => [
'role' => 'editingteacher',
'hasentries' => false,
'expected' => [
'name' => get_string('studentswhoattempted', 'mod_lesson'),
'value' => 0,
],
],
'Student' => [
'role' => 'student',
'hasentries' => true,
'expected' => null,
],
];
}
}