diff options
Diffstat (limited to 'app')
53 files changed, 658 insertions, 1186 deletions
diff --git a/app/Action/Base.php b/app/Action/Base.php index 339aeecc..80930a4c 100644 --- a/app/Action/Base.php +++ b/app/Action/Base.php @@ -14,6 +14,7 @@ use Core\Tool; * * @property \Model\Acl $acl * @property \Model\Task $task + * @property \Model\TaskFinder $taskFinder */ abstract class Base implements Listener { diff --git a/app/Controller/Base.php b/app/Controller/Base.php index ac88df04..a8e22fd8 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -153,13 +153,11 @@ abstract class Base private function attachEvents() { $models = array( + 'projectActivity', // Order is important 'action', 'project', 'webhook', 'notification', - 'taskHistory', - 'commentHistory', - 'subtaskHistory', ); foreach ($models as $model) { diff --git a/app/Controller/Project.php b/app/Controller/Project.php index 39d8d1b0..1fac3ffb 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -364,7 +364,7 @@ class Project extends Base } $this->response->xml($this->template->load('project_feed', array( - 'events' => $this->project->getActivity($project['id']), + 'events' => $this->projectActivity->getAll($project['id']), 'project' => $project, ))); } @@ -379,7 +379,7 @@ class Project extends Base $project = $this->getProject(); $this->response->html($this->template->layout('project_activity', array( - 'events' => $this->project->getActivity($project['id']), + 'events' => $this->projectActivity->getAll($project['id']), 'menu' => 'projects', 'project' => $project, 'title' => t('%s\'s activity', $project['name']) diff --git a/app/Core/Event.php b/app/Core/Event.php index 0e6df5e8..a32499d8 100644 --- a/app/Core/Event.php +++ b/app/Core/Event.php @@ -69,11 +69,14 @@ class Event { if (! $this->isEventTriggered($eventName)) { - $this->lastEvent = $eventName; $this->events[] = $eventName; if (isset($this->listeners[$eventName])) { + foreach ($this->listeners[$eventName] as $listener) { + + $this->lastEvent = $eventName; + if ($listener->execute($data)) { $this->lastListener = get_class($listener); } diff --git a/app/Event/Base.php b/app/Event/Base.php new file mode 100644 index 00000000..745871a5 --- /dev/null +++ b/app/Event/Base.php @@ -0,0 +1,79 @@ +<?php + +namespace Event; + +use Core\Listener; +use Core\Registry; +use Core\Tool; + +/** + * Base Listener + * + * @package event + * @author Frederic Guillot + * + * @property \Model\Comment $comment + * @property \Model\Project $project + * @property \Model\ProjectActivity $projectActivity + * @property \Model\SubTask $subTask + * @property \Model\Task $task + * @property \Model\TaskFinder $taskFinder + */ +abstract class Base implements Listener +{ + /** + * Registry instance + * + * @access protected + * @var \Core\Registry + */ + protected $registry; + + /** + * Constructor + * + * @access public + * @param \Core\Registry $registry Regsitry instance + */ + public function __construct(Registry $registry) + { + $this->registry = $registry; + } + + /** + * Return class information + * + * @access public + * @return string + */ + public function __toString() + { + return get_called_class(); + } + + /** + * Load automatically models + * + * @access public + * @param string $name Model name + * @return mixed + */ + public function __get($name) + { + return Tool::loadModel($this->registry, $name); + } + + /** + * Get event namespace + * + * Event = task.close | Namespace = task + * + * @access public + * @return string + */ + public function getEventNamespace() + { + $event_name = $this->registry->event->getLastTriggeredEvent(); + return substr($event_name, 0, strpos($event_name, '.')); + } +} diff --git a/app/Event/BaseNotificationListener.php b/app/Event/BaseNotificationListener.php deleted file mode 100644 index fdabaf57..00000000 --- a/app/Event/BaseNotificationListener.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php - -namespace Event; - -use Core\Listener; -use Model\Notification; - -/** - * Base notification listener - * - * @package event - * @author Frederic Guillot - */ -abstract class BaseNotificationListener implements Listener -{ - /** - * Notification model - * - * @accesss protected - * @var Model\Notification - */ - protected $notification; - - /** - * Template name - * - * @accesss private - * @var string - */ - private $template = ''; - - /** - * Fetch data for the mail template - * - * @access public - * @param array $data Event data - * @return array - */ - abstract public function getTemplateData(array $data); - - /** - * Constructor - * - * @access public - * @param \Model\Notification $notification Notification model instance - * @param string $template Template name - */ - public function __construct(Notification $notification, $template) - { - $this->template = $template; - $this->notification = $notification; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); - } - - /** - * Execute the action - * - * @access public - * @param array $data Event data dictionary - * @return bool True if the action was executed or false when not executed - */ - public function execute(array $data) - { - $values = $this->getTemplateData($data); - - // Get the list of users to be notified - $users = $this->notification->getUsersList($values['task']['project_id']); - - // Send notifications - if ($users) { - $this->notification->sendEmails($this->template, $users, $values); - return true; - } - - return false; - } -} diff --git a/app/Event/CommentHistoryListener.php b/app/Event/CommentHistoryListener.php deleted file mode 100644 index ec826615..00000000 --- a/app/Event/CommentHistoryListener.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php - -namespace Event; - -use Core\Listener; -use Model\CommentHistory; - -/** - * Comment history listener - * - * @package event - * @author Frederic Guillot - */ -class CommentHistoryListener implements Listener -{ - /** - * Comment History model - * - * @accesss private - * @var \Model\CommentHistory - */ - private $model; - - /** - * Constructor - * - * @access public - * @param \Model\CommentHistory $model Comment History model instance - */ - public function __construct(CommentHistory $model) - { - $this->model = $model; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); - } - - /** - * Execute the action - * - * @access public - * @param array $data Event data dictionary - * @return bool True if the action was executed or false when not executed - */ - public function execute(array $data) - { - $creator_id = $this->model->acl->getUserId(); - - if ($creator_id && isset($data['task_id']) && isset($data['id'])) { - - $task = $this->model->taskFinder->getById($data['task_id']); - - $this->model->create( - $task['project_id'], - $data['task_id'], - $data['id'], - $creator_id, - $this->model->event->getLastTriggeredEvent(), - $data['comment'] - ); - } - - return false; - } -} diff --git a/app/Event/CommentNotificationListener.php b/app/Event/CommentNotificationListener.php deleted file mode 100644 index 13803874..00000000 --- a/app/Event/CommentNotificationListener.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -namespace Event; - -use Event\BaseNotificationListener; - -/** - * Comment notification listener - * - * @package event - * @author Frederic Guillot - */ -class CommentNotificationListener extends BaseNotificationListener -{ - /** - * Fetch data for the mail template - * - * @access public - * @param array $data Event data - * @return array - */ - public function getTemplateData(array $data) - { - $values = array(); - $values['comment'] = $this->notification->comment->getById($data['id']); - $values['task'] = $this->notification->taskFinder->getDetails($values['comment']['task_id']); - - return $values; - } -} diff --git a/app/Event/FileNotificationListener.php b/app/Event/FileNotificationListener.php deleted file mode 100644 index 2366ce5d..00000000 --- a/app/Event/FileNotificationListener.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -namespace Event; - -use Event\BaseNotificationListener; - -/** - * File notification listener - * - * @package event - * @author Frederic Guillot - */ -class FileNotificationListener extends BaseNotificationListener -{ - /** - * Fetch data for the mail template - * - * @access public - * @param array $data Event data - * @return array - */ - public function getTemplateData(array $data) - { - $values = array(); - $values['file'] = $data; - $values['task'] = $this->notification->taskFinder->getDetails($data['task_id']); - - return $values; - } -} diff --git a/app/Event/NotificationListener.php b/app/Event/NotificationListener.php new file mode 100644 index 00000000..3c049327 --- /dev/null +++ b/app/Event/NotificationListener.php @@ -0,0 +1,83 @@ +<?php + +namespace Event; + +/** + * Notification listener + * + * @package event + * @author Frederic Guillot + */ +class NotificationListener extends Base +{ + /** + * Template name + * + * @accesss private + * @var string + */ + private $template = ''; + + /** + * Set template name + * + * @access public + * @param string $template Template name + */ + public function setTemplate($template) + { + $this->template = $template; + } + + /** + * Execute the action + * + * @access public + * @param array $data Event data dictionary + * @return bool True if the action was executed or false when not executed + */ + public function execute(array $data) + { + $values = $this->getTemplateData($data); + $users = $this->notification->getUsersList($values['task']['project_id']); + + if ($users) { + $this->notification->sendEmails($this->template, $users, $values); + return true; + } + + return false; + } + + /** + * Fetch data for the mail template + * + * @access public + * @param array $data Event data + * @return array + */ + public function getTemplateData(array $data) + { + $values = array(); + + switch ($this->getEventNamespace()) { + case 'task': + $values['task'] = $this->taskFinder->getDetails($data['task_id']); + break; + case 'subtask': + $values['subtask'] = $this->subtask->getById($data['id'], true); + $values['task'] = $this->taskFinder->getDetails($data['task_id']); + break; + case 'file': + $values['file'] = $data; + $values['task'] = $this->taskFinder->getDetails($data['task_id']); + break; + case 'comment': + $values['comment'] = $this->comment->getById($data['id']); + $values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']); + break; + } + + return $values; + } +} diff --git a/app/Event/ProjectActivityListener.php b/app/Event/ProjectActivityListener.php new file mode 100644 index 00000000..8958bd2b --- /dev/null +++ b/app/Event/ProjectActivityListener.php @@ -0,0 +1,61 @@ +<?php + +namespace Event; + +/** + * Project activity listener + * + * @package event + * @author Frederic Guillot + */ +class ProjectActivityListener extends Base +{ + /** + * Execute the action + * + * @access public + * @param array $data Event data dictionary + * @return bool True if the action was executed or false when not executed + */ + public function execute(array $data) + { + if (isset($data['task_id'])) { + + $values = $this->getValues($data); + + return $this->projectActivity->createEvent( + $values['task']['project_id'], + $values['task']['id'], + $this->acl->getUserId(), + $this->registry->event->getLastTriggeredEvent(), + $values + ); + } + + return false; + } + + /** + * Get event activity data + * + * @access private + * @param array $data Event data dictionary + * @return array + */ + private function getValues(array $data) + { + $values = array(); + $values['task'] = $this->taskFinder->getDetails($data['task_id']); + + switch ($this->getEventNamespace()) { + case 'subtask': + $values['subtask'] = $this->subTask->getById($data['id'], true); + break; + case 'comment': + $values['comment'] = $this->comment->getById($data['id']); + break; + } + + return $values; + } +} diff --git a/app/Event/ProjectModificationDate.php b/app/Event/ProjectModificationDate.php deleted file mode 100644 index 1b0b3736..00000000 --- a/app/Event/ProjectModificationDate.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php - -namespace Event; - -use Core\Listener; -use Model\Project; - -/** - * Project modification date listener - * - * Update the last modified field for a project - * - * @package event - * @author Frederic Guillot - */ -class ProjectModificationDate implements Listener -{ - /** - * Project model - * - * @accesss private - * @var \Model\Project - */ - private $project; - - /** - * Constructor - * - * @access public - * @param \Model\Project $project Project model instance - */ - public function __construct(Project $project) - { - $this->project = $project; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); - } - - /** - * Execute the action - * - * @access public - * @param array $data Event data dictionary - * @return bool True if the action was executed or false when not executed - */ - public function execute(array $data) - { - if (isset($data['project_id'])) { - return $this->project->updateModificationDate($data['project_id']); - } - - return false; - } -} diff --git a/app/Event/ProjectModificationDateListener.php b/app/Event/ProjectModificationDateListener.php new file mode 100644 index 00000000..abc176b0 --- /dev/null +++ b/app/Event/ProjectModificationDateListener.php @@ -0,0 +1,30 @@ +<?php + +namespace Event; + +/** + * Project modification date listener + * + * Update the "last_modified" field for a project + * + * @package event + * @author Frederic Guillot + */ +class ProjectModificationDateListener extends Base +{ + /** + * Execute the action + * + * @access public + * @param array $data Event data dictionary + * @return bool True if the action was executed or false when not executed + */ + public function execute(array $data) + { + if (isset($data['project_id'])) { + return $this->project->updateModificationDate($data['project_id']); + } + + return false; + } +} diff --git a/app/Event/SubTaskNotificationListener.php b/app/Event/SubTaskNotificationListener.php deleted file mode 100644 index 2b35d757..00000000 --- a/app/Event/SubTaskNotificationListener.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -namespace Event; - -use Event\BaseNotificationListener; - -/** - * SubTask notification listener - * - * @package event - * @author Frederic Guillot - */ -class SubTaskNotificationListener extends BaseNotificationListener -{ - /** - * Fetch data for the mail template - * - * @access public - * @param array $data Event data - * @return array - */ - public function getTemplateData(array $data) - { - $values = array(); - $values['subtask'] = $this->notification->subtask->getById($data['id'], true); - $values['task'] = $this->notification->taskFinder->getDetails($data['task_id']); - - return $values; - } -} diff --git a/app/Event/SubtaskHistoryListener.php b/app/Event/SubtaskHistoryListener.php deleted file mode 100644 index 6b4f1c2d..00000000 --- a/app/Event/SubtaskHistoryListener.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php - -namespace Event; - -use Core\Listener; -use Model\SubtaskHistory; - -/** - * Subtask history listener - * - * @package event - * @author Frederic Guillot - */ -class SubtaskHistoryListener implements Listener -{ - /** - * Comment History model - * - * @accesss private - * @var \Model\SubtaskHistory - */ - private $model; - - /** - * Constructor - * - * @access public - * @param \Model\SubtaskHistory $model Subtask History model instance - */ - public function __construct(SubtaskHistory $model) - { - $this->model = $model; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); - } - - /** - * Execute the action - * - * @access public - * @param array $data Event data dictionary - * @return bool True if the action was executed or false when not executed - */ - public function execute(array $data) - { - $creator_id = $this->model->acl->getUserId(); - - if ($creator_id && isset($data['task_id']) && isset($data['id'])) { - - $task = $this->model->taskFinder->getById($data['task_id']); - - $this->model->create( - $task['project_id'], - $data['task_id'], - $data['id'], - $creator_id, - $this->model->event->getLastTriggeredEvent(), - '' - ); - } - - return false; - } -} diff --git a/app/Event/TaskHistoryListener.php b/app/Event/TaskHistoryListener.php deleted file mode 100644 index d963fa71..00000000 --- a/app/Event/TaskHistoryListener.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php - -namespace Event; - -use Core\Listener; -use Model\TaskHistory; - -/** - * Task history listener - * - * @package event - * @author Frederic Guillot - */ -class TaskHistoryListener implements Listener -{ - /** - * Task History model - * - * @accesss private - * @var \Model\TaskHistory - */ - private $model; - - /** - * Constructor - * - * @access public - * @param \Model\TaskHistory $model Task History model instance - */ - public function __construct(TaskHistory $model) - { - $this->model = $model; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); - } - - /** - * Execute the action - * - * @access public - * @param array $data Event data dictionary - * @return bool True if the action was executed or false when not executed - */ - public function execute(array $data) - { - $creator_id = $this->model->acl->getUserId(); - - if ($creator_id && isset($data['task_id']) && isset($data['project_id'])) { - $this->model->create($data['project_id'], $data['task_id'], $creator_id, $this->model->event->getLastTriggeredEvent()); - } - - return false; - } -} diff --git a/app/Event/TaskNotificationListener.php b/app/Event/TaskNotificationListener.php deleted file mode 100644 index 119e61e5..00000000 --- a/app/Event/TaskNotificationListener.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php - -namespace Event; - -use Event\BaseNotificationListener; - -/** - * Task notification listener - * - * @package event - * @author Frederic Guillot - */ -class TaskNotificationListener extends BaseNotificationListener -{ - /** - * Fetch data for the mail template - * - * @access public - * @param array $data Event data - * @return array - */ - public function getTemplateData(array $data) - { - $values = array(); - $values['task'] = $this->notification->taskFinder->getDetails($data['task_id']); - - return $values; - } -} diff --git a/app/Event/WebhookListener.php b/app/Event/WebhookListener.php index c2f6d56a..f7e23e07 100644 --- a/app/Event/WebhookListener.php +++ b/app/Event/WebhookListener.php @@ -2,26 +2,15 @@ namespace Event; -use Core\Listener; -use Model\Webhook; - /** * Webhook task events * * @package event * @author Frederic Guillot */ -class WebhookListener implements Listener +class WebhookListener extends Base { /** - * Webhook model - * - * @accesss private - * @var \Model\Webhook - */ - private $webhook; - - /** * Url to call * * @access private @@ -30,27 +19,14 @@ class WebhookListener implements Listener private $url = ''; /** - * Constructor + * Set webhook url * * @access public - * @param string $url URL to call - * @param \Model\Webhook $webhook Webhook model instance + * @param string $url URL to call */ - public function __construct($url, Webhook $webhook) + public function setUrl($url) { $this->url = $url; - $this->webhook = $webhook; - } - - /** - * Return class information - * - * @access public - * @return string - */ - public function __toString() - { - return get_called_class(); } /** diff --git a/app/Locales/de_DE/translations.php b/app/Locales/de_DE/translations.php index fdf96638..4b901148 100644 --- a/app/Locales/de_DE/translations.php +++ b/app/Locales/de_DE/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/es_ES/translations.php b/app/Locales/es_ES/translations.php index 368a11ee..0cdd5f32 100644 --- a/app/Locales/es_ES/translations.php +++ b/app/Locales/es_ES/translations.php @@ -495,8 +495,8 @@ return array( 'Default values are "%s"' => 'Los valores por defecto son "%s"', 'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)', 'Task assignee change' => 'Cambiar persona asignada a la tarea', - '%s change the assignee of the task #%d' => '%s cambia la persona asignada a la tarea #%d', - '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s cambia la persona asignada a la tarea <a href="?controller=task&action=show&task_id=%d">#%d</a>', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', '[%s][Column Change] %s (#%d)' => '[%s][Cambia Columna] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Cambia Posición] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Cambia Persona Asignada] %s (#%d)', diff --git a/app/Locales/fi_FI/translations.php b/app/Locales/fi_FI/translations.php index 2a2f3e96..5d05e92d 100644 --- a/app/Locales/fi_FI/translations.php +++ b/app/Locales/fi_FI/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/fr_FR/translations.php b/app/Locales/fr_FR/translations.php index 49e6bc2f..f4bffc3b 100644 --- a/app/Locales/fr_FR/translations.php +++ b/app/Locales/fr_FR/translations.php @@ -495,8 +495,8 @@ return array( 'Default values are "%s"' => 'Les valeurs par défaut sont « %s »', 'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)', 'Task assignee change' => 'Modification de la personne assignée sur une tâche', - '%s change the assignee of the task #%d' => '%s a changé la personne assignée sur la tâche #%d', - '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s a changé la personne assignée sur la tâche <a href="?controller=task&action=show&task_id=%d">n°%d</a>', + '%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée sur la tâche #%d pour %s', + '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s a changé la personne assignée sur la tâche <a href="?controller=task&action=show&task_id=%d">n°%d</a> pour %s', '[%s][Column Change] %s (#%d)' => '[%s][Changement de colonne] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Changement de position] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Changement d\'assigné] %s (#%d)', diff --git a/app/Locales/it_IT/translations.php b/app/Locales/it_IT/translations.php index 9f532438..5854d033 100644 --- a/app/Locales/it_IT/translations.php +++ b/app/Locales/it_IT/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/pl_PL/translations.php b/app/Locales/pl_PL/translations.php index f2e96bb6..fe76b34c 100644 --- a/app/Locales/pl_PL/translations.php +++ b/app/Locales/pl_PL/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/pt_BR/translations.php b/app/Locales/pt_BR/translations.php index 3f208361..59fcc983 100644 --- a/app/Locales/pt_BR/translations.php +++ b/app/Locales/pt_BR/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/ru_RU/translations.php b/app/Locales/ru_RU/translations.php index 5c634184..1f5bfea2 100644 --- a/app/Locales/ru_RU/translations.php +++ b/app/Locales/ru_RU/translations.php @@ -495,8 +495,8 @@ return array( 'Default values are "%s"' => 'Колонки по умолчанию: "%s"', 'Default columns for new projects (Comma-separated)' => 'Колонки по умолчанию для новых проектов (разделять запятой)', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/sv_SE/translations.php b/app/Locales/sv_SE/translations.php index a96b6c9a..20b685ef 100644 --- a/app/Locales/sv_SE/translations.php +++ b/app/Locales/sv_SE/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Locales/zh_CN/translations.php b/app/Locales/zh_CN/translations.php index ea7183c7..92f46ef9 100644 --- a/app/Locales/zh_CN/translations.php +++ b/app/Locales/zh_CN/translations.php @@ -495,8 +495,8 @@ return array( // 'Default values are "%s"' => '', // 'Default columns for new projects (Comma-separated)' => '', // 'Task assignee change' => '', - // '%s change the assignee of the task #%d' => '', - // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '', + // '%s change the assignee of the task #%d to %s' => '', + // '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '', // '[%s][Column Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '', diff --git a/app/Model/BaseHistory.php b/app/Model/BaseHistory.php deleted file mode 100644 index 31578a3b..00000000 --- a/app/Model/BaseHistory.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace Model; - -use PDO; -use Core\Template; - -/** - * Task history model - * - * @package model - * @author Frederic Guillot - */ -abstract class BaseHistory extends Base -{ - /** - * SQL table name - * - * @access protected - * @var string - */ - protected $table = ''; - - /** - * Remove old event entries to avoid a large table - * - * @access public - * @param integer $max Maximum number of items to keep in the table - */ - public function cleanup($max) - { - if ($this->db->table($this->table)->count() > $max) { - - $this->db->execute(' - DELETE FROM '.$this->table.' - WHERE id <= ( - SELECT id FROM ( - SELECT id FROM '.$this->table.' ORDER BY id DESC LIMIT 1 OFFSET '.$max.' - ) foo - )'); - } - } - - /** - * Get all events for a given project - * - * @access public - * @return array - */ - public function getAllByProjectId($project_id) - { - return $this->db->table($this->table) - ->eq('project_id', $project_id) - ->desc('id') - ->findAll(); - } - - /** - * Get the event html content - * - * @access public - * @param array $params Event properties - * @return string - */ - public function getContent(array $params) - { - $tpl = new Template; - return $tpl->load('event_'.str_replace('.', '_', $params['event_name']), $params); - } -} diff --git a/app/Model/CommentHistory.php b/app/Model/CommentHistory.php deleted file mode 100644 index 5988c026..00000000 --- a/app/Model/CommentHistory.php +++ /dev/null @@ -1,152 +0,0 @@ -<?php - -namespace Model; - -use PDO; -use Core\Registry; -use Event\CommentHistoryListener; - -/** - * Comment history model - * - * @package model - * @author Frederic Guillot - */ -class CommentHistory extends BaseHistory -{ - /** - * SQL table name - * - * @var string - */ - const TABLE = 'comment_has_events'; - - /** - * Maximum number of events - * - * @var integer - */ - const MAX_EVENTS = 5000; - - /** - * Constructor - * - * @access public - * @param \Core\Registry $registry Registry instance - */ - public function __construct(Registry $registry) - { - parent::__construct($registry); - $this->table = self::TABLE; - } - - /** - * Create a new event - * - * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param integer $comment_id Comment id - * @param integer $creator_id Author of the event (user id) - * @param string $event_name Task event name - * @param string $data Current comment - * @return boolean - */ - public function create($project_id, $task_id, $comment_id, $creator_id, $event_name, $data) - { - $values = array( - 'project_id' => $project_id, - 'task_id' => $task_id, - 'comment_id' => $comment_id, - 'creator_id' => $creator_id, - 'event_name' => $event_name, - 'date_creation' => time(), - 'data' => $data, - ); - - $this->db->startTransaction(); - - $this->cleanup(self::MAX_EVENTS - 1); - $result = $this->db->table(self::TABLE)->insert($values); - - $this->db->closeTransaction(); - - return $result; - } - - /** - * Get all necessary content to display activity feed - * - * $author_name - * $author_username - * $task['id', 'title', 'position', 'column_name'] - */ - public function getAllContentByProjectId($project_id, $limit = 50) - { - $sql = ' - SELECT - comment_has_events.id, - comment_has_events.date_creation, - comment_has_events.event_name, - comment_has_events.data as comment, - comment_has_events.task_id, - tasks.title as task_title, - users.username as author_username, - users.name as author_name - FROM comment_has_events - LEFT JOIN users ON users.id=comment_has_events.creator_id - LEFT JOIN tasks ON tasks.id=comment_has_events.task_id - WHERE comment_has_events.project_id = ? - ORDER BY comment_has_events.id DESC - LIMIT '.$limit.' OFFSET 0 - '; - - $rq = $this->db->execute($sql, array($project_id)); - $events = $rq->fetchAll(PDO::FETCH_ASSOC); - - foreach ($events as &$event) { - $event['author'] = $event['author_name'] ?: $event['author_username']; - $event['event_title'] = $this->getTitle($event); - $event['event_content'] = $this->getContent($event); - $event['event_type'] = 'comment'; - } - - return $events; - } - - /** - * Get the event title (translated) - * - * @access public - * @param array $event Event properties - * @return string - */ - public function getTitle(array $event) - { - $titles = array( - Comment::EVENT_UPDATE => t('%s updated a comment on the task #%d', $event['author'], $event['task_id']), - Comment::EVENT_CREATE => t('%s commented on the task #%d', $event['author'], $event['task_id']), - ); - - return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : ''; - } - - /** - * Attach events to be able to record the history - * - * @access public - */ - public function attachEvents() - { - $events = array( - Comment::EVENT_UPDATE, - Comment::EVENT_CREATE, - ); - - $listener = new CommentHistoryListener($this); - - foreach ($events as $event_name) { - $this->event->attach($event_name, $listener); - } - } -} diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 4b7ae50f..0a80e335 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -5,12 +5,10 @@ namespace Model; use Core\Session; use Core\Translator; use Core\Template; -use Event\TaskNotificationListener; -use Event\CommentNotificationListener; -use Event\FileNotificationListener; -use Event\SubTaskNotificationListener; +use Event\NotificationListener; use Swift_Message; use Swift_Mailer; +use Swift_TransportException; /** * Notification model @@ -91,21 +89,28 @@ class Notification extends Base */ public function attachEvents() { - $this->event->attach(File::EVENT_CREATE, new FileNotificationListener($this, 'notification_file_creation')); + $events = array( + Task::EVENT_CREATE => 'notification_task_creation', + Task::EVENT_UPDATE => 'notification_task_update', + Task::EVENT_CLOSE => 'notification_task_close', + Task::EVENT_OPEN => 'notification_task_open', + Task::EVENT_MOVE_COLUMN => 'notification_task_move_column', + Task::EVENT_MOVE_POSITION => 'notification_task_move_position', + Task::EVENT_ASSIGNEE_CHANGE => 'notification_task_assignee_change', + SubTask::EVENT_CREATE => 'notification_subtask_creation', + SubTask::EVENT_UPDATE => 'notification_subtask_update', + Comment::EVENT_CREATE => 'notification_comment_creation', + Comment::EVENT_UPDATE => 'notification_comment_update', + File::EVENT_CREATE => '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')); + foreach ($events as $event_name => $template_name) { - $this->event->attach(SubTask::EVENT_CREATE, new SubTaskNotificationListener($this, 'notification_subtask_creation')); - $this->event->attach(SubTask::EVENT_UPDATE, new SubTaskNotificationListener($this, 'notification_subtask_update')); + $listener = new NotificationListener($this->registry); + $listener->setTemplate($template_name); - $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')); - $this->event->attach(Task::EVENT_MOVE_COLUMN, new TaskNotificationListener($this, 'notification_task_move_column')); - $this->event->attach(Task::EVENT_MOVE_POSITION, new TaskNotificationListener($this, 'notification_task_move_position')); - $this->event->attach(Task::EVENT_ASSIGNEE_CHANGE, new TaskNotificationListener($this, 'notification_task_assignee_change')); + $this->event->attach($event_name, $listener); + } } /** @@ -118,17 +123,22 @@ class Notification extends Base */ public function sendEmails($template, array $users, array $data) { - $transport = $this->registry->shared('mailer'); - $mailer = Swift_Mailer::newInstance($transport); + try { + $transport = $this->registry->shared('mailer'); + $mailer = Swift_Mailer::newInstance($transport); - $message = Swift_Message::newInstance() - ->setSubject($this->getMailSubject($template, $data)) - ->setFrom(array(MAIL_FROM => 'Kanboard')) - ->setBody($this->getMailContent($template, $data), 'text/html'); + $message = Swift_Message::newInstance() + ->setSubject($this->getMailSubject($template, $data)) + ->setFrom(array(MAIL_FROM => 'Kanboard')) + ->setBody($this->getMailContent($template, $data), 'text/html'); - foreach ($users as $user) { - $message->setTo(array($user['email'] => $user['name'] ?: $user['username'])); - $mailer->send($message); + foreach ($users as $user) { + $message->setTo(array($user['email'] => $user['name'] ?: $user['username'])); + $mailer->send($message); + } + } + catch (Swift_TransportException $e) { + debug($e->getMessage()); } } diff --git a/app/Model/Project.php b/app/Model/Project.php index ad0afa82..32b7fcbe 100644 --- a/app/Model/Project.php +++ b/app/Model/Project.php @@ -4,7 +4,7 @@ namespace Model; use SimpleValidator\Validator; use SimpleValidator\Validators; -use Event\ProjectModificationDate; +use Event\ProjectModificationDateListener; use Core\Security; /** @@ -512,41 +512,10 @@ class Project extends Base GithubWebhook::EVENT_COMMIT, ); - $listener = new ProjectModificationDate($this); + $listener = new ProjectModificationDateListener($this->registry); foreach ($events as $event_name) { $this->event->attach($event_name, $listener); } } - - /** - * Get project activity - * - * @access public - * @param integer $project_id Project id - * @return array - */ - public function getActivity($project_id) - { - $activity = array(); - $tasks = $this->taskHistory->getAllContentByProjectId($project_id, 25); - $comments = $this->commentHistory->getAllContentByProjectId($project_id, 25); - $subtasks = $this->subtaskHistory->getAllContentByProjectId($project_id, 25); - - foreach ($tasks as &$task) { - $activity[$task['date_creation'].'-'.$task['id']] = $task; - } - - foreach ($subtasks as &$subtask) { - $activity[$subtask['date_creation'].'-'.$subtask['id']] = $subtask; - } - - foreach ($comments as &$comment) { - $activity[$comment['date_creation'].'-'.$comment['id']] = $comment; - } - - krsort($activity); - - return $activity; - } } diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivity.php new file mode 100644 index 00000000..d2457609 --- /dev/null +++ b/app/Model/ProjectActivity.php @@ -0,0 +1,189 @@ +<?php + +namespace Model; + +use Core\Template; +use Event\ProjectActivityListener; + +/** + * Project activity model + * + * @package model + * @author Frederic Guillot + */ +class ProjectActivity extends Base +{ + /** + * SQL table name + * + * @var string + */ + const TABLE = 'project_activities'; + + /** + * Maximum number of events + * + * @var integer + */ + const MAX_EVENTS = 5000; + + /** + * Add a new event for the project + * + * @access public + * @param integer $project_id Project id + * @param integer $task_id Task id + * @param integer $creator_id User id + * @param string $event_name Event name + * @param array $data Event data (will be serialized) + * @return boolean + */ + public function createEvent($project_id, $task_id, $creator_id, $event_name, array $data) + { + $values = array( + 'project_id' => $project_id, + 'task_id' => $task_id, + 'creator_id' => $creator_id, + 'event_name' => $event_name, + 'date_creation' => time(), + 'data' => serialize($data), + ); + + $this->cleanup(self::MAX_EVENTS - 1); + return $this->db->table(self::TABLE)->insert($values); + } + + /** + * Get all events for the given project + * + * @access public + * @param integer $project_id Project id + * @param integer $limit Maximum events number + * @return array + */ + public function getAll($project_id, $limit = 50) + { + $events = $this->db->table(self::TABLE) + ->columns( + self::TABLE.'.*', + User::TABLE.'.username AS author_username', + User::TABLE.'.name AS author_name' + ) + ->eq('project_id', $project_id) + ->join(User::TABLE, 'id', 'creator_id') + ->desc('id') + ->limit($limit) + ->findAll(); + + foreach ($events as &$event) { + + $event += unserialize($event['data']); + unset($event['data']); + + $event['author'] = $event['author_name'] ?: $event['author_username']; + $event['event_title'] = $this->getTitle($event); + $event['event_content'] = $this->getContent($event); + } + + return $events; + } + + /** + * Remove old event entries to avoid large table + * + * @access public + * @param integer $max Maximum number of items to keep in the table + */ + public function cleanup($max) + { + if ($this->db->table(self::TABLE)->count() > $max) { + + $this->db->execute(' + DELETE FROM '.self::TABLE.' + WHERE id <= ( + SELECT id FROM ( + SELECT id FROM '.self::TABLE.' ORDER BY id DESC LIMIT 1 OFFSET '.$max.' + ) foo + )' + ); + } + } + + /** + * Attach events to be able to record the history + * + * @access public + */ + public function attachEvents() + { + $events = array( + Task::EVENT_ASSIGNEE_CHANGE, + Task::EVENT_UPDATE, + Task::EVENT_CREATE, + Task::EVENT_CLOSE, + Task::EVENT_OPEN, + Task::EVENT_MOVE_COLUMN, + Task::EVENT_MOVE_POSITION, + Comment::EVENT_UPDATE, + Comment::EVENT_CREATE, + SubTask::EVENT_UPDATE, + SubTask::EVENT_CREATE, + ); + + $listener = new ProjectActivityListener($this->registry); + + foreach ($events as $event_name) { + $this->event->attach($event_name, $listener); + } + } + + /** + * Get the event html content + * + * @access public + * @param array $params Event properties + * @return string + */ + public function getContent(array $params) + { + $tpl = new Template; + return $tpl->load('event_'.str_replace('.', '_', $params['event_name']), $params); + } + + /** + * Get the event title (translated) + * + * @access public + * @param array $event Event properties + * @return string + */ + public function getTitle(array $event) + { + switch ($event['event_name']) { + case Task::EVENT_ASSIGNEE_CHANGE: + return t('%s change the assignee of the task #%d to %s', $event['author'], $event['task']['id'], $event['task']['assignee_name'] ?: $event['task']['assignee_username']); + case Task::EVENT_UPDATE: + return t('%s updated the task #%d', $event['author'], $event['task']['id']); + case Task::EVENT_CREATE: + return t('%s created the task #%d', $event['author'], $event['task']['id']); + case Task::EVENT_CLOSE: + return t('%s closed the task #%d', $event['author'], $event['task']['id']); + case Task::EVENT_OPEN: + return t('%s open the task #%d', $event['author'], $event['task']['id']); + case Task::EVENT_MOVE_COLUMN: + return t('%s moved the task #%d to the column "%s"', $event['author'], $event['task']['id'], $event['task']['column_title']); + case Task::EVENT_MOVE_POSITION: + return t('%s moved the task #%d to the position %d in the column "%s"', $event['author'], $event['task']['id'], $event['task']['position'], $event['task']['column_title']); + case SubTask::EVENT_UPDATE: + return t('%s updated a subtask for the task #%d', $event['author'], $event['task']['id']); + case SubTask::EVENT_CREATE: + return t('%s created a subtask for the task #%d', $event['author'], $event['task']['id']); + case Comment::EVENT_UPDATE: + return t('%s updated a comment on the task #%d', $event['author'], $event['task']['id']); + case Comment::EVENT_CREATE: + return t('%s commented on the task #%d', $event['author'], $event['task']['id']); + default: + return ''; + } + } +} diff --git a/app/Model/SubtaskHistory.php b/app/Model/SubtaskHistory.php deleted file mode 100644 index 89076261..00000000 --- a/app/Model/SubtaskHistory.php +++ /dev/null @@ -1,161 +0,0 @@ -<?php - -namespace Model; - -use PDO; -use Core\Registry; -use Event\SubtaskHistoryListener; - -/** - * Comment history model - * - * @package model - * @author Frederic Guillot - */ -class SubtaskHistory extends BaseHistory -{ - /** - * SQL table name - * - * @var string - */ - const TABLE = 'subtask_has_events'; - - /** - * Maximum number of events - * - * @var integer - */ - const MAX_EVENTS = 5000; - - /** - * Constructor - * - * @access public - * @param \Core\Registry $registry Registry instance - */ - public function __construct(Registry $registry) - { - parent::__construct($registry); - $this->table = self::TABLE; - } - - /** - * Create a new event - * - * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param integer $subtask_id Subtask id - * @param integer $creator_id Author of the event (user id) - * @param string $event_name Task event name - * @param string $data Current comment - * @return boolean - */ - public function create($project_id, $task_id, $subtask_id, $creator_id, $event_name, $data) - { - $values = array( - 'project_id' => $project_id, - 'task_id' => $task_id, - 'subtask_id' => $subtask_id, - 'creator_id' => $creator_id, - 'event_name' => $event_name, - 'date_creation' => time(), - 'data' => $data, - ); - - $this->db->startTransaction(); - - $this->cleanup(self::MAX_EVENTS - 1); - $result = $this->db->table(self::TABLE)->insert($values); - - $this->db->closeTransaction(); - - return $result; - } - - /** - * Get all necessary content to display activity feed - * - * $author_name - * $author_username - * $task['id', 'title', 'position', 'column_name'] - */ - public function getAllContentByProjectId($project_id, $limit = 50) - { - $sql = ' - SELECT - subtask_has_events.id, - subtask_has_events.date_creation, - subtask_has_events.event_name, - subtask_has_events.task_id, - tasks.title as task_title, - users.username as author_username, - users.name as author_name, - assignees.name as subtask_assignee_name, - assignees.username as subtask_assignee_username, - task_has_subtasks.title as subtask_title, - task_has_subtasks.status as subtask_status, - task_has_subtasks.time_spent as subtask_time_spent, - task_has_subtasks.time_estimated as subtask_time_estimated - FROM subtask_has_events - LEFT JOIN users ON users.id=subtask_has_events.creator_id - LEFT JOIN tasks ON tasks.id=subtask_has_events.task_id - LEFT JOIN task_has_subtasks ON task_has_subtasks.id=subtask_has_events.subtask_id - LEFT JOIN users AS assignees ON assignees.id=task_has_subtasks.user_id - WHERE subtask_has_events.project_id = ? - ORDER BY subtask_has_events.id DESC - LIMIT '.$limit.' OFFSET 0 - '; - - $rq = $this->db->execute($sql, array($project_id)); - $events = $rq->fetchAll(PDO::FETCH_ASSOC); - - foreach ($events as &$event) { - $event['author'] = $event['author_name'] ?: $event['author_username']; - $event['subtask_assignee'] = $event['subtask_assignee_name'] ?: $event['subtask_assignee_username']; - $event['subtask_status_list'] = $this->subTask->getStatusList(); - $event['event_title'] = $this->getTitle($event); - $event['event_content'] = $this->getContent($event); - $event['event_type'] = 'subtask'; - } - - return $events; - } - - /** - * Get the event title (translated) - * - * @access public - * @param array $event Event properties - * @return string - */ - public function getTitle(array $event) - { - $titles = array( - SubTask::EVENT_UPDATE => t('%s updated a subtask for the task #%d', $event['author'], $event['task_id']), - SubTask::EVENT_CREATE => t('%s created a subtask for the task #%d', $event['author'], $event['task_id']), - ); - - return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : ''; - } - - /** - * Attach events to be able to record the history - * - * @access public - */ - public function attachEvents() - { - $events = array( - SubTask::EVENT_UPDATE, - SubTask::EVENT_CREATE, - ); - - $listener = new SubtaskHistoryListener($this); - - foreach ($events as $event_name) { - $this->event->attach($event_name, $listener); - } - } -} diff --git a/app/Model/TaskHistory.php b/app/Model/TaskHistory.php deleted file mode 100644 index 0615cba0..00000000 --- a/app/Model/TaskHistory.php +++ /dev/null @@ -1,160 +0,0 @@ -<?php - -namespace Model; - -use PDO; -use Core\Registry; -use Event\TaskHistoryListener; - -/** - * Task history model - * - * @package model - * @author Frederic Guillot - */ -class TaskHistory extends BaseHistory -{ - /** - * SQL table name - * - * @var string - */ - const TABLE = 'task_has_events'; - - /** - * Maximum number of events - * - * @var integer - */ - const MAX_EVENTS = 5000; - - /** - * Constructor - * - * @access public - * @param \Core\Registry $registry Registry instance - */ - public function __construct(Registry $registry) - { - parent::__construct($registry); - $this->table = self::TABLE; - } - - /** - * Create a new event - * - * @access public - * @param integer $project_id Project id - * @param integer $task_id Task id - * @param integer $creator_id Author of the event (user id) - * @param string $event_name Task event name - * @return boolean - */ - public function create($project_id, $task_id, $creator_id, $event_name) - { - $values = array( - 'project_id' => $project_id, - 'task_id' => $task_id, - 'creator_id' => $creator_id, - 'event_name' => $event_name, - 'date_creation' => time(), - ); - - $this->db->startTransaction(); - - $this->cleanup(self::MAX_EVENTS - 1); - $result = $this->db->table(self::TABLE)->insert($values); - - $this->db->closeTransaction(); - - return $result; - } - - /** - * Get all necessary content to display activity feed - * - * $author_name - * $author_username - * $task['id', 'title', 'position', 'column_name'] - */ - public function getAllContentByProjectId($project_id, $limit = 50) - { - $sql = ' - SELECT - task_has_events.id, - task_has_events.date_creation, - task_has_events.event_name, - task_has_events.task_id, - tasks.title as task_title, - tasks.position as task_position, - columns.title as task_column_name, - users.username as author_username, - users.name as author_name - FROM task_has_events - LEFT JOIN users ON users.id=task_has_events.creator_id - LEFT JOIN tasks ON tasks.id=task_has_events.task_id - LEFT JOIN columns ON columns.id=tasks.column_id - WHERE task_has_events.project_id = ? - ORDER BY task_has_events.id DESC - LIMIT '.$limit.' OFFSET 0 - '; - - $rq = $this->db->execute($sql, array($project_id)); - $events = $rq->fetchAll(PDO::FETCH_ASSOC); - - foreach ($events as &$event) { - $event['author'] = $event['author_name'] ?: $event['author_username']; - $event['event_title'] = $this->getTitle($event); - $event['event_content'] = $this->getContent($event); - $event['event_type'] = 'task'; - } - - return $events; - } - - /** - * Get the event title (translated) - * - * @access public - * @param array $event Event properties - * @return string - */ - public function getTitle(array $event) - { - $titles = array( - Task::EVENT_ASSIGNEE_CHANGE => t('%s change the assignee of the task #%d', $event['author'], $event['task_id']), - Task::EVENT_UPDATE => t('%s updated the task #%d', $event['author'], $event['task_id']), - Task::EVENT_CREATE => t('%s created the task #%d', $event['author'], $event['task_id']), - Task::EVENT_CLOSE => t('%s closed the task #%d', $event['author'], $event['task_id']), - Task::EVENT_OPEN => t('%s open the task #%d', $event['author'], $event['task_id']), - Task::EVENT_MOVE_COLUMN => t('%s moved the task #%d to the column "%s"', $event['author'], $event['task_id'], $event['task_column_name']), - Task::EVENT_MOVE_POSITION => t('%s moved the task #%d to the position %d in the column "%s"', $event['author'], $event['task_id'], $event['task_position'], $event['task_column_name']), - ); - - return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : ''; - } - - /** - * Attach events to be able to record the history - * - * @access public - */ - public function attachEvents() - { - $events = array( - Task::EVENT_ASSIGNEE_CHANGE, - Task::EVENT_UPDATE, - Task::EVENT_CREATE, - Task::EVENT_CLOSE, - Task::EVENT_OPEN, - Task::EVENT_MOVE_COLUMN, - Task::EVENT_MOVE_POSITION, - ); - - $listener = new TaskHistoryListener($this); - - foreach ($events as $event_name) { - $this->event->attach($event_name, $listener); - } - } -} diff --git a/app/Model/Webhook.php b/app/Model/Webhook.php index 241806ba..b84728cf 100644 --- a/app/Model/Webhook.php +++ b/app/Model/Webhook.php @@ -88,9 +88,13 @@ class Webhook extends Base Task::EVENT_UPDATE, Task::EVENT_CLOSE, Task::EVENT_OPEN, + Task::EVENT_MOVE_COLUMN, + Task::EVENT_MOVE_POSITION, + Task::EVENT_ASSIGNEE_CHANGE, ); - $listener = new WebhookListener($this->url_task_modification, $this); + $listener = new WebhookListener($this->registry); + $listener->setUrl($this->url_task_modification); foreach ($events as $event_name) { $this->event->attach($event_name, $listener); @@ -104,7 +108,10 @@ class Webhook extends Base */ public function attachCreateEvents() { - $this->event->attach(Task::EVENT_CREATE, new WebhookListener($this->url_task_creation, $this)); + $listener = new WebhookListener($this->registry); + $listener->setUrl($this->url_task_creation); + + $this->event->attach(Task::EVENT_CREATE, $listener); } /** diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index 7a0b2cd1..05bef8cd 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -5,7 +5,30 @@ namespace Schema; use PDO; use Core\Security; -const VERSION = 32; +const VERSION = 33; + +function version_33($pdo) +{ + $pdo->exec(" + CREATE TABLE project_activities ( + id INT NOT NULL AUTO_INCREMENT, + date_creation INT NOT NULL, + event_name VARCHAR(50) NOT NULL, + creator_id INT, + project_id INT, + task_id INT, + data TEXT, + PRIMARY KEY(id), + FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE + ) ENGINE=InnoDB CHARSET=utf8 + "); + + $pdo->exec('DROP TABLE task_has_events'); + $pdo->exec('DROP TABLE comment_has_events'); + $pdo->exec('DROP TABLE subtask_has_events'); +} function version_32($pdo) { @@ -355,7 +378,7 @@ function version_1($pdo) id INT NOT NULL AUTO_INCREMENT, task_id INT, user_id INT, - date INT, + `date` INT, comment TEXT, PRIMARY KEY (id), FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE, diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index e42e8e72..8aaff259 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -5,7 +5,29 @@ namespace Schema; use PDO; use Core\Security; -const VERSION = 13; +const VERSION = 14; + +function version_14($pdo) +{ + $pdo->exec(" + CREATE TABLE project_activities ( + id SERIAL PRIMARY KEY, + date_creation INTEGER NOT NULL, + event_name VARCHAR(50) NOT NULL, + creator_id INTEGER, + project_id INTEGER, + task_id INTEGER, + data TEXT, + FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE + ) + "); + + $pdo->exec('DROP TABLE task_has_events'); + $pdo->exec('DROP TABLE comment_has_events'); + $pdo->exec('DROP TABLE subtask_has_events'); +} function version_13($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index f290c824..3c220f8c 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -5,7 +5,29 @@ namespace Schema; use Core\Security; use PDO; -const VERSION = 32; +const VERSION = 33; + +function version_33($pdo) +{ + $pdo->exec(" + CREATE TABLE project_activities ( + id INTEGER PRIMARY KEY, + date_creation INTEGER NOT NULL, + event_name TEXT NOT NULL, + creator_id INTEGER, + project_id INTEGER, + task_id INTEGER, + data TEXT, + FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE, + FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE + ) + "); + + $pdo->exec('DROP TABLE task_has_events'); + $pdo->exec('DROP TABLE comment_has_events'); + $pdo->exec('DROP TABLE subtask_has_events'); +} function version_32($pdo) { diff --git a/app/Templates/event_comment_create.php b/app/Templates/event_comment_create.php index 4af59614..d2f6f97b 100644 --- a/app/Templates/event_comment_create.php +++ b/app/Templates/event_comment_create.php @@ -1,7 +1,7 @@ <p class="activity-title"> <?= e('%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> -<p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em><br/> - <div class="markdown"><?= Helper\markdown($comment) ?></div> -</p>
\ No newline at end of file +<div class="activity-description"> + <em><?= Helper\escape($task['title']) ?></em><br/> + <div class="markdown"><?= Helper\markdown($comment['comment']) ?></div> +</div>
\ No newline at end of file diff --git a/app/Templates/event_comment_update.php b/app/Templates/event_comment_update.php index fe93b691..27cc0be6 100644 --- a/app/Templates/event_comment_update.php +++ b/app/Templates/event_comment_update.php @@ -1,7 +1,7 @@ <p class="activity-title"> <?= e('%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> -<p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em><br/> - <div class="markdown"><?= Helper\markdown($comment) ?></div> -</p>
\ No newline at end of file +<div class="activity-description"> + <em><?= Helper\escape($task['title']) ?></em><br/> + <div class="markdown"><?= Helper\markdown($comment['comment']) ?></div> +</div>
\ No newline at end of file diff --git a/app/Templates/event_subtask_create.php b/app/Templates/event_subtask_create.php index 9772d807..664e9da2 100644 --- a/app/Templates/event_subtask_create.php +++ b/app/Templates/event_subtask_create.php @@ -1,12 +1,19 @@ <p class="activity-title"> <?= e('%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> -<p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em><br/> - <p><?= Helper\escape($subtask_title) ?> <strong>(<?= Helper\in_list($subtask_status, $subtask_status_list) ?>)</strong></p> - <?php if ($subtask_assignee): ?> - <p><?= t('Assigned to %s with an estimate of %s/%sh', $subtask_assignee, $subtask_time_spent, $subtask_time_estimated) ?></p> - <?php else: ?> - <p><?= t('Not assigned, estimate of %sh', $subtask_time_estimated) ?></p> - <?php endif ?> -</p>
\ No newline at end of file +<div class="activity-description"> + <p><em><?= Helper\escape($task['title']) ?></em></p> + + <ul> + <li> + <?= Helper\escape($subtask['title']) ?> (<strong><?= Helper\escape($subtask['status_name']) ?></strong>) + </li> + <li> + <?php if ($subtask['username']): ?> + <?= t('Assigned to %s with an estimate of %s/%sh', $subtask['name'] ?: $subtask['username'], $subtask['time_spent'], $subtask['time_estimated']) ?> + <?php else: ?> + <?= t('Not assigned, estimate of %sh', $subtask['time_estimated']) ?> + <?php endif ?> + </li> + </ul> +</div>
\ No newline at end of file diff --git a/app/Templates/event_subtask_update.php b/app/Templates/event_subtask_update.php index 70f9d76d..96a589dd 100644 --- a/app/Templates/event_subtask_update.php +++ b/app/Templates/event_subtask_update.php @@ -1,12 +1,19 @@ <p class="activity-title"> <?= e('%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> -<p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em><br/> - <p><?= Helper\escape($subtask_title) ?> <strong>(<?= Helper\in_list($subtask_status, $subtask_status_list) ?>)</strong></p> - <?php if ($subtask_assignee): ?> - <p><?= t('Assigned to %s with an estimate of %s/%sh', $subtask_assignee, $subtask_time_spent, $subtask_time_estimated) ?></p> - <?php else: ?> - <p><?= t('Not assigned, estimate of %sh', $subtask_time_estimated) ?></p> - <?php endif ?> -</p>
\ No newline at end of file +<div class="activity-description"> + <p><em><?= Helper\escape($task['title']) ?></em></p> + + <ul> + <li> + <?= Helper\escape($subtask['title']) ?> (<strong><?= Helper\escape($subtask['status_name']) ?></strong>) + </li> + <li> + <?php if ($subtask['username']): ?> + <?= t('Assigned to %s with an estimate of %s/%sh', $subtask['name'] ?: $subtask['username'], $subtask['time_spent'], $subtask['time_estimated']) ?> + <?php else: ?> + <?= t('Not assigned, estimate of %sh', $subtask['time_estimated']) ?> + <?php endif ?> + </li> + </ul> +</div> diff --git a/app/Templates/event_task_assignee_change.php b/app/Templates/event_task_assignee_change.php index ac18af2f..b346325e 100644 --- a/app/Templates/event_task_assignee_change.php +++ b/app/Templates/event_task_assignee_change.php @@ -1,6 +1,12 @@ <p class="activity-title"> - <?= e('%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> + <?= e( + '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s', + Helper\escape($author), + $task_id, + $task_id, + Helper\escape($task['assignee_name'] ?: $task['assignee_username']) + ) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_close.php b/app/Templates/event_task_close.php index 9d92ea55..48d25678 100644 --- a/app/Templates/event_task_close.php +++ b/app/Templates/event_task_close.php @@ -2,5 +2,5 @@ <?= e('%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_create.php b/app/Templates/event_task_create.php index 7ceab4bb..2515af05 100644 --- a/app/Templates/event_task_create.php +++ b/app/Templates/event_task_create.php @@ -2,5 +2,5 @@ <?= e('%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_move_column.php b/app/Templates/event_task_move_column.php index a674f80a..f2aac8f7 100644 --- a/app/Templates/event_task_move_column.php +++ b/app/Templates/event_task_move_column.php @@ -1,6 +1,6 @@ <p class="activity-title"> - <?= e('%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"', Helper\escape($author), $task_id, $task_id, Helper\escape($task_column_name)) ?> + <?= e('%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"', Helper\escape($author), $task_id, $task_id, Helper\escape($task['column_title'])) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_move_position.php b/app/Templates/event_task_move_position.php index 0b7e9615..26cdeb13 100644 --- a/app/Templates/event_task_move_position.php +++ b/app/Templates/event_task_move_position.php @@ -1,6 +1,6 @@ <p class="activity-title"> - <?= e('%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"', Helper\escape($author), $task_id, $task_id, $task_position, Helper\escape($task_column_name)) ?> + <?= e('%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"', Helper\escape($author), $task_id, $task_id, $task['position'], Helper\escape($task['column_title'])) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_open.php b/app/Templates/event_task_open.php index 763b0dfc..9623be74 100644 --- a/app/Templates/event_task_open.php +++ b/app/Templates/event_task_open.php @@ -2,5 +2,5 @@ <?= e('%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/event_task_update.php b/app/Templates/event_task_update.php index 313e79cb..a270b936 100644 --- a/app/Templates/event_task_update.php +++ b/app/Templates/event_task_update.php @@ -2,5 +2,5 @@ <?= e('%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>', Helper\escape($author), $task_id, $task_id) ?> </p> <p class="activity-description"> - <em><?= Helper\escape($task_title) ?></em> + <em><?= Helper\escape($task['title']) ?></em> </p>
\ No newline at end of file diff --git a/app/Templates/project_activity.php b/app/Templates/project_activity.php index ad91f8b8..50743d68 100644 --- a/app/Templates/project_activity.php +++ b/app/Templates/project_activity.php @@ -2,10 +2,10 @@ <div class="page-header"> <h2><?= t('%s\'s activity', $project['name']) ?></h2> <ul> - <li><a href="?controller=board&action=show&project_id=<?= $project['id'] ?>"><?= t('Back to the board') ?></a></li> - <li><a href="?controller=project&action=search&project_id=<?= $project['id'] ?>"><?= t('Search') ?></a></li> - <li><a href="?controller=project&action=tasks&project_id=<?= $project['id'] ?>"><?= t('Completed tasks') ?></a></li> - <li><a href="?controller=project&action=index"><?= t('List of projects') ?></a></li> + <li><?= Helper\a(t('Back to the board'), 'board', 'show', array('project_id' => $project['id'])) ?></li> + <li><?= Helper\a(t('Search'), 'project', 'search', array('project_id' => $project['id'])) ?></li> + <li><?= Helper\a(t('Completed tasks'), 'project', 'tasks', array('project_id' => $project['id'])) ?></li> + <li><?= Helper\a(t('List of projects'), 'project', 'index') ?></li> </ul> </div> <section> @@ -14,17 +14,17 @@ <?php else: ?> <?php if ($project['is_public']): ?> - <p class="pull-right"><i class="fa fa-rss-square"></i> <a href="?controller=project&action=feed&token=<?= $project['token'] ?>" target="_blank"><?= t('RSS feed') ?></a></p> + <p class="pull-right"><i class="fa fa-rss-square"></i> <?= Helper\a(t('RSS feed'), 'project', 'feed', array('token' => $project['token'])) ?></p> <?php endif ?> <?php foreach ($events as $event): ?> <div class="activity-event"> <p class="activity-datetime"> - <?php if ($event['event_type'] === 'task'): ?> + <?php if (Helper\contains($event['event_name'], 'task')): ?> <i class="fa fa-newspaper-o"></i> - <?php elseif ($event['event_type'] === 'subtask'): ?> + <?php elseif (Helper\contains($event['event_name'], 'subtask')): ?> <i class="fa fa-tasks"></i> - <?php elseif ($event['event_type'] === 'comment'): ?> + <?php elseif (Helper\contains($event['event_name'], 'comment')): ?> <i class="fa fa-comments-o"></i> <?php endif ?> <?= dt('%B %e, %Y at %k:%M %p', $event['date_creation']) ?> diff --git a/app/Templates/project_feed.php b/app/Templates/project_feed.php index b47c87ad..9d10ecb1 100644 --- a/app/Templates/project_feed.php +++ b/app/Templates/project_feed.php @@ -2,7 +2,7 @@ <feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom"> <title><?= t('%s\'s activity', $project['name']) ?></title> <link rel="alternate" type="text/html" href="<?= Helper\get_current_base_url() ?>"/> - <link rel="self" type="application/atom+xml" href="<?= Helper\get_current_base_url() ?>?controller=project&action=feed&token=<?= $project['token'] ?>"/> + <link rel="self" type="application/atom+xml" href="<?= Helper\get_current_base_url().Helper\u('project', 'feed', array('token' => $project['token'])) ?>"/> <updated><?= date(DATE_ATOM) ?></updated> <id><?= Helper\get_current_base_url() ?></id> <icon><?= Helper\get_current_base_url() ?>assets/img/favicon.png</icon> @@ -10,7 +10,7 @@ <?php foreach ($events as $e): ?> <entry> <title type="text"><?= $e['event_title'] ?></title> - <link rel="alternate" href="<?= Helper\get_current_base_url().'?controller=task&action=show&task_id='.$e['task_id'] ?>"/> + <link rel="alternate" href="<?= Helper\get_current_base_url().Helper\u('task', 'show', array('task_id' => $e['task_id'])) ?>"/> <id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id> <published><?= date(DATE_ATOM, $e['date_creation']) ?></published> <updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated> diff --git a/app/Templates/task_public.php b/app/Templates/task_public.php index bc4608d1..3f44ceec 100644 --- a/app/Templates/task_public.php +++ b/app/Templates/task_public.php @@ -2,7 +2,7 @@ <?= Helper\template('task_details', array('task' => $task, 'project' => $project)) ?> - <p class="align-right"><?= Helper\a(t('Back to the board'), 'board', 'readonly', array('token' => $project['token'])) ?></p> + <p class="pull-right"><?= Helper\a(t('Back to the board'), 'board', 'readonly', array('token' => $project['token'])) ?></p> <?= Helper\template('task_show_description', array('task' => $task)) ?> |