aboutsummaryrefslogtreecommitdiff
path: root/lib/models/FileRef.php
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:07:19 +0200
committerJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:19:12 +0200
commita3da1483a9e689846179159355badfec8073dbec (patch)
tree770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /lib/models/FileRef.php
current code from svn, revision 62608
Diffstat (limited to 'lib/models/FileRef.php')
-rw-r--r--lib/models/FileRef.php635
1 files changed, 635 insertions, 0 deletions
diff --git a/lib/models/FileRef.php b/lib/models/FileRef.php
new file mode 100644
index 0000000..d367321
--- /dev/null
+++ b/lib/models/FileRef.php
@@ -0,0 +1,635 @@
+<?php
+/**
+ * FileRef.php
+ * model class for table file_refs
+ *
+ * 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 André Noack <noack@data-quest.de>
+ * @copyright 2016 Stud.IP Core-Group
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ *
+ *
+ * @property string id database column
+ * @property string file_id database column
+ * @property string folder_id database column
+ * @property string user_id database column
+ * @property string name database column
+ * @property string downloads database column
+ * @property string description database column
+ * @property string license database column
+ * @property string content_terms_of_use_id database column
+ * @property string mkdate database column
+ * @property string chdate database column
+ * @property SimpleORMap file belongs_to File
+ * @property SimpleORMap folder belongs_to Folder
+ * @property SimpleORMap owner belongs_to User
+ * @property SimpleORMap terms_of_use belongs_to ContentTermsOfUse
+ */
+class FileRef extends SimpleORMap implements PrivacyObject, FeedbackRange
+{
+
+ protected $folder_type;
+ protected $download_url;
+ public $path_to_blob;
+
+ protected static function configure($config = [])
+ {
+ $config['db_table'] = 'file_refs';
+ $config['belongs_to']['file'] = [
+ 'class_name' => 'File',
+ 'foreign_key' => 'file_id',
+ ];
+ $config['belongs_to']['folder'] = [
+ 'class_name' => 'Folder',
+ 'foreign_key' => 'folder_id',
+ ];
+ $config['belongs_to']['owner'] = [
+ 'class_name' => 'User',
+ 'foreign_key' => 'user_id',
+ ];
+
+ $config['belongs_to']['terms_of_use'] = [
+ 'class_name' => 'ContentTermsOfUse',
+ 'foreign_key' => 'content_terms_of_use_id',
+ 'assoc_func' => 'findOrBuild'
+ ];
+
+ $config['additional_fields']['size'] = ['file', 'size'];
+ $config['additional_fields']['mime_type'] = ['file', 'mime_type'];
+ $config['additional_fields']['download_url']['set'] = 'setDownloadURL';
+ $config['additional_fields']['download_url']['get'] = 'getDownloadURL';
+ $config['additional_fields']['author_name']['get'] = 'getAuthorName';
+ $config['additional_fields']['is_link']['get'] = 'isLink';
+ $config['additional_fields']['foldertype']['set'] = 'setFolderType';
+ $config['additional_fields']['foldertype']['get'] = 'getFolderType';
+
+ $config['registered_callbacks']['after_delete'][] = 'cbRemoveFileIfOrphaned';
+ $config['registered_callbacks']['after_delete'][] = 'cbRemoveFeedbackElements';
+ $config['registered_callbacks']['before_store'][] = 'cbMakeUniqueFilename';
+
+ parent::configure($config);
+ }
+
+ /**
+ * This callback is called after deleting a FileRef.
+ * It removes the File object that is associated with the FileRef,
+ * if the File is not referenced by any other FileRef object.
+ */
+ public function cbRemoveFileIfOrphaned()
+ {
+ if (!self::countBySql('file_id = ?', [$this->file_id])) {
+ File::deleteBySQL("id = ?", [$this->file_id]);
+ }
+ }
+
+ /**
+ * This callback is called after deleting a FileRef.
+ * It removes feedback elements that are associated with the FileRef.
+ */
+ public function cbRemoveFeedbackElements()
+ {
+ FeedbackElement::deleteBySQL("range_id = ? AND range_type = 'FileRef'", [$this->id]);
+ }
+
+ /**
+ * This callback is called before storing a FileRef object.
+ * In case the name field is changed this callback assures that the
+ * name of the FileRef is unique inside the folder where
+ * the FileRef is placed.
+ */
+ public function cbMakeUniqueFilename()
+ {
+ if (isset($this->folder) && $this->isFieldDirty('name')) {
+ $this->name = $this->folder->getUniqueName($this->name);
+ }
+ if ($this->isFieldDirty('folder_id')) {
+ //We have moved the file ref. $this->folder may not work directly
+ //so we have to load the folder manually:
+ $folder = Folder::find($this->folder_id);
+ if ($folder) {
+ $this->name = $folder->getUniqueName($this->name);
+ }
+ }
+ }
+
+ /**
+ * Overrides the usual download url that this file_ref would get by the system (sendfile.php...)
+ * Use this method by cloud plugins.
+ * If you set download URL to null, the normal sendfile.php will be set as default download URL.
+ * @param $url : string as URL or null to set URL to sendfile.php-URL
+ */
+ public function setDownloadURL($field, $url) {
+ $this->download_url = $url;
+ }
+
+ /**
+ * Returns the download-URL for the FileRef.
+ *
+ * @param string $dltype The download type: 'normal', 'zip', 'force' or 'force_download'.
+ *
+ * @return string The URL for the FileRef.
+ */
+ public function getDownloadURL($dltype = 'normal')
+ {
+ if ($this->download_url) {
+ return $this->download_url;
+ }
+ $mode = Config::get()->SENDFILE_LINK_MODE ?: 'normal';
+ $link = [];
+ $params = [];
+ $type = '0';
+ $file_name = $this->name;
+ $file_id = $this->id;
+
+ switch($mode) {
+ case 'rewrite':
+ $link[] = 'download/';
+ switch ($dltype) {
+ case 'zip':
+ $link[] = 'zip/';
+ break;
+ case 'force':
+ case 'force_download':
+ $link[] = 'force_download/';
+ break;
+ default:
+ $link[] = 'normal/';
+ }
+ $link[] = $type . '/' . $file_id . '/' . $file_name;
+ break;
+ default:
+ $link[] = 'sendfile.php';
+ if ($dltype == 'zip') {
+ $params['zip'] = 1;
+ } elseif (in_array($dltype, ['force_download', 'force'])) {
+ $params['force_download'] = 1;
+ }
+ $params['type'] = $type;
+ $params['file_id'] = $file_id;
+ $params['file_name'] = $file_name;
+ }
+ return URLHelper::getScriptURL(implode('', $link), $params);
+ }
+
+ /**
+ * Returns the name of the FileRef's author.
+ *
+ * @return string The name of the FileRef's author.
+ */
+ public function getAuthorName()
+ {
+ if (isset($this->owner)) {
+ return $this->owner->getFullName('no_title_rev');
+ }
+ return $this->file->author_name;
+ }
+
+ /**
+ * This method increments the download counter of the FileRef.
+ *
+ * @return The number of rows of the file_refs table that have been altered.
+ */
+ public function incrementDownloadCounter()
+ {
+ $this->downloads += 1;
+ if (!$this->isNew()) {
+ $where_query = join(' AND ' , $this->getWhereQuery());
+ $query = "UPDATE `{$this->db_table}`
+ SET `downloads` = `downloads` + 1
+ WHERE {$where_query}";
+ return DBManager::get()->exec($query);
+ }
+ }
+
+ /**
+ * Returns the license object for this file.
+ *
+ * @return Object (to be specified!)
+ */
+ public function getLicenseObject()
+ {
+ if (class_exists($this->license)) {
+ return new $this->license();
+ }
+ throw new UnexpectedValueException("class: {$this->license} not found");
+ }
+
+ /**
+ * Determines whether this FileRef is a link or not.
+ * @deprecated
+ * @return bool True, if the FileRef references a link, false otherwise.
+ */
+ public function isLink()
+ {
+ return false;
+ }
+
+ public function setFolderType($field, FolderType $folder_type)
+ {
+ $this->folder_type = $folder_type;
+ }
+
+ public function getFolderType()
+ {
+ if ($this->folder_type) {
+ return $this->folder_type;
+ } elseif($this->folder) {
+ return $this->folder->getTypedFolder();
+ }
+ }
+
+ /**
+ * Determines if the FileRef references an image file.
+ *
+ * @return bool True, if the referenced file is an image file, false otherwise.
+ */
+ public function isImage()
+ {
+ return mb_strpos($this->mime_type, 'image/') === 0;
+ }
+
+ /**
+ * Determines if the FileRef references an audio file.
+ *
+ * @return bool True, if the referenced file is an audio file, false otherwise.
+ */
+ public function isAudio()
+ {
+ return mb_strpos($this->mime_type, 'audio/') === 0;
+ }
+
+
+ /**
+ * Determines if the FileRef references a video file.
+ *
+ * @return bool True, if the referenced file is a video file, false otherwise.
+ */
+ public function isVideo()
+ {
+ return mb_strpos($this->mime_type, 'video/') === 0;
+ }
+
+ /**
+ * Export available data of a given user into a storage object
+ * (an instance of the StoredUserData class) for that user.
+ *
+ * @param StoredUserData $storage object to store data into
+ */
+ public static function exportUserData(StoredUserData $storage)
+ {
+ $sorm = self::findBySQL("user_id = ?", [$storage->user_id]);
+ if ($sorm) {
+ $field_data = [];
+ foreach ($sorm as $row) {
+ $field_data[] = $row->toRawArray();
+ }
+ if ($field_data) {
+ $storage->addTabularData(_('Dateien'), 'file_refs', $field_data);
+ }
+ }
+ }
+
+ /**
+ * @returns FileType
+ */
+ public function getFileType()
+ {
+ $filetype = $this->file->filetype;
+ if (class_exists($filetype) && is_subclass_of($filetype, 'FileType')) {
+ return new $filetype($this);
+ } else {
+ return new UnknownFileType($this);
+ }
+ }
+
+ public function getRangeName()
+ {
+ return $this->name;
+ }
+
+ public function getRangeIcon($role)
+ {
+ return FileManager::getIconForFileRef($this, $role);
+ }
+
+ public function getRangeUrl()
+ {
+ return 'course/files/index/' . $this->foldertype->getId();
+ }
+
+ public function getRangeCourseId()
+ {
+ return $this->foldertype->range_id;
+ }
+
+ public function isRangeAccessible(string $user_id = null): bool
+ {
+ $user_id = $user_id ?? $GLOBALS['user']->id;
+
+ return $this->foldertype->isFileDownloadable($this->id, $user_id);
+ }
+
+
+ /**
+ * This is a helper method to generate the SQL query for the
+ * findAll and countAll methods. Relevant FileRef objects for these methods
+ * can be limited by a time range and a specific course. The amount
+ * and the offset of the FileRef objects to be retrieved can also be set.
+ *
+ * @param string $user_id The ID of the user that is used to count or
+ * retrieve FileRef objects.
+ *
+ * @param DateTime|null $begin The begin of the time range.
+ *
+ * @param DateTime|null $end The end of the time range.
+ *
+ * @param string $course_id The ID of the course from which FileRef objects
+ * shall be retrieved.
+ *
+ * @param int $file_limit The maximum amount of FileRef objects to be
+ * retrieved.
+ *
+ * @param int $file_offset The offset in the FileRef data from which to
+ * start retrieving objects.
+ *
+ * @returns mixed[] An array with two indexes:
+ * - sql: The SQL query string.
+ * - params: An array with SQL query parameters.
+ */
+ protected static function getAllSql($user_id, $begin = null, $end = null, $course_id = '', $file_limit = 0, $file_offset = 0)
+ {
+ $sql = '';
+ $sql_params = [];
+ if ($course_id) {
+ //Limit the result for a specific course.
+ $sql = 'INNER JOIN `folders`
+ ON `file_refs`.`folder_id` = `folders`.`id`
+ WHERE `folders`.`range_id` = :course_id ';
+ $sql_params['course_id'] = $course_id;
+ if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
+ $sql .= 'AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
+ $sql_params['begin'] = $begin->getTimestamp();
+ $sql_params['end'] = $end->getTimestamp();
+ }
+ } else {
+ if ($GLOBALS['perm']->have_perm('root', $user_id)) {
+ //This is easy: Get all recent files ordered by chdate.
+ if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
+ $sql = 'chdate BETWEEN :begin AND :end ';
+ $sql_params['begin'] = $begin->getTimestamp();
+ $sql_params['end'] = $end->getTimestamp();
+ } else {
+ $sql = 'TRUE ';
+ }
+ } else {
+ //Get the folders (all folders) of the user first and then
+ //check for new files. This means getting all folders of courses
+ //and institutes where the user has access to.
+
+ $range_ids = FileManager::getRangeIdsForFolders($user_id, true);
+
+ //Now get all file refs:
+ $sql = 'INNER JOIN `folders`
+ ON `file_refs`.`folder_id` = `folders`.`id`
+ WHERE `folders`.`range_id` IN ( :range_ids ) ';
+ $sql_params['range_ids'] = $range_ids;
+
+ if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
+ $sql .= 'AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
+ $sql_params['begin'] = $begin->getTimestamp();
+ $sql_params['end'] = $end->getTimestamp();
+ }
+ }
+ }
+ $sql .= ' ORDER BY `file_refs`.`chdate` DESC, `file_refs`.`mkdate` DESC, `file_refs`.`name` ASC';
+ if ($file_limit > 0) {
+ $sql .= ' LIMIT :limit';
+ $sql_params['limit'] = $file_limit;
+ if ($file_offset > 0) {
+ $sql .= ' OFFSET :offset';
+ $sql_params['offset'] = $file_offset;
+ }
+ }
+ return ['sql' => $sql, 'params' => $sql_params];
+ }
+
+
+ /**
+ * This method retrieves the FileRef objects a user has access to.
+ *
+ * @see FileRef::getAllSql for the parameter description.
+ *
+ * @returns FileRef[] A list of FileRef objects.
+ */
+ public static function findAll($user_id, $begin = null, $end = null, $course_id = null, $file_limit = 0, $file_offset = 0)
+ {
+ $sql_data = self::getAllSql($user_id, $begin, $end, $course_id, $file_limit, $file_offset);
+ return FileRef::findBySql($sql_data['sql'], $sql_data['params']);
+ }
+
+
+ /**
+ * This method counts all the FileRef objects a user has access to.
+ *
+ * @see FileRef::getAllSql for the parameter description.
+ *
+ * @returns int The amount of found FileRef rows.
+ */
+ public static function countAll($user_id, $begin = null, $end = null, $course_id = null)
+ {
+ $sql_data = self::getAllSql($user_id, $begin, $end, $course_id);
+ return FileRef::countBySql($sql_data['sql'], $sql_data['params']);
+ }
+
+
+ /**
+ * This is a helper method to generate the SQL query for the
+ * findPublicFiles and countPublicFiles methods. Relevant FileRef objects
+ * for these methods can be limited by a time range. The amount
+ * and the offset of the FileRef objects to be retrieved can also be set.
+ *
+ * @param string $user_id The ID of the user that is used to count or
+ * retrieve FileRef objects in public folders.
+ *
+ * @param DateTime|null $begin The begin of the time range.
+ *
+ * @param DateTime|null $end The end of the time range.
+ *
+ * @param int $file_limit The maximum amount of FileRef objects to be
+ * retrieved from public folders.
+ *
+ * @param int $file_offset The offset in the FileRef data from which to
+ * start retrieving objects from public folders.
+ *
+ * @returns mixed[] An array with two indexes:
+ * - sql: The SQL query string.
+ * - params: An array with SQL query parameters.
+ */
+ protected static function getPublicFilesSql($user_id, $begin = null, $end = null, $file_limit = 0, $file_offset = 0)
+ {
+ $sql = "INNER JOIN `folders`
+ ON `file_refs`.`folder_id` = `folders`.`id`
+ WHERE `folders`.`folder_type` = 'PublicFolder'
+ AND `folders`.`range_type` = 'user' ";
+ $sql_params = [];
+ if ($user_id) {
+ $sql .= " AND `folders`.`user_id` = :user_id";
+ $sql_params['user_id'] = $user_id;
+ }
+ if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
+ $sql .= ' AND `file_refs`.`chdate` BETWEEN :begin AND :end';
+ $sql_params['begin'] = $begin->getTimestamp();
+ $sql_params['end'] = $end->getTimestamp();
+ }
+ $sql .= " ORDER BY `file_refs`.`chdate` DESC";
+ if ($file_limit > 0) {
+ $sql .= " LIMIT :file_limit";
+ $sql_params['file_limit'] = $file_limit;
+ }
+ if ($file_offset > 0) {
+ $sql .= " OFFSET :file_offset";
+ $sql_params['file_offset'] = $file_offset;
+ }
+ return ['sql' => $sql, 'params' => $sql_params];
+ }
+
+
+ /**
+ * This method retrieves the FileRef objects in public folders which
+ * can be accessed by a user.
+ *
+ * @see FileRef::getPublicFilesSql for the parameter description.
+ *
+ * @returns FileRef[] A list of FileRef objects.
+ */
+ public static function findPublicFiles($user_id, $begin = null, $end = null, $file_limit = 0, $file_offset = 0)
+ {
+ $sql_data = self::getPublicFilesSql($user_id, $begin, $end, $file_limit, $file_offset);
+ return self::findBySql($sql_data['sql'], $sql_data['params']);
+ }
+
+
+ /**
+ * This method counts the FileRef objects in public folders which
+ * can be accessed by a user.
+ *
+ * @see FileRef::getPublicFilesSql for the parameter description.
+ *
+ * @returns int The amount of found FileRef rows.
+ */
+ public static function countPublicFiles($user_id, $begin = null, $end = null)
+ {
+ $sql_data = self::getPublicFilesSql($user_id, $begin, $end);
+ return self::countBySql($sql_data['sql'], $sql_data['params']);
+ }
+
+
+ /**
+ * This is a helper method to generate the SQL query for the
+ * findUploadedFiles and countUploadedFiles methods. Relevant FileRef
+ * objects for these methods can be limited by a time range and a specified
+ * course. Furthermore, it is possible to limit the search to FileRef
+ * objects without a license set or with the "unknown" license set.
+ * The amount and the offset of the FileRef objects to be retrieved can also
+ * be set.
+ *
+ * @param string $user_id The ID of the user whose uploaded files shall be
+ * retrieved or counted.
+ *
+ * @param DateTime|null $begin The begin of the time range.
+ *
+ * @param DateTime|null $end The end of the time range.
+ *
+ * @param string $course_id The ID of the course from which FileRef objects
+ * shall be retrieved.
+ *
+ * @param bool $unknown_license_only Whether to only query for FileRef
+ * objects without a license or with the "unknown" license set
+ * (true) or to query all uploaded FileRef objects (false).
+ * Defaults to false.
+ *
+ * @param int $file_limit The maximum amount of FileRef objects to be
+ * retrieved from public folders.
+ *
+ * @param int $file_offset The offset in the FileRef data from which to
+ * start retrieving objects from public folders.
+ *
+ * @returns mixed[] An array with two indexes:
+ * - sql: The SQL query string.
+ * - params: An array with SQL query parameters.
+ */
+ protected static function getUploadedFilesSql($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false, $file_limit = 0, $file_offset = 0)
+ {
+ $sql = '';
+ if ($course_id) {
+ $sql = 'INNER JOIN `folders`
+ ON `file_refs`.`folder_id` = `folders`.`id`
+ WHERE ';
+ }
+ $sql .= "`file_refs`.`user_id` = :user_id";
+ $sql_params = [
+ 'user_id' => $user_id
+ ];
+ if ($unknown_license_only) {
+ $sql .= " AND (
+ `file_refs`.`content_terms_of_use_id` IN ('', 'UNDEF_LICENSE')
+ OR
+ `file_refs`.`content_terms_of_use_id` IS NULL
+ )";
+ }
+
+ if (($begin instanceof DateTime) && ($end instanceof DateTime)) {
+ $active_sidebar_filters[] = 'course';
+ $sql .= ' AND `file_refs`.`chdate` BETWEEN :begin AND :end ';
+ $sql_params['begin'] = $begin->getTimestamp();
+ $sql_params['end'] = $end->getTimestamp();
+ }
+ if ($course_id) {
+ $sql .= ' AND `folders`.`range_id` = :course_id';
+ $sql_params['course_id'] = $course_id;
+ }
+ $sql .= " ORDER BY `file_refs`.`chdate` DESC";
+ if ($file_limit > 0) {
+ $sql .= " LIMIT :file_limit";
+ $sql_params['file_limit'] = $file_limit;
+ }
+ if ($file_offset > 0) {
+ $sql .= " OFFSET :file_offset";
+ $sql_params['file_offset'] = $file_offset;
+ }
+ return ['sql' => $sql, 'params' => $sql_params];
+ }
+
+
+ /**
+ * Retrieves all uploaded files a user has uploaded.
+ *
+ * @see FileRef::getUploadedFilesSql for the parameter description.
+ *
+ * @returns FileRef[] A list of FileRef objects for files the user uploaded.
+ */
+ public static function findUploadedFiles($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false, $file_limit = 0, $file_offset = 0)
+ {
+ $sql_data = self::getUploadedFilesSql($user_id, $begin, $end, $course_id, $unknown_license_only, $file_limit, $file_offset);
+ return self::findBySql($sql_data['sql'], $sql_data['params']);
+ }
+
+
+ /**
+ * Counts all uploaded files a user has uploaded.
+ *
+ * @see FileRef::getUploadedFilesSql for the parameter description.
+ *
+ * @returns int The amount of files the user uploaded.
+ */
+ public static function countUploadedFiles($user_id, $begin = null, $end = null, $course_id = '', $unknown_license_only = false)
+ {
+ $sql_data = self::getUploadedFilesSql($user_id, $begin, $end, $course_id, $unknown_license_only);
+ return self::countBySql($sql_data['sql'], $sql_data['params']);
+ }
+}