From 68b5f7b24ab0ab3c49a9b597bd1199269dc68cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikel=20Mart=C3=ADn?= Date: Mon, 19 May 2025 10:00:06 +0200 Subject: [PATCH] MDL-83894 mod_glossary: Add course overview integration - Implement course overview integration - Redirect index.php to course overview --- .../local/overview/overviewfactory_test.php | 2 +- .../overview/missingoverviewnotice_test.php | 2 +- .../classes/courseformat/overview.php | 145 +++++++ mod/glossary/index.php | 159 ++------ mod/glossary/lang/en/glossary.php | 3 + .../tests/behat/overview_report.feature | 69 ++++ .../tests/courseformat/overview_test.php | 381 ++++++++++++++++++ 7 files changed, 624 insertions(+), 137 deletions(-) create mode 100644 mod/glossary/classes/courseformat/overview.php create mode 100644 mod/glossary/tests/behat/overview_report.feature create mode 100644 mod/glossary/tests/courseformat/overview_test.php diff --git a/course/format/tests/local/overview/overviewfactory_test.php b/course/format/tests/local/overview/overviewfactory_test.php index 6083cf4df07..5982887f03c 100644 --- a/course/format/tests/local/overview/overviewfactory_test.php +++ b/course/format/tests/local/overview/overviewfactory_test.php @@ -113,7 +113,7 @@ final class overviewfactory_test extends \advanced_testcase { ], 'glossary' => [ 'resourcetype' => 'glossary', - 'expected' => resourceoverview::class, + 'expected' => \mod_glossary\courseformat\overview::class, ], 'h5pactivity' => [ 'resourcetype' => 'h5pactivity', diff --git a/course/format/tests/output/local/overview/missingoverviewnotice_test.php b/course/format/tests/output/local/overview/missingoverviewnotice_test.php index ff7ca3bc028..2b1022550ee 100644 --- a/course/format/tests/output/local/overview/missingoverviewnotice_test.php +++ b/course/format/tests/output/local/overview/missingoverviewnotice_test.php @@ -71,7 +71,7 @@ final class missingoverviewnotice_test extends \advanced_testcase { 'feedback' => ['modname' => 'feedback', 'expectempty' => true], 'folder' => ['modname' => 'folder', 'expectempty' => false], 'forum' => ['modname' => 'forum', 'expectempty' => false], - 'glossary' => ['modname' => 'glossary', 'expectempty' => false], + 'glossary' => ['modname' => 'glossary', 'expectempty' => true], 'h5pactivity' => ['modname' => 'h5pactivity', 'expectempty' => false], 'imscp' => ['modname' => 'imscp', 'expectempty' => false], 'label' => ['modname' => 'label', 'expectempty' => false], diff --git a/mod/glossary/classes/courseformat/overview.php b/mod/glossary/classes/courseformat/overview.php new file mode 100644 index 00000000000..74415eb334b --- /dev/null +++ b/mod/glossary/classes/courseformat/overview.php @@ -0,0 +1,145 @@ +. + +namespace mod_glossary\courseformat; + +use core_courseformat\local\overview\overviewitem; +use core\output\action_link; +use core\output\local\properties\button; +use core\output\local\properties\text_align; +use core\url; +use cm_info; +use mod_glossary_entry_query_builder; + +/** + * Glossary overview integration class. + * + * @package mod_glossary + * @copyright 2025 Mikel Martín + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class overview extends \core_courseformat\activityoverviewbase { + /** + * Constructor. + * + * @param cm_info $cm the course module instance. + * @param \core\output\renderer_helper $rendererhelper the renderer helper. + */ + 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 $stringmanager the string manager */ + protected readonly \core_string_manager $stringmanager, + ) { + parent::__construct($cm); + } + + #[\Override] + public function get_extra_overview_items(): array { + return [ + 'totalentries' => $this->get_extra_totalentries_overview(), + 'myentries' => $this->get_extra_myentries_overview(), + ]; + } + + #[\Override] + public function get_actions_overview(): ?overviewitem { + if (!has_capability('mod/glossary:approve', $this->context)) { + return null; + } + + $qb = new mod_glossary_entry_query_builder($this->cm->get_instance_record()); + $qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_ONLY); + $entriescount = $qb->count_records(); + + $renderer = $this->rendererhelper->get_core_renderer(); + $badge = $renderer->notice_badge( + contents: $entriescount, + title: $this->stringmanager->get_string('numberofentriesneedapprove', 'mod_glossary'), + ); + + $content = new action_link( + url: new url('/mod/glossary/view.php', ['id' => $this->cm->id, 'mode' => 'approval']), + text: $this->stringmanager->get_string('approve', 'mod_glossary') . $badge, + attributes: ['class' => button::SECONDARY_OUTLINE->classes()], + ); + + return new overviewitem( + name: $this->stringmanager->get_string('actions'), + value: $entriescount, + content: $entriescount ? $content : '-', + textalign: text_align::CENTER, + ); + } + + /** + * Get the "Total entries" overview item. + * + * @return overviewitem The overview item. + */ + private function get_extra_totalentries_overview(): overviewitem { + $columnheader = $this->stringmanager->get_string('entries', 'mod_glossary'); + if (!has_capability('mod/glossary:approve', $this->context)) { + $columnheader = $this->stringmanager->get_string('totalentries', 'mod_glossary'); + } + + $qb = new mod_glossary_entry_query_builder($this->cm->get_instance_record()); + $qb->filter_by_non_approved(mod_glossary_entry_query_builder::NON_APPROVED_NONE); + $entriescount = $qb->count_records(); + + $content = new action_link( + url: new url('/mod/glossary/view.php', ['id' => $this->cm->id]), + text: $entriescount, + attributes: [ + 'class' => button::SECONDARY_OUTLINE->classes(), + 'title' => $this->stringmanager->get_string('seeallentries', 'mod_glossary'), + ], + ); + + return new overviewitem( + name: $columnheader, + value: $entriescount, + content: $entriescount ? $content : '-', + textalign: text_align::CENTER, + ); + } + + /** + * Get the "My entries" overview item. + * + * @return overviewitem|null The overview item (or null if the user can approve entries). + */ + private function get_extra_myentries_overview(): ?overviewitem { + global $USER; + + if (has_capability('mod/glossary:approve', $this->context)) { + return null; + } + + $qb = new mod_glossary_entry_query_builder($this->cm->get_instance_record()); + $qb->join_user(true); + $qb->where('id', 'user', $USER->id); + $entriescount = $qb->count_records(); + + return new overviewitem( + name: $this->stringmanager->get_string('myentries', 'mod_glossary'), + value: $entriescount, + content: $entriescount ?: '-', + textalign: text_align::CENTER, + ); + } +} diff --git a/mod/glossary/index.php b/mod/glossary/index.php index fafb91eb1ec..3d2dd6aaec5 100644 --- a/mod/glossary/index.php +++ b/mod/glossary/index.php @@ -1,141 +1,30 @@ . + +/** + * Overview page for glossary module + * + * @package mod_glossary + * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ require_once("../../config.php"); -require_once("lib.php"); -require_once("$CFG->libdir/rsslib.php"); -require_once("$CFG->dirroot/course/lib.php"); -$id = required_param('id', PARAM_INT); // course +$courseid = required_param('id', PARAM_INT); -$PAGE->set_url('/mod/glossary/index.php', array('id'=>$id)); - -if (!$course = $DB->get_record('course', array('id'=>$id))) { - throw new \moodle_exception('invalidcourseid'); -} - -require_course_login($course); -$PAGE->set_pagelayout('incourse'); -$context = context_course::instance($course->id); - -$event = \mod_glossary\event\course_module_instance_list_viewed::create(array( - 'context' => $context -)); -$event->add_record_snapshot('course', $course); -$event->trigger(); - -/// Get all required strings - -$strglossarys = get_string("modulenameplural", "glossary"); -$strglossary = get_string("modulename", "glossary"); -$strrss = get_string("rss"); - - -/// Print the header -$PAGE->navbar->add($strglossarys, "index.php?id=$course->id"); -$PAGE->set_title($strglossarys); -$PAGE->set_heading($course->fullname); -echo $OUTPUT->header(); -echo $OUTPUT->heading(format_string($strglossarys), 2); - -/// Get all the appropriate data - -if (! $glossarys = get_all_instances_in_course("glossary", $course)) { - notice(get_string('thereareno', 'moodle', $strglossarys), "../../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"); -$strentries = get_string("entries", "glossary"); - -$table = new html_table(); - -if ($usesections) { - $strsectionname = course_get_format($course)->get_generic_section_name(); - $table->head = array ($strsectionname, $strname, $strentries); - $table->align = array ('center', 'left', 'center'); -} else { - $table->head = array ($strname, $strentries); - $table->align = array ('left', 'center'); -} - -if ($show_rss = (isset($CFG->enablerssfeeds) && isset($CFG->glossary_enablerssfeeds) && - $CFG->enablerssfeeds && $CFG->glossary_enablerssfeeds)) { - $table->head[] = $strrss; - $table->align[] = 'center'; -} - -$currentsection = ""; - -foreach ($glossarys as $glossary) { - if (!$glossary->visible && has_capability('moodle/course:viewhiddenactivities', - context_module::instance($glossary->coursemodule))) { - // Show dimmed if the mod is hidden. - $link = "coursemodule\">".format_string($glossary->name,true).""; - } else if ($glossary->visible) { - // Show normal if the mod is visible. - $link = "coursemodule\">".format_string($glossary->name,true).""; - } else { - // Don't show the glossary. - continue; - } - $printsection = ""; - if ($usesections) { - if ($glossary->section !== $currentsection) { - if ($glossary->section) { - $printsection = get_section_name($course, $glossary->section); - } - if ($currentsection !== "") { - $table->data[] = 'hr'; - } - $currentsection = $glossary->section; - } - } - - // TODO: count only approved if not allowed to see them - - $count = $DB->count_records_sql("SELECT COUNT(*) FROM {glossary_entries} WHERE (glossaryid = ? OR sourceglossaryid = ?)", array($glossary->id, $glossary->id)); - - //If this glossary has RSS activated, calculate it - if ($show_rss) { - $rsslink = ''; - if ($glossary->rsstype and $glossary->rssarticles) { - //Calculate the tolltip text - $tooltiptext = get_string("rsssubscriberss","glossary",format_string($glossary->name)); - if (!isloggedin()) { - $userid = 0; - } else { - $userid = $USER->id; - } - //Get html code for RSS link - $rsslink = rss_get_link($context->id, $userid, 'mod_glossary', $glossary->id, $tooltiptext); - } - } - - if ($usesections) { - $linedata = array ($printsection, $link, $count); - } else { - $linedata = array ($link, $count); - } - - if ($show_rss) { - $linedata[] = $rsslink; - } - - $table->data[] = $linedata; -} - -echo "
"; - -echo html_writer::table($table); - -/// Finish the page - -echo $OUTPUT->footer(); +\core_courseformat\activityoverviewbase::redirect_to_overview_page($courseid, 'glossary'); diff --git a/mod/glossary/lang/en/glossary.php b/mod/glossary/lang/en/glossary.php index e705b91daac..dd5082d30c3 100644 --- a/mod/glossary/lang/en/glossary.php +++ b/mod/glossary/lang/en/glossary.php @@ -239,6 +239,7 @@ $string['linkcategory_help'] = 'If glossary auto-linking has been enabled and th $string['linking'] = 'Auto-linking'; $string['mainglossary'] = 'Main glossary'; $string['maxtimehaspassed'] = 'Sorry, but the maximum time for editing this comment ({$a}) has passed!'; +$string['myentries'] = 'My entries'; $string['modulename'] = 'Glossary'; $string['modulename_help'] = 'The glossary activity module enables participants to create and maintain a list of definitions, like a dictionary, or to collect and organise resources or information. @@ -273,6 +274,7 @@ $string['notcategorised'] = 'Not categorised'; $string['notapproved'] = 'glossary entry is not approved yet.'; $string['entrynotapproved'] = 'Entry not approved'; $string['numberofentries'] = 'Number of entries'; +$string['numberofentriesneedapprove'] = 'Needs approve'; $string['onebyline'] = '(one per line)'; $string['page-mod-glossary-x'] = 'Any glossary module page'; $string['page-mod-glossary-edit'] = 'Glossary add/edit entry page'; @@ -313,6 +315,7 @@ $string['search:activity'] = 'Glossary - activity information'; $string['search:entry'] = 'Glossary - entries'; $string['searchindefinition'] = 'Search full text'; $string['secondaryglossary'] = 'Secondary glossary'; +$string['seeallentries'] = 'See all entries'; $string['showall'] = 'Show \'ALL\' link'; $string['showall_help'] = 'If enabled, participants can browse all entries at once.'; $string['showalphabet'] = 'Show alphabet links'; diff --git a/mod/glossary/tests/behat/overview_report.feature b/mod/glossary/tests/behat/overview_report.feature new file mode 100644 index 00000000000..541cb133ef0 --- /dev/null +++ b/mod/glossary/tests/behat/overview_report.feature @@ -0,0 +1,69 @@ +@mod @mod_glossary +Feature: Testing overview integration in mod_glossary + In order to list all glossaries in a course + As a user + I need to be able to see the glossary overview + + Background: + Given the following "users" exist: + | username | firstname | lastname | + | student1 | Username | 1 | + | student2 | Username | 2 | + | 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 | + | teacher1 | C1 | editingteacher | + And the following "activities" exist: + | activity | name | course | idnumber | defaultapproval | + | glossary | Glossary without defaultapproval | C1 | glossary1 | 0 | + | glossary | Glossary without entries | C1 | glossary2 | 0 | + And the following "mod_glossary > entries" exist: + | glossary | user | concept | definition | approved | + | glossary1 | teacher1 | Dragon | Large, winged, fire-breathing reptilian monster. | 1 | + | glossary1 | student1 | Griffin | Lion body, eagle head and wings. | 1 | + | glossary1 | student1 | Minotaur | Half-human, half-bull, lived in labyrinth. | 0 | + | glossary1 | student1 | Hydra | Many-headed serpent; regrows heads when cut. | 0 | + | glossary1 | student2 | Centaur | Half-human, half-horse creature from Greek myth. | 0 | + + @javascript + Scenario: Teacher can see the glossary relevant information in the glossary overview + When I am on the "Course 1" "course > activities > glossary" page logged in as "teacher1" + And I should not see "My Entries" in the "glossary_overview_collapsible" "region" + Then the following should exist in the "Table listing all Glossary activities" table: + | Name | Entries | Actions | + | Glossary without defaultapproval | 2 | Approve (3) | + | Glossary without entries | - | - | + And I click on "Approve (3)" "link" in the "glossary_overview_collapsible" "region" + And I should see "Pending approval (3)" is active in secondary navigation + + Scenario: Students can see the glossary relevant information in the glossary overview + When I am on the "Course 1" "course > activities > glossary" page logged in as "student1" + And I should not see "Actions" in the "glossary_overview_collapsible" "region" + Then the following should exist in the "Table listing all Glossary activities" table: + | Name | My entries | Total entries | + | Glossary without defaultapproval | 3 | 2 | + | Glossary without entries | - | - | + + Scenario: The glossary 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 "Glossaries" "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 "glossary_overview_collapsible" "region" + And I should see "Entries" in the "glossary_overview_collapsible" "region" + And I should see "Actions" in the "glossary_overview_collapsible" "region" + + Scenario: The glossary overview report should generate log events + Given I am on the "Course 1" "course > activities > glossary" 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 'glossary'" diff --git a/mod/glossary/tests/courseformat/overview_test.php b/mod/glossary/tests/courseformat/overview_test.php new file mode 100644 index 00000000000..77143e9e849 --- /dev/null +++ b/mod/glossary/tests/courseformat/overview_test.php @@ -0,0 +1,381 @@ +. + +namespace mod_glossary\courseformat; + +use core_courseformat\local\overview\overviewfactory; + +/** + * Tests for Glossary + * + * @covers \mod_glossary\courseformat\overview + * @package mod_glossary + * @category test + * @copyright 2025 Mikel Martín + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +final class overview_test extends \advanced_testcase { + /** + * Test get_actions_overview. + * + * @covers ::get_actions_overview + * @dataProvider provider_test_get_actions_overview + * + * @param string $role + * @param bool $requireapproval + * @param bool $hasentries + * @param array|null $expected + * @return void + */ + public function test_get_actions_overview( + string $role, + bool $requireapproval, + bool $hasentries, + ?array $expected + ): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $teacher1 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + + $currentuser = $this->getDataGenerator()->create_and_enrol($course, $role); + $this->setUser($currentuser); + + $activity = $this->getDataGenerator()->create_module( + 'glossary', + ['course' => $course->id, 'defaultapproval' => !$requireapproval], + ); + $cm = get_fast_modinfo($course)->get_cm($activity->cmid); + + if ($hasentries) { + /** @var \mod_glossary_generator $glossarygenerator */ + $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $currentuser->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $teacher1->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student1->id, + 'approved' => (int)!$requireapproval, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student2->id, + 'approved' => (int)!$requireapproval, + ]); + } + + $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', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => null, + ], + 'Teacher with entries (non-require approval)' => [ + 'role' => 'editingteacher', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('actions'), + 'value' => 0, + ], + ], + 'Teacher without entries (require approval)' => [ + 'role' => 'editingteacher', + 'requireapproval' => true, + 'hasentries' => false, + 'expected' => [ + 'name' => get_string('actions'), + 'value' => 0, + ], + ], + 'Teacher with entries (require approval)' => [ + 'role' => 'editingteacher', + 'requireapproval' => true, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('actions'), + 'value' => 2, + ], + ], + ]; + } + + /** + * Test get_extra_totalentries_overview. + * + * @covers ::get_extra_totalentries_overview + * @dataProvider provider_test_get_extra_totalentries_overview + * + * @param string $role + * @param bool $requireapproval + * @param bool $hasentries + * @param array $expected + * @return void + */ + public function test_get_extra_totalentries_overview( + string $role, + bool $requireapproval, + bool $hasentries, + array $expected + ): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $teacher1 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + + $currentuser = $this->getDataGenerator()->create_and_enrol($course, $role); + $this->setUser($currentuser); + + $activity = $this->getDataGenerator()->create_module( + 'glossary', + ['course' => $course->id, 'defaultapproval' => !$requireapproval], + ); + $cm = get_fast_modinfo($course)->get_cm($activity->cmid); + + if ($hasentries) { + /** @var \mod_glossary_generator $glossarygenerator */ + $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $currentuser->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $teacher1->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student1->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student2->id, + 'approved' => (int)!$requireapproval, + ]); + } + + $overview = overviewfactory::create($cm); + $reflection = new \ReflectionClass($overview); + $method = $reflection->getMethod('get_extra_totalentries_overview'); + $method->setAccessible(true); + $item = $method->invoke($overview); + + $this->assertEquals( + $expected, + ['name' => $item->get_name(), 'value' => $item->get_value()] + ); + } + + /** + * Data provider for test_get_extra_submitted_overview. + * + * @return array + */ + public static function provider_test_get_extra_totalentries_overview(): array { + return [ + 'Teacher with entries (non-require approval)' => [ + 'role' => 'editingteacher', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('entries', 'mod_glossary'), + 'value' => 4, + ], + ], + 'Student without entries' => [ + 'role' => 'student', + 'requireapproval' => false, + 'hasentries' => false, + 'expected' => [ + 'name' => get_string('totalentries', 'mod_glossary'), + 'value' => 0, + ], + ], + 'Student with entries (non-require approval)' => [ + 'role' => 'student', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('totalentries', 'mod_glossary'), + 'value' => 4, + ], + ], + 'Student with entries (require approval)' => [ + 'role' => 'student', + 'requireapproval' => true, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('totalentries', 'mod_glossary'), + 'value' => 3, + ], + ], + ]; + } + + /** + * Test get_extra_myentries_overview. + * + * @covers ::get_extra_myentries_overview + * @dataProvider provider_test_get_extra_myentries_overview + * + * @param string $role + * @param bool $requireapproval + * @param bool $hasentries + * @param array|null $expected + * @return void + */ + public function test_get_extra_myentries_overview( + string $role, + bool $requireapproval, + bool $hasentries, + ?array $expected + ): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $teacher1 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + + $currentuser = $this->getDataGenerator()->create_and_enrol($course, $role); + $this->setUser($currentuser); + + $activity = $this->getDataGenerator()->create_module( + 'glossary', + ['course' => $course->id, 'defaultapproval' => !$requireapproval], + ); + $cm = get_fast_modinfo($course)->get_cm($activity->cmid); + + if ($hasentries) { + /** @var \mod_glossary_generator $glossarygenerator */ + $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $currentuser->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $teacher1->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student1->id, + 'approved' => 1, + ]); + $glossarygenerator->create_entry([ + 'glossaryid' => $activity->id, + 'userid' => $student2->id, + 'approved' => (int)!$requireapproval, + ]); + } + + $overview = overviewfactory::create($cm); + $reflection = new \ReflectionClass($overview); + $method = $reflection->getMethod('get_extra_myentries_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_submitted_overview. + * + * @return array + */ + public static function provider_test_get_extra_myentries_overview(): array { + return [ + 'Teacher' => [ + 'role' => 'editingteacher', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => null, + ], + 'Student without responses' => [ + 'role' => 'student', + 'requireapproval' => false, + 'hasentries' => false, + 'expected' => [ + 'name' => get_string('myentries', 'mod_glossary'), + 'value' => 0, + ], + ], + 'Student with responses (non-require approval)' => [ + 'role' => 'student', + 'requireapproval' => false, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('myentries', 'mod_glossary'), + 'value' => 1, + ], + ], + 'Student with responses (require approval)' => [ + 'role' => 'student', + 'requireapproval' => true, + 'hasentries' => true, + 'expected' => [ + 'name' => get_string('myentries', 'mod_glossary'), + 'value' => 1, + ], + ], + ]; + } +}