From 2937e90bc7cea8e7f83a725dd3915e5faec48b1e Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Tue, 23 Jul 2024 22:37:36 +0100 Subject: [PATCH] MDL-82502 courseformat: align module action capability checks. The "Hide/Show/Duplicate" actions should be considered self-contained, and not also require "manageactivities" capability (per existing docs) in addition to the specific capability that controls the action itself. Also ensure the "Duplicate" capability checks are in the course context. --- course/format/classes/stateactions.php | 28 +++++++++++++++++++------- course/mod.php | 4 ++-- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/course/format/classes/stateactions.php b/course/format/classes/stateactions.php index 34535375d96..f54816ca1b4 100644 --- a/course/format/classes/stateactions.php +++ b/course/format/classes/stateactions.php @@ -521,7 +521,7 @@ class stateactions { $course, $ids, __FUNCTION__, - ['moodle/course:manageactivities', 'moodle/course:activityvisibility'] + ['moodle/course:activityvisibility'] ); $format = course_get_format($course->id); @@ -567,7 +567,8 @@ class stateactions { $course, $ids, __FUNCTION__, - ['moodle/course:manageactivities', 'moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'] + ['moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'], + false ); $modinfo = get_fast_modinfo($course); @@ -1107,10 +1108,17 @@ class stateactions { * @param stdClass $course The course where given $cmids belong. * @param array $cmids List of course module ids to validate. * @param string $info additional information in case of error. - * @param array $capabilities optional capabilities checks per each cm context. + * @param array $capabilities optional capabilities checks to require. + * @param bool $usemodcontext whether to use each module context, or the course context * @throws moodle_exception if any id is not valid */ - protected function validate_cms(stdClass $course, array $cmids, ?string $info = null, array $capabilities = []): void { + protected function validate_cms( + stdClass $course, + array $cmids, + ?string $info = null, + array $capabilities = [], + bool $usemodcontext = true, + ): void { if (empty($cmids)) { throw new moodle_exception('emptycmids', 'core', null, $info); @@ -1121,10 +1129,16 @@ class stateactions { if (count($cmids) != count($intersect)) { throw new moodle_exception('unexistingcmid', 'core', null, $info); } + if (!empty($capabilities)) { - foreach ($cmids as $cmid) { - $modcontext = context_module::instance($cmid); - require_all_capabilities($capabilities, $modcontext); + if ($usemodcontext) { + foreach ($cmids as $cmid) { + $modcontext = context_module::instance($cmid); + require_all_capabilities($capabilities, $modcontext); + } + } else { + $coursecontext = context_course::instance($course->id); + require_all_capabilities($capabilities, $coursecontext); } } } diff --git a/course/mod.php b/course/mod.php index dd433c8da0d..c365002524e 100644 --- a/course/mod.php +++ b/course/mod.php @@ -122,8 +122,8 @@ if (!empty($add)) { $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); require_login($course, false, $cm); - $modcontext = context_module::instance($cm->id); - require_capability('moodle/course:manageactivities', $modcontext); + $coursecontext = context_course::instance($course->id); + require_all_capabilities(['moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'], $coursecontext); // Duplicate the module. $newcm = duplicate_module($course, $cm);