summaryrefslogtreecommitdiff
path: root/app/Model
diff options
context:
space:
mode:
Diffstat (limited to 'app/Model')
-rw-r--r--app/Model/Acl.php2
-rw-r--r--app/Model/Action.php14
-rw-r--r--app/Model/Base.php47
-rw-r--r--app/Model/Board.php16
-rw-r--r--app/Model/Comment.php23
-rw-r--r--app/Model/File.php9
-rw-r--r--app/Model/GitHub.php25
-rw-r--r--app/Model/Google.php20
-rw-r--r--app/Model/Ldap.php3
-rw-r--r--app/Model/Notification.php215
-rw-r--r--app/Model/Project.php36
-rw-r--r--app/Model/RememberMe.php7
-rw-r--r--app/Model/ReverseProxyAuth.php18
-rw-r--r--app/Model/SubTask.php44
-rw-r--r--app/Model/Task.php152
-rw-r--r--app/Model/User.php11
-rw-r--r--app/Model/Webhook.php8
17 files changed, 486 insertions, 164 deletions
diff --git a/app/Model/Acl.php b/app/Model/Acl.php
index 8a87a6b2..c4b31079 100644
--- a/app/Model/Acl.php
+++ b/app/Model/Acl.php
@@ -33,7 +33,7 @@ class Acl extends Base
'board' => array('index', 'show', 'assign', 'assigntask', 'save', 'check'),
'project' => array('tasks', 'index', 'forbidden', 'search'),
'user' => array('index', 'edit', 'update', 'forbidden', 'logout', 'index', 'unlinkgoogle', 'unlinkgithub'),
- 'config' => array('index', 'removeremembermetoken'),
+ 'config' => array('index', 'removeremembermetoken', 'notifications'),
'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'),
'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'),
'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove'),
diff --git a/app/Model/Action.php b/app/Model/Action.php
index 25e72f58..effe8707 100644
--- a/app/Model/Action.php
+++ b/app/Model/Action.php
@@ -224,25 +224,25 @@ class Action extends Base
switch ($name) {
case 'TaskClose':
$className = '\Action\TaskClose';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
case 'TaskAssignCurrentUser':
$className = '\Action\TaskAssignCurrentUser';
- return new $className($project_id, new Task($this->db, $this->event), new Acl($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry), new Acl($this->registry));
case 'TaskAssignSpecificUser':
$className = '\Action\TaskAssignSpecificUser';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
case 'TaskDuplicateAnotherProject':
$className = '\Action\TaskDuplicateAnotherProject';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
case 'TaskAssignColorUser':
$className = '\Action\TaskAssignColorUser';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
case 'TaskAssignColorCategory':
$className = '\Action\TaskAssignColorCategory';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
case 'TaskAssignCategoryColor':
$className = '\Action\TaskAssignCategoryColor';
- return new $className($project_id, new Task($this->db, $this->event));
+ return new $className($project_id, new Task($this->registry));
default:
throw new LogicException('Action not found: '.$name);
}
diff --git a/app/Model/Base.php b/app/Model/Base.php
index 66185aeb..92578ffc 100644
--- a/app/Model/Base.php
+++ b/app/Model/Base.php
@@ -17,6 +17,8 @@ require __DIR__.'/../../vendor/SimpleValidator/Validators/Email.php';
require __DIR__.'/../../vendor/SimpleValidator/Validators/Numeric.php';
use Core\Event;
+use Core\Tool;
+use Core\Registry;
use PicoDb\Database;
/**
@@ -24,6 +26,21 @@ use PicoDb\Database;
*
* @package model
* @author Frederic Guillot
+ *
+ * @property \Model\Acl $acl
+ * @property \Model\Action $action
+ * @property \Model\Board $board
+ * @property \Model\Category $category
+ * @property \Model\Comment $comment
+ * @property \Model\Config $config
+ * @property \Model\File $file
+ * @property \Model\LastLogin $lastLogin
+ * @property \Model\Ldap $ldap
+ * @property \Model\Notification $notification
+ * @property \Model\Project $project
+ * @property \Model\SubTask $subTask
+ * @property \Model\Task $task
+ * @property \Model\User $user
*/
abstract class Base
{
@@ -44,15 +61,35 @@ abstract class Base
protected $event;
/**
+ * Registry instance
+ *
+ * @access protected
+ * @var \Core\Registry
+ */
+ protected $registry;
+
+ /**
* Constructor
*
* @access public
- * @param \PicoDb\Database $db Database instance
- * @param \Core\Event $event Event dispatcher instance
+ * @param \Core\Registry $registry Registry instance
+ */
+ public function __construct(Registry $registry)
+ {
+ $this->registry = $registry;
+ $this->db = $this->registry->shared('db');
+ $this->event = $this->registry->shared('event');
+ }
+
+ /**
+ * Load automatically models
+ *
+ * @access public
+ * @param string $name Model name
+ * @return mixed
*/
- public function __construct(Database $db, Event $event)
+ public function __get($name)
{
- $this->db = $db;
- $this->event = $event;
+ return Tool::loadModel($this->registry, $name);
}
}
diff --git a/app/Model/Board.php b/app/Model/Board.php
index a4e0a345..168b185f 100644
--- a/app/Model/Board.php
+++ b/app/Model/Board.php
@@ -24,17 +24,18 @@ class Board extends Base
* Save task positions for each column
*
* @access public
- * @param array $values [['task_id' => X, 'column_id' => X, 'position' => X], ...]
+ * @param array $positions [['task_id' => X, 'column_id' => X, 'position' => X], ...]
+ * @param integer $selected_task_id The selected task id
* @return boolean
*/
- public function saveTasksPosition(array $values)
+ public function saveTasksPosition(array $positions, $selected_task_id)
{
- $taskModel = new Task($this->db, $this->event);
-
$this->db->startTransaction();
- foreach ($values as $value) {
- if (! $taskModel->move($value['task_id'], $value['column_id'], $value['position'])) {
+ foreach ($positions as $value) {
+
+ // We trigger events only for the selected task
+ if (! $this->task->move($value['task_id'], $value['column_id'], $value['position'], $value['task_id'] == $selected_task_id)) {
$this->db->cancelTransaction();
return false;
}
@@ -201,8 +202,7 @@ class Board extends Base
$filters[] = array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id);
$filters[] = array('column' => 'is_active', 'operator' => 'eq', 'value' => Task::STATUS_OPEN);
- $taskModel = new Task($this->db, $this->event);
- $tasks = $taskModel->find($filters);
+ $tasks = $this->task->find($filters);
foreach ($columns as &$column) {
diff --git a/app/Model/Comment.php b/app/Model/Comment.php
index b5102070..b849fc23 100644
--- a/app/Model/Comment.php
+++ b/app/Model/Comment.php
@@ -21,6 +21,14 @@ class Comment extends Base
const TABLE = 'comments';
/**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_UPDATE = 'comment.update';
+ const EVENT_CREATE = 'comment.create';
+
+ /**
* Get all comments for a given task
*
* @access public
@@ -95,7 +103,14 @@ class Comment extends Base
{
$values['date'] = time();
- return $this->db->table(self::TABLE)->save($values);
+ if ($this->db->table(self::TABLE)->save($values)) {
+
+ $values['id'] = $this->db->getConnection()->getLastId();
+ $this->event->trigger(self::EVENT_CREATE, $values);
+ return true;
+ }
+
+ return false;
}
/**
@@ -107,10 +122,14 @@ class Comment extends Base
*/
public function update(array $values)
{
- return $this->db
+ $result = $this->db
->table(self::TABLE)
->eq('id', $values['id'])
->update(array('comment' => $values['comment']));
+
+ $this->event->trigger(self::EVENT_UPDATE, $values);
+
+ return $result;
}
/**
diff --git a/app/Model/File.php b/app/Model/File.php
index 2a793217..d5a0c7cd 100644
--- a/app/Model/File.php
+++ b/app/Model/File.php
@@ -25,6 +25,13 @@ class File extends Base
const BASE_PATH = 'data/files/';
/**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_CREATE = 'file.create';
+
+ /**
* Get a file by the id
*
* @access public
@@ -82,6 +89,8 @@ class File extends Base
*/
public function create($task_id, $name, $path, $is_image)
{
+ $this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id, 'name' => $name));
+
return $this->db->table(self::TABLE)->save(array(
'task_id' => $task_id,
'name' => $name,
diff --git a/app/Model/GitHub.php b/app/Model/GitHub.php
index 3380218d..bf4f4c51 100644
--- a/app/Model/GitHub.php
+++ b/app/Model/GitHub.php
@@ -26,22 +26,19 @@ class GitHub extends Base
*/
public function authenticate($github_id)
{
- $userModel = new User($this->db, $this->event);
-
- $user = $userModel->getByGitHubId($github_id);
+ $user = $this->user->getByGitHubId($github_id);
if ($user) {
// Create the user session
- $userModel->updateSession($user);
+ $this->user->updateSession($user);
// Update login history
- $lastLogin = new LastLogin($this->db, $this->event);
- $lastLogin->create(
+ $this->lastLogin->create(
LastLogin::AUTH_GITHUB,
$user['id'],
- $userModel->getIpAddress(),
- $userModel->getUserAgent()
+ $this->user->getIpAddress(),
+ $this->user->getUserAgent()
);
return true;
@@ -59,9 +56,7 @@ class GitHub extends Base
*/
public function unlink($user_id)
{
- $userModel = new User($this->db, $this->event);
-
- return $userModel->update(array(
+ return $this->user->update(array(
'id' => $user_id,
'github_id' => '',
));
@@ -78,9 +73,7 @@ class GitHub extends Base
*/
public function updateUser($user_id, array $profile)
{
- $userModel = new User($this->db, $this->event);
-
- return $userModel->update(array(
+ return $this->user->update(array(
'id' => $user_id,
'github_id' => $profile['id'],
'email' => $profile['email'],
@@ -141,7 +134,7 @@ class GitHub extends Base
try {
$gitHubService = $this->getService();
$gitHubService->requestAccessToken($code);
-
+
return json_decode($gitHubService->request('user'), true);
}
catch (TokenResponseException $e) {
@@ -150,7 +143,7 @@ class GitHub extends Base
return false;
}
-
+
/**
* Revokes this user's GitHub tokens for Kanboard
*
diff --git a/app/Model/Google.php b/app/Model/Google.php
index f5beb8f8..cca4f668 100644
--- a/app/Model/Google.php
+++ b/app/Model/Google.php
@@ -27,21 +27,19 @@ class Google extends Base
*/
public function authenticate($google_id)
{
- $userModel = new User($this->db, $this->event);
- $user = $userModel->getByGoogleId($google_id);
+ $user = $this->user->getByGoogleId($google_id);
if ($user) {
// Create the user session
- $userModel->updateSession($user);
+ $this->user->updateSession($user);
// Update login history
- $lastLogin = new LastLogin($this->db, $this->event);
- $lastLogin->create(
+ $this->lastLogin->create(
LastLogin::AUTH_GOOGLE,
$user['id'],
- $userModel->getIpAddress(),
- $userModel->getUserAgent()
+ $this->user->getIpAddress(),
+ $this->user->getUserAgent()
);
return true;
@@ -59,9 +57,7 @@ class Google extends Base
*/
public function unlink($user_id)
{
- $userModel = new User($this->db, $this->event);
-
- return $userModel->update(array(
+ return $this->user->update(array(
'id' => $user_id,
'google_id' => '',
));
@@ -77,9 +73,7 @@ class Google extends Base
*/
public function updateUser($user_id, array $profile)
{
- $userModel = new User($this->db, $this->event);
-
- return $userModel->update(array(
+ return $this->user->update(array(
'id' => $user_id,
'google_id' => $profile['id'],
'email' => $profile['email'],
diff --git a/app/Model/Ldap.php b/app/Model/Ldap.php
index dabcd5ff..007f7171 100644
--- a/app/Model/Ldap.php
+++ b/app/Model/Ldap.php
@@ -73,8 +73,7 @@ class Ldap extends Base
*/
public function create($username, $name, $email)
{
- $userModel = new User($this->db, $this->event);
- $user = $userModel->getByUsername($username);
+ $user = $this->user->getByUsername($username);
// There is an existing user account
if ($user) {
diff --git a/app/Model/Notification.php b/app/Model/Notification.php
new file mode 100644
index 00000000..e0f932a4
--- /dev/null
+++ b/app/Model/Notification.php
@@ -0,0 +1,215 @@
+<?php
+
+namespace Model;
+
+use Core\Template;
+use Event\TaskNotificationListener;
+use Event\CommentNotificationListener;
+use Event\FileNotificationListener;
+use Event\SubTaskNotificationListener;
+use Swift_Message;
+use Swift_Mailer;
+
+/**
+ * Notification model
+ *
+ * @package model
+ * @author Frederic Guillot
+ */
+class Notification extends Base
+{
+ /**
+ * SQL table name
+ *
+ * @var string
+ */
+ const TABLE = 'user_has_notifications';
+
+ /**
+ * Get the list of users to send the notification for a given project
+ *
+ * @access public
+ * @param integer $project_id Project id
+ * @return array
+ */
+ public function getUsersList($project_id)
+ {
+ $users = $this->db->table(User::TABLE)
+ ->columns('id', 'username', 'name', 'email')
+ ->eq('notifications_enabled', '1')
+ ->neq('email', '')
+ ->findAll();
+
+ foreach ($users as $index => $user) {
+
+ $projects = $this->db->table(self::TABLE)
+ ->eq('user_id', $user['id'])
+ ->findAllByColumn('project_id');
+
+ // The user have selected only some projects
+ if (! empty($projects)) {
+
+ // If the user didn't select this project we remove that guy from the list
+ if (! in_array($project_id, $projects)) {
+ unset($users[$index]);
+ }
+ }
+ }
+
+ return $users;
+ }
+
+ /**
+ * Attach events
+ *
+ * @access public
+ */
+ public function attachEvents()
+ {
+ $this->event->attach(File::EVENT_CREATE, new FileNotificationListener($this, 'notification_file_creation'));
+
+ $this->event->attach(Comment::EVENT_CREATE, new CommentNotificationListener($this, 'notification_comment_creation'));
+ $this->event->attach(Comment::EVENT_UPDATE, new CommentNotificationListener($this, 'notification_comment_update'));
+
+ $this->event->attach(SubTask::EVENT_CREATE, new SubTaskNotificationListener($this, 'notification_subtask_creation'));
+ $this->event->attach(SubTask::EVENT_UPDATE, new SubTaskNotificationListener($this, 'notification_subtask_update'));
+
+ $this->event->attach(Task::EVENT_CREATE, new TaskNotificationListener($this, 'notification_task_creation'));
+ $this->event->attach(Task::EVENT_UPDATE, new TaskNotificationListener($this, 'notification_task_update'));
+ $this->event->attach(Task::EVENT_CLOSE, new TaskNotificationListener($this, 'notification_task_close'));
+ $this->event->attach(Task::EVENT_OPEN, new TaskNotificationListener($this, 'notification_task_open'));
+ }
+
+ /**
+ * Send the email notifications
+ *
+ * @access public
+ * @param string $template Template name
+ * @param array $users List of users
+ * @param array $data Template data
+ */
+ public function sendEmails($template, array $users, array $data)
+ {
+ $transport = $this->registry->shared('mailer');
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ $message = Swift_Message::newInstance()
+ ->setSubject($this->getMailSubject($template, $data))
+ ->setFrom(array(MAIL_FROM => 'Kanboard'))
+ //->setTo(array($user['email'] => $user['name']))
+ ->setBody($this->getMailContent($template, $data), 'text/html');
+
+ foreach ($users as $user) {
+ $message->setTo(array($user['email'] => $user['name'] ?: $user['username']));
+ $mailer->send($message);
+ }
+ }
+
+ /**
+ * Get the mail subject for a given template name
+ *
+ * @access public
+ * @param string $template Template name
+ * @param array $data Template data
+ */
+ public function getMailSubject($template, array $data)
+ {
+ switch ($template) {
+ case 'notification_file_creation':
+ return t('[%s][New attachment] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_comment_creation':
+ return t('[%s][New comment] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_comment_update':
+ return t('[%s][Comment updated] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_subtask_creation':
+ return t('[%s][New subtask] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_subtask_update':
+ return t('[%s][Subtask updated] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_task_creation':
+ return t('[%s][New task] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_task_update':
+ return t('[%s][Task updated] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_task_close':
+ return t('[%s][Task closed] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_task_open':
+ return t('[%s][Task opened] %s (#%d)', $data['task']['project_name'], $data['task']['title'], $data['task']['id']);
+ case 'notification_task_due':
+ return t('[%s][Due tasks]', $data['project']);
+ }
+
+ return t('[Kanboard] Notification');
+ }
+
+ /**
+ * Get the mail content for a given template name
+ *
+ * @access public
+ * @param string $template Template name
+ * @param array $data Template data
+ */
+ public function getMailContent($template, array $data)
+ {
+ $tpl = new Template;
+ return $tpl->load($template, $data);
+ }
+
+ /**
+ * Save settings for the given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param array $values Form values
+ */
+ public function saveSettings($user_id, array $values)
+ {
+ // Delete all selected projects
+ $this->db->table(self::TABLE)->eq('user_id', $user_id)->remove();
+
+ if (isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1) {
+
+ // Activate notifications
+ $this->db->table(User::TABLE)->eq('id', $user_id)->update(array(
+ 'notifications_enabled' => '1'
+ ));
+
+ // Save selected projects
+ if (! empty($values['projects'])) {
+
+ foreach ($values['projects'] as $project_id => $checkbox_value) {
+ $this->db->table(self::TABLE)->insert(array(
+ 'user_id' => $user_id,
+ 'project_id' => $project_id,
+ ));
+ }
+ }
+ }
+ else {
+
+ // Disable notifications
+ $this->db->table(User::TABLE)->eq('id', $user_id)->update(array(
+ 'notifications_enabled' => '0'
+ ));
+ }
+ }
+
+ /**
+ * Read user settings to display the form
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return array
+ */
+ public function readSettings($user_id)
+ {
+ $values = array();
+ $values['notifications_enabled'] = $this->db->table(User::TABLE)->eq('id', $user_id)->findOneColumn('notifications_enabled');
+
+ $projects = $this->db->table(self::TABLE)->eq('user_id', $user_id)->findAllByColumn('project_id');
+
+ foreach ($projects as $project_id) {
+ $values['project_'.$project_id] = true;
+ }
+
+ return $values;
+ }
+}
diff --git a/app/Model/Project.php b/app/Model/Project.php
index f598c96f..63458fa3 100644
--- a/app/Model/Project.php
+++ b/app/Model/Project.php
@@ -55,10 +55,9 @@ class Project extends Base
public function getUsersList($project_id, $prepend_unassigned = true, $prepend_everybody = false)
{
$allowed_users = $this->getAllowedUsers($project_id);
- $userModel = new User($this->db, $this->event);
if (empty($allowed_users)) {
- $allowed_users = $userModel->getList();
+ $allowed_users = $this->user->getList();
}
if ($prepend_unassigned) {
@@ -103,8 +102,7 @@ class Project extends Base
'not_allowed' => array(),
);
- $userModel = new User($this->db, $this->event);
- $all_users = $userModel->getList();
+ $all_users = $this->user->getList();
$users['allowed'] = $this->getAllowedUsers($project_id);
@@ -253,27 +251,23 @@ class Project extends Base
->asc('name')
->findAll();
- $boardModel = new Board($this->db, $this->event);
- $taskModel = new Task($this->db, $this->event);
- $aclModel = new Acl($this->db, $this->event);
-
foreach ($projects as $pkey => &$project) {
- if ($check_permissions && ! $this->isUserAllowed($project['id'], $aclModel->getUserId())) {
+ if ($check_permissions && ! $this->isUserAllowed($project['id'], $this->acl->getUserId())) {
unset($projects[$pkey]);
}
else {
- $columns = $boardModel->getcolumns($project['id']);
+ $columns = $this->board->getcolumns($project['id']);
$project['nb_active_tasks'] = 0;
foreach ($columns as &$column) {
- $column['nb_active_tasks'] = $taskModel->countByColumnId($project['id'], $column['id']);
+ $column['nb_active_tasks'] = $this->task->countByColumnId($project['id'], $column['id']);
$project['nb_active_tasks'] += $column['nb_active_tasks'];
}
$project['columns'] = $columns;
- $project['nb_tasks'] = $taskModel->countByProjectId($project['id']);
+ $project['nb_tasks'] = $this->task->countByProjectId($project['id']);
$project['nb_inactive_tasks'] = $project['nb_tasks'] - $project['nb_active_tasks'];
}
}
@@ -416,9 +410,8 @@ class Project extends Base
*/
public function copyBoardFromAnotherProject($project_from, $project_to)
{
- $boardModel = new Board($this->db, $this->event);
$columns = $this->db->table(Board::TABLE)->eq('project_id', $project_from)->asc('position')->findAllByColumn('title');
- return $boardModel->create($project_to, $columns);
+ return $this->board->create($project_to, $columns);
}
/**
@@ -431,8 +424,7 @@ class Project extends Base
*/
public function copyCategoriesFromAnotherProject($project_from, $project_to)
{
- $categoryModel = new Category($this->db, $this->event);
- $categoriesTemplate = $categoryModel->getAll($project_from);
+ $categoriesTemplate = $this->category->getAll($project_from);
foreach ($categoriesTemplate as $category) {
@@ -478,8 +470,7 @@ class Project extends Base
*/
public function copyActionsFromAnotherProject($project_from, $project_to)
{
- $actionModel = new Action($this->db, $this->event);
- $actionTemplate = $actionModel->getAllByProject($project_from);
+ $actionTemplate = $this->action->getAllByProject($project_from);
foreach ($actionTemplate as $action) {
@@ -522,13 +513,11 @@ class Project extends Base
case 'project_id':
return $project_to;
case 'category_id':
- $categoryModel = new Category($this->db, $this->event);
- $categoryTemplate = $categoryModel->getById($param['value']);
+ $categoryTemplate = $this->category->getById($param['value']);
$categoryFromNewProject = $this->db->table(Category::TABLE)->eq('project_id', $project_to)->eq('name', $categoryTemplate['name'])->findOne();
return $categoryFromNewProject['id'];
case 'column_id':
- $boardModel = new Board($this->db, $this->event);
- $boardTemplate = $boardModel->getColumn($param['value']);
+ $boardTemplate = $this->board->getColumn($param['value']);
$boardFromNewProject = $this->db->table(Board::TABLE)->eq('project_id', $project_to)->eq('title', $boardTemplate['title'])->findOne();
return $boardFromNewProject['id'];
default:
@@ -603,8 +592,7 @@ class Project extends Base
$project_id = $this->db->getConnection()->getLastId();
- $boardModel = new Board($this->db, $this->event);
- $boardModel->create($project_id, array(
+ $this->board->create($project_id, array(
t('Backlog'),
t('Ready'),
t('Work in progress'),
diff --git a/app/Model/RememberMe.php b/app/Model/RememberMe.php
index 272b4916..e23ed887 100644
--- a/app/Model/RememberMe.php
+++ b/app/Model/RememberMe.php
@@ -92,11 +92,8 @@ class RememberMe extends Base
);
// Create the session
- $user = new User($this->db, $this->event);
- $acl = new Acl($this->db, $this->event);
-
- $user->updateSession($user->getById($record['user_id']));
- $acl->isRememberMe(true);
+ $this->user->updateSession($this->user->getById($record['user_id']));
+ $this->acl->isRememberMe(true);
return true;
}
diff --git a/app/Model/ReverseProxyAuth.php b/app/Model/ReverseProxyAuth.php
index 1b9ed06c..14d18ba3 100644
--- a/app/Model/ReverseProxyAuth.php
+++ b/app/Model/ReverseProxyAuth.php
@@ -23,24 +23,22 @@ class ReverseProxyAuth extends Base
if (isset($_SERVER[REVERSE_PROXY_USER_HEADER])) {
$login = $_SERVER[REVERSE_PROXY_USER_HEADER];
- $userModel = new User($this->db, $this->event);
- $user = $userModel->getByUsername($login);
+ $user = $this->user->getByUsername($login);
if (! $user) {
$this->createUser($login);
- $user = $userModel->getByUsername($login);
+ $user = $this->user->getByUsername($login);
}
// Create the user session
- $userModel->updateSession($user);
+ $this->user->updateSession($user);
// Update login history
- $lastLogin = new LastLogin($this->db, $this->event);
- $lastLogin->create(
+ $this->lastLogin->create(
LastLogin::AUTH_REVERSE_PROXY,
$user['id'],
- $userModel->getIpAddress(),
- $userModel->getUserAgent()
+ $this->user->getIpAddress(),
+ $this->user->getUserAgent()
);
return true;
@@ -58,9 +56,7 @@ class ReverseProxyAuth extends Base
*/
private function createUser($login)
{
- $userModel = new User($this->db, $this->event);
-
- return $userModel->create(array(
+ return $this->user->create(array(
'email' => strpos($login, '@') !== false ? $login : '',
'username' => $login,
'is_admin' => REVERSE_PROXY_DEFAULT_ADMIN === $login,
diff --git a/app/Model/SubTask.php b/app/Model/SubTask.php
index 21ccdaac..c7bab44b 100644
--- a/app/Model/SubTask.php
+++ b/app/Model/SubTask.php
@@ -42,6 +42,14 @@ class SubTask extends Base
const STATUS_TODO = 0;
/**
+ * Events
+ *
+ * @var string
+ */
+ const EVENT_UPDATE = 'subtask.update';
+ const EVENT_CREATE = 'subtask.create';
+
+ /**
* Get available status
*
* @access public
@@ -88,10 +96,27 @@ class SubTask extends Base
*
* @access public
* @param integer $subtask_id Subtask id
+ * @param bool $more Fetch more data
* @return array
*/
- public function getById($subtask_id)
+ public function getById($subtask_id, $more = false)
{
+ if ($more) {
+
+ $subtask = $this->db->table(self::TABLE)
+ ->eq(self::TABLE.'.id', $subtask_id)
+ ->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
+ ->join(User::TABLE, 'id', 'user_id')
+ ->findOne();
+
+ if ($subtask) {
+ $status = $this->getStatusList();
+ $subtask['status_name'] = $status[$subtask['status']];
+ }
+
+ return $subtask;
+ }
+
return $this->db->table(self::TABLE)->eq('id', $subtask_id)->findOne();
}
@@ -116,7 +141,14 @@ class SubTask extends Base
$values['time_spent'] = 0;
}
- return $this->db->table(self::TABLE)->save($values);
+ $result = $this->db->table(self::TABLE)->save($values);
+
+ if ($result) {
+ $values['id'] = $this->db->getConnection()->getLastId();
+ $this->event->trigger(self::EVENT_CREATE, $values);
+ }
+
+ return $result;
}
/**
@@ -136,7 +168,13 @@ class SubTask extends Base
$values['time_spent'] = 0;
}
- return $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
+ $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
+
+ if ($result) {
+ $this->event->trigger(self::EVENT_UPDATE, $values);
+ }
+
+ return $result;
}
/**
diff --git a/app/Model/Task.php b/app/Model/Task.php
index 0b2b9cf9..6647f041 100644
--- a/app/Model/Task.php
+++ b/app/Model/Task.php
@@ -63,6 +63,35 @@ class Task extends Base
}
/**
+ * Get a list of due tasks for all projects
+ *
+ * @access public
+ * @return array
+ */
+ public function getTasksDue()
+ {
+ $tasks = $this->db->table(self::TABLE)
+ ->columns(
+ self::TABLE.'.id',
+ self::TABLE.'.title',
+ self::TABLE.'.date_due',
+ self::TABLE.'.project_id',
+ Project::TABLE.'.name AS project_name',
+ User::TABLE.'.username AS assignee_username',
+ User::TABLE.'.name AS assignee_name'
+ )
+ ->join(Project::TABLE, 'id', 'project_id')
+ ->join(User::TABLE, 'id', 'owner_id')
+ ->eq(Project::TABLE.'.is_active', 1)
+ ->eq(self::TABLE.'.is_active', 1)
+ ->neq(self::TABLE.'.date_due', '')
+ ->lte(self::TABLE.'.date_due', mktime(23, 59, 59))
+ ->findAll();
+
+ return $tasks;
+ }
+
+ /**
* Fetch one task
*
* @access public
@@ -182,7 +211,7 @@ class Task extends Base
'tasks.category_id',
'users.username'
)
- ->join('users', 'id', 'owner_id');
+ ->join(User::TABLE, 'id', 'owner_id');
foreach ($filters as $key => $filter) {
@@ -282,8 +311,6 @@ class Task extends Base
{
$this->db->startTransaction();
- $boardModel = new Board($this->db, $this->event);
-
// Get the original task
$task = $this->getById($task_id);
@@ -296,7 +323,7 @@ class Task extends Base
$task['owner_id'] = 0;
$task['category_id'] = 0;
$task['is_active'] = 1;
- $task['column_id'] = $boardModel->getFirstColumn($project_id);
+ $task['column_id'] = $this->board->getFirstColumn($project_id);
$task['project_id'] = $project_id;
$task['position'] = $this->countByColumnId($task['project_id'], $task['column_id']);
@@ -318,17 +345,13 @@ class Task extends Base
}
/**
- * Create a task
+ * Prepare data before task creation or modification
*
* @access public
- * @param array $values Form values
- * @return boolean
+ * @param array $values Form values
*/
- public function create(array $values)
+ public function prepare(array &$values)
{
- $this->db->startTransaction();
-
- // Prepare data
if (isset($values['another_task'])) {
unset($values['another_task']);
}
@@ -336,14 +359,30 @@ class Task extends Base
if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
$values['date_due'] = $this->parseDate($values['date_due']);
}
- else {
+
+ // Force integer fields at 0 (for Postgresql)
+ if (isset($values['date_due']) && empty($values['date_due'])) {
$values['date_due'] = 0;
}
- if (empty($values['score'])) {
+ if (isset($values['score']) && empty($values['score'])) {
$values['score'] = 0;
}
+ }
+ /**
+ * Create a task
+ *
+ * @access public
+ * @param array $values Form values
+ * @return boolean
+ */
+ public function create(array $values)
+ {
+ $this->db->startTransaction();
+
+ // Prepare data
+ $this->prepare($values);
$values['date_creation'] = time();
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']);
@@ -368,31 +407,21 @@ class Task extends Base
* Update a task
*
* @access public
- * @param array $values Form values
+ * @param array $values Form values
+ * @param boolean $trigger_events Flag to trigger events
* @return boolean
*/
- public function update(array $values)
+ public function update(array $values, $trigger_events = true)
{
- // Prepare data
- if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
- $values['date_due'] = $this->parseDate($values['date_due']);
- }
-
- // Force integer fields at 0 (for Postgresql)
- if (isset($values['date_due']) && empty($values['date_due'])) {
- $values['date_due'] = 0;
- }
-
- if (isset($values['score']) && empty($values['score'])) {
- $values['score'] = 0;
- }
-
+ // Fetch original task
$original_task = $this->getById($values['id']);
if ($original_task === false) {
return false;
}
+ // Prepare data
+ $this->prepare($values);
$updated_task = $values;
$updated_task['date_modification'] = time();
unset($updated_task['id']);
@@ -400,29 +429,40 @@ class Task extends Base
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($updated_task);
// Trigger events
- if ($result) {
-
- $events = array(
- self::EVENT_CREATE_UPDATE,
- self::EVENT_UPDATE,
- );
+ if ($result && $trigger_events) {
+ $this->triggerUpdateEvents($original_task, $updated_task);
+ }
- if (isset($values['column_id']) && $original_task['column_id'] != $values['column_id']) {
- $events[] = self::EVENT_MOVE_COLUMN;
- }
- else if (isset($values['position']) && $original_task['position'] != $values['position']) {
- $events[] = self::EVENT_MOVE_POSITION;
- }
+ return $result;
+ }
- $event_data = array_merge($original_task, $values);
- $event_data['task_id'] = $original_task['id'];
+ /**
+ * Trigger events for task modification
+ *
+ * @access public
+ * @param array $original_task Original task data
+ * @param array $updated_task Updated task data
+ */
+ public function triggerUpdateEvents(array $original_task, array $updated_task)
+ {
+ $events = array(
+ self::EVENT_CREATE_UPDATE,
+ self::EVENT_UPDATE,
+ );
- foreach ($events as $event) {
- $this->event->trigger($event, $event_data);
- }
+ if (isset($updated_task['column_id']) && $original_task['column_id'] != $updated_task['column_id']) {
+ $events[] = self::EVENT_MOVE_COLUMN;
+ }
+ else if (isset($updated_task['position']) && $original_task['position'] != $updated_task['position']) {
+ $events[] = self::EVENT_MOVE_POSITION;
}
- return $result;
+ $event_data = array_merge($original_task, $updated_task);
+ $event_data['task_id'] = $original_task['id'];
+
+ foreach ($events as $event) {
+ $this->event->trigger($event, $event_data);
+ }
}
/**
@@ -482,8 +522,7 @@ class Task extends Base
*/
public function remove($task_id)
{
- $file = new File($this->db, $this->event);
- $file->removeAll($task_id);
+ $this->file->removeAll($task_id);
return $this->db->table(self::TABLE)->eq('id', $task_id)->remove();
}
@@ -492,20 +531,23 @@ class Task extends Base
* Move a task to another column or to another position
*
* @access public
- * @param integer $task_id Task id
- * @param integer $column_id Column id
- * @param integer $position Position (must be greater than 1)
+ * @param integer $task_id Task id
+ * @param integer $column_id Column id
+ * @param integer $position Position (must be greater than 1)
+ * @param boolean $trigger_events Flag to trigger events
* @return boolean
*/
- public function move($task_id, $column_id, $position)
+ public function move($task_id, $column_id, $position, $trigger_events = true)
{
$this->event->clearTriggeredEvents();
- return $this->update(array(
+ $values = array(
'id' => $task_id,
'column_id' => $column_id,
'position' => $position,
- ));
+ );
+
+ return $this->update($values, $trigger_events);
}
/**
diff --git a/app/Model/User.php b/app/Model/User.php
index b5744c44..d0e33fd0 100644
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -340,8 +340,7 @@ class User extends Base
$this->updateSession($user);
// Update login history
- $lastLogin = new LastLogin($this->db, $this->event);
- $lastLogin->create(
+ $this->lastLogin->create(
$method,
$user['id'],
$this->getIpAddress(),
@@ -350,9 +349,8 @@ class User extends Base
// Setup the remember me feature
if (! empty($values['remember_me'])) {
- $rememberMe = new RememberMe($this->db, $this->event);
- $credentials = $rememberMe->create($user['id'], $this->getIpAddress(), $this->getUserAgent());
- $rememberMe->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
+ $credentials = $this->rememberMe->create($user['id'], $this->getIpAddress(), $this->getUserAgent());
+ $this->rememberMe->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
}
}
else {
@@ -384,8 +382,7 @@ class User extends Base
// LDAP authentication
if (! $authenticated && LDAP_AUTH) {
- $ldap = new Ldap($this->db, $this->event);
- $authenticated = $ldap->authenticate($username, $password);
+ $authenticated = $this->ldap->authenticate($username, $password);
$method = LastLogin::AUTH_LDAP;
}
diff --git a/app/Model/Webhook.php b/app/Model/Webhook.php
index 679d3edc..872031cc 100644
--- a/app/Model/Webhook.php
+++ b/app/Model/Webhook.php
@@ -64,11 +64,9 @@ class Webhook extends Base
*/
public function attachEvents()
{
- $config = new Config($this->db, $this->event);
-
- $this->url_task_creation = $config->get('webhooks_url_task_creation');
- $this->url_task_modification = $config->get('webhooks_url_task_modification');
- $this->token = $config->get('webhooks_token');
+ $this->url_task_creation = $this->config->get('webhooks_url_task_creation');
+ $this->url_task_modification = $this->config->get('webhooks_url_task_modification');
+ $this->token = $this->config->get('webhooks_token');
if ($this->url_task_creation) {
$this->attachCreateEvents();