From 5bbea7338da178b8906556764c8162c5a61b0deb Mon Sep 17 00:00:00 2001 From: Jake Dallimore Date: Fri, 6 Oct 2017 11:12:22 +0800 Subject: [PATCH] MDL-35429 backup: Only show relevant actions for automated backups - Users without permission to download or restore won't see the respective links. - The 'Manage backup files' button for the 'automated' backup filearea now requires the same permissions as downloading does for this filearea, those being 'restore:userinfo' and 'backup:downloadfile'. --- backup/backupfilesedit.php | 3 ++ backup/util/ui/renderer.php | 50 ++++++++++++++++++++++++--------- course/lib.php | 29 +++++++++++++++++++ course/tests/courselib_test.php | 50 +++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 13 deletions(-) diff --git a/backup/backupfilesedit.php b/backup/backupfilesedit.php index 86ce136b865..9c171ae4152 100644 --- a/backup/backupfilesedit.php +++ b/backup/backupfilesedit.php @@ -42,6 +42,9 @@ $url = new moodle_url('/backup/backupfilesedit.php', array('currentcontext'=>$cu require_login($course, false, $cm); require_capability('moodle/restore:uploadfile', $context); +if ($filearea == 'automated' && !can_download_from_backup_filearea($filearea, $context)) { + throw new required_capability_exception($context, 'moodle/backup:downloadfile', 'nopermissions', ''); +} $PAGE->set_url($url); $PAGE->set_context($context); diff --git a/backup/util/ui/renderer.php b/backup/util/ui/renderer.php index b4855bb6844..7499d6f601e 100644 --- a/backup/util/ui/renderer.php +++ b/backup/util/ui/renderer.php @@ -573,27 +573,51 @@ class core_backup_renderer extends plugin_renderer_base { $params['contextid'] = $viewer->currentcontext->id; $params['itemid'] = $file->get_itemid(); $restoreurl = new moodle_url('/backup/restorefile.php', $params); + $restorelink = html_writer::link($restoreurl, get_string('restore')); + $downloadlink = html_writer::link($fileurl, get_string('download')); + + // Conditional display of the restore and download links, initially only for the 'automated' filearea. + if ($params['filearea'] == 'automated') { + if (!has_capability('moodle/restore:viewautomatedfilearea', $viewer->currentcontext)) { + $restorelink = ''; + } + if (!can_download_from_backup_filearea($params['filearea'], $viewer->currentcontext)) { + $downloadlink = ''; + } + } $table->data[] = array( $file->get_filename(), userdate($file->get_timemodified()), display_size($file->get_filesize()), - html_writer::link($fileurl, get_string('download')), - html_writer::link($restoreurl, get_string('restore')), + $downloadlink, + $restorelink, ); } $html = html_writer::table($table); - $html .= $this->output->single_button( - new moodle_url('/backup/backupfilesedit.php', array( - 'currentcontext' => $viewer->currentcontext->id, - 'contextid' => $viewer->filecontext->id, - 'filearea' => $viewer->filearea, - 'component' => $viewer->component, - 'returnurl' => $this->page->url->out()) - ), - get_string('managefiles', 'backup'), - 'post' - ); + + // For automated backups, the ability to manage backup files is controlled by the ability to download them. + // All files must be from the same file area in a backup_files_viewer. + $canmanagebackups = true; + if ($viewer->filearea == 'automated') { + if (!can_download_from_backup_filearea($viewer->filearea, $viewer->currentcontext)) { + $canmanagebackups = false; + } + } + + if ($canmanagebackups) { + $html .= $this->output->single_button( + new moodle_url('/backup/backupfilesedit.php', array( + 'currentcontext' => $viewer->currentcontext->id, + 'contextid' => $viewer->filecontext->id, + 'filearea' => $viewer->filearea, + 'component' => $viewer->component, + 'returnurl' => $this->page->url->out()) + ), + get_string('managefiles', 'backup'), + 'post' + ); + } return $html; } diff --git a/course/lib.php b/course/lib.php index b38c641640a..c6887911513 100644 --- a/course/lib.php +++ b/course/lib.php @@ -4266,3 +4266,32 @@ function course_require_view_participants($context) { throw new required_capability_exception($context, $viewparticipantscap, 'nopermissions', ''); } } + +/** + * Return whether the user can download from the specified backup file area in the given context. + * + * @param string $filearea the backup file area. E.g. 'course', 'backup' or 'automated'. + * @param \context $context + * @param stdClass $user the user object. If not provided, the current user will be checked. + * @return bool true if the user is allowed to download in the context, false otherwise. + */ +function can_download_from_backup_filearea($filearea, \context $context, stdClass $user = null) { + $candownload = false; + switch ($filearea) { + case 'course': + case 'backup': + $candownload = has_capability('moodle/backup:downloadfile', $context, $user); + break; + case 'automated': + // Given the automated backups may contain userinfo, we restrict access such that only users who are able to + // restore with userinfo are able to download the file. Users can't create these backups, so checking 'backup:userinfo' + // doesn't make sense here. + $candownload = has_capability('moodle/backup:downloadfile', $context, $user) && + has_capability('moodle/restore:userinfo', $context, $user); + break; + default: + break; + + } + return $candownload; +} diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php index 6d53ba5b8f5..78f1934e5f6 100644 --- a/course/tests/courselib_test.php +++ b/course/tests/courselib_test.php @@ -4074,4 +4074,54 @@ class core_course_courselib_testcase extends advanced_testcase { $this->expectException('required_capability_exception'); course_require_view_participants(context_system::instance()); } + + /** + * Testing the can_download_from_backup_filearea fn. + */ + public function test_can_download_from_backup_filearea() { + global $DB; + $this->resetAfterTest(); + $course = $this->getDataGenerator()->create_course(); + $context = context_course::instance($course->id); + $user = $this->getDataGenerator()->create_user(); + $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id); + + // The 'automated' backup area. Downloading from this area requires two capabilities. + // If the user has only the 'backup:downloadfile' capability. + unassign_capability('moodle/restore:userinfo', $teacherrole->id, $context); + assign_capability('moodle/backup:downloadfile', CAP_ALLOW, $teacherrole->id, $context); + $this->assertFalse(can_download_from_backup_filearea('automated', $context, $user)); + + // If the user has only the 'restore:userinfo' capability. + unassign_capability('moodle/backup:downloadfile', $teacherrole->id, $context); + assign_capability('moodle/restore:userinfo', CAP_ALLOW, $teacherrole->id, $context); + $this->assertFalse(can_download_from_backup_filearea('automated', $context, $user)); + + // If the user has both capabilities. + assign_capability('moodle/backup:downloadfile', CAP_ALLOW, $teacherrole->id, $context); + assign_capability('moodle/restore:userinfo', CAP_ALLOW, $teacherrole->id, $context); + $this->assertTrue(can_download_from_backup_filearea('automated', $context, $user)); + + // Is the user has neither of the capabilities. + unassign_capability('moodle/backup:downloadfile', $teacherrole->id, $context); + unassign_capability('moodle/restore:userinfo', $teacherrole->id, $context); + $this->assertFalse(can_download_from_backup_filearea('automated', $context, $user)); + + // The 'course ' and 'backup' backup file areas. These are governed by the same download capability. + // User has the capability. + unassign_capability('moodle/restore:userinfo', $teacherrole->id, $context); + assign_capability('moodle/backup:downloadfile', CAP_ALLOW, $teacherrole->id, $context); + $this->assertTrue(can_download_from_backup_filearea('course', $context, $user)); + $this->assertTrue(can_download_from_backup_filearea('backup', $context, $user)); + + // User doesn't have the capability. + unassign_capability('moodle/backup:downloadfile', $teacherrole->id, $context); + $this->assertFalse(can_download_from_backup_filearea('course', $context, $user)); + $this->assertFalse(can_download_from_backup_filearea('backup', $context, $user)); + + // A file area that doesn't exist. No permissions, regardless of capabilities. + assign_capability('moodle/backup:downloadfile', CAP_ALLOW, $teacherrole->id, $context); + $this->assertFalse(can_download_from_backup_filearea('testing', $context, $user)); + } }