mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-35429-master' of https://github.com/snake/moodle
This commit is contained in:
commit
c8ee0b642d
@ -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);
|
||||
|
@ -79,6 +79,9 @@ if (!check_dir_exists($tmpdir, true, true)) {
|
||||
|
||||
// choose the backup file from backup files tree
|
||||
if ($action == 'choosebackupfile') {
|
||||
if ($filearea == 'automated') {
|
||||
require_capability('moodle/restore:viewautomatedfilearea', $context);
|
||||
}
|
||||
if ($fileinfo = $browser->get_file_info($filecontext, $component, $filearea, $itemid, $filepath, $filename)) {
|
||||
if (is_a($fileinfo, 'file_info_stored')) {
|
||||
// Use the contenthash rather than copying the file where possible,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ $string['restore:restoretargetimport'] = 'Restore from files targeted as import'
|
||||
$string['restore:rolldates'] = 'Allowed to roll activity configuration dates on restore';
|
||||
$string['restore:uploadfile'] = 'Upload files to backup areas';
|
||||
$string['restore:userinfo'] = 'Restore user data';
|
||||
$string['restore:viewautomatedfilearea'] = 'View automated backup area';
|
||||
$string['restore:viewautomatedfilearea'] = 'Restore courses from automated backups';
|
||||
$string['risks'] = 'Risks';
|
||||
$string['roleallowheader'] = 'Allow role:';
|
||||
$string['roleallowinfo'] = 'Select a role to be added to the list of allowed roles in context "{$a->context}", capability "{$a->cap}":';
|
||||
|
@ -305,6 +305,10 @@ $capabilities = array(
|
||||
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
),
|
||||
|
||||
'moodle/restore:restoretargethub' => array(
|
||||
|
@ -338,7 +338,9 @@ class file_info_context_course extends file_info {
|
||||
}
|
||||
}
|
||||
|
||||
$downloadable = has_capability('moodle/site:config', $this->context);
|
||||
// Automated backup files are only downloadable if the user has both 'backup:downloadfile and 'restore:userinfo'.
|
||||
$downloadable = has_capability('moodle/backup:downloadfile', $this->context) &&
|
||||
has_capability('moodle/restore:userinfo', $this->context);
|
||||
$uploadable = false;
|
||||
|
||||
$urlbase = $CFG->wwwroot.'/pluginfile.php';
|
||||
|
@ -78,6 +78,10 @@ class file_browser_testcase extends advanced_testcase {
|
||||
|
||||
$this->teacher = $this->getDataGenerator()->create_user();
|
||||
$this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
|
||||
// Make sure we're testing what should be the default capabilities.
|
||||
assign_capability('moodle/restore:viewautomatedfilearea', CAP_ALLOW, $this->teacherrole->id, $coursecontext1);
|
||||
|
||||
$this->getDataGenerator()->enrol_user($this->teacher->id, $this->course1->id, $this->teacherrole->id);
|
||||
$this->getDataGenerator()->enrol_user($this->teacher->id, $this->course2->id, $this->teacherrole->id);
|
||||
|
||||
@ -175,9 +179,9 @@ class file_browser_testcase extends advanced_testcase {
|
||||
// Filearea "Course summary" has a child that is the actual image file.
|
||||
$this->assertEquals($this->course1filerecord, $child->get_children()[0]->get_params());
|
||||
|
||||
// There are six course-level file areas and no modules in this course.
|
||||
// There are seven course-level file areas available to teachers with default caps and no modules in this course.
|
||||
$allchildren = $fileinfo->get_children();
|
||||
$this->assertEquals(6, count($allchildren));
|
||||
$this->assertEquals(7, count($allchildren));
|
||||
$modulechildren = array_filter($allchildren, function($a) {
|
||||
return $a instanceof file_info_context_module;
|
||||
});
|
||||
|
@ -4623,7 +4623,8 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null, $offlin
|
||||
// Backup files that were generated by the automated backup systems.
|
||||
|
||||
require_login($course);
|
||||
require_capability('moodle/site:config', $context);
|
||||
require_capability('moodle/backup:downloadfile', $context);
|
||||
require_capability('moodle/restore:userinfo', $context);
|
||||
|
||||
$filename = array_pop($args);
|
||||
$filepath = $args ? '/'.implode('/', $args).'/' : '/';
|
||||
|
Loading…
x
Reference in New Issue
Block a user