diff options
-rw-r--r-- | app/Core/Lexer.php | 5 | ||||
-rw-r--r-- | app/Model/TaskFilter.php | 66 | ||||
-rw-r--r-- | docs/search.markdown | 96 | ||||
-rw-r--r-- | tests/units/LexerTest.php | 65 |
4 files changed, 165 insertions, 67 deletions
diff --git a/app/Core/Lexer.php b/app/Core/Lexer.php index 0a237254..d7e6fde4 100644 --- a/app/Core/Lexer.php +++ b/app/Core/Lexer.php @@ -28,6 +28,9 @@ class Lexer "/^(assignee:)/" => 'T_ASSIGNEE', "/^(color:)/" => 'T_COLOR', "/^(due:)/" => 'T_DUE', + "/^(updated:)/" => 'T_UPDATED', + "/^(modified:)/" => 'T_UPDATED', + "/^(created:)/" => 'T_CREATED', "/^(status:)/" => 'T_STATUS', "/^(description:)/" => 'T_DESCRIPTION', "/^(category:)/" => 'T_CATEGORY', @@ -128,6 +131,8 @@ class Lexer case 'T_STATUS': case 'T_DUE': + case 'T_UPDATED': + case 'T_CREATED': case 'T_DESCRIPTION': case 'T_REFERENCE': $next = next($tokens); diff --git a/app/Model/TaskFilter.php b/app/Model/TaskFilter.php index 0dbadbf8..77ab1f3c 100644 --- a/app/Model/TaskFilter.php +++ b/app/Model/TaskFilter.php @@ -50,6 +50,12 @@ class TaskFilter extends Base case 'T_DUE': $this->filterByDueDate($value); break; + case 'T_UPDATED': + $this->filterByModificationDate($value); + break; + case 'T_CREATED': + $this->filterByCreationDate($value); + break; case 'T_TITLE': $this->filterByTitle($value); break; @@ -580,6 +586,22 @@ class TaskFilter extends Base * Filter by creation date * * @access public + * @param string $date ISO8601 date format + * @return TaskFilter + */ + public function filterByCreationDate($date) + { + if ($date === 'recently') { + return $this->filterRecentlyDate(Task::TABLE.'.date_creation'); + } + + return $this->filterWithOperator(Task::TABLE.'.date_creation', $date, true); + } + + /** + * Filter by creation date + * + * @access public * @param string $start * @param string $end * @return TaskFilter @@ -597,6 +619,22 @@ class TaskFilter extends Base } /** + * Filter by modification date + * + * @access public + * @param string $date ISO8601 date format + * @return TaskFilter + */ + public function filterByModificationDate($date) + { + if ($date === 'recently') { + return $this->filterRecentlyDate(Task::TABLE.'.date_modification'); + } + + return $this->filterWithOperator(Task::TABLE.'.date_modification', $date, true); + } + + /** * Get all results of the filter * * @access public @@ -826,7 +864,6 @@ class TaskFilter extends Base ); foreach ($operators as $operator => $method) { - if (strpos($value, $operator) === 0) { $value = substr($value, strlen($operator)); $this->query->$method($field, $is_date ? $this->dateParser->getTimestampFromIsoFormat($value) : $value); @@ -834,7 +871,32 @@ class TaskFilter extends Base } } - $this->query->eq($field, $is_date ? $this->dateParser->getTimestampFromIsoFormat($value) : $value); + if ($is_date) { + $timestamp = $this->dateParser->getTimestampFromIsoFormat($value); + $this->query->gte($field, $timestamp); + $this->query->lte($field, $timestamp + 86399); + } + else { + $this->query->eq($field, $value); + } + + return $this; + } + + /** + * Use the board_highlight_period for the "recently" keyword + * + * @access private + * @param string $field + * @return TaskFilter + */ + private function filterRecentlyDate($field) + { + $duration = $this->config->get('board_highlight_period', 0); + + if ($duration > 0) { + $this->query->gte($field, time() - $duration); + } return $this; } diff --git a/docs/search.markdown b/docs/search.markdown index 4674a07e..c269b5c1 100644 --- a/docs/search.markdown +++ b/docs/search.markdown @@ -31,94 +31,60 @@ Search by assignee Attribute: **assignee** -Query with the full name: +- Query with the full name: `assignee:"Frederic Guillot"` +- Query with the username: `assignee:fguillot` +- Multiple assignee lookup: `assignee:user1 assignee:"John Doe"` +- Query for unassigned tasks: `assignee:nobody` +- Query for my assigned tasks: `assignee:me` -``` -assignee:"Frederic Guillot" -``` - -Query with the username: - -``` -assignee:fguillot -``` - -Multiple assignee lookup: - -``` -assignee:user1 assignee:"John Doe" -``` - -Kanboard will search tasks assigned to the "user1" or "John Doe". - -Query for unassigned tasks: - -``` -assignee:nobody -``` - -Query for my assigned tasks - -``` -assignee:me -``` - -Note: Results will also include subtasks assignee with the status todo or in progress. +Note: Kanboard will also search in assigned subtasks with the status todo and in progress. Search by color --------------- Attribute: **color** -Query to search by color id: - -``` -color:blue -``` - -Query to search by color name: - -``` -color:"Deep Orange" -``` +- Query to search by color id: `color:blue` +- Query to search by color name: `color:"Deep Orange"` Search by due date ------------------ Attribute: **due** -Query to search tasks due today: +- Search tasks due today: `due:today` +- Search tasks due tomorrow: `due:tomorrow` +- Search tasks due yesterday: `due:yesterday` +- Search tasks due with the exact date: `due:2015-06-29` -``` -due:today -``` +The date must use the ISO8601 format: **YYYY-MM-DD**. -Query to search tasks due tomorrow: +All string formats supported by the `strtotime()` function are supported, by example `next Thursday`, `-2 days`, `+2 months`, `tomorrow`, etc... -``` -due:tomorrow -``` +Operators supported with a date: -Query to search tasks due yesterday: +- Greater than: **due:>2015-06-29** +- Lower than: **due:<2015-06-29** +- Greater than or equal: **due:>=2015-06-29** +- Lower than or equal: **due:<=2015-06-29** -``` -due:yesterday -``` +Search by modification date +--------------------------- -Query to search tasks due with the exact date: +Attribute: **modified** or **updated** -``` -due:2015-06-29 -``` +The date formats are the same as the due date. -The date must use the ISO8601 format: **YYYY-MM-DD**. +There is also a filter by recently modified tasks: `modified:recently`. -Operators supported: +This query will use the same value as the board highlight period configured in settings. -- Greater than: **due:>2015-06-29** -- Lower than: **due:<2015-06-29** -- Greater than or equal: **due:>=2015-06-29** -- Lower than or equal: **due:<=2015-06-29** +Search by creation date +----------------------- + +Attribute: **created** + +Works in the same way as the modification date queries. Search by description --------------------- diff --git a/tests/units/LexerTest.php b/tests/units/LexerTest.php index 8710f79a..3b15810e 100644 --- a/tests/units/LexerTest.php +++ b/tests/units/LexerTest.php @@ -311,6 +311,71 @@ class LexerTest extends Base ); } + public function testModifiedQuery() + { + $lexer = new Lexer; + + $this->assertEquals( + array(array('match' => 'modified:', 'token' => 'T_UPDATED'), array('match' => '2015-05-01', 'token' => 'T_DATE')), + $lexer->tokenize('modified:2015-05-01') + ); + + $this->assertEquals( + array(array('match' => 'modified:', 'token' => 'T_UPDATED'), array('match' => '<2015-05-01', 'token' => 'T_DATE')), + $lexer->tokenize('modified:<2015-05-01') + ); + + $this->assertEquals( + array(array('match' => 'modified:', 'token' => 'T_UPDATED'), array('match' => '>2015-05-01', 'token' => 'T_DATE')), + $lexer->tokenize('modified:>2015-05-01') + ); + + $this->assertEquals( + array(array('match' => 'updated:', 'token' => 'T_UPDATED'), array('match' => '<=2015-05-01', 'token' => 'T_DATE')), + $lexer->tokenize('updated:<=2015-05-01') + ); + + $this->assertEquals( + array(array('match' => 'updated:', 'token' => 'T_UPDATED'), array('match' => '>=2015-05-01', 'token' => 'T_DATE')), + $lexer->tokenize('updated:>=2015-05-01') + ); + + $this->assertEquals( + array(array('match' => 'updated:', 'token' => 'T_UPDATED'), array('match' => 'yesterday', 'token' => 'T_DATE')), + $lexer->tokenize('updated:yesterday') + ); + + $this->assertEquals( + array(array('match' => 'updated:', 'token' => 'T_UPDATED'), array('match' => 'tomorrow', 'token' => 'T_DATE')), + $lexer->tokenize('updated:tomorrow') + ); + + $this->assertEquals( + array(), + $lexer->tokenize('updated:#2015-05-01') + ); + + $this->assertEquals( + array(), + $lexer->tokenize('modified:01-05-1024') + ); + + $this->assertEquals( + array('T_UPDATED' => '2015-05-01'), + $lexer->map($lexer->tokenize('modified:2015-05-01')) + ); + + $this->assertEquals( + array('T_UPDATED' => '<2015-05-01'), + $lexer->map($lexer->tokenize('modified:<2015-05-01')) + ); + + $this->assertEquals( + array('T_UPDATED' => 'today'), + $lexer->map($lexer->tokenize('modified:today')) + ); + } + public function testMultipleCriterias() { $lexer = new Lexer; |