Skip to content
Snippets Groups Projects
StandardFile.php 16.3 KiB
Newer Older
<?php
/**
 * StandardFile.php
 *
 * 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    Rasmus Fuhse <fuhse@data-quest.de>
 * @copyright 2020 Stud.IP Core-Group
 * @license   http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
 * @category  Stud.IP
 */
class StandardFile implements FileType, ArrayAccess, StandardFileInterface
{

    /**
     * @var FileRef
     */
    protected $fileref = null;
    /**
     * @var File
     */
    protected $file = null;

    /**
     * Creates a prepared file with ids that could be added to a folder
     * @param array $data : ['name': "myfilename", 'type': "mime_type", 'size': "1234", 'tmp_name': "", 'error': null]
     * @param null|string $user_id : the id of the user that should own the new file
     * @return FileType|array : FileType (of called class) on success or an array with errors if an error occurred.
     */
    public static function create($data, $user_id = null)
    {
        $errors = [];
        $user_id || $user_id = $GLOBALS['user']->id;

        $filename   = $data['name'];
        $mime_type  = $data['type'] ?: get_mime_type($data['name']);
        $filesize   = $data['size'] ?: filesize($data['tmp_name']);
        $file_path  = $data['tmp_name'];
        $error_code = $data['error'];

        if ($error_code) {
            //error handling
            if ($error_code === UPLOAD_ERR_INI_SIZE) {
                $errors[] = sprintf(_('Die maximale Dateigröße von %s wurde überschritten!'), ini_get('upload_max_filesize'));
            } elseif ($error_code > 0) {
                $errors[] = sprintf(
                    _('Ein Systemfehler ist beim Upload aufgetreten. Fehlercode: %s.'),
                    $error_code
                );
            }
            return $errors;
        }

        $file = new File();
        $file['name']      = $filename;
        $file['mime_type'] = $mime_type;
        $file['filetype']  = get_called_class();
        $file['size']      = $filesize;
        $file['user_id']   = $user_id;
        $file->store();
        $file->connectWithDataFile($file_path);

        $fileref = new FileRef();
        $fileref['name']                    = $filename;
        $fileref['description']             = $data['description'] ?: "";
        $fileref['downloads']               = 0;
        $fileref['user_id']                 = $user_id;
        $fileref['file_id']                 = $file->getId();
        $fileref['content_terms_of_use_id'] = $data['content_terms_of_use_id'] ?: ContentTermsOfUse::findDefault()->id;

        return new static($fileref, $file);
    }

    /**
     * StandardFile constructor.
     * @param $fileref
     * @param null $file : (optional) Is set if fileref and file are both new and not connected with
     *                     each other in the database.
     */
    public function __construct($fileref, $file = null)
    {
        $this->fileref = $fileref;
        $this->file = $file ?: $fileref->file;
    }

    /**
     * magic method for dynamic properties
     */
    public function __get($name)
    {
        return isset($this->fileref->$name) ? $this->fileref->$name : null;
    }

    /**
     * magic method for dynamic properties
     */
    public function __set($name, $value)
    {
        return isset($this->fileref->$name) ? $this->fileref->$name = $value : null;
    }

    /**
     * magic method for dynamic properties
     */
    public function __isset($name)
    {
        return isset($this->fileref->$name);
    }

    /**
     * ArrayAccess: Check whether the given offset exists.
     */
    public function offsetExists($offset)
    {
        return $this->__isset($offset);
    }

    /**
     * ArrayAccess: Get the value at the given offset.
     */
    public function offsetGet($offset)
    {
        return $this->__get($offset);
    }

    /**
     * ArrayAccess: Set the value at the given offset.
     */
    public function offsetSet($offset, $value)
    {
        $this->__set($offset, $value);
    }

    /**
     * ArrayAccess: unset the value at the given offset (not applicable)
     */
    public function offsetUnset($offset)
    {

    }

    /**
     * Returns the name of the icon shape that shall be used with the FileType implementation.
     *
     * @param string $role role of icon
     * @return Icon icon for the FileType implementation.
     */
    public function getIcon($role)
    {
        $shape = FileManager::getIconNameForMimeType($this->fileref['mime_type']);
        return Icon::create($shape, $role);
    }

    public function getId()
    {
        return $this->fileref->getId();
    }

    public function getFilename()
    {
        return $this->fileref['name'];
    }

    public function getUserId()
    {
        return $this->fileref['user_id'];
    }

    public function getUserName()
    {
        return $this->fileref['author_name'];
    }


    public function getUser()
    {
        return $this->fileref->owner;
    }

    public function getSize()
    {
        return $this->fileref['size'];
    }

    public function getMimeType()
    {
        return $this->fileref['mime_type'];
    }

    public function getDownloadURL()
    {
        return $this->fileref->getDownloadURL();
    }

    public function getDownloads()
    {
        return $this->fileref['downloads'];
    }


    public function getPath() : string
    {
        return $this->file instanceof File ? $this->file->getPath() : '';
    }


    public function getLastChangeDate()
    {
        return $this->fileref['chdate'];
    }

    public function getMakeDate()
    {
        return $this->fileref['mkdate'];
    }

    public function getDescription()
    {
        return $this->fileref['description'];
    }

    public function getTermsOfUse()
    {
        return $this->fileref->terms_of_use;
    }

    public function getActionmenu()
    {
Moritz Strohm's avatar
Moritz Strohm committed
        $actionMenu = ActionMenu::get()->setContext($this->fileref->name);
        $actionMenu->addLink(
            URLHelper::getURL("dispatch.php/file/details/{$this->fileref->id}/1"),
            _('Info'),
            Icon::create('info-circle', Icon::ROLE_CLICKABLE, ['size' => 20]),
            ['data-dialog' => ''],
            'file-display-info'
        );
        if ($current_action === 'flat') {
            if (Navigation::hasItem('/course/files') && Navigation::getItem('/course/files')->isActive()) {
                $actionMenu->addLink(
                    URLHelper::getURL('dispatch.php/course/files/index/' . $this->fileref->folder_id),
                    _('Ordner öffnen'),
                    Icon::create('folder-empty', Icon::ROLE_CLICKABLE, ['size' => 20])
                );
            } elseif (Navigation::hasItem('/files_dashboard/files') && Navigation::getItem('/files_dashboard/files')->isActive()) {
                $actionMenu->addLink(
                    URLHelper::getURL('dispatch.php/files/index/' . $this->fileref->folder_id),
                    _('Ordner öffnen'),
                    Icon::create('folder-empty', Icon::ROLE_CLICKABLE, ['size' => 20])
                );
            }
        }
        if ($this->isEditable($GLOBALS['user']->id)) {
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/edit/' . $this->fileref->id),
                _('Datei bearbeiten'),
                Icon::create('edit', Icon::ROLE_CLICKABLE, ['size' => 20]),
                ['data-dialog' => ''],
                'file-edit'
            );
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/update/' . $this->fileref->id),
                _('Datei aktualisieren'),
                Icon::create('refresh', Icon::ROLE_CLICKABLE, ['size' => 20]),
                ['data-dialog' => ''],
                'file-update'
            );
        }
        if ($this->isWritable($GLOBALS['user']->id)) {
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/choose_destination/move/' . $this->fileref->id),
                _('Datei verschieben'),
                Icon::create('file+move_right', Icon::ROLE_CLICKABLE, ['size' => 20]),
                ['data-dialog' => 'size=auto'],
                'file-move'
            );
        }
        if ($this->isDownloadable($GLOBALS['user']->id) && $GLOBALS['user']->id !== 'nobody') {
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/choose_destination/copy/' . $this->fileref->id),
                _('Datei kopieren'),
                Icon::create('file+add', Icon::ROLE_CLICKABLE, ['size' => 20]),
                ['data-dialog' => 'size=auto'],
                'file-copy'
            );
            $actionMenu->addLink(
                $this->fileref->getDownloadURL('force_download'),
                _('Link kopieren'),
                Icon::create('group'),
                ['class' => 'copyable-link'],
                'link-to-clipboard'
            );
        }
        if ($this->isEditable($GLOBALS['user']->id) && Config::get()->OERCAMPUS_ENABLED) {
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/share_oer/' . $this->fileref->id),
                _('Im OER Campus veröffentlichen'),
                Icon::create('oer-campus'),
                ['data-dialog' => '1']
            );
        }
        if (Config::get()->OERCAMPUS_ENABLED && Config::get()->OER_ENABLE_SUGGESTIONS &&
            $GLOBALS['user']->id !== 'nobody' && $this->fileref->user_id !== $GLOBALS['user']->id &&
            in_array($this->fileref->content_terms_of_use_id, ['SELFMADE_NONPUB', 'FREE_LICENSE'])
        ) {
            $actionMenu->addLink(
                URLHelper::getURL('dispatch.php/file/suggest_oer/' . $this->fileref->id),
                _('Material für OER Campus vorschlagen'),
                Icon::create('oer-campus'),
                ['data-dialog' => 'reload-on-close;size=auto']
        if (Context::isCourse() && Feedback::isActivated()) {
            if (Feedback::hasCreatePerm(Context::getId())) {
                $actionMenu->addLink(
                    URLHelper::getURL('dispatch.php/course/feedback/create_form/'. $this->fileref->id . '/FileRef'),
                    _('Neues Feedback-Element'),
                    Icon::create('star+add', Icon::ROLE_CLICKABLE, ['size' => 20]),
                    ['data-dialog' => '1']
                );
            }
        }
        if ($this->isWritable($GLOBALS['user']->id)) {
            $actionMenu->addButton(
                'delete',
                _('Datei löschen'),
                Icon::create('trash', Icon::ROLE_CLICKABLE, ['size' => 20]),
                [
                    'formaction'   => URLHelper::getURL("dispatch.php/file/delete/{$this->fileref->id}", $flat_view ? ['from_flat_view' => 1] : []),
                    'data-confirm' => sprintf(_('Soll die Datei "%s" wirklich gelöscht werden?'), $this->fileref->name),
                ]
            );
        }
        NotificationCenter::postNotification("FileActionMenuWillRender", $actionMenu, $this);
        return $actionMenu;
    }


    public function getInfoDialogButtons(array $extra_link_params = []) : array
    {
        $buttons = [];
        if ($this->isEditable($GLOBALS['user']->id)) {
            $buttons[] = Studip\LinkButton::create(
                _('Bearbeiten'),
                URLHelper::getURL("dispatch.php/file/edit/{$this->getId()}", $extra_link_params),
                ['data-dialog' => '']
            );
        }
        if ($this->isDownloadable($GLOBALS['user']->id)) {
            $buttons[] = Studip\LinkButton::createDownload(
                _('Herunterladen'),
                $this->fileref->getDownloadURL('force_download')
            );
        }
        return $buttons;
    }


    public function delete()
    {
        return $this->fileref->delete();
    }

    public function getFolderType()
    {
        return $this->fileref->folder->getTypedFolder();
    }


    public function isVisible($user_id = null)
    {
        $user_id || $user_id = $GLOBALS['user']->id;
        return $this->getFolderType()->isReadable($user_id);
    }


    /**
     * Determines if a user may download the file.
     * @param string $user_id The user who wishes to download the file.
     * @return boolean True, if the user is permitted to download the file, false otherwise.
     */
    public function isDownloadable($user_id = null)
    {
        $user_id || $user_id = $GLOBALS['user']->id;
        return $this->getFolderType()->isFileDownloadable(
            $this->fileref->getId(),
            $user_id
        );
    }

    /**
     * Determines if a user may edit the file.
     * @param string $user_id The user who wishes to edit the file.
     * @return boolean True, if the user is permitted to edit the file, false otherwise.
     */
    public function isEditable($user_id = null)
    {
        $user_id || $user_id = $GLOBALS['user']->id;
        return $this->getFolderType()->isFileEditable(
            $this->fileref->getId(),
            $user_id
        );
    }

    /**
     * Determines if a user may write to the file.
     * @param string $user_id The user who wishes to write to the file.
     * @return boolean True, if the user is permitted to write to the file, false otherwise.
     */
    public function isWritable($user_id = null)
    {
        $user_id || $user_id = $GLOBALS['user']->id;
        return $this->getFolderType()->isFileWritable(
            $this->fileref->getId(),
            $user_id
        );
    }

    public function convertToStandardFile()
    {
        return $this;
    }

    public function addToFolder(FolderType $standard_folder, $filename, $user_id = null)
    {
        $user_id || $user_id = $GLOBALS['user']->id;
        if ($user_id !== $this->file['user_id']) {
            $file = new File();
            $file->setData($this->file->toArray());
            $file->setId($file->getNewId());
            $file['user_id'] = $user_id;
            $file['filetype'] = get_called_class();
            $file->store();
            $file->connectWithDataFile($this->file->getPath());
        } else {
            $file = $this->file;
        }
        $fileref = new FileRef();
        $fileref->setData($this->fileref->toRawArray());
        $fileref->setId($fileref->getNewId());

        if ($file->isNew()) {
            $file->store();
        }
        $fileref['file_id'] = $file->getId();
        $fileref['folder_id'] = $standard_folder->getId();
        $fileref['user_id'] = $user_id;
        $fileref['downloads'] = 0;
        $fileref['name'] = $filename;
        if (!$fileref['content_terms_of_use_id']) {
            $fileref['content_terms_of_use_id'] = ContentTermsOfUse::findDefault()->id;
        }
        $fileref->store();
        return new static($fileref);
    }

    public function getFileRef()
    {
        return $this->fileref;
    }

    /**
     * Returns the content for that additional column, if it exists. You can return null a string
     * or a Flexi_Template as the content.
     * @param string $column_index
     * @return null|string|Flexi_Template
     */
    public function getContentForAdditionalColumn($column_index)
    {
        return null;
    }

    /**
     * Returns an integer or text that marks the value the content of the given column should be
     * ordered by.
     * @param string $column_index
     * @return mixed : order value
     */
    public function getAdditionalColumnOrderWeigh($column_index)
    {
        return 0;
    }


    public function getInfoTemplate(bool $include_downloadable_infos = false)
    {
        if (!$include_downloadable_infos) {
            return null;
        }
        $mime_type = $this->getMimeType();
        $relevant_mime_type = false;
        if (FileManager::fileIsImage($this) || FileManager::fileIsAudio($this)
            || FileManager::fileIsVideo($this) ||
            in_array($mime_type, ['application/pdf', 'text/plain'])) {
            $relevant_mime_type = true;
        }
        if (!$relevant_mime_type) {
            return null;
        }

        $factory = new Flexi_TemplateFactory(
            $GLOBALS['STUDIP_BASE_PATH'] . '/templates/filesystem/file_types/'
        );
        $template = $factory->open('standard_file_info');
        $template->set_attribute('mime_type', $mime_type);
        $template->set_attribute('file', $this);
        return $template;
    }
}