MDL-83900 mod_wiki: Add course overview page for wiki

This commit is contained in:
Laurent David
2025-07-10 09:00:24 +02:00
parent da2b765125
commit 6a7963faad
4 changed files with 510 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
<?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_wiki\courseformat;
use core\output\renderer_helper;
use core\url;
use cm_info;
use core_courseformat\local\overview\overviewitem;
use core\output\action_link;
use core\output\local\properties\text_align;
use core\output\local\properties\button;
use mod_wiki\manager;
/**
* Wiki overview integration.
*
* @package mod_wiki
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class overview extends \core_courseformat\activityoverviewbase {
/**
* @var manager the wiki manager.
*/
private manager $manager;
/**
* Constructor.
*
* @param cm_info $cm the course module instance.
* @param renderer_helper $rendererhelper the renderer helper.
* @param \core_string_manager $stringmanager
*/
public function __construct(
cm_info $cm,
/** @var renderer_helper $rendererhelper the renderer helper */
protected readonly renderer_helper $rendererhelper,
/** @var \core_string_manager $stringmanager the string manager */
protected readonly \core_string_manager $stringmanager,
) {
parent::__construct($cm);
$this->manager = manager::create_from_coursemodule($cm);
}
#[\Override]
public function get_actions_overview(): ?overviewitem {
if (!has_capability('mod/wiki:managewiki', $this->cm->context)) {
return null; // If the user cannot manage the wiki, we don't show the actions.
}
// If a wiki does not have a main page means it is not used yet, so we do not show the action link.
$pageid = $this->manager->get_main_wiki_pageid();
if (!$pageid) {
return null;
}
$text = $this->stringmanager->get_string('view');
$content = new action_link(
url: new url(
'/mod/wiki/map.php',
['pageid' => $pageid],
),
text: $text,
attributes: ['class' => button::SECONDARY_OUTLINE->classes()],
);
return new overviewitem(
name: $this->stringmanager->get_string('actions'),
value: $text,
content: $content,
textalign: text_align::CENTER,
);
}
#[\Override]
public function get_extra_overview_items(): array {
return [
'wiki_type' => $this->get_extra_wiki_type(),
'totalentries' => $this->get_total_entries(),
'my_entries' => $this->get_extra_my_entries(),
];
}
/**
* Get the overview item for wiki type.
*
* @return overviewitem An overview item for the wiki type.
*/
private function get_extra_wiki_type(): overviewitem {
return new overviewitem(
name: $this->stringmanager->get_string('wikimode', 'wiki'),
value: $this->manager->get_wiki_mode()->value,
content: $this->manager->get_wiki_mode()->to_string(),
textalign: text_align::CENTER,
);
}
/**
* Get the entries for a user
*
* @return overviewitem|null An overview item, or null if the user lacks the required capability.
*/
private function get_extra_my_entries(): ?overviewitem {
global $USER;
if (has_capability('mod/wiki:managewiki', $this->cm->context)) {
return null; // If the user manage the wiki, we don't show the my entries.
}
$entriescount = $this->manager->get_user_entries_count($USER->id);
return new overviewitem(
name: $this->stringmanager->get_string('myentries', 'wiki'),
value: $entriescount,
content: $entriescount,
textalign: text_align::CENTER,
);
}
/**
* Get the overview item for total entries.
*
* @return overviewitem An overview item for total entries.
*/
private function get_total_entries(): overviewitem {
global $USER;
$entriescount = $this->manager->get_all_entries_count($USER->id);
$label = $this->stringmanager->get_string('totalentries', 'wiki');
if (has_capability('mod/wiki:managewiki', $this->cm->context)) {
$label = $this->stringmanager->get_string('entries', 'wiki');
}
return new overviewitem(
name: $label,
value: $entriescount,
content: $entriescount,
textalign: text_align::CENTER,
);
}
}
+4
View File
@@ -64,6 +64,7 @@ $string['editing'] = 'Editing wiki page';
$string['editingcomment'] = 'Editing comment';
$string['editingpage'] = 'Editing this page \'{$a}\'';
$string['editsection'] = 'edit';
$string['entries'] = 'Entries';
$string['eventdiffviewed'] = 'Wiki diff viewed';
$string['eventhistoryviewed'] = 'Wiki history viewed';
$string['eventmapviewed'] = 'Wiki page map viewed';
@@ -151,6 +152,7 @@ Wikis have many uses, such as
* As a personal journal for examination notes or revision (using an individual wiki)';
$string['modulename_link'] = 'mod/wiki/view';
$string['modulenameplural'] = 'Wikis';
$string['myentries'] = 'My entries';
$string['navigation'] = 'Navigation';
$string['navigationfrom'] = 'This page comes from';
$string['navigationfrom_help'] = 'The wiki pages linking to this page';
@@ -259,6 +261,7 @@ $string['tableofcontents'] = 'Table of contents';
$string['tagarea_wiki_pages'] = 'Wiki pages';
$string['teacherrating'] = 'Teacher rating';
$string['timesrating'] = 'This page has been rated {$a->c} times with an average of: {$a->s}';
$string['totalentries'] = 'Total entries';
$string['updatedpages'] = "Updated pages";
$string['updatedpages_help'] = "Recently updated wiki pages";
$string['updatedwikipages'] = "Updated wiki pages";
@@ -292,6 +295,7 @@ $string['wikimode'] = 'Wiki mode';
$string['wikimode_help'] = 'The wiki mode determines whether everyone can edit the wiki - a collaborative wiki - or whether everyone has their own wiki which only they can edit - an individual wiki.';
$string['wikimodecollaborative'] = 'Collaborative wiki';
$string['wikimodeindividual'] = 'Individual wiki';
$string['wikimodeundefined'] = 'Wikimode undefined';
$string['wikiname'] = 'Wiki name';
$string['wikinowikitext'] = 'No wiki text';
$string['wikiorderedlist'] = 'Ordered list';
@@ -0,0 +1,79 @@
@mod @mod_wiki
Feature: Testing overview integration in mod_wiki
In order to summarize the wikis
As a user
I need to be able to see the wiki overview
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Student | 1 |
| student2 | Student | 2 |
| student3 | Student | 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 |
Given the following "groups" exist:
| name | course | idnumber | participation |
| Group 1 | C1 | G1 | 1 |
| Group 2 | C1 | G2 | 1 |
| Group 3 | C1 | G3 | 0 |
And the following "group members" exist:
| user | group |
| student1 | G1 |
| student2 | G2 |
| student3 | G3 |
And the following "activities" exist:
| activity | course | name | idnumber | wikimode | firstpagetitle | groupmode |
| wiki | C1 | Separate wiki | wiki1 | collaborative | Separate page 1 | 1 |
| wiki | C1 | Visible wiki | wiki2 | collaborative | Visible page 1 | 2 |
And the following wiki pages exist:
| wiki | title | content | group |
| wiki1 | Separate page 1 | Group 1 page | G1 |
| wiki1 | Separate page 1 | Group 2 page | G2 |
| wiki2 | Visible page 1 | Group 1 page | G1 |
| wiki2 | Visible page 1 | Group 2 page | G2 |
And the following wiki pages exist:
| wiki | title | content |
| wiki1 | Separate page 1 | No group page |
| wiki2 | Visible page 1 | No group page |
Scenario: The wiki overview report should generate log events
Given I am on the "Course 1" "course > activities > wiki" 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 'wiki'"
Scenario: Students can see relevant columns in the wiki overview
Given I am on the "Course 1" "course > activities > wiki" page logged in as "student1"
Then the following should exist in the "Table listing all Wiki activities" table:
| Name | My entries | Total entries |
| Separate wiki | 0 | 0 |
| Visible wiki | 0 | 3 |
Scenario: Teachers can see relevant columns in the wiki overview
Given I am on the "Course 1" "course > activities > wiki" page logged in as "teacher1"
Then the following should exist in the "Table listing all Wiki activities" table:
| Name | Wiki mode | Entries | Actions |
| Separate wiki | Collaborative wiki | 3 | View |
| Visible wiki | Collaborative wiki | 3 | View |
Scenario: The wiki 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 "Wikis" "link" in the "Activities" "block"
Then I should see "An overview of all activities in the course"
And I should see "Name" in the "wiki_overview_collapsible" "region"
And I should see "Wiki mode" in the "wiki_overview_collapsible" "region"
And I should see "Entries" in the "wiki_overview_collapsible" "region"
@@ -0,0 +1,279 @@
<?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_wiki\courseformat;
use core_courseformat\local\overview\overviewfactory;
use mod_wiki\wiki_mode;
use ReflectionClass;
/**
* Tests for Wiki integration.
*
* @covers \mod_wiki\courseformat\overview
* @package mod_wiki
* @category test
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class overview_test extends \advanced_testcase {
/**
* Data provider for wiki modes.
*
* @return array
*/
public static function get_wiki_mode_provider(): array {
return [
'collaborative' => ['mode' => wiki_mode::COLLABORATIVE],
'individual' => ['mode' => wiki_mode::INDIVIDUAL],
];
}
/**
* Test get_extra_my_entries method.
*
* @param string $username
* @param int|null $expectedcount
* @return void
*
* @covers ::get_extra_my_entries
* @dataProvider get_extra_my_entries_provider
*/
public function test_get_extra_my_entries(string $username, ?int $expectedcount = null): void {
$this->resetAfterTest();
['users' => $users, 'instance' => $instance, 'course' => $course] = $this->setup_users_and_activity();
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$overview = overviewfactory::create($cm);
$this->setUser($users[$username]->id);
$items = $overview->get_extra_overview_items();
$item = $items['my_entries'] ?? null;
$this->assertEquals(
$expectedcount,
$item?->get_value()
);
}
/**
* Data provider for get_extra_my_entries.
*
* @return array
*/
public static function get_extra_my_entries_provider(): array {
return [
'student 1' => ['s1', 1],
'student 2' => ['s2', 1],
'teacher 1' => ['t1', null], // Teacher 1 does not have any entries.
];
}
/**
* Test the wiki mode of the wiki instance.
*
* @param wiki_mode $mode the expected wiki mode.
*
* @covers ::get_extra_wiki_type
* @dataProvider get_wiki_mode_provider
*/
public function test_wiki_mode(wiki_mode $mode): void {
$this->resetAfterTest();
['users' => $users, 'instance' => $instance, 'course' => $course] =
$this->setup_users_and_activity(NOGROUPS, $mode->value);
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$overview = overviewfactory::create($cm);
$this->setUser($users['t1']->id);
$items = $overview->get_extra_overview_items();
$item = $items['wiki_type'] ?? null;
$this->assertEquals(
$mode->value,
$item->get_value(),
);
}
/**
* Setup users and activity for testing answers retrieval.
*
* @param int $groupmode the group mode to use for the course.
* @param string $mode the mode of the wiki instance.
* @return array indexed array with 'users', 'course' and 'instance'.
*/
private function setup_users_and_activity(int $groupmode = NOGROUPS, string $mode = 'collaborative'): array {
global $CFG;
require_once($CFG->dirroot . '/mod/wiki/locallib.php');
$users = [];
$generator = $this->getDataGenerator();
$courseparams = [];
if ($groupmode !== NOGROUPS) {
// Set the group mode for the course.
$courseparams['groupmode'] = $groupmode;
}
$course = $generator->create_course($courseparams);
foreach (['s1' => 'student', 's2' => 'student', 't1' => 'teacher', 't2' => 'teacher'] as $username => $role) {
$users[$username] = $generator->create_and_enrol($course, $role, ['username' => $username]);
}
$groups = [];
if ($groupmode !== NOGROUPS) {
// Create a group if the group mode is not NOGROUPS.
$groups[] = $generator->create_group(['courseid' => $course->id]);
$groups[] = $generator->create_group(['courseid' => $course->id]);
groups_add_member($groups[0], $users['s1']->id);
groups_add_member($groups[1], $users['s2']->id);
groups_add_member($groups[0], $users['t1']->id);
}
$instance = $generator->create_module(
'wiki',
[
'course' => $course,
'wikimode' => $mode,
'groupmode' => $groupmode,
'firstpagetitle' => 'Wiki first page title',
],
);
$wikigenerator = $generator->get_plugin_generator('mod_wiki');
$pages = [];
foreach (['s1', 's2'] as $username) {
$user = $users[$username];
// Create a first page for each user.
$this->setUser($user->id);
$groups = groups_get_my_groups();
foreach ($groups as $group) {
$authorid = ($mode === wiki_mode::INDIVIDUAL->value) ? $user->id : 0;
// Ensure the user is in the group.
$pages[] = $wikigenerator->create_first_page(
$instance,
[
'wikiid' => $instance->id,
'userid' => $authorid,
'group' => $group->id,
'content' => "Wiki first page content for $username",
'title' => "Wiki first page title",
],
);
}
if (empty($groups)) {
$pages[] = $wikigenerator->create_page(
$instance,
[
'wikiid' => $instance->id,
'userid' => $user->id,
'content' => "Wiki first page content for $username",
'title' => "Wiki first page title",
],
);
}
}
return [
'users' => $users,
'course' => $course,
'instance' => $instance,
'pages' => $pages,
];
}
/**
* Test get_extra_entries method.
*
* @param string $username
* @param int $coursegroupmode
* @param int $expectedcount
*
* @covers ::get_extra_entries
* @dataProvider data_provider_get_extra_entries
*/
public function test_get_extra_entries(
string $username,
int $coursegroupmode,
int $expectedcount
): void {
$this->resetAfterTest();
[
'users' => $users,
'instance' => $instance,
'course' => $course
] = $this->setup_users_and_activity($coursegroupmode);
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$this->setUser($users[$username]->id);
$overview = overviewfactory::create($cm);
$items = $overview->get_extra_overview_items();
$item = $items['totalentries'] ?? null;
$this->assertEquals($expectedcount, $item->get_value());
}
/**
* Data provider for get_extra_entries.
*
* @return array
*/
public static function data_provider_get_extra_entries(): array {
return [
'teacher 1 (no group mode)' => ['t1', NOGROUPS, 2],
'teacher 1 (separate group mode)' => ['t1', SEPARATEGROUPS, 1], // Teacher 1 belongs to group 1, so should see s1.
'teacher 1 (visible group mode)' => ['t1', VISIBLEGROUPS, 2],
// Teacher 2 does not belong to any group.
'teacher 2 (no group mode)' => ['t2', NOGROUPS, 2],
'teacher 2 (separate group mode)' => ['t2', SEPARATEGROUPS, 0], // Teacher 2 does not belong to any group.
'teacher 2 (visible group mode)' => ['t2', VISIBLEGROUPS, 2],
];
}
/**
* Test get_extra_entries method.
*
* @covers ::get_actions_overview
*/
public function test_get_actions_overview(): void {
$this->resetAfterTest();
[
'users' => $users,
'instance' => $instance,
'course' => $course
] = $this->setup_users_and_activity(SEPARATEGROUPS);
$notinitinstance = $this->getDataGenerator()->create_module(
'wiki',
[
'course' => $course,
'wikimode' => wiki_mode::INDIVIDUAL->value,
]
);
$this->setUser($users['t1']->id);
$cm = get_fast_modinfo($course)->get_cm($instance->cmid);
$emptycm = get_fast_modinfo($course)->get_cm($notinitinstance->cmid);
$overview = overviewfactory::create($cm);
$item = $overview->get_actions_overview();
$this->assertNotNull($item);
$overview = overviewfactory::create($emptycm);
$item = $overview->get_actions_overview();
$this->assertNull($item);
}
}