mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
Merge branch 'MDL-36985-master' of https://github.com/snake/moodle
This commit is contained in:
commit
474c7ee757
@ -29,4 +29,5 @@ $string['managefiles'] = 'Manage files';
|
||||
$string['missingfiles'] = 'Missing files';
|
||||
$string['pluginname'] = 'Manage files';
|
||||
$string['unusedfilesdesc'] = 'The following embedded files are not used in the text area:';
|
||||
$string['unusedfilesremovalnotice'] = 'Any unused files will be automatically deleted when saving changes.';
|
||||
$string['unusedfilesheader'] = 'Unused files';
|
||||
|
@ -55,7 +55,8 @@ function atto_managefiles_params_for_js($elementid, $options, $fpoptions) {
|
||||
|
||||
if (!$disabled) {
|
||||
$params['usercontext'] = context_user::instance($USER->id)->id;
|
||||
foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types') as $key) {
|
||||
foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types',
|
||||
'removeorphaneddrafts') as $key) {
|
||||
if (isset($options[$key])) {
|
||||
if ($key === 'context' && is_object($options[$key])) {
|
||||
// Just context id is enough.
|
||||
|
@ -35,6 +35,7 @@ $return_types = optional_param('return_types', null, PARAM_INT);
|
||||
$areamaxbytes = optional_param('areamaxbytes', FILE_AREA_MAX_BYTES_UNLIMITED, PARAM_INT);
|
||||
$contextid = optional_param('context', SYSCONTEXTID, PARAM_INT);
|
||||
$elementid = optional_param('elementid', '', PARAM_TEXT);
|
||||
$removeorphaneddrafts = optional_param('removeorphaneddrafts', 0, PARAM_INT);
|
||||
|
||||
$context = context::instance_by_id($contextid);
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
@ -75,7 +76,7 @@ $options = array(
|
||||
'accepted_types' => $accepted_types,
|
||||
'areamaxbytes' => $areamaxbytes,
|
||||
'return_types' => $return_types,
|
||||
'context' => $context,
|
||||
'context' => $context
|
||||
);
|
||||
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
@ -87,8 +88,8 @@ foreach ($files as $file) {
|
||||
}
|
||||
|
||||
$mform = new atto_managefiles_manage_form(null,
|
||||
array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames, 'elementid' => $elementid),
|
||||
'post', '', array('id' => 'atto_managefiles_manageform'));
|
||||
array('options' => $options, 'draftitemid' => $itemid, 'files' => $filenames, 'elementid' => $elementid,
|
||||
'removeorphaneddrafts' => $removeorphaneddrafts), 'post', '', array('id' => 'atto_managefiles_manageform'));
|
||||
|
||||
if ($data = $mform->get_data()) {
|
||||
if (!empty($data->deletefile)) {
|
||||
|
@ -47,6 +47,7 @@ class atto_managefiles_manage_form extends moodleform {
|
||||
$elementid = $this->_customdata['elementid'];
|
||||
$options = $this->_customdata['options'];
|
||||
$files = $this->_customdata['files'];
|
||||
$removeorphaneddrafts = $this->_customdata['removeorphaneddrafts'];
|
||||
|
||||
$mform->addElement('header', 'filemanagerhdr', get_string('filemanager', 'atto_managefiles'));
|
||||
|
||||
@ -69,6 +70,12 @@ class atto_managefiles_manage_form extends moodleform {
|
||||
|
||||
$mform->addElement('filemanager', 'files_filemanager', '', null, $options);
|
||||
|
||||
// Let the user know that any drafts not referenced in the text will be removed automatically.
|
||||
if ($removeorphaneddrafts) {
|
||||
$mform->addElement('static', '', '',
|
||||
html_writer::tag('div', get_string('unusedfilesremovalnotice', 'atto_managefiles')));
|
||||
}
|
||||
|
||||
$mform->addElement('header', 'missingfileshdr', get_string('missingfiles', 'atto_managefiles'));
|
||||
$mform->addElement('static', '', '',
|
||||
html_writer::tag('div',
|
||||
|
@ -237,6 +237,9 @@ function file_postupdate_standard_editor($data, $field, array $options, $context
|
||||
if (!isset($options['maxbytes'])) {
|
||||
$options['maxbytes'] = 0; // unlimited
|
||||
}
|
||||
if (!isset($options['removeorphaneddrafts'])) {
|
||||
$options['removeorphaneddrafts'] = false; // Don't remove orphaned draft files by default.
|
||||
}
|
||||
|
||||
if ($options['trusttext']) {
|
||||
$data->{$field.'trust'} = trusttext_trusted($context);
|
||||
@ -249,6 +252,10 @@ function file_postupdate_standard_editor($data, $field, array $options, $context
|
||||
if ($options['maxfiles'] == 0 or is_null($filearea) or is_null($itemid) or empty($editor['itemid'])) {
|
||||
$data->{$field} = $editor['text'];
|
||||
} else {
|
||||
// Clean the user drafts area of any files not referenced in the editor text.
|
||||
if ($options['removeorphaneddrafts']) {
|
||||
file_remove_editor_orphaned_files($editor);
|
||||
}
|
||||
$data->{$field} = file_save_draft_area_files($editor['itemid'], $context->id, $component, $filearea, $itemid, $options, $editor['text'], $options['forcehttps']);
|
||||
}
|
||||
$data->{$field.'format'} = $editor['format'];
|
||||
@ -792,6 +799,38 @@ function file_restore_source_field_from_draft_file($storedfile) {
|
||||
}
|
||||
return $storedfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes those files from the user drafts filearea which are not referenced in the editor text.
|
||||
*
|
||||
* @param stdClass $editor The online text editor element from the submitted form data.
|
||||
*/
|
||||
function file_remove_editor_orphaned_files($editor) {
|
||||
global $CFG, $USER;
|
||||
|
||||
// Find those draft files included in the text, and generate their hashes.
|
||||
$context = context_user::instance($USER->id);
|
||||
$baseurl = $CFG->wwwroot . '/draftfile.php/' . $context->id . '/user/draft/' . $editor['itemid'] . '/';
|
||||
$pattern = "/" . preg_quote($baseurl, '/') . "(.+?)[\?\"']/";
|
||||
preg_match_all($pattern, $editor['text'], $matches);
|
||||
$usedfilehashes = [];
|
||||
foreach ($matches[1] as $matchedfilename) {
|
||||
$matchedfilename = urldecode($matchedfilename);
|
||||
$usedfilehashes[] = \file_storage::get_pathname_hash($context->id, 'user', 'draft', $editor['itemid'], '/',
|
||||
$matchedfilename);
|
||||
}
|
||||
|
||||
// Now, compare the hashes of all draft files, and remove those which don't match used files.
|
||||
$fs = get_file_storage();
|
||||
$files = $fs->get_area_files($context->id, 'user', 'draft', $editor['itemid'], 'id', false);
|
||||
foreach ($files as $file) {
|
||||
$tmphash = $file->get_pathnamehash();
|
||||
if (!in_array($tmphash, $usedfilehashes)) {
|
||||
$file->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves files from a draft file area to a real one (merging the list of files).
|
||||
* Can rewrite URLs in some content at the same time if desired.
|
||||
|
@ -58,7 +58,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element implements templatab
|
||||
/** @var array options provided to initalize filepicker */
|
||||
protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
|
||||
'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
|
||||
'return_types' => 15, 'enable_filemanagement' => true);
|
||||
'return_types' => 15, 'enable_filemanagement' => true, 'removeorphaneddrafts' => false);
|
||||
// 15 is $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE | FILE_CONTROLLED_LINK.
|
||||
|
||||
/** @var array values for editor */
|
||||
|
@ -1340,6 +1340,51 @@ EOF;
|
||||
$this->assertEquals(0, $fileinfo['foldercount']); // No subdirectories inside the directory.
|
||||
$this->assertEquals($file->get_filesize(), $fileinfo['filesize_without_references']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test confirming that draft files not referenced in the editor text are removed.
|
||||
*/
|
||||
public function test_file_remove_editor_orphaned_files() {
|
||||
global $USER, $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create three draft files.
|
||||
$filerecord = ['filename' => 'file1.png'];
|
||||
$file = self::create_draft_file($filerecord);
|
||||
$draftitemid = $file->get_itemid();
|
||||
|
||||
$filerecord['itemid'] = $draftitemid;
|
||||
|
||||
$filerecord['filename'] = 'file2.png';
|
||||
self::create_draft_file($filerecord);
|
||||
|
||||
$filerecord['filename'] = 'file 3.png';
|
||||
self::create_draft_file($filerecord);
|
||||
|
||||
// Confirm the user drafts area lists 3 files.
|
||||
$fs = get_file_storage();
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
|
||||
$this->assertCount(3, $draftfiles);
|
||||
|
||||
// Now, spoof some editor text content, referencing 2 of the files; one requiring name encoding, one not.
|
||||
$editor = [
|
||||
'itemid' => $draftitemid,
|
||||
'text' => '
|
||||
<img src="'.$CFG->wwwroot.'/draftfile.php/'.$usercontext->id.'/user/draft/'.$draftitemid.'/file%203.png" alt="">
|
||||
<img src="'.$CFG->wwwroot.'/draftfile.php/'.$usercontext->id.'/user/draft/'.$draftitemid.'/file1.png" alt="">'
|
||||
];
|
||||
|
||||
// Run the remove orphaned drafts function and confirm that only the referenced files remain in the user drafts.
|
||||
$expected = ['file1.png', 'file 3.png']; // The drafts we expect will not be removed (are referenced in the online text).
|
||||
file_remove_editor_orphaned_files($editor);
|
||||
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'itemid', 0);
|
||||
$this->assertCount(2, $draftfiles);
|
||||
foreach ($draftfiles as $file) {
|
||||
$this->assertContains($file->get_filename(), $expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,12 +169,13 @@ class assign_submission_onlinetext extends assign_submission_plugin {
|
||||
* @return array
|
||||
*/
|
||||
private function get_edit_options() {
|
||||
$editoroptions = array(
|
||||
'noclean' => false,
|
||||
'maxfiles' => EDITOR_UNLIMITED_FILES,
|
||||
'maxbytes' => $this->assignment->get_course()->maxbytes,
|
||||
'context' => $this->assignment->get_context(),
|
||||
'return_types' => (FILE_INTERNAL | FILE_EXTERNAL | FILE_CONTROLLED_LINK)
|
||||
$editoroptions = array(
|
||||
'noclean' => false,
|
||||
'maxfiles' => EDITOR_UNLIMITED_FILES,
|
||||
'maxbytes' => $this->assignment->get_course()->maxbytes,
|
||||
'context' => $this->assignment->get_context(),
|
||||
'return_types' => (FILE_INTERNAL | FILE_EXTERNAL | FILE_CONTROLLED_LINK),
|
||||
'removeorphaneddrafts' => true // Whether or not to remove any draft files which aren't referenced in the text.
|
||||
);
|
||||
return $editoroptions;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user