From eadd93065c70ecc0ab3feceb1a0152130be764b3 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 848e9227e0a..485bdc7d723 100644 --- a/course/format/classes/stateactions.php +++ b/course/format/classes/stateactions.php @@ -515,7 +515,7 @@ class stateactions { $course, $ids, __FUNCTION__, - ['moodle/course:manageactivities', 'moodle/course:activityvisibility'] + ['moodle/course:activityvisibility'] ); $format = course_get_format($course->id); @@ -561,7 +561,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); @@ -1101,10 +1102,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); @@ -1115,10 +1123,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 3fc5647df94..fa95eddaee8 100644 --- a/course/mod.php +++ b/course/mod.php @@ -98,8 +98,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);