summaryrefslogtreecommitdiff
path: root/app/Model
diff options
context:
space:
mode:
Diffstat (limited to 'app/Model')
-rw-r--r--app/Model/File.php282
-rw-r--r--app/Model/Notification.php4
-rw-r--r--app/Model/ProjectFile.php40
-rw-r--r--app/Model/ProjectGroupRole.php1
-rw-r--r--app/Model/ProjectPermission.php3
-rw-r--r--app/Model/ProjectUserRole.php5
-rw-r--r--app/Model/Task.php2
-rw-r--r--app/Model/TaskFile.php54
-rw-r--r--app/Model/TaskFinder.php2
-rw-r--r--app/Model/User.php40
10 files changed, 273 insertions, 160 deletions
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/ProjectGroupRole.php b/app/Model/ProjectGroupRole.php
index 591b28c6..750ba7fb 100644
--- a/app/Model/ProjectGroupRole.php
+++ b/app/Model/ProjectGroupRole.php
@@ -106,6 +106,7 @@ class ProjectGroupRole extends Base
->join(GroupMember::TABLE, 'user_id', 'id', User::TABLE)
->join(self::TABLE, 'group_id', 'group_id', GroupMember::TABLE)
->eq(self::TABLE.'.project_id', $project_id)
+ ->eq(User::TABLE.'.is_active', 1)
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
->asc(User::TABLE.'.username')
->findAll();
diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php
index cea62e13..db1573ae 100644
--- a/app/Model/ProjectPermission.php
+++ b/app/Model/ProjectPermission.php
@@ -107,7 +107,8 @@ class ProjectPermission extends Base
*/
public function isAssignable($project_id, $user_id)
{
- return in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
+ return $this->user->isActive($user_id) &&
+ in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
}
/**
diff --git a/app/Model/ProjectUserRole.php b/app/Model/ProjectUserRole.php
index 8149a253..56da679c 100644
--- a/app/Model/ProjectUserRole.php
+++ b/app/Model/ProjectUserRole.php
@@ -152,13 +152,14 @@ class ProjectUserRole extends Base
public function getAssignableUsers($project_id)
{
if ($this->projectPermission->isEverybodyAllowed($project_id)) {
- return $this->user->getList();
+ return $this->user->getActiveUsersList();
}
$userMembers = $this->db->table(self::TABLE)
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
->join(User::TABLE, 'id', 'user_id')
- ->eq('project_id', $project_id)
+ ->eq(User::TABLE.'.is_active', 1)
+ ->eq(self::TABLE.'.project_id', $project_id)
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
->findAll();
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/Model/User.php b/app/Model/User.php
index dd622207..e2494c4c 100644
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -41,6 +41,18 @@ class User extends Base
}
/**
+ * Return true if the user is active
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return boolean
+ */
+ public function isActive($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $user_id)->eq('is_active', 1)->exists();
+ }
+
+ /**
* Get query to fetch all users
*
* @access public
@@ -193,9 +205,9 @@ class User extends Base
* @param boolean $prepend Prepend "All users"
* @return array
*/
- public function getList($prepend = false)
+ public function getActiveUsersList($prepend = false)
{
- $users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll();
+ $users = $this->db->table(self::TABLE)->eq('is_active', 1)->columns('id', 'username', 'name')->findAll();
$listing = $this->prepareList($users);
if ($prepend) {
@@ -281,6 +293,30 @@ class User extends Base
}
/**
+ * Disable a specific user
+ *
+ * @access public
+ * @param integer $user_id
+ * @return boolean
+ */
+ public function disable($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 0));
+ }
+
+ /**
+ * Enable a specific user
+ *
+ * @access public
+ * @param integer $user_id
+ * @return boolean
+ */
+ public function enable($user_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 1));
+ }
+
+ /**
* Remove a specific user
*
* @access public