Skip to content

Commit a438ea0

Browse files
Fix section checking
1 parent c373cdf commit a438ea0

4 files changed

Lines changed: 192 additions & 8 deletions

File tree

classes/actions.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,21 +270,21 @@ public static function duplicate_to_course(array $modules, int $targetcourseid,
270270
$sourcemodinfo = get_fast_modinfo($sourcecourseid);
271271
$targetmodinfo = get_fast_modinfo($targetcourseid);
272272
$targetformat = course_get_format($targetmodinfo->get_course());
273-
$targetsectionnum = $targetformat->get_last_section_number();
273+
$lastsectionnum = $targetformat->get_last_section_number();
274274

275275
$filtersectionshook = new filter_sections_different_course($targetcourseid,
276276
array_keys($targetmodinfo->get_section_info_all()));
277277
\core\di::get(\core\hook\manager::class)->dispatch($filtersectionshook);
278278
$filteredsections = $filtersectionshook->get_sectionnums();
279279

280-
if ($targetsectionnum == -1 && !$filtersectionshook->is_originsectionkept()) {
280+
if ($sectionnum == -1 && !$filtersectionshook->is_originsectionkept()) {
281281
// The course modules should be in the same section number as in the original course. However, the hook listener(s)
282282
// disabled this option, so we cancel the operation.
283283
// This is only a security measure and should not happen unless someone manipulates the UI.
284284
return;
285285
}
286286

287-
if (!in_array($targetsectionnum, $filteredsections)) {
287+
if (($sectionnum >= 0) && ($sectionnum <= $lastsectionnum) && !in_array($sectionnum, $filteredsections)) {
288288
// The target section number has been filtered by a hook callback, thus must not be used.
289289
// This is only a security measure and should not happen unless someone manipulates the UI.
290290
return;
@@ -293,16 +293,16 @@ public static function duplicate_to_course(array $modules, int $targetcourseid,
293293
$canaddsection = has_capability('moodle/course:update', context_course::instance($targetcourseid))
294294
&& $filtersectionshook->is_makesectionallowed();
295295

296-
// If a new section (that means that $sectionnum of the user is higher than $targetsectionnum), we create one.
297-
if ($sectionnum > $targetsectionnum) {
296+
// If a new section (that means that $sectionnum of the user is higher than $lastsectionnum), we create one.
297+
if ($sectionnum > $lastsectionnum) {
298298
// No permissions to add section.
299299
if (!$canaddsection) {
300300
return;
301301
}
302302

303303
$targetformatopt = $targetformat->get_format_options();
304304
// No course format setting or no orphaned sections exist.
305-
if (!isset($targetformatopt['numsections']) || !($targetformatopt['numsections'] < $targetsectionnum)) {
305+
if (!isset($targetformatopt['numsections']) || !($targetformatopt['numsections'] < $lastsectionnum)) {
306306
course_create_section($targetcourseid);
307307
}
308308

@@ -312,7 +312,7 @@ public static function duplicate_to_course(array $modules, int $targetcourseid,
312312
}
313313

314314
// Make sure new sectionnum is set accurately.
315-
$sectionnum = $targetsectionnum + 1;
315+
$sectionnum = $lastsectionnum + 1;
316316
}
317317

318318
if ($sectionnum == -1) {
@@ -323,7 +323,7 @@ public static function duplicate_to_course(array $modules, int $targetcourseid,
323323
}, $modules));
324324

325325
// If target course needs sections added but user does not have permission.
326-
if ($srcmaxsectionnum > $targetsectionnum && !$canaddsection) {
326+
if ($srcmaxsectionnum > $lastsectionnum && !$canaddsection) {
327327
return; // No permission to add section.
328328
}
329329

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace block_massaction;
18+
19+
use block_massaction\hook\filter_sections_different_course;
20+
21+
/**
22+
* block_massaction phpunit tests fixture.
23+
* Callbacks for the filter_sections_different_course hook.
24+
*
25+
* @package block_massaction
26+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27+
*/
28+
final class filter_sections_different_course_callbacks {
29+
/**
30+
* Callback for the filter_sections_different_course hook.
31+
*
32+
* @param filter_sections_different_course $hook
33+
* @return void
34+
*/
35+
public static function filter_sections_different_course(filter_sections_different_course $hook): void {
36+
foreach ($hook->get_sectionnums() as $sectionnum) {
37+
// Restrict section 3 onward.
38+
if ($sectionnum >= 3) {
39+
$hook->remove_sectionnum($sectionnum);
40+
}
41+
}
42+
43+
// Disable the options to keep the original section.
44+
$hook->disable_originsectionkept();
45+
46+
// Disable the option to create a new section.
47+
$hook->disable_makesection(true);
48+
}
49+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace block_massaction;
18+
19+
defined('MOODLE_INTERNAL') || die();
20+
21+
/**
22+
* block_massaction phpunit tests fixture.
23+
* Hook register.
24+
*
25+
* @package block_massaction
26+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27+
*/
28+
29+
$callbacks = [
30+
[
31+
'hook' => \block_massaction\hook\filter_sections_different_course::class,
32+
'callback' => [
33+
\block_massaction\filter_sections_different_course_callbacks::class,
34+
'filter_sections_different_course',
35+
],
36+
],
37+
];

tests/massaction_test.php

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use base_setting_exception;
2222
use block_massaction;
2323
use coding_exception;
24+
use core\di;
2425
use core\event\course_module_updated;
2526
use core\task\manager;
2627
use dml_exception;
@@ -860,4 +861,101 @@ private function shuffle_modules(): void {
860861
moveto_module(get_fast_modinfo($this->course->id)->get_cm(get_fast_modinfo($this->course->id)->get_sections()[3][3]),
861862
get_fast_modinfo($this->course->id)->get_section_info(3));
862863
}
864+
865+
/**
866+
* Tests the duplication of modules to a course with filter_sections hook.
867+
*
868+
* @covers \block_massaction\actions::duplicate_to_course
869+
* @return void
870+
*/
871+
public function test_duplicate_to_course_with_filter_sections_different_course_hook(): void {
872+
$this->resetAfterTest();
873+
874+
// Load the callback classes.
875+
require_once(__DIR__ . '/fixtures/filter_sections_different_course_callbacks.php');
876+
877+
// Replace the version of the manager in the DI container with a phpunit one.
878+
di::set(
879+
\core\hook\manager::class,
880+
\core\hook\manager::phpunit_get_instance([
881+
'test_plugin1' => __DIR__ . '/fixtures/filter_sections_different_course_hooks.php',
882+
]),
883+
);
884+
885+
// Source course.
886+
$sourcecourseid = $this->course->id;
887+
$sourcecoursemodinfo = get_fast_modinfo($sourcecourseid);
888+
889+
// Move modules around so that they are not in id order.
890+
$this->shuffle_modules();
891+
892+
// Select some random course modules from different sections to be duplicated.
893+
$selectedmoduleids[] = $sourcecoursemodinfo->get_sections()[1][0];
894+
$selectedmoduleids[] = $sourcecoursemodinfo->get_sections()[1][1];
895+
$selectedmoduleids[] = $sourcecoursemodinfo->get_sections()[3][0];
896+
$selectedmoduleids[] = $sourcecoursemodinfo->get_sections()[3][2];
897+
898+
$selectedmodules = array_filter($this->get_test_course_modules(), function($module) use ($selectedmoduleids) {
899+
return in_array($module->id, $selectedmoduleids);
900+
});
901+
902+
// Target course.
903+
$targetcourseid = $this->setup_target_course_for_duplicating(3);
904+
$targetcoursemodinfo = get_fast_modinfo($targetcourseid);
905+
// Four sections (0 1 2 3).
906+
$this->assertCount(4, $targetcoursemodinfo->get_section_info_all());
907+
// There is no module.
908+
$this->assertEmpty($targetcoursemodinfo->get_cms());
909+
910+
// Test keep origin section.
911+
actions::duplicate_to_course($selectedmodules, $targetcourseid, -1);
912+
$targetcoursemodinfo = get_fast_modinfo($targetcourseid);
913+
// Four sections (0 1 2 3).
914+
$this->assertCount(4, $targetcoursemodinfo->get_section_info_all());
915+
// There is no module as we cannot keep origin section.
916+
$this->assertEmpty($targetcoursemodinfo->get_cms());
917+
918+
// Test create new section.
919+
actions::duplicate_to_course($selectedmodules, $targetcourseid, 4);
920+
$targetcoursemodinfo = get_fast_modinfo($targetcourseid);
921+
// Still four sections (0 1 2 3).
922+
$this->assertCount(4, $targetcoursemodinfo->get_section_info_all());
923+
// And still no module.
924+
$this->assertEmpty($targetcoursemodinfo->get_cms());
925+
926+
// Duplicate to section 3, which is restricted by the hook.
927+
actions::duplicate_to_course($selectedmodules, $targetcourseid, 3);
928+
$targetcoursemodinfo = get_fast_modinfo($targetcourseid);
929+
// Still four sections (0 1 2 3).
930+
$this->assertCount(4, $targetcoursemodinfo->get_section_info_all());
931+
// And still no module.
932+
$this->assertEmpty($targetcoursemodinfo->get_cms());
933+
934+
// Duplicate to section 1, this should work as normal.
935+
actions::duplicate_to_course($selectedmodules, $targetcourseid, 1);
936+
$targetcoursemodinfo = get_fast_modinfo($targetcourseid);
937+
$this->assertCount(4, $targetcoursemodinfo->get_section_info_all());
938+
// There should be 4 modules now.
939+
$this->assertCount(4, $targetcoursemodinfo->get_cms());
940+
// These module ids should be in section 1.
941+
$duplicatedmoduleids = $targetcoursemodinfo->get_sections()[1];
942+
$this->assertCount(4, $duplicatedmoduleids);
943+
944+
// Sort name of the modules to be able to compare them.
945+
$sourcemodulenames = [];
946+
foreach ($selectedmoduleids as $selectedmoduleid) {
947+
$sourcemodulenames[] = $sourcecoursemodinfo->get_cm($selectedmoduleid)->name;
948+
}
949+
sort($sourcemodulenames);
950+
951+
// Sort name of the duplicated modules to be able to compare them.
952+
$duplicatedmodulenames = [];
953+
foreach ($duplicatedmoduleids as $moduleid) {
954+
$duplicatedmodulenames[] = $targetcoursemodinfo->get_cm($moduleid)->name;
955+
}
956+
sort($duplicatedmodulenames);
957+
958+
// The names of the duplicated modules should be the same as the source module names.
959+
$this->assertEquals($sourcemodulenames, $duplicatedmodulenames);
960+
}
863961
}

0 commit comments

Comments
 (0)