Add ProjecFile and TaskFile models
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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']),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
* Get PicoDb query to get all files
|
||||
*
|
||||
* @var string
|
||||
* @access protected
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
const TABLE = 'files';
|
||||
|
||||
/**
|
||||
* Events
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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,7 +50,96 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all files
|
||||
*
|
||||
* @access public
|
||||
* @param integer $id
|
||||
* @return array
|
||||
*/
|
||||
public function getAll($id)
|
||||
{
|
||||
return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all images
|
||||
*
|
||||
* @access public
|
||||
* @param integer $id
|
||||
* @return array
|
||||
*/
|
||||
public function getAllImages($id)
|
||||
{
|
||||
return $this->getQuery()->eq(static::FOREIGN_KEY, $id)->eq('is_image', 1)->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $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($id, $name, $path, $size)
|
||||
{
|
||||
$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(),
|
||||
);
|
||||
|
||||
$result = $this->db->table(static::TABLE)->insert($values);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all files
|
||||
*
|
||||
* @access public
|
||||
* @param integer $id
|
||||
* @return bool
|
||||
*/
|
||||
public function removeAll($id)
|
||||
{
|
||||
$file_ids = $this->db->table(static::TABLE)->eq(static::FOREIGN_KEY, $id)->asc('id')->findAllByColumn('id');
|
||||
$results = array();
|
||||
|
||||
foreach ($file_ids as $file_id) {
|
||||
$results[] = $this->remove($file_id);
|
||||
}
|
||||
|
||||
return ! in_array(false, $results, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,135 +152,20 @@ class File extends Base
|
||||
public function remove($file_id)
|
||||
{
|
||||
try {
|
||||
$file = $this->getbyId($file_id);
|
||||
$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();
|
||||
return $this->db->table(static::TABLE)->eq('id', $file['id'])->remove();
|
||||
} catch (ObjectStorageException $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all files for a given task
|
||||
*
|
||||
* @access public
|
||||
* @param integer $task_id Task id
|
||||
* @return bool
|
||||
*/
|
||||
public function removeAll($task_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 ! in_array(false, $results, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file entry in the database
|
||||
*
|
||||
* @access public
|
||||
* @param integer $task_id Task id
|
||||
* @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)
|
||||
{
|
||||
$result = $this->db->table(self::TABLE)->save(array(
|
||||
'task_id' => $task_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))
|
||||
);
|
||||
|
||||
return (int) $this->db->getLastId();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PicoDb query to get all files
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all files without images for a given task
|
||||
*
|
||||
* @access public
|
||||
* @param integer $task_id Task id
|
||||
* @return array
|
||||
*/
|
||||
public function getAllDocuments($task_id)
|
||||
{
|
||||
return $this->getQuery()->eq('task_id', $task_id)->eq('is_image', 0)->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a filename is an image (file types that can be shown as thumbnail)
|
||||
*
|
||||
@@ -225,20 +212,6 @@ class File extends Base
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the path for a new filename
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $task_id Task id
|
||||
* @param string $filename Filename
|
||||
* @return string
|
||||
*/
|
||||
public function generatePath($project_id, $task_id, $filename)
|
||||
{
|
||||
return $project_id.DIRECTORY_SEPARATOR.$task_id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the path for a thumbnails
|
||||
*
|
||||
@@ -252,77 +225,84 @@ class File extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file upload
|
||||
* Generate the path for a new filename
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $task_id Task id
|
||||
* @param string $form_name File form name
|
||||
* @param integer $id Foreign key
|
||||
* @param string $filename Filename
|
||||
* @return string
|
||||
*/
|
||||
public function generatePath($id, $filename)
|
||||
{
|
||||
return static::PATH_PREFIX.DIRECTORY_SEPARATOR.$id.DIRECTORY_SEPARATOR.hash('sha1', $filename.time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload multiple files
|
||||
*
|
||||
* @access public
|
||||
* @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);
|
||||
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],
|
||||
);
|
||||
|
||||
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]
|
||||
);
|
||||
}
|
||||
$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)
|
||||
|
||||
@@ -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']);
|
||||
|
||||
40
app/Model/ProjectFile.php
Normal file
40
app/Model/ProjectFile.php
Normal file
@@ -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';
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
54
app/Model/TaskFile.php
Normal file
54
app/Model/TaskFile.php
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user