mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
MDL-33671 core: Allow for bulk delete of files
* Enable bulk delete in a details view * Behat tests for new functionality * Unit test for new function
This commit is contained in:
parent
d7374522ed
commit
2f03923602
@ -113,7 +113,8 @@ class core_files_renderer extends plugin_renderer_base {
|
||||
array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
|
||||
array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
|
||||
array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
|
||||
array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle')
|
||||
array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle'),
|
||||
['nofilesselected', 'repository'], ['confirmdeleteselectedfile', 'repository']
|
||||
)
|
||||
);
|
||||
if ($this->page->requires->should_create_one_time_item_now('core_file_managertemplate')) {
|
||||
|
@ -67,6 +67,7 @@ $string['configsyncfiletimeout'] = 'Timeout in seconds for synchronising the ext
|
||||
$string['configsyncimagetimeout'] = 'Timeout in seconds for downloading an image file from external repository during synchronisation.';
|
||||
$string['confirmdelete'] = 'Are you sure you want to delete the repository {$a}? If you choose "Continue and download", file references to external contents will be downloaded to Moodle. This could take a long time to process.';
|
||||
$string['confirmdeletefile'] = 'Are you sure you want to delete this file?';
|
||||
$string['confirmdeleteselectedfile'] = 'Are you sure you want to delete the selected {$a} file(s)?';
|
||||
$string['confirmrenamefile'] = 'Are you sure you want to rename/move this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
|
||||
$string['confirmdeletefilewithhref'] = 'Are you sure you want to delete this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
|
||||
$string['confirmdeletefolder'] = 'Are you sure you want to delete this folder? All files and subfolders will be deleted.';
|
||||
@ -97,6 +98,7 @@ $string['displaytree'] = 'Display folder as file tree';
|
||||
$string['download'] = 'Download';
|
||||
$string['downloadallfiles'] = 'Download all files';
|
||||
$string['downloadfolder'] = 'Download all';
|
||||
$string['deleteselected'] = 'Delete selected';
|
||||
$string['downloadsucc'] = 'The file has been downloaded successfully';
|
||||
$string['draftareanofiles'] = 'Cannot be downloaded because there is no files attached';
|
||||
$string['editrepositoryinstance'] = 'Edit repository instance';
|
||||
@ -174,6 +176,7 @@ $string['newfoldername'] = 'New folder name';
|
||||
$string['noenter'] = 'Nothing entered';
|
||||
$string['nofilesattached'] = 'No files attached';
|
||||
$string['nofilesavailable'] = 'No files available';
|
||||
$string['nofilesselected'] = 'No files selected';
|
||||
$string['nomorefiles'] = 'No more attachments allowed';
|
||||
$string['nopathselected'] = 'No destination path select yet (double click tree node to select)';
|
||||
$string['nopermissiontoaccess'] = 'No permission to access this repository.';
|
||||
|
@ -273,6 +273,7 @@ M.form_filemanager.init = function(Y, options) {
|
||||
var button_download = this.filemanager.one('.fp-btn-download');
|
||||
var button_create = this.filemanager.one('.fp-btn-mkdir');
|
||||
var button_addfile = this.filemanager.one('.fp-btn-add');
|
||||
var buttonDeleteFile = this.filemanager.one('.fp-btn-delete');
|
||||
|
||||
// setup 'add file' button
|
||||
button_addfile.on('click', this.show_filepicker, this);
|
||||
@ -403,6 +404,54 @@ M.form_filemanager.init = function(Y, options) {
|
||||
});
|
||||
}, this);
|
||||
|
||||
buttonDeleteFile.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var dialogOptions = {};
|
||||
var markedForDeletion = this.filemanager.all('.mark-for-deletion:checked');
|
||||
var filenames = [];
|
||||
markedForDeletion.each(function(item) {
|
||||
var fileinfo = this.options.list.find(function(element) {
|
||||
return item.getData().fullname == element.fullname;
|
||||
});
|
||||
if (fileinfo && fileinfo != undefined) {
|
||||
filenames.push({
|
||||
filepath: fileinfo.filepath,
|
||||
filename: fileinfo.filename
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (!filenames.length) {
|
||||
this.print_msg(M.util.get_string('nofilesselected', 'repository'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
dialogOptions.scope = this;
|
||||
var params = {
|
||||
selected: Y.JSON.stringify(filenames)
|
||||
};
|
||||
dialogOptions.message = M.util.get_string('confirmdeleteselectedfile', 'repository', filenames.length);
|
||||
dialogOptions.callbackargs = [params];
|
||||
dialogOptions.callback = function(params) {
|
||||
this.request({
|
||||
action: 'deleteselected',
|
||||
scope: this,
|
||||
params: params,
|
||||
callback: function(id, obj, args) {
|
||||
// Do something here
|
||||
args.scope.filecount -= params.length;
|
||||
if (obj && obj.length) {
|
||||
args.scope.refresh(obj[0]);
|
||||
}
|
||||
if (typeof M.core_formchangechecker != 'undefined') {
|
||||
M.core_formchangechecker.set_form_changed();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
this.show_confirm_dialog(dialogOptions);
|
||||
}, this);
|
||||
|
||||
this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').
|
||||
on('click', function(e) {
|
||||
e.preventDefault();
|
||||
@ -569,6 +618,12 @@ M.form_filemanager.init = function(Y, options) {
|
||||
this.viewmode = 1;
|
||||
element_template = Y.Node.create(M.form_filemanager.templates.iconfilename);
|
||||
}
|
||||
|
||||
if (this.viewmode == 1 || this.viewmode == 2) {
|
||||
this.filemanager.one('.fp-btn-delete').addClass('d-none');
|
||||
} else {
|
||||
this.filemanager.one('.fp-btn-delete').removeClass('d-none');
|
||||
}
|
||||
var options = {
|
||||
viewmode : this.viewmode,
|
||||
appendonly : appendfiles != null,
|
||||
|
@ -49,6 +49,11 @@
|
||||
{{#pix}}a/download_all{{/pix}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="fp-btn-delete">
|
||||
<a role="button" title="{{#str}}deleteselected, repository{{/str}}" class="btn btn-secondary btn-sm" href="#">
|
||||
{{#pix}}i/trash{{/pix}}
|
||||
</a>
|
||||
</div>
|
||||
<span class="fp-img-downloading">
|
||||
<span class="sr-only">{{#str}}loadinghelp{{/str}}</span>
|
||||
{{#pix}}i/loading_small{{/pix}}
|
||||
|
@ -41,7 +41,7 @@ $action = required_param('action', PARAM_ALPHA);
|
||||
$draftid = required_param('itemid', PARAM_INT);
|
||||
$filepath = optional_param('filepath', '/', PARAM_PATH);
|
||||
|
||||
$user_context = context_user::instance($USER->id);
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
|
||||
echo $OUTPUT->header(); // send headers
|
||||
|
||||
@ -73,7 +73,7 @@ switch ($action) {
|
||||
$newdirname = required_param('newdirname', PARAM_FILE);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$fs->create_directory($user_context->id, 'user', 'draft', $draftid, file_correct_filepath(file_correct_filepath($filepath).$newdirname));
|
||||
$fs->create_directory($usercontext->id, 'user', 'draft', $draftid, file_correct_filepath(file_correct_filepath($filepath).$newdirname));
|
||||
$return = new stdClass();
|
||||
$return->filepath = $filepath;
|
||||
echo json_encode($return);
|
||||
@ -82,31 +82,28 @@ switch ($action) {
|
||||
case 'delete':
|
||||
$filename = required_param('filename', PARAM_FILE);
|
||||
$filepath = required_param('filepath', PARAM_PATH);
|
||||
$selectedfile = (object)[
|
||||
'filename' => $filename,
|
||||
'filepath' => $filepath
|
||||
];
|
||||
$return = repository_delete_selected_files($usercontext, 'user', 'draft', $draftid, [$selectedfile]);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$filepath = file_correct_filepath($filepath);
|
||||
$return = new stdClass();
|
||||
if ($stored_file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, $filename)) {
|
||||
$parent_path = $stored_file->get_parent_directory()->get_filepath();
|
||||
if ($stored_file->is_directory()) {
|
||||
$files = $fs->get_directory_files($user_context->id, 'user', 'draft', $draftid, $filepath, true);
|
||||
foreach ($files as $file) {
|
||||
$file->delete();
|
||||
}
|
||||
$stored_file->delete();
|
||||
$return->filepath = $parent_path;
|
||||
echo json_encode($return);
|
||||
} else {
|
||||
if($result = $stored_file->delete()) {
|
||||
$return->filepath = $parent_path;
|
||||
echo json_encode($return);
|
||||
} else {
|
||||
echo json_encode(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo json_encode(false);
|
||||
if ($return) {
|
||||
$response = new stdClass();
|
||||
$response->filepath = array_keys($return)[0];
|
||||
echo json_encode($response);
|
||||
die;
|
||||
}
|
||||
|
||||
echo json_encode(false);
|
||||
die;
|
||||
|
||||
case 'deleteselected':
|
||||
$selected = required_param('selected', PARAM_RAW);
|
||||
$return = [];
|
||||
$selectedfiles = json_decode($selected);
|
||||
$return = repository_delete_selected_files($usercontext, 'user', 'draft', $draftid, $selectedfiles);
|
||||
echo (json_encode($return ? array_keys($return) : false));
|
||||
die;
|
||||
|
||||
case 'setmainfile':
|
||||
@ -115,9 +112,9 @@ switch ($action) {
|
||||
|
||||
$filepath = file_correct_filepath($filepath);
|
||||
// reset sort order
|
||||
file_reset_sortorder($user_context->id, 'user', 'draft', $draftid);
|
||||
file_reset_sortorder($usercontext->id, 'user', 'draft', $draftid);
|
||||
// set main file
|
||||
$return = file_set_sortorder($user_context->id, 'user', 'draft', $draftid, $filepath, $filename, 1);
|
||||
$return = file_set_sortorder($usercontext->id, 'user', 'draft', $draftid, $filepath, $filename, 1);
|
||||
echo json_encode($return);
|
||||
die;
|
||||
|
||||
@ -159,7 +156,7 @@ switch ($action) {
|
||||
$zipper = get_file_packer('application/zip');
|
||||
$fs = get_file_storage();
|
||||
|
||||
$file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, '.');
|
||||
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, '.');
|
||||
|
||||
$parent_path = $file->get_parent_directory()->get_filepath();
|
||||
|
||||
@ -167,7 +164,7 @@ switch ($action) {
|
||||
$filepath = array_pop($filepath);
|
||||
$zipfile = repository::get_unused_filename($draftid, $parent_path, $filepath . '.zip');
|
||||
|
||||
if ($newfile = $zipper->archive_to_storage(array($filepath => $file), $user_context->id, 'user', 'draft', $draftid, $parent_path, $zipfile, $USER->id)) {
|
||||
if ($newfile = $zipper->archive_to_storage([$filepath => $file], $usercontext->id, 'user', 'draft', $draftid, $parent_path, $zipfile, $USER->id)) {
|
||||
$return = new stdClass();
|
||||
$return->filepath = $parent_path;
|
||||
echo json_encode($return);
|
||||
@ -187,7 +184,7 @@ switch ($action) {
|
||||
die;
|
||||
}
|
||||
|
||||
$stored_file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, '.');
|
||||
$stored_file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, '.');
|
||||
if ($filepath === '/') {
|
||||
$filename = get_string('files').'.zip';
|
||||
} else {
|
||||
@ -197,7 +194,7 @@ switch ($action) {
|
||||
|
||||
// archive compressed file to an unused draft area
|
||||
$newdraftitemid = file_get_unused_draft_itemid();
|
||||
if ($newfile = $zipper->archive_to_storage(array('/' => $stored_file), $user_context->id, 'user', 'draft', $newdraftitemid, '/', $filename, $USER->id)) {
|
||||
if ($newfile = $zipper->archive_to_storage(['/' => $stored_file], $usercontext->id, 'user', 'draft', $newdraftitemid, '/', $filename, $USER->id)) {
|
||||
$return = new stdClass();
|
||||
$return->fileurl = moodle_url::make_draftfile_url($newdraftitemid, '/', $filename)->out();
|
||||
$return->filepath = $filepath;
|
||||
@ -215,15 +212,15 @@ switch ($action) {
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
$file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
|
||||
// Find unused name for directory to extract the archive.
|
||||
$temppath = $fs->get_unused_dirname($user_context->id, 'user', 'draft', $draftid, $filepath. pathinfo($filename, PATHINFO_FILENAME). '/');
|
||||
$temppath = $fs->get_unused_dirname($usercontext->id, 'user', 'draft', $draftid, $filepath. pathinfo($filename, PATHINFO_FILENAME). '/');
|
||||
$donotremovedirs = array();
|
||||
$doremovedirs = array($temppath);
|
||||
// Extract archive and move all files from $temppath to $filepath
|
||||
if ($file->extract_to_storage($zipper, $user_context->id, 'user', 'draft', $draftid, $temppath, $USER->id) !== false) {
|
||||
$extractedfiles = $fs->get_directory_files($user_context->id, 'user', 'draft', $draftid, $temppath, true);
|
||||
if ($file->extract_to_storage($zipper, $usercontext->id, 'user', 'draft', $draftid, $temppath, $USER->id) !== false) {
|
||||
$extractedfiles = $fs->get_directory_files($usercontext->id, 'user', 'draft', $draftid, $temppath, true);
|
||||
$xtemppath = preg_quote($temppath, '|');
|
||||
foreach ($extractedfiles as $file) {
|
||||
$realpath = preg_replace('|^'.$xtemppath.'|', $filepath, $file->get_filepath());
|
||||
@ -231,7 +228,7 @@ switch ($action) {
|
||||
// Set the source to the extracted file to indicate that it came from archive.
|
||||
$file->set_source(serialize((object)array('source' => $filepath)));
|
||||
}
|
||||
if (!$fs->file_exists($user_context->id, 'user', 'draft', $draftid, $realpath, $file->get_filename())) {
|
||||
if (!$fs->file_exists($usercontext->id, 'user', 'draft', $draftid, $realpath, $file->get_filename())) {
|
||||
// File or directory did not exist, just move it.
|
||||
$file->rename($realpath, $file->get_filename());
|
||||
} else if (!$file->is_directory()) {
|
||||
@ -250,7 +247,7 @@ switch ($action) {
|
||||
}
|
||||
// Remove remaining temporary directories.
|
||||
foreach (array_diff($doremovedirs, $donotremovedirs) as $filepath) {
|
||||
if ($file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, '.')) {
|
||||
if ($file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, '.')) {
|
||||
$file->delete();
|
||||
}
|
||||
}
|
||||
@ -261,7 +258,7 @@ switch ($action) {
|
||||
$filepath = required_param('filepath', PARAM_PATH);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
if (!$file) {
|
||||
echo json_encode(false);
|
||||
} else {
|
||||
@ -275,7 +272,7 @@ switch ($action) {
|
||||
$filepath = required_param('filepath', PARAM_PATH);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, $filename);
|
||||
if (!$file) {
|
||||
echo json_encode(false);
|
||||
} else {
|
||||
|
@ -317,6 +317,16 @@ YUI.add('moodle-core_filepicker', function(Y) {
|
||||
// TODO add tooltip with o.data['title'] (o.value) or o.data['thumbnail_title']
|
||||
return el.getContent();
|
||||
}
|
||||
var formatCheckbox = function(o) {
|
||||
var el = Y.Node.create('<div/>');
|
||||
var checkbox = Y.Node.create('<input/>');
|
||||
checkbox.setAttribute('type', 'checkbox')
|
||||
.setAttribute('class', 'mark-for-deletion')
|
||||
.setAttribute('data-fullname', o.data.fullname);
|
||||
|
||||
el.appendChild(checkbox);
|
||||
return el.getContent();
|
||||
};
|
||||
/** sorting function for table view */
|
||||
var sortFoldersFirst = function(a, b, desc) {
|
||||
if (a.get('isfolder') && !b.get('isfolder')) {
|
||||
@ -331,6 +341,9 @@ YUI.add('moodle-core_filepicker', function(Y) {
|
||||
/** initialize table view */
|
||||
var initialize_table_view = function() {
|
||||
var cols = [
|
||||
{key: "", label: "<input type='checkbox' id='select-all'/>",
|
||||
allowHTML: true, formatter: formatCheckbox,
|
||||
sortable: false},
|
||||
{key: "displayname", label: M.util.get_string('name', 'moodle'), allowHTML: true, formatter: formatTitle,
|
||||
sortable: true, sortFn: sortFoldersFirst},
|
||||
{key: "datemodified", label: M.util.get_string('lastmodified', 'moodle'), allowHTML: true, formatter: formatValue,
|
||||
@ -350,7 +363,15 @@ YUI.add('moodle-core_filepicker', function(Y) {
|
||||
}
|
||||
Y.bind(callback, this)(e, record.getAttrs());
|
||||
}
|
||||
}, 'tr', options.callbackcontext, scope.tableview);
|
||||
}, 'tr td:not(:first-child)', options.callbackcontext, scope.tableview);
|
||||
scope.tableview.delegate('change', function(e) {
|
||||
e.preventDefault();
|
||||
if (e.target.get('checked')) {
|
||||
e.container.all('.mark-for-deletion').setAttribute('checked', true);
|
||||
} else {
|
||||
e.container.all('.mark-for-deletion').removeAttribute('checked');
|
||||
}
|
||||
}, '#select-all', options.callbackcontext, scope.tableview);
|
||||
if (options.rightclickcallback) {
|
||||
scope.tableview.delegate('contextmenu', function (e, tableview) {
|
||||
var record = tableview.getRecord(e.currentTarget.get('id'));
|
||||
|
@ -3209,3 +3209,43 @@ function initialise_filepicker($args) {
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to handle deletion of files.
|
||||
*
|
||||
* @param object $context The context where the delete is called
|
||||
* @param string $component component
|
||||
* @param string $filearea filearea
|
||||
* @param int $itemid the item id
|
||||
* @param array $files Array of files object with each item having filename/filepath as values
|
||||
* @return array $return Array of strings matching up to the parent directory of the deleted files
|
||||
* @throws coding_exception
|
||||
*/
|
||||
function repository_delete_selected_files($context, string $component, string $filearea, $itemid, array $files) {
|
||||
$fs = get_file_storage();
|
||||
$return = [];
|
||||
|
||||
foreach ($files as $selectedfile) {
|
||||
$filename = clean_filename($selectedfile->filename);
|
||||
$filepath = clean_param($selectedfile->filepath, PARAM_PATH);
|
||||
$filepath = file_correct_filepath($filepath);
|
||||
|
||||
if ($storedfile = $fs->get_file($context->id, $component, $filearea, $itemid, $filepath, $filename)) {
|
||||
$parentpath = $storedfile->get_parent_directory()->get_filepath();
|
||||
if ($storedfile->is_directory()) {
|
||||
$files = $fs->get_directory_files($context->id, $component, $filearea, $itemid, $filepath, true);
|
||||
foreach ($files as $file) {
|
||||
$file->delete();
|
||||
}
|
||||
$storedfile->delete();
|
||||
$return[$parentpath] = "";
|
||||
} else {
|
||||
if ($result = $storedfile->delete()) {
|
||||
$return[$parentpath] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -176,6 +176,38 @@ class behat_filepicker extends behat_base {
|
||||
$okbutton->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks for deletion the specified file or folder from the specified filemanager field.
|
||||
*
|
||||
* @Given /^I mark for deletion "(?P<file_or_folder_name_string>(?:[^"]|\\")*)" from filemanager$/
|
||||
* @throws ExpectationException Thrown by behat_base::find
|
||||
* @param string $name
|
||||
*/
|
||||
public function i_mark_for_deletion_from_filemanager($name) {
|
||||
$name = behat_context_helper::escape($name);
|
||||
$okbutton = $this->find('css', "input.mark-for-deletion[data-fullname=$name]");
|
||||
$okbutton->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes delete function and confirms delete
|
||||
*
|
||||
* @Given /^I confirm deletion$/
|
||||
* @throws ExpectationException Thrown by behat_base::find
|
||||
*/
|
||||
public function i_confirm_deletion() {
|
||||
$name = get_string('deleteselected');
|
||||
|
||||
// Execute the action.
|
||||
$okbutton = $this->find('css', "a[title='$name']");
|
||||
$okbutton->click();
|
||||
|
||||
// Yes, we are sure.
|
||||
// Using xpath + click instead of pressButton as 'Ok' it is a common string.
|
||||
$okbutton = $this->find('css', 'div.fp-dlg button.fp-dlg-butconfirm');
|
||||
$okbutton->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure user can see the exact number of elements (files in folders) in the filemanager.
|
||||
*
|
||||
|
@ -19,3 +19,42 @@ Feature: Delete files and folders from the file manager
|
||||
And I delete "Delete me" from "Files" filemanager
|
||||
And I press "Save changes"
|
||||
And I should not see "Delete me"
|
||||
|
||||
@javascript
|
||||
Scenario: Delete a file and a folder using bulk functionality (individually)
|
||||
Given I log in as "admin"
|
||||
And I follow "Manage private files"
|
||||
And I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager
|
||||
And I create "Delete me" folder in "Files" filemanager
|
||||
And I press "Save changes"
|
||||
And I follow "Manage private files"
|
||||
And I click on "[title='Display folder with file details']" "css_element"
|
||||
And I mark for deletion "empty.txt" from filemanager
|
||||
And I confirm deletion
|
||||
Then I should not see "empty.txt"
|
||||
And I press "Save changes"
|
||||
And I follow "Manage private files"
|
||||
Then I should not see "empty.txt"
|
||||
And I mark for deletion "Delete me" from filemanager
|
||||
And I confirm deletion
|
||||
Then I should not see "Delete me"
|
||||
And I press "Save changes"
|
||||
And I should not see "Delete me"
|
||||
|
||||
@javascript
|
||||
Scenario: Delete a file and a folder using bulk functionality (multiple)
|
||||
Given I log in as "admin"
|
||||
And I follow "Manage private files"
|
||||
And I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager
|
||||
And I create "Delete me" folder in "Files" filemanager
|
||||
And I press "Save changes"
|
||||
And I follow "Manage private files"
|
||||
And I click on "[title='Display folder with file details']" "css_element"
|
||||
And I mark for deletion "empty.txt" from filemanager
|
||||
And I mark for deletion "Delete me" from filemanager
|
||||
And I confirm deletion
|
||||
Then I should not see "Delete me"
|
||||
Then I should not see "empty.txt"
|
||||
And I press "Save changes"
|
||||
And I should not see "Delete me"
|
||||
Then I should not see "empty.txt"
|
||||
|
@ -154,6 +154,60 @@ class core_repositorylib_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
public function test_delete_selected_files() {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$this->setAdminUser();
|
||||
$fs = get_file_storage();
|
||||
|
||||
$draftitemid = file_get_unused_draft_itemid();
|
||||
$context = context_user::instance($USER->id);
|
||||
|
||||
$dummy = [
|
||||
'contextid' => $context->id,
|
||||
'component' => 'user',
|
||||
'filearea' => 'draft',
|
||||
'itemid' => $draftitemid,
|
||||
'filepath' => '/',
|
||||
'filename' => ''
|
||||
];
|
||||
|
||||
// Create some files.
|
||||
$existingfiles = [
|
||||
'The Matrix.movie',
|
||||
'Astalavista.txt',
|
||||
'foobar',
|
||||
];
|
||||
|
||||
$selectedfiles = [
|
||||
'The Matrix.movie' => [],
|
||||
'Astalavista.txt' => []
|
||||
];
|
||||
foreach ($existingfiles as $filename) {
|
||||
$dummy['filename'] = $filename;
|
||||
$file = $fs->create_file_from_string($dummy, 'Content of ' . $filename);
|
||||
if (array_key_exists($filename, $selectedfiles)) {
|
||||
$selectedfiles[$filename] = (object)[
|
||||
'filename' => $filename,
|
||||
'filepath' => $file->get_filepath()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Get area files with default options.
|
||||
$areafiles = $fs->get_area_files($context->id, 'user', 'draft', $draftitemid);
|
||||
// Should be the 3 files we added plus the folder.
|
||||
$this->assertEquals(4, count($areafiles));
|
||||
|
||||
repository_delete_selected_files($context, 'user', 'draft', $draftitemid, $selectedfiles);
|
||||
|
||||
$areafiles = $fs->get_area_files($context->id, 'user', 'draft', $draftitemid);
|
||||
// Should be the 1 file left plus the folder.
|
||||
$this->assertEquals(2, count($areafiles));
|
||||
}
|
||||
|
||||
public function test_can_be_edited_by_user() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
|
@ -553,6 +553,7 @@ a.ygtvspacer:hover {
|
||||
.filemanager.fm-maxfiles .fp-btn-add,
|
||||
.filemanager.fm-maxfiles .dndupload-message,
|
||||
.filemanager.fm-noitems .fp-btn-download,
|
||||
.filemanager.fm-noitems .fp-btn-delete,
|
||||
.filemanager .fm-empty-container,
|
||||
.filemanager.fm-noitems .filemanager-container .fp-content {
|
||||
display: none;
|
||||
|
@ -13930,6 +13930,7 @@ a.ygtvspacer:hover {
|
||||
.filemanager.fm-maxfiles .fp-btn-add,
|
||||
.filemanager.fm-maxfiles .dndupload-message,
|
||||
.filemanager.fm-noitems .fp-btn-download,
|
||||
.filemanager.fm-noitems .fp-btn-delete,
|
||||
.filemanager .fm-empty-container,
|
||||
.filemanager.fm-noitems .filemanager-container .fp-content {
|
||||
display: none; }
|
||||
|
@ -14145,6 +14145,7 @@ a.ygtvspacer:hover {
|
||||
.filemanager.fm-maxfiles .fp-btn-add,
|
||||
.filemanager.fm-maxfiles .dndupload-message,
|
||||
.filemanager.fm-noitems .fp-btn-download,
|
||||
.filemanager.fm-noitems .fp-btn-delete,
|
||||
.filemanager .fm-empty-container,
|
||||
.filemanager.fm-noitems .filemanager-container .fp-content {
|
||||
display: none; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user