* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @category Stud.IP * @since 4.0 */ class FileController extends AuthenticatedController { protected $allow_nobody = true; function validate_args(&$args, $types = NULL) { reset($args); } /** * This is a helper method that decides where a redirect shall be made * in case of error or success after an action was executed. */ public function redirectToFolder($folder) { switch ($folder->range_type) { case 'course': case 'institute': $this->relocate($folder->range_type . '/files/index/' . $folder->getId(), ['cid' => $folder->range_id]); break; case 'user': $this->relocate('files/index/' . $folder->getId(), ['cid' => null]); break; case 'Resource': $this->relocate( 'resources/resource/files/' . $folder->range_id . '/' . $folder->getId() ); break; default: //Plugins should not be available in the flat view. $this->relocate('files/system/' . $folder->range_type . '/' . $folder->getId(), ['cid' => null]); break; } } public function upload_window_action() { // just send the template } public function upload_action($folder_id) { if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/upload/") + strlen("dispatch.php/file/upload/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { $folder = FileManager::getTypedFolder($folder_id); } 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(); } if (Request::isPost()) { if (isset($_FILES['file']) && is_array($_FILES['file'])) { $validatedFiles = FileManager::handleFileUpload( $_FILES['file'], $folder, $GLOBALS['user']->id ); if (count($validatedFiles['error']) > 0) { $this->response->add_header( 'X-Filesystem-Changes', json_encode(['message' => null]) ); // error during upload: display error message: $this->render_json([ 'message' => (string) MessageBox::error( _('Beim Hochladen ist ein Fehler aufgetreten '), array_map('htmlready', $validatedFiles['error']) ), ]); return; } //all files were uploaded successfully: if (count($validatedFiles['files']) > 0) { PageLayout::postSuccess( sprintf( _('Es wurden %s Dateien hochgeladen'), count($validatedFiles['files']) ), array_map(function ($file) { return htmlReady($file->getFilename()); }, $validatedFiles['files']), true ); } } else { $this->response->add_header('X-Filesystem-Changes', json_encode(['message' => null])); $this->render_json([ 'message' => (string) MessageBox::error( _('Ein Systemfehler ist beim Upload aufgetreten.') ) ]); return; } if (Request::isXhr()) { $changes = ['added_files' => null]; $output = ['added_files' => []]; if (count($validatedFiles['files']) === 1 && strtolower(substr($validatedFiles['files'][0]->getFilename(), -4)) === '.zip' && ($folder->range_id === $GLOBALS['user']->id || Seminar_Perm::get()->have_studip_perm('tutor', $folder->range_id))) { $ref_ids = []; foreach ($validatedFiles['files'] as $file) { $ref_ids[] = $file->getId(); } $changes['redirect'] = $this->url_for('file/unzipquestion', [ 'file_refs' => $ref_ids ]); } elseif (in_array($folder->range_type, ['course', 'institute', 'user'])) { $ref_ids = []; foreach ($validatedFiles['files'] as $file) { $ref_ids[] = $file->getId(); } $changes['redirect'] = $this->url_for("file/edit_license/{$folder->getId()}", [ 'file_refs' => $ref_ids, ]); } elseif ($folder->range_type === 'Resource') { $changes['close_dialog'] = [ 'reload-on-close' => true ]; } else { $changes['close_dialog'] = true; } $this->current_folder = $folder; foreach ($validatedFiles['files'] as $file) { $output['added_files'][] = FilesystemVueDataManager::getFileVueData($file, $folder); } $this->response->add_header( 'X-Filesystem-Changes', json_encode($changes) ); $this->render_json($output); } } $this->folder_id = $folder_id; } public function unzipquestion_action() { $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->files = FileArchiveManager::extractArchiveFileToFolder( $this->first_file, $this->current_folder, $GLOBALS['user']->id ); $ref_ids = []; foreach ($this->files as $file) { $ref_ids[] = $file->getId(); } //Delete the original zip file: $changes['removed_files'] = [$this->first_file->getId()]; $this->first_file->delete(); } else { $ref_ids = [$this->first_file->getId()]; } $this->flash->set('file_refs', $ref_ids); if (Request::isXhr()) { $topFolder = null; $changes['redirect'] = $this->url_for("file/edit_license/{$this->current_folder->getId()}"); $changes['added_files'] = null; $changes['added_folders'] = null; $payload = [ 'add_files' => [], 'add_folders' => [], ]; $added_folders = []; 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 ( $folder->getParent() && $folder->getParent()->getId() === $this->current_folder->getId() && !in_array($folder->getId(), $added_folders) ) { if ($topFolder === null) { $topFolder = $this->current_folder; while ($topFolder->getParent() !== null) { $topFolder = $topFolder->getParent(); } } $payload['added_folders'][] = FilesystemVueDataManager::getFolderVueData($folder, $this->current_folder); $added_folders[] = $folder->getId(); } } $this->response->add_header( 'X-Filesystem-Changes', json_encode($changes) ); $this->render_json($payload); } else { $this->redirect("file/edit_license/{$this->current_folder->getId()}"); } } } /** * Displays details about a file or a folder. * * @param string $file_area_object_id A file area object like a Folder or a FileRef. */ public function details_action($file_area_object_id = null) { $this->include_navigation = Request::get('file_navigation', false); //check if the file area object is a FileRef: $this->from_plugin = Request::get("from_plugin"); if ($this->from_plugin) { $file_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/details/") + strlen("dispatch.php/file/details/")); if (strpos($file_id, "?") !== false) { $file_id = substr($file_id, 0, strpos($file_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin($this->from_plugin); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); } else { $file_ref = FileRef::find($file_area_object_id); if ($file_ref) { $this->file = $file_ref->getFileType(); } } if ($this->file) { //file system object is a FileRef PageLayout::setTitle($this->file->getFilename()); //Check if file is downloadable for the current user: $this->show_preview = false; $this->is_downloadable = false; $this->is_standard_file = get_class($this->file) === StandardFile::class; // NOTE: The following can only work properly for folders which are // stored in the database, since remote folders // (for example owncloud/nextcloud folders) are not stored in the database. $folder = $this->file->getFolderType(); if (!$folder->isVisible(User::findCurrent()->id)) { throw new AccessDeniedException(); } $this->is_downloadable = $this->file->isDownloadable(User::findCurrent()->id); $this->is_editable = $this->file->isEditable(User::findCurrent()->id); $this->file_info_template = $this->file->getInfoTemplate($this->is_downloadable); //load the previous and next file in the folder, //if the folder is of type FolderType. $this->previous_file_ref_id = false; $this->next_file_ref_id = false; if ($this->include_navigation && $folder->isReadable(User::findCurrent()->id)) { $current_file_ref_id = null; foreach ($folder->getFiles() as $folder_file) { $last_file_ref_id = $current_file_ref_id; $current_file_ref_id = $folder_file->getId(); if ($folder_file->getId() === $this->file->getId()) { $this->previous_file_ref_id = $last_file_ref_id; } if ($last_file_ref_id === $this->file->getId()) { $this->next_file_ref_id = $folder_file->getId(); //at this point we have the ID of the previous //and the next file ref so that we can exit //the foreach loop: break; } } } $this->fullpath = FileManager::getFullPath($folder); $this->render_action('file_details'); } else { //file area object is not a FileRef: maybe it's a folder: if ($this->from_plugin) { $this->folder = $plugin->getFolder($file_id); } else { $this->folder = FileManager::getTypedFolder($file_area_object_id); } if (!$this->folder || !$this->folder->isVisible($GLOBALS['user']->id)) { throw new AccessDeniedException(); } //The file system object is a folder. //Calculate the files and the folder size: [$this->folder_size, $this->folder_file_amount] = $this->getFolderSize($this->folder); PageLayout::setTitle($this->folder->name); $this->render_action('folder_details'); } } /** * The action for editing a file reference. */ public function edit_action($file_ref_id) { if (Request::get("from_plugin")) { $file_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/edit/") + strlen("dispatch.php/file/edit/")); if (strpos($file_id, "?") !== false) { $file_id = substr($file_id, 0, strpos($file_id, "?")); } $file_ref_id = $file_id; $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); $this->from_plugin = Request::get("from_plugin"); } else { $this->file_ref = FileRef::find($file_ref_id); $this->file = $this->file_ref->getFileType(); } $this->folder = $this->file->getFoldertype(); if (!$this->folder || !$this->folder->isFileEditable($this->file->getId(), $GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->content_terms_of_use_entries = ContentTermsOfUse::findAll(); $this->show_force_button = false; if (Request::isPost()) { //form was sent CSRFProtection::verifyUnsafeRequest(); $this->errors = []; $force_save = Request::submitted('force_save'); $this->name = trim(Request::get('name')); $this->description = Request::get('description'); $this->store_accessibility_flag($this->file); $this->content_terms_of_use_id = Request::get('content_terms_of_use_id'); //Check if the FileRef is unmodified: if (($this->name == $this->file_ref->name) && ($this->description == $this->file_ref->description) && ($this->content_terms_of_use_id == $this->file_ref->content_terms_of_use_id)) { $this->redirectToFolder($this->folder); return; } //Check if the file extension has changed: $old_file_extension = pathinfo($this->file_ref->name, PATHINFO_EXTENSION); $new_file_extension = pathinfo($this->name, PATHINFO_EXTENSION); if ($old_file_extension !== $new_file_extension && !$force_save) { if (!$new_file_extension) { PageLayout::postWarning( sprintf( _('Die Dateiendung "%1$s" wird entfernt. Soll die Datei trotzdem gespeichert werden?'), htmlReady($old_file_extension) ) ); } elseif (!$old_file_extension) { PageLayout::postWarning( sprintf( _('Die Dateiendung wird auf "%1$s" gesetzt. Soll die Datei trotzdem gespeichert werden?'), htmlReady($new_file_extension) ) ); } else { PageLayout::postWarning( sprintf( _('Die Dateiendung wird von "%1$s" auf "%2$s" geändert. Soll die Datei trotzdem gespeichert werden?'), htmlReady($old_file_extension), htmlReady($new_file_extension) ) ); } $this->show_force_button = true; return; } if (Request::get("from_plugin")) { $result = $this->folder->editFile( $file_ref_id, $this->name, $this->description, $this->content_terms_of_use_id ); } else { $result = FileManager::editFileRef( $this->file_ref, User::findCurrent(), $this->name, $this->description, $this->content_terms_of_use_id ); } if (!$result instanceof FileRef) { $this->errors = array_merge($this->errors, $result); } if ($this->errors) { PageLayout::postError( sprintf( _('Fehler beim Ändern der Datei %s!'), htmlReady($this->file_ref->name) ), $this->errors ); } else { PageLayout::postSuccess(_('Änderungen gespeichert!')); $this->redirectToFolder($this->folder); } } $this->name = $this->file->getFilename(); $this->description = $this->file->getDescription(); $this->content_terms_of_use = $this->file->getTermsOfUse(); } public function oer_post_upload_action($file_ref_id) { $this->file_ref_id = $file_ref_id; PageLayout::setTitle(_('Datei für OER-Campus bereitstellen')); $this->semester_ende = date('d.m.Y', Semester::findCurrent()->ende); if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); $oer_share = Request::int('oer_upload'); $redirect = Request::get('redirect_to_files'); if ($oer_share === 1) { // share now return $this->share_oer_action($this->file_ref_id, $redirect); } else if ($oer_share === 2) { // save and send a reminder to share later $oer_post_upload = new OERPostUpload(); $oer_post_upload->file_ref_id = $this->file_ref_id; $oer_post_upload->user_id = $GLOBALS['user']->id; $oer_post_upload->reminder_date = Semester::findCurrent()->ende; $oer_post_upload->store(); $this->response->add_header('X-Dialog-Close', '1'); $this->render_nothing(); PageLayout::postSuccess(_('Erinnerung wurde gespeichert.')); } else { $this->response->add_header('X-Dialog-Close', '1'); } } } /** * The action for sharing a file on the oer campus */ public function share_oer_action($file_ref_id, $redirect = null) { $this->redirect = $redirect; $this->file_ref = FileRef::find($file_ref_id); $this->file = $this->file_ref->getFileType(); $this->folder = $this->file->getFoldertype(); if ( !$this->folder || !$this->folder->isFileEditable($this->file->getId(), $GLOBALS['user']->id) || !$GLOBALS['perm']->have_perm(Config::get()->OER_PUBLIC_STATUS) ) { throw new AccessDeniedException(); } $_SESSION['NEW_OER'] = [ 'name' => $this->file->getFilename(), 'filename' => $this->file->getFilename(), 'description' => $this->file->getDescription(), 'player_url' => null, 'tags' => [], 'tmp_name' => $this->file->getPath(), 'content_type' => $this->file->getMimeType(), 'image_tmp_name' => null ]; // only if you were in Dateibereich if ($this->redirect === 'redirect_to_files') { $_SESSION['NEW_OER']['redirect_url'] = 'files'; $_SESSION['NEW_OER']['dir'] = $this->folder->getId(); $_SESSION['NEW_OER']['cid'] = $this->folder->range_id; } $this->redirect('oer/mymaterial/edit'); } /** * The action for suggesting a file for the oer campus to the file owner */ public function suggest_oer_action($file_ref_id) { $this->file_ref_id = $file_ref_id; $file_ref = FileRef::find($file_ref_id); $filetype = $file_ref->getFileType(); $this->file = $filetype->convertToStandardFile(); $this->icon_shape = $this->file->getIcon(Icon::ROLE_INFO)->getShape(); $this->author = $file_ref->owner->username; $this->author_fullname = $file_ref->owner->getFullName('no_title'); $this->link_to_share = URLHelper::getURL("dispatch.php/file/share_oer/" . $file_ref_id); $this->linktext = _('Klicken Sie hier, um das Material im OER Campus zu veröffentlichen.'); $this->formatted_link = '['. $this->linktext .']' . $this->link_to_share; $additional_text = htmlReady(Request::get('additional_text')); $oer_suggestion_message = sprintf(_("Ihre hochgeladene Datei wurde zur Veröffentlichung im OER Campus vorgeschlagen:\n\n" . "Dateiname: %s \n" . "Beschreibung: %s \n\n" . "%s \n\n" . "Zusätzliche Info: \n %s"), $this->file->getFilename(), $this->file->getDescription(), $this->formatted_link, $additional_text ); if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); // send a private message to the file author $messaging = new messaging(); $messaging->insert_message( $oer_suggestion_message, $this->author, '____%system%____', '', Request::option('message_id'), '', null, _('Vorschlag zur Veröffentlichung einer Datei im OER Campus') ); $this->response->add_header('X-Dialog-Close', '1'); $this->render_nothing(); PageLayout::postSuccess(_('Vorschlag wurde eingereicht.')); } } public function edit_urlfile_action($file_ref_id) { $this->file_ref = FileRef::find($file_ref_id); $this->file = $this->file_ref->getFileType(); $this->folder = $this->file_ref->foldertype; if (!$this->folder || !$this->folder->isFileEditable($this->file_ref->id, $GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->content_terms_of_use_entries = ContentTermsOfUse::findAll(); $this->show_force_button = false; if (Request::isPost()) { //form was sent CSRFProtection::verifyUnsafeRequest(); $this->file_ref['name'] = trim(Request::get('name')); $this->file_ref['description'] = trim(Request::get('description')); $this->file_ref['content_terms_of_use_id'] = Request::get('content_terms_of_use_id'); $this->file_ref->file['metadata']['url'] = Request::get('url'); $this->file_ref->file['metadata']['access_type'] = Request::get('access_type'); $this->file_ref->file->store(); $this->file_ref->store(); PageLayout::postSuccess(_('Änderungen gespeichert!')); $this->redirectToFolder($this->folder); } $this->name = $this->file_ref->name; $this->url = $this->file_ref->file['metadata']['url']; $this->description = $this->file_ref->description; $this->content_terms_of_use_id = $this->file_ref->content_terms_of_use_id; } /** * This action is responsible for updating a file reference. */ public function update_action($file_ref_id) { if (Request::get("from_plugin")) { $file_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/update/") + strlen("dispatch.php/file/update/")); if (strpos($file_id, "?") !== false) { $file_id = substr($file_id, 0, strpos($file_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); $this->from_plugin = Request::get("from_plugin"); } else { $this->file_ref = FileRef::find($file_ref_id); $this->file = $this->file_ref->getFileType(); } $this->folder = $this->file->getFolderType(); if (!$this->file->isEditable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->errors = []; if (Request::submitted('confirm')) { $update_filename = (bool) Request::get('update_filename', false); $update_all_instances = (bool) Request::get('update_all_instances', false); CSRFProtection::verifyUnsafeRequest(); //Form was sent if (Request::isPost() && is_array($_FILES['file'])) { if ($this->file_ref) { $result = FileManager::updateFileRef( $this->file_ref, User::findCurrent(), $_FILES['file'], $update_filename, $update_all_instances ); } else { } if (!$result instanceof FileRef) { $this->errors = array_merge($this->errors, $result); } } else { $this->errors[] = _('Es wurde keine neue Dateiversion gewählt!'); } if ($this->errors) { PageLayout::postError( sprintf( _('Fehler beim Aktualisieren der Datei %s!'), htmlReady($this->file_ref->name) ), $this->errors ); } else { PageLayout::postSuccess( sprintf( _('Datei %s wurde aktualisiert!'), htmlReady($this->file_ref->name) ) ); } $this->redirectToFolder($this->folder); } } public function choose_destination_action($copymode, $fileref_id = null) { PageLayout::setTitle(_('Ziel wählen')); $this->hidden = false; //This is used in the view. if (empty($fileref_id)) { $fileref_id = Request::getArray('fileref_id'); } elseif ($fileref_id === 'bulk') { $fileref_id = Request::getArray('ids'); } $this->copymode = $copymode; $this->fileref_id = $fileref_id; $this->is_folder = false; if (Request::get("from_plugin")) { if (is_array($fileref_id)) { $file_id = $fileref_id[0]; } else { $file_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/choose_destination/".$copymode."/") + strlen("dispatch.php/file/choose_destination/".$copymode."/")); if (strpos($file_id, "?") !== false) { $file_id = substr($file_id, 0, strpos($file_id, "?")); } $fileref_id = [$file_id]; } $file_id = $fileref_id[0]; $this->fileref_id = $fileref_id; $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file_ref = $plugin->getPreparedFile($file_id); if (!$this->file_ref) { //Maybe it is a folder: $folder = $plugin->getFolder($file_id); if ($folder instanceof FolderType) { $this->parent_folder = $folder->getParent(); $this->is_folder = true; } } } else { if (is_array($fileref_id)) { $this->file_ref = FileRef::find($fileref_id[0]); } else { $this->file_ref = FileRef::find($fileref_id); $this->fileref_id = [$fileref_id]; } } if ($this->file_ref && Request::submitted("from_plugin")) { $this->parent_folder = $this->file_ref->getFoldertype(); } elseif ($this->file_ref) { $this->parent_folder = Folder::find($this->file_ref->folder_id); $this->parent_folder = $this->parent_folder->getTypedFolder(); } elseif (!Request::submitted("from_plugin")) { $folder = Folder::find(is_array($fileref_id) ? $fileref_id[0] : $fileref_id); if ($folder) { $this->parent_folder = Folder::find($folder->parent_id); $this->parent_folder = $this->parent_folder->getTypedFolder(); $this->is_folder = true; } } elseif (!$this->parent_folder) { throw new AccessDeniedException(); } $this->plugin = Request::get('from_plugin'); } public function download_folder_action($folder_id) { $user = User::findCurrent(); if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/download_folder/") + strlen("dispatch.php/file/download_folder/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $foldertype = $plugin->getFolder($folder_id); } else { $folder = Folder::find($folder_id); if ($folder) { $foldertype = $folder->getTypedFolder(); } } if ($foldertype) { $tmp_file = tempnam($GLOBALS['TMP_PATH'], 'doc'); $result = FileArchiveManager::createArchive( [$foldertype], $user->id, $tmp_file, true, true, false, 'UTF-8', true ); if ($result) { $filename = $folder ? $folder->name : basename($tmp_file); //ZIP file was created successfully $this->redirect(FileManager::getDownloadURLForTemporaryFile( basename($tmp_file), FileManager::cleanFileName("{$filename}.zip") )); } else { throw new Exception('Error while creating ZIP archive!'); } } else { throw new Exception('Folder not found in database!'); } } public function choose_folder_from_course_action() { PageLayout::setTitle(_('Zielordner von Veranstaltung wählen')); if (Request::get('course_id')) { $folder = Folder::findTopFolder(Request::get("course_id")); $this->redirect($this->url_for( 'file/choose_folder/' . $folder->getId(), [ 'from_plugin' => Request::get('from_plugin'), 'fileref_id' => Request::getArray('fileref_id'), 'copymode' => Request::get('copymode'), 'isfolder' => Request::get('isfolder') ] )); return; } $this->plugin = Request::get('from_plugin'); if (!$GLOBALS['perm']->have_perm("admin")) { $query = "SELECT seminare.*, MAX(`beginn`) as sorter FROM seminare INNER JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id) LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id) WHERE seminar_user.user_id = :user_id GROUP BY seminare.Seminar_id "; if (Config::get()->DEPUTIES_ENABLE) { $query .= " UNION SELECT `seminare`.*, MAX(`beginn`) as sorter FROM `seminare` INNER JOIN `deputies` ON (`deputies`.`range_id` = `seminare`.`Seminar_id`) LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id) WHERE `deputies`.`user_id` = :user_id GROUP BY seminare.Seminar_id"; } $query .= " ORDER BY sorter DESC, Name ASC"; $statement = DBManager::get()->prepare($query); $statement->execute([':user_id' => $GLOBALS['user']->id]); $this->courses = []; foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $coursedata) { $this->courses[] = Course::buildExisting($coursedata); } } } public function choose_folder_from_institute_action() { PageLayout::setTitle(_('Zielordner von Einrichtung wählen')); if (Request::get('Institut_id')) { $folder = Folder::findTopFolder(Request::get("Institut_id")); $this->redirect($this->url_for( 'file/choose_folder/' . $folder->getId(), [ 'from_plugin' => Request::get('from_plugin'), 'fileref_id' => Request::getArray('fileref_id'), 'copymode' => Request::get('copymode'), 'isfolder' => Request::get('isfolder'), ] )); return; } if ($GLOBALS['perm']->have_perm('root')) { $sql = "SELECT DISTINCT Institute.Institut_id, Institute.Name FROM Institute LEFT JOIN range_tree ON (range_tree.item_id = Institute.Institut_id) WHERE Institute.Name LIKE :input OR Institute.Strasse LIKE :input OR Institute.email LIKE :input OR range_tree.name LIKE :input ORDER BY Institute.Name"; } else { $quoted_user_id = DBManager::get()->quote($GLOBALS['user']->id); $sql = "SELECT DISTINCT Institute.Institut_id, Institute.Name FROM Institute LEFT JOIN range_tree ON (range_tree.item_id = Institute.Institut_id) LEFT JOIN user_inst ON (user_inst.Institut_id = Institute.Institut_id) WHERE user_inst.user_id = {$quoted_user_id} AND ( Institute.Name LIKE :input OR Institute.Strasse LIKE :input OR Institute.email LIKE :input OR range_tree.name LIKE :input ) ORDER BY Institute.Name"; } $this->instsearch = SQLSearch::get($sql, _('Einrichtung suchen'), 'Institut_id'); $this->plugin = Request::get('from_plugin'); } public function choose_folder_action($folder_id = null) { PageLayout::setTitle(_('Zielordner wählen')); if (Request::isPost()) { //copy if (Request::get('to_plugin')) { $plugin = PluginManager::getInstance()->getPlugin(Request::get('to_plugin')); //$file = $plugin->getPreparedFile(Request::get("file_id")); } else { $folder = new Folder($folder_id); $this->to_folder_type = new StandardFolder($folder); } } $this->filesystemplugin = null; if (Request::get('to_plugin')) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/choose_folder") + strlen("dispatch.php/file/choose_folder")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } if ($folder_id[0] === "/") { $folder_id = substr($folder_id, 1); } $this->filesystemplugin = PluginManager::getInstance()->getPlugin(Request::get('to_plugin')); if (Request::get('search') && $this->filesystemplugin->hasSearch()) { $this->top_folder = $this->filesystemplugin->search( Request::get('search'), Request::getArray('parameter') ); } else { $this->top_folder = $this->filesystemplugin->getFolder($folder_id, true); if ($this->top_folder instanceof Flexi\Template) { $this->top_folder->select = true; $this->top_folder->to_folder = $this->to_folder; $this->render_text($this->top_folder); } } } else { $this->top_folder = new StandardFolder(new Folder($folder_id)); if (!$this->top_folder->isReadable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } } $this->top_folder_name = _('Hauptordner'); //A top folder can have its parent-ID set to an emtpy string //or its folder_type is set to 'RootFolder'. if ($this->top_folder->parent_id == '' or $this->top_folder->folder_type == 'RootFolder') { //We have a top folder. Now we check if its range-ID //references a Stud.IP object and set the displayed folder name //to the name of that object. if ($this->top_folder->range_id) { $range_type = Folder::findRangeTypeById($this->top_folder->range_id); switch ($range_type) { case 'course': $course = Course::find($this->top_folder->range_id); if ($course) { $this->top_folder_name = $course->getFullName(); } break; case 'institute': $institute = Institute::find($this->top_folder->range_id); if ($institute) { $this->top_folder_name = $institute->getFullName(); } break; case 'user': $user = User::find($this->top_folder->range_id); if ($user) { $this->top_folder_name = $user->getFullName(); } break; case 'message': $message = Message::find($this->top_folder->range_id); if ($message) { $this->top_folder_name = $message->subject; } break; case 'resource': { $resource = Resource::find($this->top_folder->range_id); if ($resource) { $resource = $resource->getDerivedClassInstance(); if ($resource) { $this->top_folder_name = $resource->getFullName(); } } } } } }else { //$top_folder is not a top folder. We can use its name directly. $this->top_folder_name = $this->top_folder->name; } } public function add_from_library_action($folder_id = null) { PageLayout::setTitle(_('Suche im Bibliothekskatalog')); if (!Config::get()->LITERATURE_ENABLE) { throw new AccessDeniedException(_('Die Literaturverwaltung ist ausgeschaltet!')); } $this->top_folder = new StandardFolder(new Folder($folder_id)); if (!$this->top_folder->isReadable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $course = $this->top_folder->getRangeObject(); if (!($course instanceof Course) || !$GLOBALS['perm']->have_studip_perm('tutor', $course->id)) { throw new AccessDeniedException(); } if (!LibrarySearchManager::catalogsConfigured()) { PageLayout::postError( _('In dieser Stud.IP-Installation sind keine Bibliothekskataloge aktiviert!') ); return; } $this->folder_id = $folder_id; $plugin_manager = PluginManager::getInstance(); $this->page_size = 30; $this->limit = 100; //the limit for items from each catalog $this->next_page = 0; $this->page = 0; $this->order_by = LibrarySearch::ORDER_BY_RELEVANCE; $this->global_stylesheet = $GLOBALS['LIBRARY_STYLESHEET_ID']; if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); if (Request::submitted('search')) { $this->title = Request::get('title'); $this->author = Request::get('author'); $this->year = Request::get('year'); $this->number = Request::get('number'); $this->publication = Request::get('publication'); $this->signature = Request::get('signature'); $this->order_by = Request::get('order_by'); if (!$this->title && !$this->author && !$this->year && !$this->number && !$this->publication && !$this->signature) { PageLayout::postError( _('Es muss mindestens ein Suchkriterium angegeben werden!') ); return; } $this->library_plugins = $plugin_manager->getPlugins(LibraryPlugin::class); //Build the query parameter array: $search_parameters = []; if ($this->title) { $search_parameters[LibrarySearch::TITLE] = $this->title; } if ($this->author) { $search_parameters[LibrarySearch::AUTHOR] = $this->author; } if ($this->year) { $search_parameters[LibrarySearch::YEAR] = $this->year; } if ($this->number) { $search_parameters[LibrarySearch::NUMBER] = $this->number; } if ($this->publication) { $search_parameters[LibrarySearch::PUBLICATION] = $this->publication; } if ($this->signature) { $search_parameters[LibrarySearch::SIGNATURE] = $this->signature; } $this->search_id = md5(json_encode($search_parameters)); $cache = \Studip\Cache\Factory::getCache(); $merged_results = LibrarySearchManager::search( $search_parameters, $this->order_by, $this->limit ); $this->total_results = count($merged_results); $cache_data = [ 'search_params' => $search_parameters, 'results' => $merged_results ]; $cache->write($this->search_id, $cache_data); if (count($merged_results) > $this->page_size) { $this->next_page = 2; } $this->result_set = array_slice($merged_results, 0, $this->page_size); $this->pagination_link_closure = function($page_id) { return URLHelper::getLink( 'dispatch.php/file/add_from_library/' . $this->top_folder->getId(), [ 'search_id' => $this->search_id, 'page' => $page_id, ] ); }; return; } elseif (Request::submitted('add_to_file_area')) { $search_id = Request::get('search_id'); $result_id = Request::get('result_id'); $this->redirect( $this->url_for( 'file/create_library_file/' . $this->top_folder->getId(), [ 'search_and_item_id' => $search_id . '_' . $result_id, 'create_only' => '1' ] ) ); } elseif (Request::submitted('create_library_request')) { $search_id = Request::get('search_id'); $result_id = Request::get('result_id'); $plugin_id = Request::get('plugin_id'); $this->redirect( $this->url_for( 'file/create_library_file/' . $this->top_folder->getId(), [ 'search_and_item_id' => $search_id . '_' . $result_id, 'plugin_id' => $plugin_id ] ) ); } } elseif (Request::get('search_id')) { $this->library_plugins = $plugin_manager->getPlugins(LibraryPlugin::class); $this->search_id = Request::get('search_id'); $this->page = Request::get('page'); $cache = \Studip\Cache\Factory::getCache(); $cache_data = $cache->read($this->search_id); $results = $cache_data['results']; $this->total_results = count($results); $search_parameters = $cache_data['search_params']; $this->title = $search_parameters[LibrarySearch::TITLE]; $this->author = $search_parameters[LibrarySearch::AUTHOR]; $this->year = $search_parameters[LibrarySearch::YEAR]; $this->number = $search_parameters[LibrarySearch::NUMBER]; $this->publication = $search_parameters[LibrarySearch::PUBLICATION]; $this->signature = $search_parameters[LibrarySearch::SIGNATURE]; $offset = $this->page_size * $this->page; $this->result_set = array_slice($results, $offset, $this->page_size); $this->pagination_link_closure = function($page_id) { return URLHelper::getLink( 'dispatch.php/file/add_from_library/' . $this->top_folder->getId(), [ 'search_id' => $this->search_id, 'page' => $page_id, ] ); }; } } public function create_library_file_action($folder_id = null) { PageLayout::setTitle(_('Bibliothekseintrag erstellen')); if (!Config::get()->LITERATURE_ENABLE) { throw new AccessDeniedException(_('Die Literaturverwaltung ist ausgeschaltet!')); } $this->top_folder = new StandardFolder(new Folder($folder_id)); if (!$this->top_folder->isReadable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $course = $this->top_folder->getRangeObject(); if (!($course instanceof Course) || !$GLOBALS['perm']->have_studip_perm('tutor', $course->id)) { throw new AccessDeniedException(); } $create_only = Request::submitted('create_only'); $plugin_id = Request::get('plugin_id'); $search_and_item_id = Request::get('search_and_item_id'); if (!$search_and_item_id) { PageLayout::postError(_('Es wurde kein Suchergebnis ausgewählt!')); return; } if (!$plugin_id && !$create_only) { throw new Exception('No plugin ID has been provided!'); } $search_and_item_id = explode('_', $search_and_item_id); $search_id = $search_and_item_id[0]; $item_id = $search_and_item_id[1]; if (!$search_id) { throw new Exception('No search_id provided!'); } if ($item_id) { $cache = \Studip\Cache\Factory::getCache(); $documents = $cache->read($search_id); $document = $documents['results'][$item_id]; if (!($document instanceof LibraryDocument)) { throw new Exception('Library file not found in result cache!'); } $file = LibraryFile::createFromLibraryDocument($document, $folder_id); } else { $cache = \Studip\Cache\Factory::getCache(); $search = $cache->read($search_id); if (!$search) { throw new Exception('Search not found in cache!'); } $search_params = $search['search_params']; $document = new LibraryDocument(); $document->search_params = $search_params; $file = LibraryFile::createFromLibraryDocument($document, $folder_id); } if ($create_only) { $this->redirect($this->url_for('file/edit_license/' . $this->top_folder->getId(), [ 'file_refs' => [$file->getFileRef()->getId()], 're_location' => $this->url_for($this->top_folder->range_type . '/files/index/' . $this->top_folder->getId(), ['cid' => $this->top_folder->range_id]) ])); return; } if ($plugin_id) { $plugin_manager = PluginManager::getInstance(); $plugin = $plugin_manager->getPluginById($plugin_id); if (!($plugin instanceof LibraryPlugin)) { throw new Exception(sprintf('The plugin with the ID %s is not a LibraryPlugin!', $plugin_id)); } if ($file instanceof LibraryFile) { //Redirect to the request page of the plugin. $this->redirect($plugin->getRequestURL($file->getId())); } else { throw new Exception('Library file could not be stored!'); } } } public function getFolders_action() { $rangeId = Request::get('range'); $folders = Folder::findBySQL('range_id = ?', [$rangeId]); $folderray = []; $pathes = []; foreach ($folders as $folder) { $pathes[] = $folder->getPath(); $folderray[][$folder->getPath()] = $folder->id; } array_multisort($pathes, SORT_ASC, SORT_STRING, $folderray); if (Request::isXhr()) { $this->render_json($folderray); } else { $this->render_nothing(); } } /** * The action for deleting a file reference. */ public function delete_action($file_ref_id) { CSRFProtection::verifyUnsafeRequest(); if (Request::get("from_plugin")) { $file_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/delete/") + strlen("dispatch.php/file/delete/")); if (strpos($file_id, "?") !== false) { $file_id = substr($file_id, 0, strpos($file_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $filetype = $plugin->getPreparedFile($file_id); $folder = $filetype->getFolderType(); } else { $file_ref = FileRef::find($file_ref_id); if (!$file_ref) { throw new Trails\Exception(404, _('Datei nicht gefunden.')); } $folder = $file_ref->foldertype; $filetype = $file_ref->getFileType(); } if (!$filetype) { throw new Trails\Exception(404, _('Datei nicht gefunden.')); } if (!$filetype->isWritable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } if ($filetype->delete()) { PageLayout::postSuccess(_('Datei wurde gelöscht.')); } else { PageLayout::postError(_('Datei konnte nicht gelöscht werden.')); } if (Request::submitted('from_flat_view')) { $this->redirectToFlatView($folder); } else { $this->redirectToFolder($folder); } } public function add_files_window_action($folder_id) { $this->folder_id = $folder_id; $this->range = Context::getType(); $this->upload_type = FileManager::getUploadTypeConfig( Context::getId(), $GLOBALS['user']->id ); $config = Config::get(); $this->show_library_functions = $config->LITERATURE_ENABLE; if ($this->show_library_functions) { $this->library_search_description = $config->LIBRARY_ADD_ITEM_ACTION_DESCRIPTION; } $this->plugin = Request::get('to_plugin'); } public function choose_file_from_course_action($folder_id) { if (Request::get('course_id')) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/choose_file_from_course/") + strlen("dispatch.php/file/choose_file_from_course/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $folder = Folder::findTopFolder(Request::get('course_id')); $this->redirect($this->url_for( 'file/choose_file/' . $folder->getId(), [ 'to_plugin' => Request::get('to_plugin'), 'to_folder_id' => $folder_id ] )); return; } $this->folder_id = $folder_id; $this->plugin = Request::get('to_plugin'); if (!$GLOBALS['perm']->have_perm('admin')) { $query = "SELECT seminare.*, MAX(semester_data.`beginn`) as sorter FROM seminare INNER JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id) LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id) WHERE seminar_user.user_id = :user_id GROUP BY seminare.Seminar_id"; if (Config::get()->DEPUTIES_ENABLE) { $query .= " UNION SELECT `seminare`.*, MAX(semester_data.`beginn`) as sorter FROM `seminare` INNER JOIN `deputies` ON (`deputies`.`range_id` = `seminare`.`Seminar_id`) LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id) WHERE `deputies`.`user_id` = :user_id GROUP BY seminare.Seminar_id"; } $query .= " ORDER BY sorter DESC, Name ASC"; $statement = DBManager::get()->prepare($query); $statement->execute(['user_id' => $GLOBALS['user']->id]); $this->courses = []; foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $coursedata) { $this->courses[] = Course::buildExisting($coursedata); } } } public function choose_file_action($folder_id = null) { $this->filesystemplugin = null; if (Request::get('to_plugin')) { $to_plugin = PluginManager::getInstance()->getPlugin(Request::get('to_plugin')); $this->to_folder_type = $to_plugin->getFolder(Request::get('to_folder_id', '')); } else { if (!Request::get('to_folder_id')) { throw new Exception('target folder_id must be set.'); } $folder = new Folder(Request::option('to_folder_id', '')); $this->to_folder_type = $folder->getTypedFolder(); } if (Request::isPost()) { //copy if (Request::get('from_plugin')) { $plugin = PluginManager::getInstance()->getPlugin(Request::get('from_plugin')); $file = $plugin->getPreparedFile(Request::get('file_id'), true); } else { $from_file_ref = FileRef::find(Request::get('file_id')); $file = $from_file_ref->getFileType(); } $newfile = FileManager::copyFile( $file, $this->to_folder_type, User::findCurrent() ); if (is_array($newfile)) { PageLayout::postError( _('Beim Kopieren ist ein Fehler aufgetreten'), array_map('htmlReady', $newfile) ); $this->redirectToFolder($this->to_folder_type); return; } if (Request::isXhr()) { $this->current_folder = $this->to_folder_type; $this->marked_element_ids = []; $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirects = []; foreach ($plugins as $plugin) { $url = $plugin->getAdditionalUploadWizardPage($newfile); if ($url) { $redirects[] = $url; } } $payload = [ 'html' => FilesystemVueDataManager::getFileVueData($newfile, $this->current_folder), 'redirect' => $redirects[0] ?? '', 'url' => $this->generateFilesUrl($this->current_folder, $newfile), ]; $this->response->add_header( 'X-Dialog-Execute', 'STUDIP.Files.addFile' ); $this->render_json($payload); return; } else { PageLayout::postSuccess(_('Datei wurde hinzugefügt.')); $this->redirectToFolder($this->to_folder_type); return; } } if (Request::get('from_plugin')) { $this->filesystemplugin = PluginManager::getInstance()->getPlugin(Request::get('from_plugin')); PageLayout::setTitle(sprintf( _('Dokument hinzufügen von %s'), $this->filesystemplugin->getPluginName() )); if (Request::get('search') && $this->filesystemplugin->hasSearch()) { $this->top_folder = $this->filesystemplugin->search(Request::get('search'), Request::getArray('parameter')); } else { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/choose_file/") + strlen("dispatch.php/file/choose_file/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $this->top_folder = $this->filesystemplugin->getFolder($folder_id, true); if ($this->top_folder instanceof Flexi\Template) { $this->top_folder->select = true; $this->top_folder->to_folder = $this->to_folder; $this->render_text($this->top_folder->render()); } } } else { //Load the folder by its ID. $folder = new Folder($folder_id); $folder_type = $folder->folder_type; //Check if the specified folder type is a FolderType implementation. if (is_a($folder_type, 'FolderType', true)) { //Get an instance of the FolderType implementation //and use it in the code below this point. $this->top_folder = new $folder_type($folder); if (!$this->top_folder->isReadable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } } } $this->to_folder_name = _('Hauptordner'); //A top folder can have its parent-ID set to an empty string //or its folder_type set to 'RootFolder'. if ($this->to_folder_type->parent_id == '' or $this->to_folder_type->folder_type == 'RootFolder') { //We have a top folder. Now we check if its range-ID //references a Stud.IP object and set the displayed folder name //to the name of that object. if ($this->to_folder_type->range_id) { $range_type = Folder::findRangeTypeById($this->to_folder_type->range_id); switch ($range_type) { case 'course': { $course = Course::find($this->to_folder_type->range_id); if ($course) { $this->to_folder_name = $course->getFullName(); } break; } case 'institute': { $institute = Institute::find($this->to_folder_type->range_id); if ($institute) { $this->to_folder_name = $institute->getFullName(); } break; } case 'user': { $user = User::find($this->to_folder_type->range_id); if ($user) { $this->to_folder_name = $user->getFullName(); } break; } case 'message': { $message = Message::find($this->to_folder_type->range_id); if ($message) { $this->to_folder_name = $message->subject; } break; } } } } else { //The folder is not a top folder. We can use its name directly. $this->to_folder_name = $this->to_folder_type->name; } } protected function loadFiles($param = 'files', $plugin = null, $with_blob = false) { $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_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; } } } 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; } if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); if (count($this->files) === 1) { // store flag if file is an accessible file $this->store_accessibility_flag($this->files[0]); } if (($folder_id == 'bulk') && !Request::submitted('accept')) { $this->files = $this->loadFiles('ids', $this->plugin); } else { $description = Request::get('description'); $success_files = []; $error_files = []; foreach ($this->files as $file) { //Check if the user may change the license of the file: $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['name']); continue; } 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->getFilename(); } else { $error_files[] = sprintf(_('Fehler beim Speichern der Datei "%s"!'), $file['name']); } } $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->files as $file) { $folder = $file->getFolderType(); // Skip files not in current folder (during archive extract) if ($folder_id && $folder_id !== $folder->getId()) { continue; } $payload['html'][] = FilesystemVueDataManager::getFileVueData( $file, $file->getFolderType() ); } $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirect = null; foreach ($plugins as $upload_hook_plugin) { $url = $upload_hook_plugin->getAdditionalUploadWizardPage($file_ref); if ($url) { $redirect = $url; break; } } if (count($this->files) === 1) { if (Config::get()->OERCAMPUS_ENABLED && Config::get()->OER_ENABLE_POST_UPLOAD && $GLOBALS['perm']->have_perm('tutor') ) { 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; } } } } if ($redirect) { $this->redirect($redirect); return; } $payload['url'] = $this->generateFilesUrl( $this->folder, $this->file ); 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->files[0]->getName()) )); } else { sort($success_files); PageLayout::postSuccess( _('Die Lizenzen der folgenden Dateien wurden geändert:'), array_map('htmlReady', $success_files) ); } } if ($error_files) { if (count($error_files) == 1) { PageLayout::postError(sprintf( _('Die Lizenz der Datei "%s" konnte nicht geändert werden!'), htmlReady($this->files[0]->getName()) )); } else { PageLayout::postError( _('Die Lizenzen der folgenden Dateien konnten nicht geändert werden:'), array_map('htmlReady', $error_files) ); } } } $this->response->add_header( 'X-Dialog-Execute', 'STUDIP.Files.addFile' ); $this->render_json($payload); return; } else { PageLayout::postSuccess(_('Datei wurde bearbeitet.')); if ($this->re_location) { return $this->relocate(URLHelper::getURL($this->re_location));; } else { return $this->redirectToFolder($this->folder); } } } } PageLayout::setTitle(sprintf( ngettext( 'Zusatzangaben und Lizenz wählen', 'Zusatzangaben und Lizenz auswählen: %s Dateien', count($this->files) ), count($this->files) )); $this->licenses = ContentTermsOfUse::findBySQL("1 ORDER BY position ASC, id ASC"); } public function add_url_action($folder_id) { $this->content_terms_of_use_entries = ContentTermsOfUse::findAll(); $this->content_terms_of_use_id = Request::get('content_terms_of_use_id'); if (Request::get("to_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/add_url/") + strlen("dispatch.php/file/add_url/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("to_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->top_folder = $plugin->getFolder($folder_id); } else { $this->top_folder = FileManager::getTypedFolder($folder_id); } URLHelper::addLinkParam('to_plugin', Request::get('to_plugin')); if (!$this->top_folder || !$this->top_folder->isWritable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } if (Request::submitted('store')) { CSRFProtection::verifyUnsafeRequest(); $url = trim(Request::get('url')); $url_parts = parse_url($url); if (filter_var($url, FILTER_VALIDATE_URL) !== false && in_array($url_parts['scheme'], ['http', 'https','ftp'])) { $this->file = $this->top_folder->addFile(URLFile::create([ 'name' => Request::get('name'), 'url' => $url, 'access_type' => Request::get('access_type', "redirect"), 'content_terms_of_use_id' => Request::get('content_terms_of_use_id') ])); if ($this->file) { $payload = []; $payload['html'][] = FilesystemVueDataManager::getFileVueData($this->file, $this->top_folder); $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirects = []; foreach ($plugins as $plugin) { $url = $plugin->getAdditionalUploadWizardPage($this->file); if ($url) { $redirects[] = $url; } } if (count($redirects) > 0) { $payload['html'] = $redirects[0]; } $this->response->add_header( 'X-Dialog-Execute', 'STUDIP.Files.addFile' ); $this->render_json($payload); } } else { PageLayout::postError(_('Die angegebene URL ist ungültig.')); } } } /** * Action for creating a new folder. */ public function new_folder_action($folder_id) { if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/new_folder/") + strlen("dispatch.php/file/new_folder/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $parent_folder = $plugin->getFolder($folder_id); } else { $parent_folder = FileManager::getTypedFolder($folder_id); } URLHelper::addLinkParam('from_plugin', Request::get('from_plugin')); if (!$parent_folder || !$parent_folder->isSubfolderAllowed($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->parent_folder_id = $parent_folder->getId(); $folder_types = FileManager::getAvailableFolderTypes($parent_folder->range_id, $GLOBALS['user']->id); $this->name = Request::get('name'); $this->description = Request::get('description'); $this->folder_types = []; $this->show_confirmation_button = false; foreach ($folder_types as $folder_type) { $folder_type_instance = new $folder_type( ['range_id' => $parent_folder->range_id, 'range_type' => $parent_folder->range_type, 'parent_id' => $parent_folder->getId()] ); $this->folder_types[] = [ 'class' => $folder_type, 'instance' => $folder_type_instance, 'name' => $folder_type::getTypeName(), 'icon' => $folder_type_instance->getIcon('clickable') ]; } $new_folder = null; if (Request::submitted('create') || Request::submitted('force_creation')) { CSRFProtection::verifyUnsafeRequest(); $force_creation = Request::submitted('force_creation'); // Get class name of folder type and check if the class // is a subclass of FolderType before initialising it: $folder_type = Request::get('folder_type', 'StandardFolder'); if (!is_subclass_of($folder_type, 'FolderType')) { throw new Exception( _('Der gewünschte Ordnertyp ist ungültig!') ); } $request = Request::getInstance(); $request->offsetSet('parent_id', $folder_id); $new_folder = new $folder_type( ['range_id' => $parent_folder->range_id, 'range_type' => $parent_folder->range_type, 'parent_id' => $parent_folder->getId()] ); $result = $new_folder->setDataFromEditTemplate($request); if ($result instanceof FolderType) { $new_folder->user_id = User::findCurrent()->id; if ($result instanceof CourseDateFolder && !$force_creation) { // Check if there is already a folder for the // selected course date: $course_date = $result->getDate(); if ($course_date instanceof CourseDate && count($course_date->folders) > 0 ) { PageLayout::postWarning(sprintf( _('Für den Termin am %s existiert bereits ein Sitzungsordner. Möchten Sie trotzdem einen weiteren Sitzungsordner erstellen?'), htmlReady($course_date->getFullName()) )); $this->show_confirmation_button = true; $this->folder = $new_folder ?: new StandardFolder(); return; } } if ($parent_folder->createSubfolder($new_folder)) { PageLayout::postSuccess(_('Der Ordner wurde angelegt.')); $this->response->add_header('X-Dialog-Close', '1'); $this->render_nothing(); } else { PageLayout::postError( _('Fehler beim Anlegen des Ordners!') ); } } else { PageLayout::postMessage($result); } } $this->folder = $new_folder ?: new StandardFolder(); } /** * Action for editing an existing folder, referenced by its ID. * * @param $folder_id string The ID of the folder that shall be edited. */ public function edit_folder_action($folder_id) { if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/edit_folder/") + strlen("dispatch.php/file/edit_folder/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { $folder = FileManager::getTypedFolder($folder_id); } URLHelper::addLinkParam('from_plugin', Request::get('from_plugin')); if (!$folder || !$folder->isEditable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->name = Request::get('name', $folder->name); $this->description = Request::get('description', $folder->description); $this->folder = $folder; $this->folder_template = $folder->getEditTemplate(); $this->folder_types = []; if (!is_a($folder, 'VirtualFolderType') && !is_a($folder, 'RootFolder')) { $folder_types = FileManager::getAvailableFolderTypes( $folder->range_id, $GLOBALS['user']->id ); foreach ($folder_types as $folder_type) { $folder_type_instance = new $folder_type( [ 'range_id' => $folder->range_id, 'range_type' => $folder->range_type ] ); $this->folder_types[] = [ 'class' => $folder_type, 'instance' => $folder_type_instance, 'name' => $folder_type::getTypeName(), 'icon' => $folder_type_instance->getIcon('clickable') ]; } } else { //It is a virtual folder or a root folder (folder without parent): $this->folder_types[] = [ 'class' => get_class($folder), 'instance' => $folder, 'name' => $folder::getTypeName(), 'icon' => $folder->getIcon('clickable') ]; } if (Request::submitted('edit')) { CSRFProtection::verifyUnsafeRequest(); if (!is_a($folder, 'VirtualFolderType')) { $folder_type = Request::get('folder_type', get_class($folder)); if (!is_subclass_of($folder_type, 'FolderType') || !class_exists($folder_type)) { throw new InvalidArgumentException(_('Unbekannter Ordnertyp!')); } if ($folder_type !== get_class($folder)) { $folder = new $folder_type($folder); } } $request = Request::getInstance(); if ($folder->getParent()) { $request->offsetSet('parent_id', $folder->getParent()->getId()); } $result = $folder->setDataFromEditTemplate($request); if ($result instanceof FolderType) { if ($folder->store()) { PageLayout::postSuccess(_('Der Ordner wurde bearbeitet.')); } $this->response->add_header('X-Dialog-Close', '1'); $this->render_nothing(); } else { PageLayout::postMessage($result); } } [$this->folder_size, $this->folder_file_amount] = $this->getFolderSize($folder); } public function delete_folder_action($folder_id) { CSRFProtection::verifyUnsafeRequest(); if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/delete_folder/") + strlen("dispatch.php/file/delete_folder/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { $folder = FileManager::getTypedFolder($folder_id); } URLHelper::addLinkParam('from_plugin', Request::get('from_plugin')); if (!$folder || !$folder->isEditable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $parent_folder = $folder->getParent(); if ($folder->delete()) { PageLayout::postSuccess(_('Ordner wurde gelöscht!')); } else { PageLayout::postError(_('Ordner konnte nicht gelöscht werden!')); } $this->redirectToFolder($parent_folder); } /** * This action allows downloading, copying, moving and deleting files and folders in bulk. */ public function bulk_action($folder_id) { CSRFProtection::verifyUnsafeRequest(); if (Request::get("from_plugin")) { $folder_id = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], "dispatch.php/file/bulk/") + strlen("dispatch.php/file/bulk/")); if (strpos($folder_id, "?") !== false) { $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $parent_folder = $plugin->getFolder($folder_id); } else { $parent_folder = FileManager::getTypedFolder($folder_id); } URLHelper::addLinkParam('from_plugin', Request::get('from_plugin')); if (!$parent_folder || !$parent_folder->isReadable($GLOBALS['user']->id)) { throw new AccessDeniedException(); } //check, if at least one ID was given: $ids = Request::getArray('ids'); if (empty($ids)) { $this->redirectToFolder($parent_folder); return; } //check, which action was chosen: if (Request::submitted('download')) { //bulk downloading: $tmp_file = tempnam($GLOBALS['TMP_PATH'], 'doc'); $user = User::findCurrent(); $use_dos_encoding = strpos($_SERVER['HTTP_USER_AGENT'], 'Windows') !== false; //collect file area objects by looking at their IDs: $file_area_objects = []; foreach ($ids as $id) { if (Request::get('from_plugin')) { $fa_object = $plugin->getFolder($id); if (!$fa_object) { $fa_object = $plugin->getPreparedFile($id, true); } if ($fa_object) { $file_area_objects[] = $fa_object; } } else { //check if the ID references a FileRef: $filesystem_item = FileRef::find($id); if (!$filesystem_item) { //check if the ID references a Folder: $filesystem_item = Folder::find($id); if ($filesystem_item) { $file_area_objects[] = $filesystem_item->getTypedFolder(); } } else { $file_area_objects[] = $filesystem_item; } } } if (count($file_area_objects) === 1 && is_a($file_area_objects[0], 'FileRef')) { //we have only one file to deliver, so no need for zipping it: $this->redirect($file_area_objects[0]->getDownloadURL('force_download')); return; } //create a ZIP archive: try { $result = FileArchiveManager::createArchive( $file_area_objects, $user->id, $tmp_file, true, true, false, $use_dos_encoding ? 'CP850' : 'UTF-8', true ); } catch (FileArchiveManagerException $fame) { PageLayout::postError(_('Es ist ein Fehler aufgetreten.'), [$fame->getMessage()]); $this->redirectToFolder($parent_folder); return; } if ($result) { if (count($file_area_objects) === 1 && $file_area_objects[0] instanceof FolderType) { $zip_file_name = $file_area_objects[0]->name; } else { $zip_file_name = $parent_folder->name; } //ZIP file was created successfully $this->redirect(FileManager::getDownloadURLForTemporaryFile( basename($tmp_file), ($zip_file_name ?: basename($tmp_file)) . '.zip' )); } else { throw new Exception('Error while creating ZIP archive!'); } } elseif (Request::submitted('copy')) { //bulk copying $this->flash['fileref_id'] = Request::getArray('ids'); $this->redirect($this->url_for('file/choose_destination/copy/flash')); } elseif (Request::submitted('move')) { //bulk moving $this->flash['fileref_id'] = Request::getArray('ids'); $this->redirect($this->url_for('file/choose_destination/move/flash')); } elseif (Request::submitted('delete')) { //bulk deleting $errors = []; $count_files = 0; $count_folders = 0; $user = User::findCurrent(); $selected_elements = Request::getArray('ids'); foreach ($selected_elements as $element) { if (Request::get("from_plugin")) { $foldertype = $plugin->getFolder($element); if (!$foldertype) { $file_ref = $plugin->getPreparedFile($element, true); } } else { $file_ref = FileRef::find($element); if(!$file_ref) { $foldertype = FileManager::getTypedFolder($element); } } if (!empty($file_ref)) { $current_folder = $file_ref->getFolderType(); $result = $current_folder ? $current_folder->deleteFile($element) : false; if ($result && !is_array($result)) { $count_files += 1; } } elseif ($foldertype) { $folder_files = count($foldertype->getFiles()); $folder_subfolders = count($foldertype->getSubfolders()); $result = FileManager::deleteFolder($foldertype, $user); if (!is_array($result)) { $count_folders += 1; $count_files += $folder_files; $count_folders += $folder_subfolders; } } if (!empty($result) && is_array($result)) { $errors = array_merge($errors, $result); } } if (empty($errors) || $count_files > 0 || $count_folders > 0) { if ($count_files == 1 || $count_folders == 1) { if ($count_folders) { PageLayout::postSuccess(_('Der Ordner wurde gelöscht!')); } else { PageLayout::postSuccess(_('Die Datei wurde gelöscht!')); } } elseif ($count_files > 0 && $count_folders > 0) { PageLayout::postSuccess(sprintf(_('Es wurden %s Ordner und %s Dateien gelöscht!'), $count_folders, $count_files)); } elseif ($count_files > 0) { PageLayout::postSuccess(sprintf(_('Es wurden %s Dateien gelöscht!'), $count_files)); } else { PageLayout::postSuccess(sprintf(_('Es wurden %s Ordner gelöscht!'), $count_folders)); } } else { PageLayout::postError(_('Es ist ein Fehler aufgetreten.'), array_map('htmlReady', $errors)); } $this->redirectToFolder($parent_folder); } } public function open_folder_action($folder_id) { $folder = FileManager::getTypedFolder($folder_id, Request::get('from_plugin')); URLHelper::addLinkParam('from_plugin', Request::get('from_plugin')); if (!$folder || !$folder->isVisible($GLOBALS['user']->id)) { throw new AccessDeniedException(); } $this->redirectToFolder($folder); } private function generateFilesUrl($folder, $fileRef) { require_once 'app/controllers/files.php'; return \FilesController::getRangeLink($folder) . '#fileref_' . $fileRef->getId(); } private function getFolderSize($folder): array { $folder_size = 0; $folder_file_amount = 0; foreach ($folder->getFiles() as $file) { $folder_size += $file->getSize(); $folder_file_amount++; } return [$folder_size, $folder_file_amount]; } private function store_accessibility_flag(FileType $file) { if ($file instanceof StandardFile) { $file_ref = $file->getFileRef(); if ($file_ref) { $file_ref->file['is_accessible'] = Request::get('is_accessible'); $file_ref->file->store(); } } } }