Skip to content

Commit

Permalink
MDL-35429 backup: Only show relevant actions for automated backups
Browse files Browse the repository at this point in the history
- 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'.
  • Loading branch information
snake committed Oct 10, 2017
1 parent 54945fa commit 5bbea73
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 13 deletions.
3 changes: 3 additions & 0 deletions backup/backupfilesedit.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@

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);
Expand Down
50 changes: 37 additions & 13 deletions backup/util/ui/renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -573,27 +573,51 @@ public function render_backup_files_viewer(backup_files_viewer $viewer) {
$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;
}
Expand Down
29 changes: 29 additions & 0 deletions course/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
50 changes: 50 additions & 0 deletions course/tests/courselib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -4074,4 +4074,54 @@ public function test_course_require_view_participants_as_student_on_site() {
$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));
}
}

0 comments on commit 5bbea73

Please sign in to comment.