diff --git a/lang/en/repository.php b/lang/en/repository.php index a8b62a74fa6..f14ef53a754 100644 --- a/lang/en/repository.php +++ b/lang/en/repository.php @@ -120,7 +120,7 @@ $string['filepicker'] = 'File picker'; $string['filesizenull'] = 'File size cannot be determined'; $string['folderexists'] = 'Folder name already being used, please use another name'; $string['foldernotfound'] = 'Folder not found'; -$string['folderrecurse'] = 'Folder can not be moved to it\s own subfolder'; +$string['folderrecurse'] = 'Folder can not be moved to it\'s own subfolder'; $string['getfile'] = 'Select this file'; $string['hidden'] = 'Hidden'; $string['help'] = 'Help'; diff --git a/repository/draftfiles_ajax.php b/repository/draftfiles_ajax.php index 3f08b80b660..d962cd8d1a4 100644 --- a/repository/draftfiles_ajax.php +++ b/repository/draftfiles_ajax.php @@ -125,90 +125,33 @@ switch ($action) { // Allows to Rename file, move it to another directory, change it's license and author information in one request $filename = required_param('filename', PARAM_FILE); $filepath = required_param('filepath', PARAM_PATH); - - $fs = get_file_storage(); - if (!($file = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, $filename))) { - die(json_encode((object)array('error' => get_string('filenotfound', 'error')))); - } - $updatedata = array(); - $updatedata['filename'] = $newfilename = optional_param('newfilename', $file->get_filename(), PARAM_FILE); - $updatedata['filepath'] = $newfilepath = optional_param('newfilepath', $file->get_filepath(), PARAM_PATH); - $updatedata['license'] = optional_param('newlicense', $file->get_license(), PARAM_TEXT); - $updatedata['author'] = optional_param('newauthor', $file->get_author(), PARAM_TEXT); - foreach ($updatedata as $key => $value) { - if (''.$value === ''.$file->{'get_'.$key}()) { - unset($updatedata[$key]); - } + $updatedata['filename'] = optional_param('newfilename', $filename, PARAM_FILE); + $updatedata['filepath'] = $newfilepath = optional_param('newfilepath', $filepath, PARAM_PATH); + if (($v = optional_param('newlicense', false, PARAM_TEXT)) !== false) { + $updatedata['license'] = $v; } - - if (!empty($updatedata)) { - if (array_key_exists('filename', $updatedata) || array_key_exists('filepath', $updatedata)) { - // check that target file name does not exist - if ($fs->file_exists($user_context->id, 'user', 'draft', $draftid, $newfilepath, $newfilename)) { - die(json_encode((object)array('error' => get_string('fileexists', 'repository')))); - } - $file->rename($newfilepath, $newfilename); - } - if (array_key_exists('license', $updatedata)) { - $file->set_license($updatedata['license']); - } - if (array_key_exists('author', $updatedata)) { - $file->set_author($updatedata['author']); - } - $changes = array_diff(array_keys($updatedata), array('filepath')); - if (!empty($changes)) { - // any change except for the moving to another folder alters 'Date modified' of the file - $file->set_timemodified(time()); - } + if (($v = optional_param('newauthor', false, PARAM_TEXT)) !== false) { + $updatedata['author'] = $v; + } + try { + repository::update_draftfile($draftid, $filepath, $filename, $updatedata); + } catch (moodle_exception $e) { + die(json_encode((object)array('error' => $e->getMessage()))); } - die(json_encode((object)array('filepath' => $newfilepath))); case 'updatedir': $filepath = required_param('filepath', PARAM_PATH); - $fs = get_file_storage(); - if (!$dir = $fs->get_file($user_context->id, 'user', 'draft', $draftid, $filepath, '.')) { - die(json_encode((object)array('error' => get_string('foldernotfound', 'repository')))); - } - $parts = explode('/', trim($dir->get_filepath(), '/')); - $dirname = end($parts); $newdirname = required_param('newdirname', PARAM_FILE); $parent = required_param('newfilepath', PARAM_PATH); $newfilepath = clean_param($parent . '/' . $newdirname . '/', PARAM_PATH); - if ($newfilepath == $filepath) { - // no action required - die(json_encode((object)array('filepath' => $parent))); + try { + repository::update_draftfile($draftid, $filepath, '.', array('filepath' => $newfilepath)); + } catch (moodle_exception $e) { + die(json_encode((object)array('error' => $e->getMessage()))); } - if ($fs->get_directory_files($user_context->id, 'user', 'draft', $draftid, $newfilepath, true)) { - //bad luck, we can not rename if something already exists there - die(json_encode((object)array('error' => get_string('folderexists', 'repository')))); - } - $xfilepath = preg_quote($filepath, '|'); - if (preg_match("|^$xfilepath|", $parent)) { - // we can not move folder to it's own subfolder - die(json_encode((object)array('error' => get_string('folderrecurse', 'repository')))); - } - - //we must update directory and all children too - $files = $fs->get_area_files($user_context->id, 'user', 'draft', $draftid); - foreach ($files as $file) { - if (!preg_match("|^$xfilepath|", $file->get_filepath())) { - continue; - } - // move one by one - $path = preg_replace("|^$xfilepath|", $newfilepath, $file->get_filepath()); - if ($dirname !== $newdirname && $file->get_filepath() === $filepath && $file->get_filename() === '.') { - // this is the main directory we move/rename AND it has actually been renamed - $file->set_timemodified(time()); - } - $file->rename($path, $file->get_filename()); - } - - $return = new stdClass(); - $return->filepath = $parent; - echo json_encode($return); - die; + die(json_encode((object)array('filepath' => $parent))); case 'zip': $filepath = required_param('filepath', PARAM_PATH); diff --git a/repository/draftfiles_manager.php b/repository/draftfiles_manager.php index e398b5340d3..cc096419fd7 100644 --- a/repository/draftfiles_manager.php +++ b/repository/draftfiles_manager.php @@ -122,14 +122,7 @@ case 'renameform': break; case 'rename': - - if ($fs->file_exists($user_context->id, 'user', 'draft', $itemid, $draftpath, $newfilename)) { - print_error('fileexists'); - } else if ($file = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $draftpath, $filename)) { - $newfile = $fs->create_file_from_storedfile(array('filename'=>$newfilename), $file); - $file->delete(); - } - + repository::update_draftfile($itemid, $draftpath, $filename, array('filename' => $newfilename)); $home_url->param('action', 'browse'); $home_url->param('draftpath', $draftpath); redirect($home_url); @@ -194,15 +187,7 @@ case 'unzip': case 'movefile': if (!empty($targetpath)) { - if ($fs->file_exists($user_context->id, 'user', 'draft', $itemid, $targetpath, $filename)) { - print_error('cannotmovefile'); - } else if ($file = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $draftpath, $filename)) { - $newfile = $fs->create_file_from_storedfile(array('filepath'=>$targetpath), $file); - $file->delete(); - } else { - var_dump('cannot find file'); - die; - } + repository::update_draftfile($itemid, $draftpath, $filename, array('filepath' => $targetpath)); $home_url->param('action', 'browse'); $home_url->param('draftpath', $targetpath); redirect($home_url); diff --git a/repository/lib.php b/repository/lib.php index a12396ae5b9..0e28f1c3fa8 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -2574,6 +2574,102 @@ abstract class repository implements cacheable_object { return false; } + /** + * Updates a file in draft filearea. + * + * This function can only update fields filepath, filename, author, license. + * If anything (except filepath) is updated, timemodified is set to current time. + * If filename or filepath is updated the file unconnects from it's origin + * and therefore all references to it will be converted to copies when + * filearea is saved. + * + * @param int $draftid + * @param string $filepath path to the directory containing the file, or full path in case of directory + * @param string $filename name of the file, or '.' in case of directory + * @param array $updatedata array of fields to change (only filename, filepath, license and/or author can be updated) + * @throws moodle_exception if for any reason file can not be updated (file does not exist, target already exists, etc.) + */ + public static function update_draftfile($draftid, $filepath, $filename, $updatedata) { + global $USER; + $fs = get_file_storage(); + $usercontext = context_user::instance($USER->id); + // make sure filename and filepath are present in $updatedata + $updatedata = $updatedata + array('filepath' => $filepath, 'filename' => $filename); + $filemodified = false; + if (!$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftid, $filepath, $filename)) { + if ($filename === '.') { + throw new moodle_exception('foldernotfound', 'repository'); + } else { + throw new moodle_exception('filenotfound', 'error'); + } + } + if (!$file->is_directory()) { + // This is a file + if ($updatedata['filepath'] !== $filepath || $updatedata['filename'] !== $filename) { + // Rename/move file: check that target file name does not exist. + if ($fs->file_exists($usercontext->id, 'user', 'draft', $draftid, $updatedata['filepath'], $updatedata['filename'])) { + throw new moodle_exception('fileexists', 'repository'); + } + if (($filesource = @unserialize($file->get_source())) && isset($filesource->original)) { + unset($filesource->original); + $file->set_source(serialize($filesource)); + } + $file->rename($updatedata['filepath'], $updatedata['filename']); + // timemodified is updated only when file is renamed and not updated when file is moved. + $filemodified = $filemodified || ($updatedata['filename'] !== $filename); + } + if (array_key_exists('license', $updatedata) && $updatedata['license'] !== $file->get_license()) { + // Update license and timemodified. + $file->set_license($updatedata['license']); + $filemodified = true; + } + if (array_key_exists('author', $updatedata) && $updatedata['author'] !== $file->get_author()) { + // Update author and timemodified. + $file->set_author($updatedata['author']); + $filemodified = true; + } + // Update timemodified: + if ($filemodified) { + $file->set_timemodified(time()); + } + } else { + // This is a directory - only filepath can be updated for a directory (it was moved). + if ($updatedata['filepath'] === $filepath) { + // nothing to update + return; + } + if ($fs->file_exists($usercontext->id, 'user', 'draft', $draftid, $updatedata['filepath'], '.')) { + // bad luck, we can not rename if something already exists there + throw new moodle_exception('folderexists', 'repository'); + } + $xfilepath = preg_quote($filepath, '|'); + if (preg_match("|^$xfilepath|", $updatedata['filepath'])) { + // we can not move folder to it's own subfolder + throw new moodle_exception('folderrecurse', 'repository'); + } + + // If directory changed the name, update timemodified. + $filemodified = (basename(rtrim($file->get_filepath(), '/')) !== basename(rtrim($updatedata['filepath'], '/'))); + + // Now update directory and all children. + $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftid); + foreach ($files as $f) { + if (preg_match("|^$xfilepath|", $f->get_filepath())) { + $path = preg_replace("|^$xfilepath|", $updatedata['filepath'], $f->get_filepath()); + if (($filesource = @unserialize($f->get_source())) && isset($filesource->original)) { + // unset original so the references are not shown any more + unset($filesource->original); + $f->set_source(serialize($filesource)); + } + $f->rename($path, $f->get_filename()); + if ($filemodified && $f->get_filepath() === $updatedata['filepath'] && $f->get_filename() === $filename) { + $f->set_timemodified(time()); + } + } + } + } + } + /** * Delete a temp file from draft area *