Skip to content
Snippets Groups Projects
Commit 5f82d725 authored by Moritz Strohm's avatar Moritz Strohm
Browse files

file/unzipquestion: allow unzipping of ZIP files in file system plugin file areas, re #2988

Merge request studip/studip!2007
parent 43d9d711
No related branches found
No related tags found
No related merge requests found
......@@ -74,6 +74,7 @@ class FileController extends AuthenticatedController
}
URLHelper::addLinkParam('from_plugin', Request::get('from_plugin'));
URLHelper::addLinkParam('to_plugin', Request::get('to_plugin'));
if (!$folder || !$folder->isWritable($GLOBALS['user']->id)) {
throw new AccessDeniedException();
......@@ -171,32 +172,58 @@ class FileController extends AuthenticatedController
public function unzipquestion_action()
{
$this->file_refs = FileRef::findMany(Request::getArray('file_refs'));
$this->file_ref = $this->file_refs[0];
$this->current_folder = $this->file_ref->folder->getTypedFolder();
$this->to_plugin = Request::get('to_plugin');
URLHelper::addLinkParam('to_plugin', $this->to_plugin);
$this->files = [];
if ($this->to_plugin) {
//Plugin file area.
$plugin = PluginManager::getInstance()->getPlugin($this->to_plugin);
if (!$plugin) {
throw new Trails_Exception(404, _('Plugin existiert nicht.'));
}
if (!($plugin instanceof FilesystemPlugin)) {
throw new Trails_Exception(400, _('Das Plugin ist kein Dateibereich-Plugin.'));
}
$file_ids = Request::getArray('file_refs');
foreach ($file_ids as $file_id) {
$file = $plugin->getPreparedFile($file_id);
if ($file instanceof FileType) {
$this->files[] = $file;
}
}
} else {
//Stud.IP file area.
$file_refs = FileRef::findMany(Request::getArray('file_refs'));
foreach ($file_refs as $file_ref) {
$this->files[] = $file_ref->getFileType();
}
}
$this->first_file = $this->files[0];
$this->current_folder = $this->first_file->getFolderType();
if (Request::isPost()) {
$changes = [];
if (Request::submitted('unzip')) {
//unzip!
$this->file_refs = FileArchiveManager::extractArchiveFileToFolder(
$this->file_ref,
$this->files = FileArchiveManager::extractArchiveFileToFolder(
$this->first_file,
$this->current_folder,
$GLOBALS['user']->id
);
$ref_ids = [];
foreach ($this->file_refs as $file_ref) {
$ref_ids[] = $file_ref->id;
foreach ($this->files as $file) {
$ref_ids[] = $file->getId();
}
//Delete the original zip file:
$changes['removed_files'] = [$this->file_ref->id];
$this->file_ref->delete();
$changes['removed_files'] = [$this->first_file->getId()];
$this->first_file->delete();
} else {
$ref_ids = [$this->file_ref->getId()];
$ref_ids = [$this->first_file->getId()];
}
$this->flash->set('file_refs', $ref_ids);
......@@ -213,23 +240,25 @@ class FileController extends AuthenticatedController
'add_folders' => [],
];
$added_folders = [];
foreach ($this->file_refs as $fileref) {
if ($fileref->folder->id === $this->current_folder->id) {
$payload['added_files'][] = FilesystemVueDataManager::getFileVueData($fileref->getFileType(), $this->current_folder);
foreach ($this->files as $file) {
$folder = $file->getFolderType();
if ($folder && $folder->getId() === $this->current_folder->getId()) {
$payload['added_files'][] = FilesystemVueDataManager::getFileVueData($file, $this->current_folder);
} elseif (
$fileref->folder->parentfolder->id === $this->current_folder->id
&& !in_array($fileref->folder->id, $added_folders)
$folder->getParent() &&
$folder->getParent()->getId() === $this->current_folder->getId()
&& !in_array($folder->getId(), $added_folders)
) {
if ($topFolder === null) {
$topFolder = $this->current_folder;
while ($topFolder->parentfolder !== null) {
$topFolder = $topFolder->parentFolder;
while ($topFolder->getParent() !== null) {
$topFolder = $topFolder->getParent();
}
}
$payload['added_folders'][] = FilesystemVueDataManager::getFolderVueData($fileref->getFolderType(), $this->current_folder);
$payload['added_folders'][] = FilesystemVueDataManager::getFolderVueData($folder, $this->current_folder);
$added_folders[] = $fileref->folder->id;
$added_folders[] = $folder->getId();
}
}
......@@ -378,7 +407,7 @@ class FileController extends AuthenticatedController
$force_save = Request::submitted('force_save');
$this->name = trim(Request::get('name'));
$this->description = Request::get('description');
$this->store_accessibility_flag($file_ref_id);
$this->store_accessibility_flag($this->file);
$this->content_terms_of_use_id = Request::get('content_terms_of_use_id');
......@@ -1570,17 +1599,48 @@ class FileController extends AuthenticatedController
}
}
public function edit_license_action($folder_id = null)
protected function loadFiles($param = 'files', $plugin = null, $with_blob = false)
{
$this->re_location = Request::get('re_location');
$file_ref_ids = Request::getArray('file_refs');
if (!$file_ref_ids) {
$result = [];
$file_ids = Request::getArray($param);
if (!$file_ids) {
//In case the file ref IDs are not set in the request
//they may still be set in the flash object of the controller:
$file_ref_ids = $this->flash->get('file_refs');
$file_ids = $this->flash->get($param);
}
if ($plugin instanceof FilesystemPlugin) {
foreach ($file_ids as $file_id) {
$file = $plugin->getPreparedFile($file_id);
if ($file instanceof FileType) {
$result[] = $file;
}
}
} else {
//Stud.IP core file system:
$file_refs = FileRef::findMany($file_ids);
foreach ($file_refs as $file_ref) {
$file = $file_ref->getFileType();
if ($file instanceof FileType) {
$result[] = $file;
}
}
}
$this->file_refs = FileRef::findMany($file_ref_ids);
$this->folder = $this->file_refs[0]->folder;
return $result;
}
public function edit_license_action($folder_id = null)
{
$this->re_location = Request::get('re_location');
$this->files = [];
$this->file = null;
$this->file_ref = null;
$this->plugin = null;
if (Request::submitted('to_plugin')) {
$this->plugin = PluginManager::getInstance()->getPlugin(Request::get('to_plugin'));
}
$this->files = $this->loadFiles('file_refs', $this->plugin);
$this->folder = $this->files[0]->getFolderType();
$this->show_description_field = Config::get()->ENABLE_DESCRIPTION_ENTRY_ON_UPLOAD;
if ($folder_id == 'bulk') {
$this->show_description_field = false;
......@@ -1589,51 +1649,54 @@ class FileController extends AuthenticatedController
if (Request::isPost()) {
CSRFProtection::verifyUnsafeRequest();
if (count($file_ref_ids) === 1) {
if (count($this->files) === 1) {
// store flag if file is an accessible file
$this->store_accessibility_flag($file_ref_ids[0]);
$this->store_accessibility_flag($this->files[0]);
}
if (($folder_id == 'bulk') && !Request::submitted('accept')) {
$file_ref_ids = Request::getArray('ids');
$this->file_refs = FileRef::findMany($file_ref_ids);
$this->files = $this->loadFiles('ids', $this->plugin);
} else {
$description = Request::get('description');
$success_files = [];
$error_files = [];
foreach ($this->file_refs as $file_ref) {
foreach ($this->files as $file) {
//Check if the user may change the license of the file:
$folder = $file_ref['folder'];
$folder = $file->getFolderType();
if (!$folder) {
//We have no way of determining whether the user may change
//the license.
$error_files[] = sprintf(_('Die Datei "%s" ist ungültig!'), $file_ref['name']);
$error_files[] = sprintf(_('Die Datei "%s" ist ungültig!'), $file['name']);
continue;
}
$file_ref['content_terms_of_use_id'] = Request::option('content_terms_of_use_id');
if ($this->show_description_field && $description) {
$file_ref['description'] = $description;
}
if ($file_ref->isDirty()) {
if ($file instanceof StandardFile) {
//Due to missing methods in the FileType interface,
//terms of use and the description can only be set
//for StandardFile instances.
$file_ref = $file->getFileRef();
$file_ref->content_terms_of_use_id = Request::option('content_terms_of_use_id');
if ($this->show_description_field && $description) {
$file_ref->description = $description;
}
if ($file_ref->store()) {
$success_files[] = $file_ref['name'];
$success_files[] = $file->getFilename();
} else {
$error_files[] = sprintf(_('Fehler beim Speichern der Datei "%s"!'), $file_ref['name']);
$error_files[] = sprintf(_('Fehler beim Speichern der Datei "%s"!'), $file['name']);
}
} else {
$success_files[] = $file_ref['name'];
}
$this->file = $file_ref->getFileType();
$this->current_folder = $file_ref->folder->getTypedFolder();
$this->file = $file;
if ($file instanceof StandardFile) {
$this->file_ref = $file->getFileRef();
}
$this->current_folder = $folder;
$this->marked_element_ids = [];
$payload['html'][] = FilesystemVueDataManager::getFileVueData($this->file, $this->current_folder);
}
if (Request::isXhr() && !$this->re_location) {
$payload = ['html' => []];
foreach ($this->file_refs as $file_ref) {
$folder = $file_ref->folder->getTypedFolder();
foreach ($this->files as $file) {
$folder = $file->getFolderType();
// Skip files not in current folder (during archive extract)
if ($folder_id && $folder_id !== $folder->getId()) {
......@@ -1641,31 +1704,34 @@ class FileController extends AuthenticatedController
}
$payload['html'][] = FilesystemVueDataManager::getFileVueData(
$file_ref->getFileType(),
$file_ref->folder->getTypedFolder()
$file,
$file->getFolderType()
);
}
$plugins = PluginManager::getInstance()->getPlugins('FileUploadHook');
$redirect = null;
foreach ($plugins as $plugin) {
$url = $plugin->getAdditionalUploadWizardPage($file_ref);
foreach ($plugins as $upload_hook_plugin) {
$url = $upload_hook_plugin->getAdditionalUploadWizardPage($file_ref);
if ($url) {
$redirect = $url;
break;
}
}
if (count($file_ref_ids) === 1) {
if (count($this->files) === 1) {
if (Config::get()->OERCAMPUS_ENABLED
&& Config::get()->OER_ENABLE_POST_UPLOAD
&& $GLOBALS['perm']->have_perm('tutor')
) {
if ($file_ref['content_terms_of_use_id'] === 'SELFMADE_NONPUB'
|| $file_ref['content_terms_of_use_id'] === 'FREE_LICENSE'
) {
$this->redirect('file/oer_post_upload/' . $file_ref['id']);
return;
if ($this->file instanceof StandardFile) {
$file_ref = $this->file->getFileRef();
if ($file_ref['content_terms_of_use_id'] === 'SELFMADE_NONPUB'
|| $file_ref['content_terms_of_use_id'] === 'FREE_LICENSE'
) {
$this->redirect('file/oer_post_upload/' . $file_ref['id']);
return;
}
}
}
}
......@@ -1677,15 +1743,15 @@ class FileController extends AuthenticatedController
$payload['url'] = $this->generateFilesUrl(
$this->folder,
$file_ref
$this->file
);
if ($folder_id == 'bulk' && $this->file_refs) {
if ($folder_id == 'bulk' && $this->files) {
if ($success_files) {
if (count($success_files) == 1) {
PageLayout::postSuccess(sprintf(
_('Die Lizenz der Datei "%s" wurde geändert.'),
htmlReady($this->file_refs[0]->name)
htmlReady($this->files[0]->getName())
));
} else {
sort($success_files);
......@@ -1699,7 +1765,7 @@ class FileController extends AuthenticatedController
if (count($error_files) == 1) {
PageLayout::postError(sprintf(
_('Die Lizenz der Datei "%s" konnte nicht geändert werden!'),
htmlReady($this->file_refs[0]->name)
htmlReady($this->files[0]->getName())
));
} else {
PageLayout::postError(
......@@ -1731,9 +1797,9 @@ class FileController extends AuthenticatedController
ngettext(
'Zusatzangaben und Lizenz wählen',
'Zusatzangaben und Lizenz auswählen: %s Dateien',
count($this->file_refs)
count($this->files)
),
count($this->file_refs)
count($this->files)
));
$this->licenses = ContentTermsOfUse::findBySQL("1 ORDER BY position ASC, id ASC");
......@@ -2224,7 +2290,7 @@ class FileController extends AuthenticatedController
{
require_once 'app/controllers/files.php';
return \FilesController::getRangeLink($folder) . '#fileref_' . $fileRef->id;
return \FilesController::getRangeLink($folder) . '#fileref_' . $fileRef->getId();
}
private function getFolderSize($folder): array
......@@ -2238,10 +2304,14 @@ class FileController extends AuthenticatedController
return [$folder_size, $folder_file_amount];
}
private function store_accessibility_flag($file_ref_id)
private function store_accessibility_flag(FileType $file)
{
$file_ref = FileRef::find($file_ref_id);
$file_ref->file['is_accessible'] = Request::get('is_accessible');
$file_ref->file->store();
if ($file instanceof StandardFile) {
$file_ref = $file->getFileRef();
if ($file_ref) {
$file_ref->file['is_accessible'] = Request::get('is_accessible');
$file_ref->file->store();
}
}
}
}
<form action="<?= $controller->link_for('file/edit_license', $origin_folder_id ?? null) ?>"
method="post" class="default" data-dialog="reload-on-close">
<input type="hidden" name="re_location" value="<?= htmlReady($re_location) ?>">
<? foreach ($file_refs as $file_ref) : ?>
<input type="hidden" name="file_refs[]" value="<?= htmlReady($file_ref->id) ?>">
<input type="hidden" name="to_plugin" value="<?= $plugin ? $plugin->getPluginName() : '' ?>">
<? foreach ($files as $file) : ?>
<input type="hidden" name="file_refs[]" value="<?= htmlReady($file->getId()) ?>">
<? endforeach ?>
......@@ -17,7 +18,7 @@
<? endif ?>
<? if (count($file_refs) === 1) : ?>
<? if (count($files) === 1) : ?>
<fieldset>
<legend><?= _('Barrierefreiheit') ?></legend>
<label>
......@@ -30,7 +31,7 @@
<?= $this->render_partial('file/_terms_of_use_select.php', [
'content_terms_of_use_entries' => $licenses,
'selected_terms_of_use_id' => $file_ref->content_terms_of_use_id
'selected_terms_of_use_id' => $file_ref->content_terms_of_use_id ?? ''
]) ?>
<footer data-dialog-button>
......
<form action="<?= $controller->url_for('file/unzipquestion') ?>" method="post" data-dialog>
<? foreach ($file_refs as $file_ref): ?>
<input type="hidden" name="file_refs[]" value="<?= htmlReady($file_ref->id) ?>">
<? foreach ($files as $file): ?>
<input type="hidden" name="file_refs[]" value="<?= htmlReady($file->getId()) ?>">
<? endforeach ?>
<?= Icon::create('unit-test', Icon::ROLE_INACTIVE)->asImg(120, ['style' => 'display: block; margin-left: auto; margin-right: auto;']) ?>
......
......@@ -828,7 +828,7 @@ class FileArchiveManager
* @param FolderType $target_folder The folder where the file shall be stored.
* @param User $user The user who wishes to extract the file from the archive.
*
* @return FileRef|null FileRef instance on success, null otherwise.
* @return FileType|null FileType instance on success, null otherwise.
*/
public static function extractFileFromArchive(
Studip\ZipArchive $archive,
......@@ -844,59 +844,62 @@ class FileArchiveManager
return null;
}
$file = new File();
$file->user_id = $user->id;
$file->name = $archive->convertArchiveFilename(basename($archive_path));
$file->mime_type = get_mime_type($file->name);
$file->size = $file_info['size'];
$file->store();
$studip_file = new File();
$studip_file->user_id = $user->id;
$studip_file->name = $archive->convertArchiveFilename(basename($archive_path));
$studip_file->mime_type = get_mime_type($studip_file->name);
$studip_file->size = $file_info['size'];
$studip_file->id = $studip_file->getNewId();
//$file->store();
// Ok, we have a file object in the database. Now we must connect
// it with the data file by extracting the data file into
// the place, where the file's content has to be placed.
$file_path = pathinfo($file->getPath(), PATHINFO_DIRNAME);
$file_dir = pathinfo($studip_file->getPath(), PATHINFO_DIRNAME);
$file_path = $file_dir . '/' . $studip_file->id;
// Create the directory for the file, if necessary:
if (!is_dir($file_path)) {
mkdir($file_path);
if (!is_dir($file_dir)) {
mkdir($file_dir);
}
// Ok, now we read all data from $file_resource and put it into
// the file's path:
if (file_put_contents($file->getPath(), $file_resource) === false) {
if (file_put_contents($file_path, $file_resource) === false) {
//Something went wrong: abort and clean up!
$file->delete();
//$file->delete();
return null;
}
// Ok, we now must create a FileRef:
// Ok, we now must create a File:
$file_ref = new FileRef();
$file_ref->file_id = $file->id;
$file_ref->file_id = $studip_file->id;
$file_ref->folder_id = $target_folder->getId();
$file_ref->user_id = $user->id;
$file_ref->name = $file->name;
if ($file_ref->store()) {
return $file_ref;
$file_ref->name = $studip_file->name;
$file_ref->file = $studip_file;
$file = new StandardFile($file_ref);
if ($saved_file = $target_folder->addFile($file, $user->id)) {
return $saved_file;
}
//Something went wrong: abort and clean up!
$file_ref->delete();
//Something went wrong:
return null;
}
/**
* Extracts an archive into a folder inside the Stud.IP file area.
*
* @param FileRef $archive_file_ref The archive file which shall be extracted.
* @param FileType $archive_file The archive file which shall be extracted.
* @param FolderType $folder The folder where the archive shall be extracted.
* @param string $user_id The ID of the user who wants to extract the archive.
*
* @return FileRef[] Array with extracted files, represented as FileRef objects.
* @return FileType[] Array with extracted files, represented as FileRef objects.
*/
public static function extractArchiveFileToFolder(
FileRef $archive_file_ref,
FileType $archive_file,
FolderType $folder,
$user_id = null
$user_id = null
)
{
$user = $user_id ? User::find($user_id) : User::findCurrent();
......@@ -913,11 +916,16 @@ class FileArchiveManager
$keep_hierarchy = $folder->isSubfolderAllowed($user->id);
$archive = new Studip\ZipArchive();
$archive->open($archive_file_ref->file->getPath());
$standard_archive_file = $archive_file->convertToStandardFile();
if (!($standard_archive_file instanceof StandardFile)) {
//Error converting the archive file.
return [];
}
$archive->open($standard_archive_file->getPath());
// loop over all entries in the zip archive and put each entry
// in the current folder or one of its subfolders:
$file_refs = [];
$files = [];
for ($i = 0; $i < $archive->numFiles; $i++) {
$entry_info = $archive->statIndex($i);
......@@ -972,19 +980,19 @@ class FileArchiveManager
//we extract one file:
//$entry_info['name'] is necessary because we need the full path
//to the entry inside the archive.
$file_ref = self::extractFileFromArchive(
$file = self::extractFileFromArchive(
$archive,
$entry_info['name'],
$extracted_entry_destination_folder,
$user
);
if ($file_ref instanceof FileRef) {
$file_refs[] = $file_ref;
if ($file instanceof FileType) {
$files[] = $file;
}
}
}
return $file_refs;
return $files;
}
}
......@@ -39,7 +39,7 @@ class StandardFile implements FileType, ArrayAccess, StandardFileInterface
$mime_type = $data['type'] ?: get_mime_type($data['name']);
$filesize = $data['size'] ?: filesize($data['tmp_name']);
$file_path = $data['tmp_name'];
$error_code = $data['error'];
$error_code = $data['error'] ?? '';
if ($error_code) {
//error handling
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment