Skip to content
Snippets Groups Projects
file.php 94.2 KiB
Newer Older
<?php
/**
 * file.php - controller to display files in a course
 *
 * This controller contains actions related to single files.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * @author      Moritz Strohm <strohm@data-quest.de>
 * @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 (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();
            }

            $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);
                        $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);
                    }
                }

                $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:
            list($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->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();
    }

Michaela Brückner's avatar
Michaela Brückner committed
    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
     */
Michaela Brückner's avatar
Michaela Brückner committed
    public function share_oer_action($file_ref_id, $redirect = null)
Michaela Brückner's avatar
Michaela Brückner committed
        $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
        ];

Michaela Brückner's avatar
Michaela Brückner committed
        // 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');
Michaela Brückner's avatar
Michaela Brückner committed
    /**
     * 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();
Michaela Brückner's avatar
Michaela Brückner committed
        $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
Elmar Ludwig's avatar
Elmar Ludwig committed
            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,
Elmar Ludwig's avatar
Elmar Ludwig committed
                _('Vorschlag zur Veröffentlichung einer Datei im OER Campus')
            );
            $this->response->add_header('X-Dialog-Close', '1');
            $this->render_nothing();
Elmar Ludwig's avatar
Elmar Ludwig committed

            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 (is_a($this->top_folder, '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 == ''