diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/Api/File.php | 55 | ||||
-rw-r--r-- | app/Controller/BoardTooltip.php | 2 | ||||
-rw-r--r-- | app/Controller/File.php | 26 | ||||
-rw-r--r-- | app/Controller/Task.php | 4 | ||||
-rw-r--r-- | app/Core/Base.php | 3 | ||||
-rw-r--r-- | app/Model/File.php | 282 | ||||
-rw-r--r-- | app/Model/Notification.php | 4 | ||||
-rw-r--r-- | app/Model/ProjectFile.php | 40 | ||||
-rw-r--r-- | app/Model/Task.php | 2 | ||||
-rw-r--r-- | app/Model/TaskFile.php | 54 | ||||
-rw-r--r-- | app/Model/TaskFinder.php | 2 | ||||
-rw-r--r-- | app/Notification/Mail.php | 4 | ||||
-rw-r--r-- | app/Schema/Mysql.php | 22 | ||||
-rw-r--r-- | app/Schema/Postgres.php | 23 | ||||
-rw-r--r-- | app/Schema/Sqlite.php | 21 | ||||
-rw-r--r-- | app/ServiceProvider/ClassProvider.php | 3 | ||||
-rw-r--r-- | app/Subscriber/NotificationSubscriber.php | 4 | ||||
-rw-r--r-- | app/Template/event/task_file_create.php (renamed from app/Template/event/file_create.php) | 0 | ||||
-rw-r--r-- | app/Template/notification/task_file_create.php (renamed from app/Template/notification/file_create.php) | 0 |
19 files changed, 359 insertions, 192 deletions
diff --git a/app/Api/File.php b/app/Api/File.php index 269803e1..e4204e6d 100644 --- a/app/Api/File.php +++ b/app/Api/File.php @@ -2,6 +2,7 @@ namespace Kanboard\Api; +use Kanboard\Core\Base; use Kanboard\Core\ObjectStorage\ObjectStorageException; /** @@ -10,22 +11,22 @@ use Kanboard\Core\ObjectStorage\ObjectStorageException; * @package api * @author Frederic Guillot */ -class File extends \Kanboard\Core\Base +class File extends Base { - public function getFile($file_id) + public function getTaskFile($file_id) { - return $this->file->getById($file_id); + return $this->taskFile->getById($file_id); } - public function getAllFiles($task_id) + public function getAllTaskFiles($task_id) { - return $this->file->getAll($task_id); + return $this->taskFile->getAll($task_id); } - public function downloadFile($file_id) + public function downloadTaskFile($file_id) { try { - $file = $this->file->getById($file_id); + $file = $this->taskFile->getById($file_id); if (! empty($file)) { return base64_encode($this->objectStorage->get($file['path'])); @@ -36,23 +37,55 @@ class File extends \Kanboard\Core\Base } } - public function createFile($project_id, $task_id, $filename, $blob) + public function createTaskFile($project_id, $task_id, $filename, $blob) { try { - return $this->file->uploadContent($project_id, $task_id, $filename, $blob); + return $this->taskFile->uploadContent($task_id, $filename, $blob); } catch (ObjectStorageException $e) { $this->logger->error($e->getMessage()); return false; } } + public function removeTaskFile($file_id) + { + return $this->taskFile->remove($file_id); + } + + public function removeAllTaskFiles($task_id) + { + return $this->taskFile->removeAll($task_id); + } + + // Deprecated procedures + + public function getFile($file_id) + { + return $this->getTaskFile($file_id); + } + + public function getAllFiles($task_id) + { + return $this->getAllTaskFiles($task_id); + } + + public function downloadFile($file_id) + { + return $this->downloadTaskFile($file_id); + } + + public function createFile($project_id, $task_id, $filename, $blob) + { + return $this->createTaskFile($project_id, $task_id, $filename, $blob); + } + public function removeFile($file_id) { - return $this->file->remove($file_id); + return $this->removeTaskFile($file_id); } public function removeAllFiles($task_id) { - return $this->file->removeAll($task_id); + return $this->removeAllTaskFiles($task_id); } } diff --git a/app/Controller/BoardTooltip.php b/app/Controller/BoardTooltip.php index da07ec4e..bc07ce09 100644 --- a/app/Controller/BoardTooltip.php +++ b/app/Controller/BoardTooltip.php @@ -62,7 +62,7 @@ class BoardTooltip extends Base $task = $this->getTask(); $this->response->html($this->template->render('board/tooltip_files', array( - 'files' => $this->file->getAll($task['id']), + 'files' => $this->taskFile->getAll($task['id']), 'task' => $task, ))); } diff --git a/app/Controller/File.php b/app/Controller/File.php index 4ac45fbd..c5517df8 100644 --- a/app/Controller/File.php +++ b/app/Controller/File.php @@ -21,7 +21,7 @@ class File extends Base { $task = $this->getTask(); - if ($this->request->isPost() && $this->file->uploadScreenshot($task['project_id'], $task['id'], $this->request->getValue('screenshot')) !== false) { + if ($this->request->isPost() && $this->taskFile->uploadScreenshot($task['id'], $this->request->getValue('screenshot')) !== false) { $this->flash->success(t('Screenshot uploaded successfully.')); return $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true); } @@ -55,7 +55,7 @@ class File extends Base { $task = $this->getTask(); - if (! $this->file->uploadFiles($task['project_id'], $task['id'], 'files')) { + if (! $this->taskFile->uploadFiles($task['id'], $this->request->getFileInfo('files'))) { $this->flash->failure(t('Unable to upload the file.')); } @@ -71,7 +71,7 @@ class File extends Base { try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] != $task['id']) { $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); @@ -92,7 +92,7 @@ class File extends Base public function open() { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { $this->response->html($this->template->render('file/open', array( @@ -111,10 +111,10 @@ class File extends Base { try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->response->contentType($this->file->getImageMimeType($file['name'])); + $this->response->contentType($this->taskFile->getImageMimeType($file['name'])); $this->objectStorage->output($file['path']); } } catch (ObjectStorageException $e) { @@ -133,18 +133,18 @@ class File extends Base try { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->objectStorage->output($this->file->getThumbnailPath($file['path'])); + $this->objectStorage->output($this->taskFile->getThumbnailPath($file['path'])); } } catch (ObjectStorageException $e) { $this->logger->error($e->getMessage()); // Try to generate thumbnail on the fly for images uploaded before Kanboard < 1.0.19 $data = $this->objectStorage->get($file['path']); - $this->file->generateThumbnailFromData($file['path'], $data); - $this->objectStorage->output($this->file->getThumbnailPath($file['path'])); + $this->taskFile->generateThumbnailFromData($file['path'], $data); + $this->objectStorage->output($this->taskFile->getThumbnailPath($file['path'])); } } @@ -157,9 +157,9 @@ class File extends Base { $this->checkCSRFParam(); $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); - if ($file['task_id'] == $task['id'] && $this->file->remove($file['id'])) { + if ($file['task_id'] == $task['id'] && $this->taskFile->remove($file['id'])) { $this->flash->success(t('File removed successfully.')); } else { $this->flash->failure(t('Unable to remove this file.')); @@ -176,7 +176,7 @@ class File extends Base public function confirm() { $task = $this->getTask(); - $file = $this->file->getById($this->request->getIntegerParam('file_id')); + $file = $this->taskFile->getById($this->request->getIntegerParam('file_id')); $this->response->html($this->helper->layout->task('file/remove', array( 'task' => $task, diff --git a/app/Controller/Task.php b/app/Controller/Task.php index 4db8f86e..98b7a041 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -66,8 +66,8 @@ class Task extends Base $this->response->html($this->helper->layout->task('task/show', array( 'project' => $this->project->getById($task['project_id']), - 'files' => $this->file->getAllDocuments($task['id']), - 'images' => $this->file->getAllImages($task['id']), + 'files' => $this->taskFile->getAllDocuments($task['id']), + 'images' => $this->taskFile->getAllImages($task['id']), 'comments' => $this->comment->getAll($task['id'], $this->userSession->getCommentSorting()), 'subtasks' => $subtasks, 'links' => $this->taskLink->getAllGroupedByLabel($task['id']), diff --git a/app/Core/Base.php b/app/Core/Base.php index ab99fcea..31c07355 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -67,7 +67,8 @@ use Pimple\Container; * @property \Kanboard\Model\Config $config * @property \Kanboard\Model\Currency $currency * @property \Kanboard\Model\CustomFilter $customFilter - * @property \Kanboard\Model\File $file + * @property \Kanboard\Model\TaskFile $taskFile + * @property \Kanboard\Model\ProjectFile $projectFile * @property \Kanboard\Model\Group $group * @property \Kanboard\Model\GroupMember $groupMember * @property \Kanboard\Model\LastLogin $lastLogin diff --git a/app/Model/File.php b/app/Model/File.php index 46fc4bb9..e17ecb2b 100644 --- a/app/Model/File.php +++ b/app/Model/File.php @@ -2,31 +2,44 @@ namespace Kanboard\Model; +use Exception; use Kanboard\Event\FileEvent; use Kanboard\Core\Tool; use Kanboard\Core\ObjectStorage\ObjectStorageException; /** - * File model + * Base File Model * * @package model * @author Frederic Guillot */ -class File extends Base +abstract class File extends Base { /** - * SQL table name - * - * @var string - */ - const TABLE = 'files'; - - /** - * Events + * Get PicoDb query to get all files * - * @var string + * @access protected + * @return \PicoDb\Table */ - const EVENT_CREATE = 'file.create'; + protected function getQuery() + { + return $this->db + ->table(static::TABLE) + ->columns( + static::TABLE.'.id', + static::TABLE.'.name', + static::TABLE.'.path', + static::TABLE.'.is_image', + static::TABLE.'.'.static::FOREIGN_KEY, + static::TABLE.'.date', + static::TABLE.'.user_id', + static::TABLE.'.size', + User::TABLE.'.username', + User::TABLE.'.name as user_name' + ) + ->join(User::TABLE, 'id', 'user_id') + ->asc(static::TABLE.'.name'); + } /** * Get a file by the id @@ -37,146 +50,120 @@ class File extends Base */ public function getById($file_id) { - return $this->db->table(self::TABLE)->eq('id', $file_id)->findOne(); + return $this->db->table(static::TABLE)->eq('id', $file_id)->findOne(); } /** - * Remove a file + * Get all files * * @access public - * @param integer $file_id File id - * @return bool + * @param integer $id + * @return array */ - public function remove($file_id) + public function getAll($id) { - try { - $file = $this->getbyId($file_id); - $this->objectStorage->remove($file['path']); - - if ($file['is_image'] == 1) { - $this->objectStorage->remove($this->getThumbnailPath($file['path'])); - } - - return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove(); - } catch (ObjectStorageException $e) { - $this->logger->error($e->getMessage()); - return false; - } + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->findAll(); } /** - * Remove all files for a given task + * Get all images * * @access public - * @param integer $task_id Task id - * @return bool + * @param integer $id + * @return array */ - public function removeAll($task_id) + public function getAllImages($id) { - $file_ids = $this->db->table(self::TABLE)->eq('task_id', $task_id)->asc('id')->findAllByColumn('id'); - $results = array(); - - foreach ($file_ids as $file_id) { - $results[] = $this->remove($file_id); - } + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 1)->findAll(); + } - return ! in_array(false, $results, true); + /** + * Get all files without images + * + * @access public + * @param integer $id + * @return array + */ + public function getAllDocuments($id) + { + return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 0)->findAll(); } /** * Create a file entry in the database * * @access public - * @param integer $task_id Task id + * @param integer $id Foreign key * @param string $name Filename * @param string $path Path on the disk * @param integer $size File size * @return bool|integer */ - public function create($task_id, $name, $path, $size) + public function create($id, $name, $path, $size) { - $result = $this->db->table(self::TABLE)->save(array( - 'task_id' => $task_id, + $values = array( + static::FOREIGN_KEY => $id, 'name' => substr($name, 0, 255), 'path' => $path, 'is_image' => $this->isImage($name) ? 1 : 0, 'size' => $size, 'user_id' => $this->userSession->getId() ?: 0, 'date' => time(), - )); + ); - if ($result) { - $this->container['dispatcher']->dispatch( - self::EVENT_CREATE, - new FileEvent(array('task_id' => $task_id, 'name' => $name)) - ); + $result = $this->db->table(static::TABLE)->insert($values); - return (int) $this->db->getLastId(); + if ($result) { + $file_id = (int) $this->db->getLastId(); + $event = new FileEvent($values + array('file_id' => $file_id)); + $this->dispatcher->dispatch(static::EVENT_CREATE, $event); + return $file_id; } return false; } /** - * Get PicoDb query to get all files + * Remove all files * * @access public - * @return \PicoDb\Table + * @param integer $id + * @return bool */ - public function getQuery() + public function removeAll($id) { - return $this->db - ->table(self::TABLE) - ->columns( - self::TABLE.'.id', - self::TABLE.'.name', - self::TABLE.'.path', - self::TABLE.'.is_image', - self::TABLE.'.task_id', - self::TABLE.'.date', - self::TABLE.'.user_id', - self::TABLE.'.size', - User::TABLE.'.username', - User::TABLE.'.name as user_name' - ) - ->join(User::TABLE, 'id', 'user_id') - ->asc(self::TABLE.'.name'); - } + $file_ids = $this->db->table(static::TABLE)->eq(static::FOREIGN_KEY, $id)->asc('id')->findAllByColumn('id'); + $results = array(); - /** - * Get all files for a given task - * - * @access public - * @param integer $task_id Task id - * @return array - */ - public function getAll($task_id) - { - return $this->getQuery()->eq('task_id', $task_id)->findAll(); - } + foreach ($file_ids as $file_id) { + $results[] = $this->remove($file_id); + } - /** - * Get all images for a given task - * - * @access public - * @param integer $task_id Task id - * @return array - */ - public function getAllImages($task_id) - { - return $this->getQuery()->eq('task_id', $task_id)->eq('is_image', 1)->findAll(); + return ! in_array(false, $results, true); } /** - * Get all files without images for a given task + * Remove a file * * @access public - * @param integer $task_id Task id - * @return array + * @param integer $file_id File id + * @return bool */ - public function getAllDocuments($task_id) + public function remove($file_id) { - return $this->getQuery()->eq('task_id', $task_id)->eq('is_image', 0)->findAll(); + try { + $file = $this->getById($file_id); + $this->objectStorage->remove($file['path']); + + if ($file['is_image'] == 1) { + $this->objectStorage->remove($this->getThumbnailPath($file['path'])); + } + + return $this->db->table(static::TABLE)->eq('id', $file['id'])->remove(); + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } } /** @@ -226,103 +213,96 @@ class File extends Base } /** - * Generate the path for a new filename + * Generate the path for a thumbnails * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $filename Filename + * @param string $key Storage key * @return string */ - public function generatePath($project_id, $task_id, $filename) + public function getThumbnailPath($key) { - return $project_id.DIRECTORY_SEPARATOR.$task_id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time()); + return 'thumbnails'.DIRECTORY_SEPARATOR.$key; } /** - * Generate the path for a thumbnails + * Generate the path for a new filename * * @access public - * @param string $key Storage key + * @param integer $id Foreign key + * @param string $filename Filename * @return string */ - public function getThumbnailPath($key) + public function generatePath($id, $filename) { - return 'thumbnails'.DIRECTORY_SEPARATOR.$key; + return static::PATH_PREFIX.DIRECTORY_SEPARATOR.$id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time()); } /** - * Handle file upload + * Upload multiple files * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $form_name File form name + * @param integer $id + * @param array $files * @return bool */ - public function uploadFiles($project_id, $task_id, $form_name) + public function uploadFiles($id, array $files) { try { - $file = $this->request->getFileInfo($form_name); - - if (empty($file)) { + if (empty($files)) { return false; } - foreach ($file['error'] as $key => $error) { - if ($error == UPLOAD_ERR_OK && $file['size'][$key] > 0) { - $original_filename = $file['name'][$key]; - $uploaded_filename = $file['tmp_name'][$key]; - $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); - - if ($this->isImage($original_filename)) { - $this->generateThumbnailFromFile($uploaded_filename, $destination_filename); - } - - $this->objectStorage->moveUploadedFile($uploaded_filename, $destination_filename); - - $this->create( - $task_id, - $original_filename, - $destination_filename, - $file['size'][$key] - ); - } + foreach (array_keys($files['error']) as $key) { + $file = array( + 'name' => $files['name'][$key], + 'tmp_name' => $files['tmp_name'][$key], + 'size' => $files['size'][$key], + 'error' => $files['error'][$key], + ); + + $this->uploadFile($id, $file); } return true; - } catch (ObjectStorageException $e) { + } catch (Exception $e) { $this->logger->error($e->getMessage()); return false; } } /** - * Handle screenshot upload + * Upload a file * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $blob Base64 encoded image - * @return bool|integer + * @param integer $id + * @param array $file */ - public function uploadScreenshot($project_id, $task_id, $blob) + public function uploadFile($id, array $file) { - $original_filename = e('Screenshot taken %s', $this->helper->dt->datetime(time())).'.png'; - return $this->uploadContent($project_id, $task_id, $original_filename, $blob); + if ($file['error'] == UPLOAD_ERR_OK && $file['size'] > 0) { + $destination_filename = $this->generatePath($id, $file['name']); + + if ($this->isImage($file['name'])) { + $this->generateThumbnailFromFile($file['tmp_name'], $destination_filename); + } + + $this->objectStorage->moveUploadedFile($file['tmp_name'], $destination_filename); + $this->create($id, $file['name'], $destination_filename, $file['size']); + } else { + throw new Exception('File not uploaded: '.var_export($file['error'], true)); + } } /** * Handle file upload (base64 encoded content) * * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param string $original_filename Filename - * @param string $blob Base64 encoded file + * @param integer $id + * @param string $original_filename + * @param string $blob * @return bool|integer */ - public function uploadContent($project_id, $task_id, $original_filename, $blob) + public function uploadContent($id, $original_filename, $blob) { try { $data = base64_decode($blob); @@ -331,7 +311,7 @@ class File extends Base return false; } - $destination_filename = $this->generatePath($project_id, $task_id, $original_filename); + $destination_filename = $this->generatePath($id, $original_filename); $this->objectStorage->put($destination_filename, $data); if ($this->isImage($original_filename)) { @@ -339,7 +319,7 @@ class File extends Base } return $this->create( - $task_id, + $id, $original_filename, $destination_filename, strlen($data) diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 87c1a796..c252aa31 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -72,7 +72,7 @@ class Notification extends Base return e('%s updated a comment on the task #%d', $event_author, $event_data['task']['id']); case Comment::EVENT_CREATE: return e('%s commented on the task #%d', $event_author, $event_data['task']['id']); - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: return e('%s attached a file to the task #%d', $event_author, $event_data['task']['id']); case Task::EVENT_USER_MENTION: return e('%s mentioned you in the task #%d', $event_author, $event_data['task']['id']); @@ -94,7 +94,7 @@ class Notification extends Base public function getTitleWithoutAuthor($event_name, array $event_data) { switch ($event_name) { - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: return e('New attachment on task #%d: %s', $event_data['file']['task_id'], $event_data['file']['name']); case Comment::EVENT_CREATE: return e('New comment on task #%d', $event_data['comment']['task_id']); diff --git a/app/Model/ProjectFile.php b/app/Model/ProjectFile.php new file mode 100644 index 00000000..aa9bf15b --- /dev/null +++ b/app/Model/ProjectFile.php @@ -0,0 +1,40 @@ +<?php + +namespace Kanboard\Model; + +/** + * Project File Model + * + * @package model + * @author Frederic Guillot + */ +class ProjectFile extends File +{ + /** + * SQL table name + * + * @var string + */ + const TABLE = 'project_has_files'; + + /** + * SQL foreign key + * + * @var string + */ + const FOREIGN_KEY = 'project_id'; + + /** + * Path prefix + * + * @var string + */ + const PATH_PREFIX = 'projects'; + + /** + * Events + * + * @var string + */ + const EVENT_CREATE = 'project.file.create'; +} diff --git a/app/Model/Task.php b/app/Model/Task.php index 38fdd0d5..f8b41b9f 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -92,7 +92,7 @@ class Task extends Base return false; } - $this->file->removeAll($task_id); + $this->taskFile->removeAll($task_id); return $this->db->table(self::TABLE)->eq('id', $task_id)->remove(); } diff --git a/app/Model/TaskFile.php b/app/Model/TaskFile.php new file mode 100644 index 00000000..45a3b97f --- /dev/null +++ b/app/Model/TaskFile.php @@ -0,0 +1,54 @@ +<?php + +namespace Kanboard\Model; + +/** + * Task File Model + * + * @package model + * @author Frederic Guillot + */ +class TaskFile extends File +{ + /** + * SQL table name + * + * @var string + */ + const TABLE = 'task_has_files'; + + /** + * SQL foreign key + * + * @var string + */ + const FOREIGN_KEY = 'task_id'; + + /** + * Path prefix + * + * @var string + */ + const PATH_PREFIX = 'tasks'; + + /** + * Events + * + * @var string + */ + const EVENT_CREATE = 'task.file.create'; + + /** + * Handle screenshot upload + * + * @access public + * @param integer $task_id Task id + * @param string $blob Base64 encoded image + * @return bool|integer + */ + public function uploadScreenshot($task_id, $blob) + { + $original_filename = e('Screenshot taken %s', $this->helper->dt->datetime(time())).'.png'; + return $this->uploadContent($task_id, $original_filename, $blob); + } +} diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php index 4d673097..95ddc12f 100644 --- a/app/Model/TaskFinder.php +++ b/app/Model/TaskFinder.php @@ -89,7 +89,7 @@ class TaskFinder extends Base ->table(Task::TABLE) ->columns( '(SELECT COUNT(*) FROM '.Comment::TABLE.' WHERE task_id=tasks.id) AS nb_comments', - '(SELECT COUNT(*) FROM '.File::TABLE.' WHERE task_id=tasks.id) AS nb_files', + '(SELECT COUNT(*) FROM '.TaskFile::TABLE.' WHERE task_id=tasks.id) AS nb_files', '(SELECT COUNT(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id) AS nb_subtasks', '(SELECT COUNT(*) FROM '.Subtask::TABLE.' WHERE '.Subtask::TABLE.'.task_id=tasks.id AND status=2) AS nb_completed_subtasks', '(SELECT COUNT(*) FROM '.TaskLink::TABLE.' WHERE '.TaskLink::TABLE.'.task_id = tasks.id) AS nb_links', diff --git a/app/Notification/Mail.php b/app/Notification/Mail.php index d05dbdf2..c924fb50 100644 --- a/app/Notification/Mail.php +++ b/app/Notification/Mail.php @@ -4,7 +4,7 @@ namespace Kanboard\Notification; use Kanboard\Core\Base; use Kanboard\Model\Task; -use Kanboard\Model\File; +use Kanboard\Model\TaskFile; use Kanboard\Model\Comment; use Kanboard\Model\Subtask; @@ -82,7 +82,7 @@ class Mail extends Base implements NotificationInterface public function getMailSubject($event_name, array $event_data) { switch ($event_name) { - case File::EVENT_CREATE: + case TaskFile::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New attachment'), $event_data); break; case Comment::EVENT_CREATE: diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 1cebbd22..c85dde6f 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,27 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 105; +const VERSION = 106; + +function version_106(PDO $pdo) +{ + $pdo->exec('RENAME TABLE files TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + `id` INT NOT NULL AUTO_INCREMENT, + `project_id` INT NOT NULL, + `name` VARCHAR(255) NOT NULL, + `path` VARCHAR(255) NOT NULL, + `is_image` TINYINT(1) DEFAULT 0, + `size` INT DEFAULT 0 NOT NULL, + `user_id` INT DEFAULT 0 NOT NULL, + `date` INT DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + PRIMARY KEY(id) + ) ENGINE=InnoDB CHARSET=utf8" + ); +} function version_105(PDO $pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index b0b89a7c..dc8de510 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,26 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 85; +const VERSION = 86; + +function version_86(PDO $pdo) +{ + $pdo->exec('ALTER TABLE files RENAME TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + id SERIAL PRIMARY KEY, + project_id INTEGER NOT NULL, + name VARCHAR(255) NOT NULL, + path VARCHAR(255) NOT NULL, + is_image BOOLEAN DEFAULT '0', + size INTEGER DEFAULT 0 NOT NULL, + user_id INTEGER DEFAULT 0 NOT NULL, + date INTEGER DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE + )" + ); +} function version_85(PDO $pdo) { @@ -17,7 +36,7 @@ function version_84(PDO $pdo) { $pdo->exec(" CREATE TABLE task_has_external_links ( - id SERIAL, + id SERIAL PRIMARY KEY, link_type VARCHAR(100) NOT NULL, dependency VARCHAR(100) NOT NULL, title VARCHAR(255) NOT NULL, diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index aa10e58b..e88f621f 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,26 @@ use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; use PDO; -const VERSION = 97; +const VERSION = 98; + +function version_98(PDO $pdo) +{ + $pdo->exec('ALTER TABLE files RENAME TO task_has_files'); + + $pdo->exec(" + CREATE TABLE project_has_files ( + id INTEGER PRIMARY KEY, + project_id INTEGER NOT NULL, + name TEXT COLLATE NOCASE NOT NULL, + path TEXT NOT NULL, + is_image INTEGER DEFAULT 0, + size INTEGER DEFAULT 0 NOT NULL, + user_id INTEGER DEFAULT 0 NOT NULL, + date INTEGER DEFAULT 0 NOT NULL, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE + )" + ); +} function version_97(PDO $pdo) { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index 61a4c512..a4fa1ff2 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -31,7 +31,6 @@ class ClassProvider implements ServiceProviderInterface 'Config', 'Currency', 'CustomFilter', - 'File', 'Group', 'GroupMember', 'LastLogin', @@ -40,6 +39,7 @@ class ClassProvider implements ServiceProviderInterface 'OverdueNotification', 'PasswordReset', 'Project', + 'ProjectFile', 'ProjectActivity', 'ProjectDuplication', 'ProjectDailyColumnStats', @@ -63,6 +63,7 @@ class ClassProvider implements ServiceProviderInterface 'TaskExport', 'TaskExternalLink', 'TaskFinder', + 'TaskFile', 'TaskFilter', 'TaskLink', 'TaskModification', diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php index 07660050..651b8a96 100644 --- a/app/Subscriber/NotificationSubscriber.php +++ b/app/Subscriber/NotificationSubscriber.php @@ -6,7 +6,7 @@ use Kanboard\Event\GenericEvent; use Kanboard\Model\Task; use Kanboard\Model\Comment; use Kanboard\Model\Subtask; -use Kanboard\Model\File; +use Kanboard\Model\TaskFile; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class NotificationSubscriber extends BaseSubscriber implements EventSubscriberInterface @@ -28,7 +28,7 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn Comment::EVENT_CREATE => 'handleEvent', Comment::EVENT_UPDATE => 'handleEvent', Comment::EVENT_USER_MENTION => 'handleEvent', - File::EVENT_CREATE => 'handleEvent', + TaskFile::EVENT_CREATE => 'handleEvent', ); } diff --git a/app/Template/event/file_create.php b/app/Template/event/task_file_create.php index 1a36bc8f..1a36bc8f 100644 --- a/app/Template/event/file_create.php +++ b/app/Template/event/task_file_create.php diff --git a/app/Template/notification/file_create.php b/app/Template/notification/task_file_create.php index 63f7d1b8..63f7d1b8 100644 --- a/app/Template/notification/file_create.php +++ b/app/Template/notification/task_file_create.php |