summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--app/Filter/TaskCommentFilter.php41
-rw-r--r--app/ServiceProvider/FilterProvider.php2
-rw-r--r--doc/search.markdown23
-rw-r--r--tests/units/Filter/TaskCommentFilterTest.php52
5 files changed, 116 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index ea12d9b9..941c46c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
Version 1.0.28 (unreleased)
--------------
+New features:
+
+* Search in comments
+
Improvements:
* Filter/Lexer/QueryBuilder refactoring
diff --git a/app/Filter/TaskCommentFilter.php b/app/Filter/TaskCommentFilter.php
new file mode 100644
index 00000000..455098c2
--- /dev/null
+++ b/app/Filter/TaskCommentFilter.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Kanboard\Filter;
+
+use Kanboard\Core\Filter\FilterInterface;
+use Kanboard\Model\Comment;
+use Kanboard\Model\Task;
+
+/**
+ * Filter tasks by comment
+ *
+ * @package filter
+ * @author Frederic Guillot
+ */
+class TaskCommentFilter extends BaseFilter implements FilterInterface
+{
+ /**
+ * Get search attribute
+ *
+ * @access public
+ * @return string[]
+ */
+ public function getAttributes()
+ {
+ return array('comment');
+ }
+
+ /**
+ * Apply filter
+ *
+ * @access public
+ * @return FilterInterface
+ */
+ public function apply()
+ {
+ $this->query->ilike(Comment::TABLE.'.comment', '%'.$this->value.'%');
+ $this->query->join(Comment::TABLE, 'task_id', 'id', Task::TABLE);
+
+ return $this;
+ }
+}
diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php
index 555cb262..66608b8c 100644
--- a/app/ServiceProvider/FilterProvider.php
+++ b/app/ServiceProvider/FilterProvider.php
@@ -8,6 +8,7 @@ use Kanboard\Filter\TaskAssigneeFilter;
use Kanboard\Filter\TaskCategoryFilter;
use Kanboard\Filter\TaskColorFilter;
use Kanboard\Filter\TaskColumnFilter;
+use Kanboard\Filter\TaskCommentFilter;
use Kanboard\Filter\TaskCreationDateFilter;
use Kanboard\Filter\TaskDescriptionFilter;
use Kanboard\Filter\TaskDueDateFilter;
@@ -85,6 +86,7 @@ class FilterProvider implements ServiceProviderInterface
->withFilter(new TaskCategoryFilter())
->withFilter(TaskColorFilter::getInstance()->setColorModel($c['color']))
->withFilter(new TaskColumnFilter())
+ ->withFilter(new TaskCommentFilter())
->withFilter(new TaskCreationDateFilter())
->withFilter(new TaskDescriptionFilter())
->withFilter(new TaskDueDateFilter())
diff --git a/doc/search.markdown b/doc/search.markdown
index 1a97a7fc..93c8214e 100644
--- a/doc/search.markdown
+++ b/doc/search.markdown
@@ -38,7 +38,12 @@ Attribute: **assignee**
- Query for unassigned tasks: `assignee:nobody`
- Query for my assigned tasks: `assignee:me`
-Note: Kanboard will also search in assigned subtasks with the status todo and in progress.
+Search by subtask assignee
+--------------------------
+
+Attribute: **subtask:assignee**
+
+- Example: `subtask:assignee:"John Doe"`
Search by color
---------------
@@ -90,7 +95,7 @@ Works in the same way as the modification date queries.
Search by description
---------------------
-Attribute: **description**
+Attribute: **description** or **desc**
Example: `description:"text search"`
@@ -127,14 +132,14 @@ Attribute: **column**
- Find tasks by column name: `column:"Work in progress"`
- Find tasks for several columns: `column:"Backlog" column:ready`
-Search by swim lane
+Search by swim-lane
-------------------
Attribute: **swimlane**
-- Find tasks by swim lane: `swimlane:"Version 42"`
-- Find tasks in the default swim lane: `swimlane:default`
-- Find tasks into several swim lanes: `swimlane:"Version 1.2" swimlane:"Version 1.3"`
+- Find tasks by swim-lane: `swimlane:"Version 42"`
+- Find tasks in the default swim-lane: `swimlane:default`
+- Find tasks into several swim-lanes: `swimlane:"Version 1.2" swimlane:"Version 1.3"`
Search by task link
------------------
@@ -144,3 +149,9 @@ Attribute: **link**
- Find tasks by link name: `link:"is a milestone of"`
- Find tasks into several links: `link:"is a milestone of" link:"relates to"`
+Search by comment
+-----------------
+
+Attribute: **comment**
+
+- Find comments that contains this title: `comment:"My comment message"`
diff --git a/tests/units/Filter/TaskCommentFilterTest.php b/tests/units/Filter/TaskCommentFilterTest.php
new file mode 100644
index 00000000..8d1b7f44
--- /dev/null
+++ b/tests/units/Filter/TaskCommentFilterTest.php
@@ -0,0 +1,52 @@
+<?php
+
+use Kanboard\Filter\TaskCommentFilter;
+use Kanboard\Model\Comment;
+use Kanboard\Model\Project;
+use Kanboard\Model\TaskCreation;
+use Kanboard\Model\TaskFinder;
+
+require_once __DIR__.'/../Base.php';
+
+class TaskCommentFilterTest extends Base
+{
+ public function testMatch()
+ {
+ $taskFinder = new TaskFinder($this->container);
+ $taskCreation = new TaskCreation($this->container);
+ $commentModel = new Comment($this->container);
+ $projectModel = new Project($this->container);
+ $query = $taskFinder->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+ $this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
+ $this->assertEquals(1, $commentModel->create(array('task_id' => 1, 'user_id' => 1, 'comment' => 'This is a test')));
+
+ $filter = new TaskCommentFilter();
+ $filter->withQuery($query);
+ $filter->withValue('test');
+ $filter->apply();
+
+ $this->assertCount(1, $query->findAll());
+ }
+
+ public function testNoMatch()
+ {
+ $taskFinder = new TaskFinder($this->container);
+ $taskCreation = new TaskCreation($this->container);
+ $commentModel = new Comment($this->container);
+ $projectModel = new Project($this->container);
+ $query = $taskFinder->getExtendedQuery();
+
+ $this->assertEquals(1, $projectModel->create(array('name' => 'Test')));
+ $this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
+ $this->assertEquals(1, $commentModel->create(array('task_id' => 1, 'user_id' => 1, 'comment' => 'This is a test')));
+
+ $filter = new TaskCommentFilter();
+ $filter->withQuery($query);
+ $filter->withValue('foobar');
+ $filter->apply();
+
+ $this->assertCount(0, $query->findAll());
+ }
+}