summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2016-07-17 17:15:14 -0400
committerFrederic Guillot <fred@kanboard.net>2016-07-17 17:15:14 -0400
commitec0ecc5b0387924f061865f4ec12dbfc5b7018fe (patch)
tree146fe907e300fa88587b621aaf53a9ca05e8c2d8
parent3aa0f8574898876518dddf29ced43dd32efa2375 (diff)
Added event for removed comments with some refactoring
-rw-r--r--ChangeLog1
-rw-r--r--app/Core/Base.php2
-rw-r--r--app/Core/Queue/JobHandler.php24
-rw-r--r--app/Core/Queue/QueueManager.php6
-rw-r--r--app/EventBuilder/BaseEventBuilder.php23
-rw-r--r--app/EventBuilder/CommentEventBuilder.php48
-rw-r--r--app/Job/CommentEventJob.php50
-rw-r--r--app/Job/NotificationJob.php3
-rw-r--r--app/Model/CommentModel.php9
-rw-r--r--app/Model/NotificationModel.php5
-rw-r--r--app/ServiceProvider/ClassProvider.php4
-rw-r--r--app/Subscriber/NotificationSubscriber.php1
-rw-r--r--app/Template/event/comment_remove.php11
-rw-r--r--app/Template/event/comment_update.php3
-rw-r--r--app/Template/notification/comment_remove.php7
-rw-r--r--tests/units/EventBuilder/CommentEventBuilderTest.php37
-rw-r--r--tests/units/Job/CommentEventJobTest.php52
-rw-r--r--tests/units/Model/CommentModelTest.php (renamed from tests/units/Model/CommentTest.php)4
18 files changed, 272 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index e87c0965..a1e39436 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Version 1.0.32 (unreleased)
New features:
* New automated action to close tasks without activity in a specific column
+* Added new event for removed comments
* Added search filter for task priority
* Added the possibility to hide tasks in dashboard for a specific column
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 8103ec14..e413a4ac 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -150,6 +150,8 @@ use Pimple\Container;
* @property \Kanboard\Core\Filter\QueryBuilder $taskQuery
* @property \Kanboard\Core\Filter\LexerBuilder $taskLexer
* @property \Kanboard\Core\Filter\LexerBuilder $projectActivityLexer
+ * @property \Kanboard\Job\CommentEventJob $commentEventJob
+ * @property \Kanboard\Job\NotificationJob $notificationJob
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
diff --git a/app/Core/Queue/JobHandler.php b/app/Core/Queue/JobHandler.php
index 7ca36328..326f3cef 100644
--- a/app/Core/Queue/JobHandler.php
+++ b/app/Core/Queue/JobHandler.php
@@ -2,6 +2,7 @@
namespace Kanboard\Core\Queue;
+use Exception;
use Kanboard\Core\Base;
use Kanboard\Job\BaseJob;
use SimpleQueue\Job;
@@ -39,16 +40,23 @@ class JobHandler extends Base
public function executeJob(Job $job)
{
$payload = $job->getBody();
- $className = $payload['class'];
- $this->memoryCache->flush();
- $this->prepareJobSession($payload['user_id']);
- if (DEBUG) {
- $this->logger->debug(__METHOD__.' Received job => '.$className.' ('.getmypid().')');
- }
+ try {
+ $className = $payload['class'];
+ $this->memoryCache->flush();
+ $this->prepareJobSession($payload['user_id']);
+
+ if (DEBUG) {
+ $this->logger->debug(__METHOD__.' Received job => '.$className.' ('.getmypid().')');
+ $this->logger->debug(__METHOD__.' => '.json_encode($payload));
+ }
- $worker = new $className($this->container);
- call_user_func_array(array($worker, 'execute'), $payload['params']);
+ $worker = new $className($this->container);
+ call_user_func_array(array($worker, 'execute'), $payload['params']);
+ } catch (Exception $e) {
+ $this->logger->error(__METHOD__.': Error during job execution: '.$e->getMessage());
+ $this->logger->error(__METHOD__ .' => '.json_encode($payload));
+ }
}
/**
diff --git a/app/Core/Queue/QueueManager.php b/app/Core/Queue/QueueManager.php
index f34cb220..dcf0ebf5 100644
--- a/app/Core/Queue/QueueManager.php
+++ b/app/Core/Queue/QueueManager.php
@@ -42,9 +42,13 @@ class QueueManager extends Base
*/
public function push(BaseJob $job)
{
+ $jobClassName = get_class($job);
+
if ($this->queue !== null) {
+ $this->logger->debug(__METHOD__.': Job pushed in queue: '.$jobClassName);
$this->queue->push(JobHandler::getInstance($this->container)->serializeJob($job));
} else {
+ $this->logger->debug(__METHOD__.': Job executed synchronously: '.$jobClassName);
call_user_func_array(array($job, 'execute'), $job->getJobParams());
}
@@ -60,7 +64,7 @@ class QueueManager extends Base
public function listen()
{
if ($this->queue === null) {
- throw new LogicException('No Queue Driver defined!');
+ throw new LogicException('No queue driver defined!');
}
while ($job = $this->queue->pull()) {
diff --git a/app/EventBuilder/BaseEventBuilder.php b/app/EventBuilder/BaseEventBuilder.php
new file mode 100644
index 00000000..c677563e
--- /dev/null
+++ b/app/EventBuilder/BaseEventBuilder.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Kanboard\EventBuilder;
+
+use Kanboard\Core\Base;
+use Kanboard\Event\GenericEvent;
+
+/**
+ * Class BaseEventBuilder
+ *
+ * @package Kanboard\EventBuilder
+ * @author Frederic Guillot
+ */
+abstract class BaseEventBuilder extends Base
+{
+ /**
+ * Build event data
+ *
+ * @access public
+ * @return GenericEvent|null
+ */
+ abstract public function build();
+}
diff --git a/app/EventBuilder/CommentEventBuilder.php b/app/EventBuilder/CommentEventBuilder.php
new file mode 100644
index 00000000..7b4060e4
--- /dev/null
+++ b/app/EventBuilder/CommentEventBuilder.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Kanboard\EventBuilder;
+
+use Kanboard\Event\CommentEvent;
+
+/**
+ * Class CommentEventBuilder
+ *
+ * @package Kanboard\EventBuilder
+ * @author Frederic Guillot
+ */
+class CommentEventBuilder extends BaseEventBuilder
+{
+ protected $commentId = 0;
+
+ /**
+ * Set commentId
+ *
+ * @param int $commentId
+ * @return $this
+ */
+ public function withCommentId($commentId)
+ {
+ $this->commentId = $commentId;
+ return $this;
+ }
+
+ /**
+ * Build event data
+ *
+ * @access public
+ * @return CommentEvent|null
+ */
+ public function build()
+ {
+ $comment = $this->commentModel->getById($this->commentId);
+
+ if (empty($comment)) {
+ return null;
+ }
+
+ return new CommentEvent(array(
+ 'comment' => $comment,
+ 'task' => $this->taskFinderModel->getDetails($comment['task_id']),
+ ));
+ }
+}
diff --git a/app/Job/CommentEventJob.php b/app/Job/CommentEventJob.php
new file mode 100644
index 00000000..c89350ed
--- /dev/null
+++ b/app/Job/CommentEventJob.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Kanboard\Job;
+
+use Kanboard\EventBuilder\CommentEventBuilder;
+use Kanboard\Model\CommentModel;
+
+/**
+ * Class CommentEventJob
+ *
+ * @package Kanboard\Job
+ * @author Frederic Guillot
+ */
+class CommentEventJob extends BaseJob
+{
+ /**
+ * Set job params
+ *
+ * @param int $commentId
+ * @param string $eventName
+ * @return $this
+ */
+ public function withParams($commentId, $eventName)
+ {
+ $this->jobParams = array($commentId, $eventName);
+ return $this;
+ }
+
+ /**
+ * Execute job
+ *
+ * @param int $commentId
+ * @param string $eventName
+ * @return $this
+ */
+ public function execute($commentId, $eventName)
+ {
+ $event = CommentEventBuilder::getInstance($this->container)
+ ->withCommentId($commentId)
+ ->build();
+
+ if ($event !== null) {
+ $this->dispatcher->dispatch($eventName, $event);
+
+ if ($eventName === CommentModel::EVENT_CREATE) {
+ $this->userMentionModel->fireEvents($event['comment']['comment'], CommentModel::EVENT_USER_MENTION, $event);
+ }
+ }
+ }
+}
diff --git a/app/Job/NotificationJob.php b/app/Job/NotificationJob.php
index 904a9273..cfd0699d 100644
--- a/app/Job/NotificationJob.php
+++ b/app/Job/NotificationJob.php
@@ -75,8 +75,7 @@ class NotificationJob extends BaseJob
$values['task'] = $this->taskFinderModel->getDetails($values['file']['task_id']);
break;
case 'Kanboard\Event\CommentEvent':
- $values['comment'] = $this->commentModel->getById($event['id']);
- $values['task'] = $this->taskFinderModel->getDetails($values['comment']['task_id']);
+ $values = $event;
break;
}
diff --git a/app/Model/CommentModel.php b/app/Model/CommentModel.php
index 4231f29d..6b983858 100644
--- a/app/Model/CommentModel.php
+++ b/app/Model/CommentModel.php
@@ -2,7 +2,6 @@
namespace Kanboard\Model;
-use Kanboard\Event\CommentEvent;
use Kanboard\Core\Base;
/**
@@ -27,6 +26,7 @@ class CommentModel extends Base
*/
const EVENT_UPDATE = 'comment.update';
const EVENT_CREATE = 'comment.create';
+ const EVENT_REMOVE = 'comment.remove';
const EVENT_USER_MENTION = 'comment.user.mention';
/**
@@ -130,9 +130,7 @@ class CommentModel extends Base
$comment_id = $this->db->table(self::TABLE)->persist($values);
if ($comment_id !== false) {
- $event = new CommentEvent(array('id' => $comment_id) + $values);
- $this->dispatcher->dispatch(self::EVENT_CREATE, $event);
- $this->userMentionModel->fireEvents($values['comment'], self::EVENT_USER_MENTION, $event);
+ $this->queueManager->push($this->commentEventJob->withParams($comment_id, self::EVENT_CREATE));
}
return $comment_id;
@@ -153,7 +151,7 @@ class CommentModel extends Base
->update(array('comment' => $values['comment']));
if ($result) {
- $this->container['dispatcher']->dispatch(self::EVENT_UPDATE, new CommentEvent($values));
+ $this->queueManager->push($this->commentEventJob->withParams($values['id'], self::EVENT_UPDATE));
}
return $result;
@@ -168,6 +166,7 @@ class CommentModel extends Base
*/
public function remove($comment_id)
{
+ $this->commentEventJob->execute($comment_id, self::EVENT_REMOVE);
return $this->db->table(self::TABLE)->eq('id', $comment_id)->remove();
}
}
diff --git a/app/Model/NotificationModel.php b/app/Model/NotificationModel.php
index 4d697b5e..df481fc7 100644
--- a/app/Model/NotificationModel.php
+++ b/app/Model/NotificationModel.php
@@ -74,6 +74,8 @@ class NotificationModel extends Base
return e('%s updated a comment on the task #%d', $event_author, $event_data['task']['id']);
case CommentModel::EVENT_CREATE:
return e('%s commented on the task #%d', $event_author, $event_data['task']['id']);
+ case CommentModel::EVENT_REMOVE:
+ return e('%s removed a comment on the task #%d', $event_author, $event_data['task']['id']);
case TaskFileModel::EVENT_CREATE:
return e('%s attached a file to the task #%d', $event_author, $event_data['task']['id']);
case TaskModel::EVENT_USER_MENTION:
@@ -102,6 +104,8 @@ class NotificationModel extends Base
return e('New comment on task #%d', $event_data['comment']['task_id']);
case CommentModel::EVENT_UPDATE:
return e('Comment updated on task #%d', $event_data['comment']['task_id']);
+ case CommentModel::EVENT_REMOVE:
+ return e('Comment removed on task #%d', $event_data['comment']['task_id']);
case SubtaskModel::EVENT_CREATE:
return e('New subtask on task #%d', $event_data['subtask']['task_id']);
case SubtaskModel::EVENT_UPDATE:
@@ -149,6 +153,7 @@ class NotificationModel extends Base
return $event_data['file']['task_id'];
case CommentModel::EVENT_CREATE:
case CommentModel::EVENT_UPDATE:
+ case CommentModel::EVENT_REMOVE:
return $event_data['comment']['task_id'];
case SubtaskModel::EVENT_CREATE:
case SubtaskModel::EVENT_UPDATE:
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index e32c0d43..43ade56e 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -26,6 +26,10 @@ class ClassProvider implements ServiceProviderInterface
'AverageLeadCycleTimeAnalytic',
'AverageTimeSpentColumnAnalytic',
),
+ 'Job' => array(
+ 'CommentEventJob',
+ 'NotificationJob',
+ ),
'Model' => array(
'ActionModel',
'ActionParameterModel',
diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php
index db11e585..6cd7675c 100644
--- a/app/Subscriber/NotificationSubscriber.php
+++ b/app/Subscriber/NotificationSubscriber.php
@@ -28,6 +28,7 @@ class NotificationSubscriber extends BaseSubscriber implements EventSubscriberIn
SubtaskModel::EVENT_UPDATE => 'handleEvent',
CommentModel::EVENT_CREATE => 'handleEvent',
CommentModel::EVENT_UPDATE => 'handleEvent',
+ CommentModel::EVENT_REMOVE => 'handleEvent',
CommentModel::EVENT_USER_MENTION => 'handleEvent',
TaskFileModel::EVENT_CREATE => 'handleEvent',
);
diff --git a/app/Template/event/comment_remove.php b/app/Template/event/comment_remove.php
new file mode 100644
index 00000000..ead7d56a
--- /dev/null
+++ b/app/Template/event/comment_remove.php
@@ -0,0 +1,11 @@
+<p class="activity-title">
+ <?= e('%s removed a comment on the task %s',
+ $this->text->e($author),
+ $this->url->link(t('#%d', $task['id']), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))
+ ) ?>
+ <span class="activity-date"><?= $this->dt->datetime($date_creation) ?></span>
+</p>
+<div class="activity-description">
+ <p class="activity-task-title"><?= $this->text->e($task['title']) ?></p>
+ <div class="markdown"><?= $this->text->markdown($comment['comment']) ?></div>
+</div>
diff --git a/app/Template/event/comment_update.php b/app/Template/event/comment_update.php
index 5a0821bd..5be598ac 100644
--- a/app/Template/event/comment_update.php
+++ b/app/Template/event/comment_update.php
@@ -7,4 +7,7 @@
</p>
<div class="activity-description">
<p class="activity-task-title"><?= $this->text->e($task['title']) ?></p>
+ <?php if (! empty($comment['comment'])): ?>
+ <div class="markdown"><?= $this->text->markdown($comment['comment']) ?></div>
+ <?php endif ?>
</div>
diff --git a/app/Template/notification/comment_remove.php b/app/Template/notification/comment_remove.php
new file mode 100644
index 00000000..928623ec
--- /dev/null
+++ b/app/Template/notification/comment_remove.php
@@ -0,0 +1,7 @@
+<h2><?= $this->text->e($task['title']) ?> (#<?= $task['id'] ?>)</h2>
+
+<h3><?= t('Comment removed') ?></h3>
+
+<?= $this->text->markdown($comment['comment']) ?>
+
+<?= $this->render('notification/footer', array('task' => $task, 'application_url' => $application_url)) ?>
diff --git a/tests/units/EventBuilder/CommentEventBuilderTest.php b/tests/units/EventBuilder/CommentEventBuilderTest.php
new file mode 100644
index 00000000..a490799e
--- /dev/null
+++ b/tests/units/EventBuilder/CommentEventBuilderTest.php
@@ -0,0 +1,37 @@
+<?php
+
+use Kanboard\EventBuilder\CommentEventBuilder;
+use Kanboard\Model\CommentModel;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskCreationModel;
+
+require_once __DIR__.'/../Base.php';
+
+class CommentEventBuilderTest extends Base
+{
+ public function testWithMissingComment()
+ {
+ $commentEventBuilder = new CommentEventBuilder($this->container);
+ $commentEventBuilder->withCommentId(42);
+ $this->assertNull($commentEventBuilder->build());
+ }
+
+ public function testBuild()
+ {
+ $commentModel = new CommentModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+ $commentEventBuilder = new CommentEventBuilder($this->container);
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
+ $this->assertEquals(1, $taskCreationModel->create(array('title' => 'test', 'project_id' => 1)));
+ $this->assertEquals(1, $commentModel->create(array('task_id' => 1, 'comment' => 'bla bla', 'user_id' => 1)));
+
+ $commentEventBuilder->withCommentId(1);
+ $event = $commentEventBuilder->build();
+
+ $this->assertInstanceOf('Kanboard\Event\CommentEvent', $event);
+ $this->assertNotEmpty($event['comment']);
+ $this->assertNotEmpty($event['task']);
+ }
+}
diff --git a/tests/units/Job/CommentEventJobTest.php b/tests/units/Job/CommentEventJobTest.php
new file mode 100644
index 00000000..88742feb
--- /dev/null
+++ b/tests/units/Job/CommentEventJobTest.php
@@ -0,0 +1,52 @@
+<?php
+
+use Kanboard\Job\CommentEventJob;
+use Kanboard\Model\CommentModel;
+use Kanboard\Model\ProjectModel;
+use Kanboard\Model\TaskCreationModel;
+
+require_once __DIR__.'/../Base.php';
+
+class CommentEventJobTest extends Base
+{
+ public function testJobParams()
+ {
+ $commentEventJob = new CommentEventJob($this->container);
+ $commentEventJob->withParams(123, 'foobar');
+
+ $this->assertSame(array(123, 'foobar'), $commentEventJob->getJobParams());
+ }
+
+ public function testWithMissingComment()
+ {
+ $this->container['dispatcher']->addListener(CommentModel::EVENT_CREATE, function() {});
+
+ $commentEventJob = new CommentEventJob($this->container);
+ $commentEventJob->execute(42, CommentModel::EVENT_CREATE);
+
+ $called = $this->container['dispatcher']->getCalledListeners();
+ $this->assertEmpty($called);
+ }
+
+ public function testTriggerEvents()
+ {
+ $this->container['dispatcher']->addListener(CommentModel::EVENT_CREATE, function() {});
+ $this->container['dispatcher']->addListener(CommentModel::EVENT_UPDATE, function() {});
+ $this->container['dispatcher']->addListener(CommentModel::EVENT_REMOVE, function() {});
+
+ $commentModel = new CommentModel($this->container);
+ $taskCreationModel = new TaskCreationModel($this->container);
+ $projectModel = new ProjectModel($this->container);
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'test1')));
+ $this->assertEquals(1, $taskCreationModel->create(array('title' => 'test', 'project_id' => 1)));
+ $this->assertEquals(1, $commentModel->create(array('task_id' => 1, 'comment' => 'foobar', 'user_id' => 1)));
+ $this->assertTrue($commentModel->update(array('id' => 1, 'comment' => 'test')));
+ $this->assertTrue($commentModel->remove(1));
+
+ $called = $this->container['dispatcher']->getCalledListeners();
+ $this->assertArrayHasKey(CommentModel::EVENT_CREATE.'.closure', $called);
+ $this->assertArrayHasKey(CommentModel::EVENT_UPDATE.'.closure', $called);
+ $this->assertArrayHasKey(CommentModel::EVENT_REMOVE.'.closure', $called);
+ }
+}
diff --git a/tests/units/Model/CommentTest.php b/tests/units/Model/CommentModelTest.php
index 574b5a87..4178a839 100644
--- a/tests/units/Model/CommentTest.php
+++ b/tests/units/Model/CommentModelTest.php
@@ -6,7 +6,7 @@ use Kanboard\Model\TaskCreationModel;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\CommentModel;
-class CommentTest extends Base
+class CommentModelTest extends Base
{
public function testCreate()
{
@@ -75,7 +75,7 @@ class CommentTest extends Base
$this->assertEquals('bla', $comment['comment']);
}
- public function validateRemove()
+ public function testRemove()
{
$commentModel = new CommentModel($this->container);
$taskCreationModel = new TaskCreationModel($this->container);