Added search in activity stream
This commit is contained in:
parent
2eadfb2291
commit
9f0166502b
|
|
@ -3,6 +3,7 @@ Version 1.0.28 (unreleased)
|
||||||
|
|
||||||
New features:
|
New features:
|
||||||
|
|
||||||
|
* Search in activity stream
|
||||||
* Search in comments
|
* Search in comments
|
||||||
* Search by task creator
|
* Search by task creator
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,22 @@ class Search extends Base
|
||||||
'title' => t('Search tasks').($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '')
|
'title' => t('Search tasks').($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function activity()
|
||||||
|
{
|
||||||
|
$search = urldecode($this->request->getStringParam('search'));
|
||||||
|
$events = $this->helper->projectActivity->searchEvents($search);
|
||||||
|
$nb_events = count($events);
|
||||||
|
|
||||||
|
$this->response->html($this->helper->layout->app('search/activity', array(
|
||||||
|
'values' => array(
|
||||||
|
'search' => $search,
|
||||||
|
'controller' => 'search',
|
||||||
|
'action' => 'activity',
|
||||||
|
),
|
||||||
|
'title' => t('Search in activity stream').($nb_events > 0 ? ' ('.$nb_events.')' : ''),
|
||||||
|
'nb_events' => $nb_events,
|
||||||
|
'events' => $events,
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
|
use Kanboard\Core\DateParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base date filter class
|
||||||
|
*
|
||||||
|
* @package filter
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
abstract class BaseDateFilter extends BaseFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DateParser object
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @var DateParser
|
||||||
|
*/
|
||||||
|
protected $dateParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set DateParser object
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param DateParser $dateParser
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setDateParser(DateParser $dateParser)
|
||||||
|
{
|
||||||
|
$this->dateParser = $dateParser;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse operator in the input string
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function parseOperator()
|
||||||
|
{
|
||||||
|
$operators = array(
|
||||||
|
'<=' => 'lte',
|
||||||
|
'>=' => 'gte',
|
||||||
|
'<' => 'lt',
|
||||||
|
'>' => 'gt',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($operators as $operator => $method) {
|
||||||
|
if (strpos($this->value, $operator) === 0) {
|
||||||
|
$this->value = substr($this->value, strlen($operator));
|
||||||
|
return $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a date filter
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @param string $field
|
||||||
|
*/
|
||||||
|
protected function applyDateFilter($field)
|
||||||
|
{
|
||||||
|
$method = $this->parseOperator();
|
||||||
|
$timestamp = $this->dateParser->getTimestampFromIsoFormat($this->value);
|
||||||
|
|
||||||
|
if ($method !== '') {
|
||||||
|
$this->query->$method($field, $this->getTimestampFromOperator($method, $timestamp));
|
||||||
|
} else {
|
||||||
|
$this->query->gte($field, $timestamp);
|
||||||
|
$this->query->lte($field, $timestamp + 86399);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get timestamp from the operator
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $method
|
||||||
|
* @param integer $timestamp
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
protected function getTimestampFromOperator($method, $timestamp)
|
||||||
|
{
|
||||||
|
switch ($method) {
|
||||||
|
case 'lte':
|
||||||
|
return $timestamp + 86399;
|
||||||
|
case 'lt':
|
||||||
|
return $timestamp;
|
||||||
|
case 'gte':
|
||||||
|
return $timestamp;
|
||||||
|
case 'gt':
|
||||||
|
return $timestamp + 86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -72,48 +72,4 @@ abstract class BaseFilter
|
||||||
$this->value = $value;
|
$this->value = $value;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse operator in the input string
|
|
||||||
*
|
|
||||||
* @access protected
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function parseOperator()
|
|
||||||
{
|
|
||||||
$operators = array(
|
|
||||||
'<=' => 'lte',
|
|
||||||
'>=' => 'gte',
|
|
||||||
'<' => 'lt',
|
|
||||||
'>' => 'gt',
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($operators as $operator => $method) {
|
|
||||||
if (strpos($this->value, $operator) === 0) {
|
|
||||||
$this->value = substr($this->value, strlen($operator));
|
|
||||||
return $method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a date filter
|
|
||||||
*
|
|
||||||
* @access protected
|
|
||||||
* @param string $field
|
|
||||||
*/
|
|
||||||
protected function applyDateFilter($field)
|
|
||||||
{
|
|
||||||
$timestamp = strtotime($this->value);
|
|
||||||
$method = $this->parseOperator();
|
|
||||||
|
|
||||||
if ($method !== '') {
|
|
||||||
$this->query->$method($field, $timestamp);
|
|
||||||
} else {
|
|
||||||
$this->query->gte($field, $timestamp);
|
|
||||||
$this->query->lte($field, $timestamp + 86399);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
|
use Kanboard\Core\Filter\FilterInterface;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter activity events by creation date
|
||||||
|
*
|
||||||
|
* @package filter
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivityCreationDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get search attribute
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return array('created');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filter
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return FilterInterface
|
||||||
|
*/
|
||||||
|
public function apply()
|
||||||
|
{
|
||||||
|
$this->applyDateFilter(ProjectActivity::TABLE.'.date_creation');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
|
use Kanboard\Core\Filter\FilterInterface;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter activity events by creator
|
||||||
|
*
|
||||||
|
* @package filter
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivityCreatorFilter extends BaseFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Current user id
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $currentUserId = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set current user id
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $userId
|
||||||
|
* @return TaskAssigneeFilter
|
||||||
|
*/
|
||||||
|
public function setCurrentUserId($userId)
|
||||||
|
{
|
||||||
|
$this->currentUserId = $userId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get search attribute
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return array('creator');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filter
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function apply()
|
||||||
|
{
|
||||||
|
if ($this->value === 'me') {
|
||||||
|
$this->query->eq(ProjectActivity::TABLE . '.creator_id', $this->currentUserId);
|
||||||
|
} else {
|
||||||
|
$this->query->beginOr();
|
||||||
|
$this->query->ilike('uc.username', '%'.$this->value.'%');
|
||||||
|
$this->query->ilike('uc.name', '%'.$this->value.'%');
|
||||||
|
$this->query->closeOr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ class ProjectActivityProjectIdsFilter extends BaseFilter implements FilterInterf
|
||||||
*/
|
*/
|
||||||
public function getAttributes()
|
public function getAttributes()
|
||||||
{
|
{
|
||||||
return array('project_ids');
|
return array('projects');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
|
use Kanboard\Core\Filter\FilterInterface;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter activity events by project name
|
||||||
|
*
|
||||||
|
* @package filter
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivityProjectNameFilter extends BaseFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get search attribute
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return array('project');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filter
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return FilterInterface
|
||||||
|
*/
|
||||||
|
public function apply()
|
||||||
|
{
|
||||||
|
$this->query->ilike(Project::TABLE.'.name', '%'.$this->value.'%');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
|
use Kanboard\Core\Filter\FilterInterface;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter activity events by task status
|
||||||
|
*
|
||||||
|
* @package filter
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivityTaskStatusFilter extends BaseFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get search attribute
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return array('status');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filter
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return FilterInterface
|
||||||
|
*/
|
||||||
|
public function apply()
|
||||||
|
{
|
||||||
|
if ($this->value === 'open') {
|
||||||
|
$this->query->eq(Task::TABLE.'.is_active', Task::STATUS_OPEN);
|
||||||
|
} elseif ($this->value === 'closed') {
|
||||||
|
$this->query->eq(Task::TABLE.'.is_active', Task::STATUS_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
namespace Kanboard\Filter;
|
namespace Kanboard\Filter;
|
||||||
|
|
||||||
use Kanboard\Core\Filter\FilterInterface;
|
use Kanboard\Core\Filter\FilterInterface;
|
||||||
use Kanboard\Model\Task;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter activity events by task title
|
* Filter activity events by task title
|
||||||
|
|
@ -11,7 +10,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class ProjectActivityTaskTitleFilter extends BaseFilter implements FilterInterface
|
class ProjectActivityTaskTitleFilter extends TaskTitleFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
@ -23,16 +22,4 @@ class ProjectActivityTaskTitleFilter extends BaseFilter implements FilterInterfa
|
||||||
{
|
{
|
||||||
return array('title');
|
return array('title');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply filter
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return FilterInterface
|
|
||||||
*/
|
|
||||||
public function apply()
|
|
||||||
{
|
|
||||||
$this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%');
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class TaskCompletionDateFilter extends BaseFilter implements FilterInterface
|
class TaskCompletionDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class TaskCreationDateFilter extends BaseFilter implements FilterInterface
|
class TaskCreationDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class TaskDueDateFilter extends BaseFilter implements FilterInterface
|
class TaskDueDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class TaskModificationDateFilter extends BaseFilter implements FilterInterface
|
class TaskModificationDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,12 @@ class TaskProjectsFilter extends BaseFilter implements FilterInterface
|
||||||
*/
|
*/
|
||||||
public function apply()
|
public function apply()
|
||||||
{
|
{
|
||||||
$this->query->in(Task::TABLE.'.project_id', $this->value);
|
if (empty($this->value)) {
|
||||||
|
$this->query->eq(Task::TABLE.'.project_id', 0);
|
||||||
|
} else {
|
||||||
|
$this->query->in(Task::TABLE.'.project_id', $this->value);
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use Kanboard\Model\Task;
|
||||||
* @package filter
|
* @package filter
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class TaskStartDateFilter extends BaseFilter implements FilterInterface
|
class TaskStartDateFilter extends BaseDateFilter implements FilterInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get search attribute
|
* Get search attribute
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,33 @@ use Kanboard\Model\ProjectActivity;
|
||||||
*/
|
*/
|
||||||
class ProjectActivityHelper extends Base
|
class ProjectActivityHelper extends Base
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Search events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $search
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function searchEvents($search)
|
||||||
|
{
|
||||||
|
$projects = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
|
||||||
|
$events = array();
|
||||||
|
|
||||||
|
if ($search !== '') {
|
||||||
|
$queryBuilder = $this->projectActivityLexer->build($search);
|
||||||
|
$queryBuilder
|
||||||
|
->withFilter(new ProjectActivityProjectIdsFilter(array_keys($projects)))
|
||||||
|
->getQuery()
|
||||||
|
->desc(ProjectActivity::TABLE.'.id')
|
||||||
|
->limit(500)
|
||||||
|
;
|
||||||
|
|
||||||
|
$events = $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get project activity events
|
* Get project activity events
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
'Upload my avatar image' => 'Mein Avatar Bild hochladen',
|
'Upload my avatar image' => 'Mein Avatar Bild hochladen',
|
||||||
'Remove my image' => 'Mein Bild entfernen',
|
'Remove my image' => 'Mein Bild entfernen',
|
||||||
'The OAuth2 state parameter is invalid' => 'Der OAuth2 Statusparameter ist ungültig',
|
'The OAuth2 state parameter is invalid' => 'Der OAuth2 Statusparameter ist ungültig',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
'Upload my avatar image' => 'Uploader mon image d\'avatar',
|
'Upload my avatar image' => 'Uploader mon image d\'avatar',
|
||||||
'Remove my image' => 'Supprimer mon image',
|
'Remove my image' => 'Supprimer mon image',
|
||||||
'The OAuth2 state parameter is invalid' => 'Le paramètre "state" de OAuth2 est invalide',
|
'The OAuth2 state parameter is invalid' => 'Le paramètre "state" de OAuth2 est invalide',
|
||||||
|
'User not found.' => 'Utilisateur introuvable.',
|
||||||
|
'Search in activity stream' => 'Chercher dans le flux d\'activité',
|
||||||
|
'My activities' => 'Mes activités',
|
||||||
|
'Activity until yesterday' => 'Activités jusqu\'à hier',
|
||||||
|
'Activity until today' => 'Activités jusqu\'à aujourd\'hui',
|
||||||
|
'Search by creator: ' => 'Rechercher par créateur : ',
|
||||||
|
'Search by creation date: ' => 'Rechercher par date de création : ',
|
||||||
|
'Search by task status: ' => 'Rechercher par le statut des tâches : ',
|
||||||
|
'Search by task title: ' => 'Rechercher par le titre des tâches : ',
|
||||||
|
'Activity stream search' => 'Recherche dans le flux d\'activité',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
||||||
'Remove my image' => 'Remover a minha imagem',
|
'Remove my image' => 'Remover a minha imagem',
|
||||||
'The OAuth2 state parameter is invalid' => 'O parâmetro "state" de OAuth2 não é válido',
|
'The OAuth2 state parameter is invalid' => 'O parâmetro "state" de OAuth2 não é válido',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
'Upload my avatar image' => 'Enviar a minha imagem de avatar',
|
||||||
'Remove my image' => 'Remover a minha imagem',
|
'Remove my image' => 'Remover a minha imagem',
|
||||||
'The OAuth2 state parameter is invalid' => 'O parametro de estado do OAuth2 é inválido',
|
'The OAuth2 state parameter is invalid' => 'O parametro de estado do OAuth2 é inválido',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1152,5 +1152,15 @@ return array(
|
||||||
'Avatar' => 'Аватар',
|
'Avatar' => 'Аватар',
|
||||||
'Upload my avatar image' => 'Загрузить моё изображение для аватара',
|
'Upload my avatar image' => 'Загрузить моё изображение для аватара',
|
||||||
'Remove my image' => 'Удалить моё изображение',
|
'Remove my image' => 'Удалить моё изображение',
|
||||||
'The OAuth2 state parameter is invalid' => 'Параметр состояние OAuth2 неправильный'
|
'The OAuth2 state parameter is invalid' => 'Параметр состояние OAuth2 неправильный',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1153,4 +1153,14 @@ return array(
|
||||||
// 'Upload my avatar image' => '',
|
// 'Upload my avatar image' => '',
|
||||||
// 'Remove my image' => '',
|
// 'Remove my image' => '',
|
||||||
// 'The OAuth2 state parameter is invalid' => '',
|
// 'The OAuth2 state parameter is invalid' => '',
|
||||||
|
// 'User not found.' => '',
|
||||||
|
// 'Search in activity stream' => '',
|
||||||
|
// 'My activities' => '',
|
||||||
|
// 'Activity until yesterday' => '',
|
||||||
|
// 'Activity until today' => '',
|
||||||
|
// 'Search by creator: ' => '',
|
||||||
|
// 'Search by creation date: ' => '',
|
||||||
|
// 'Search by task status: ' => '',
|
||||||
|
// 'Search by task title: ' => '',
|
||||||
|
// 'Activity stream search' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ class ProjectActivity extends Base
|
||||||
'uc.avatar_path'
|
'uc.avatar_path'
|
||||||
)
|
)
|
||||||
->join(Task::TABLE, 'id', 'task_id')
|
->join(Task::TABLE, 'id', 'task_id')
|
||||||
|
->join(Project::TABLE, 'id', 'project_id')
|
||||||
->left(User::TABLE, 'uc', 'id', ProjectActivity::TABLE, 'creator_id');
|
->left(User::TABLE, 'uc', 'id', ProjectActivity::TABLE, 'creator_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ namespace Kanboard\ServiceProvider;
|
||||||
|
|
||||||
use Kanboard\Core\Filter\LexerBuilder;
|
use Kanboard\Core\Filter\LexerBuilder;
|
||||||
use Kanboard\Core\Filter\QueryBuilder;
|
use Kanboard\Core\Filter\QueryBuilder;
|
||||||
|
use Kanboard\Filter\ProjectActivityCreationDateFilter;
|
||||||
|
use Kanboard\Filter\ProjectActivityCreatorFilter;
|
||||||
|
use Kanboard\Filter\ProjectActivityProjectNameFilter;
|
||||||
|
use Kanboard\Filter\ProjectActivityTaskStatusFilter;
|
||||||
use Kanboard\Filter\ProjectActivityTaskTitleFilter;
|
use Kanboard\Filter\ProjectActivityTaskTitleFilter;
|
||||||
use Kanboard\Filter\TaskAssigneeFilter;
|
use Kanboard\Filter\TaskAssigneeFilter;
|
||||||
use Kanboard\Filter\TaskCategoryFilter;
|
use Kanboard\Filter\TaskCategoryFilter;
|
||||||
|
|
@ -86,8 +90,18 @@ class FilterProvider implements ServiceProviderInterface
|
||||||
|
|
||||||
$container['projectActivityLexer'] = $container->factory(function ($c) {
|
$container['projectActivityLexer'] = $container->factory(function ($c) {
|
||||||
$builder = new LexerBuilder();
|
$builder = new LexerBuilder();
|
||||||
$builder->withQuery($c['projectActivity']->getQuery());
|
$builder
|
||||||
$builder->withFilter(new ProjectActivityTaskTitleFilter());
|
->withQuery($c['projectActivity']->getQuery())
|
||||||
|
->withFilter(new ProjectActivityTaskTitleFilter(), true)
|
||||||
|
->withFilter(new ProjectActivityTaskStatusFilter())
|
||||||
|
->withFilter(new ProjectActivityProjectNameFilter())
|
||||||
|
->withFilter(ProjectActivityCreationDateFilter::getInstance()
|
||||||
|
->setDateParser($c['dateParser'])
|
||||||
|
)
|
||||||
|
->withFilter(ProjectActivityCreatorFilter::getInstance()
|
||||||
|
->setCurrentUserId($c['userSession']->getId())
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
return $builder;
|
return $builder;
|
||||||
});
|
});
|
||||||
|
|
@ -124,17 +138,23 @@ class FilterProvider implements ServiceProviderInterface
|
||||||
)
|
)
|
||||||
->withFilter(new TaskColumnFilter())
|
->withFilter(new TaskColumnFilter())
|
||||||
->withFilter(new TaskCommentFilter())
|
->withFilter(new TaskCommentFilter())
|
||||||
->withFilter(new TaskCreationDateFilter())
|
->withFilter(TaskCreationDateFilter::getInstance()
|
||||||
|
->setDateParser($c['dateParser'])
|
||||||
|
)
|
||||||
->withFilter(TaskCreatorFilter::getInstance()
|
->withFilter(TaskCreatorFilter::getInstance()
|
||||||
->setCurrentUserId($c['userSession']->getId())
|
->setCurrentUserId($c['userSession']->getId())
|
||||||
)
|
)
|
||||||
->withFilter(new TaskDescriptionFilter())
|
->withFilter(new TaskDescriptionFilter())
|
||||||
->withFilter(new TaskDueDateFilter())
|
->withFilter(TaskDueDateFilter::getInstance()
|
||||||
|
->setDateParser($c['dateParser'])
|
||||||
|
)
|
||||||
->withFilter(new TaskIdFilter())
|
->withFilter(new TaskIdFilter())
|
||||||
->withFilter(TaskLinkFilter::getInstance()
|
->withFilter(TaskLinkFilter::getInstance()
|
||||||
->setDatabase($c['db'])
|
->setDatabase($c['db'])
|
||||||
)
|
)
|
||||||
->withFilter(new TaskModificationDateFilter())
|
->withFilter(TaskModificationDateFilter::getInstance()
|
||||||
|
->setDateParser($c['dateParser'])
|
||||||
|
)
|
||||||
->withFilter(new TaskProjectFilter())
|
->withFilter(new TaskProjectFilter())
|
||||||
->withFilter(new TaskReferenceFilter())
|
->withFilter(new TaskReferenceFilter())
|
||||||
->withFilter(new TaskStatusFilter())
|
->withFilter(new TaskStatusFilter())
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class RouteProvider implements ServiceProviderInterface
|
||||||
|
|
||||||
// Search routes
|
// Search routes
|
||||||
$container['route']->addRoute('search', 'search', 'index');
|
$container['route']->addRoute('search', 'search', 'index');
|
||||||
$container['route']->addRoute('search/:search', 'search', 'index');
|
$container['route']->addRoute('search/activity', 'search', 'activity');
|
||||||
|
|
||||||
// ProjectCreation routes
|
// ProjectCreation routes
|
||||||
$container['route']->addRoute('project/create', 'ProjectCreation', 'create');
|
$container['route']->addRoute('project/create', 'ProjectCreation', 'create');
|
||||||
|
|
@ -62,6 +62,7 @@ class RouteProvider implements ServiceProviderInterface
|
||||||
$container['route']->addRoute('project/:project_id/enable', 'project', 'enable');
|
$container['route']->addRoute('project/:project_id/enable', 'project', 'enable');
|
||||||
$container['route']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index');
|
$container['route']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index');
|
||||||
$container['route']->addRoute('project/:project_id/import', 'taskImport', 'step1');
|
$container['route']->addRoute('project/:project_id/import', 'taskImport', 'step1');
|
||||||
|
$container['route']->addRoute('project/:project_id/activity', 'activity', 'project');
|
||||||
|
|
||||||
// Project Overview
|
// Project Overview
|
||||||
$container['route']->addRoute('project/:project_id/overview', 'ProjectOverview', 'show');
|
$container['route']->addRoute('project/:project_id/overview', 'ProjectOverview', 'show');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<div class="dropdown">
|
||||||
|
<a href="#" class="dropdown-menu dropdown-menu-link-icon" title="<?= t('Default filters') ?>"><i class="fa fa-filter fa-fw"></i><i class="fa fa-caret-down"></i></a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#" class="filter-helper filter-reset" data-filter="" title="<?= t('Keyboard shortcut: "%s"', 'r') ?>"><?= t('Reset filters') ?></a></li>
|
||||||
|
<li><a href="#" class="filter-helper" data-filter="creator:me"><?= t('My activities') ?></a></li>
|
||||||
|
<li><a href="#" class="filter-helper" data-filter="created:<=<?= date('Y-m-d', strtotime('yesterday')) ?>"><?= t('Activity until yesterday') ?></a></li>
|
||||||
|
<li><a href="#" class="filter-helper" data-filter="created:<=<?= date('Y-m-d')?>"><?= t('Activity until today') ?></a></li>
|
||||||
|
<li><a href="#" class="filter-helper" data-filter="status:closed"><?= t('Closed tasks') ?></a></li>
|
||||||
|
<li><a href="#" class="filter-helper" data-filter="status:open"><?= t('Open tasks') ?></a></li>
|
||||||
|
<li>
|
||||||
|
<?= $this->url->doc(t('View advanced search syntax'), 'search') ?>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<section id="main">
|
||||||
|
<div class="page-header">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-search fa-fw"></i>
|
||||||
|
<?= $this->url->link(t('Search tasks'), 'search', 'index') ?>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter-box">
|
||||||
|
<form method="get" action="<?= $this->url->dir() ?>" class="search">
|
||||||
|
<?= $this->form->hidden('controller', $values) ?>
|
||||||
|
<?= $this->form->hidden('action', $values) ?>
|
||||||
|
<?= $this->form->text('search', $values, array(), array(empty($values['search']) ? 'autofocus' : '', 'placeholder="'.t('Search').'"'), 'form-input-large') ?>
|
||||||
|
<?= $this->render('activity/filter_dropdown') ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (empty($values['search'])): ?>
|
||||||
|
<div class="listing">
|
||||||
|
<h3><?= t('Advanced search') ?></h3>
|
||||||
|
<p><?= t('Example of query: ') ?><strong>project:"My project" creator:me</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><?= t('Search by project: ') ?><strong>project:"My project"</strong></li>
|
||||||
|
<li><?= t('Search by creator: ') ?><strong>creator:admin</strong></li>
|
||||||
|
<li><?= t('Search by creation date: ') ?><strong>created:today</strong></li>
|
||||||
|
<li><?= t('Search by task status: ') ?><strong>status:open</strong></li>
|
||||||
|
<li><?= t('Search by task title: ') ?><strong>title:"My task"</strong></li>
|
||||||
|
</ul>
|
||||||
|
<p><i class="fa fa-external-link fa-fw"></i><?= $this->url->doc(t('View advanced search syntax'), 'search') ?></p>
|
||||||
|
</div>
|
||||||
|
<?php elseif (! empty($values['search']) && $nb_events === 0): ?>
|
||||||
|
<p class="alert"><?= t('Nothing found.') ?></p>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $this->render('event/events', array('events' => $events)) ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<i class="fa fa-folder fa-fw"></i>
|
<i class="fa fa-search fa-fw"></i>
|
||||||
<?= $this->url->link(t('All projects'), 'project', 'index') ?>
|
<?= $this->url->link(t('Activity stream search'), 'search', 'activity') ?>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
Advanced Search Syntax
|
Advanced Search Syntax
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Kanboard uses a simple query language for advanced search.
|
Kanboard uses a simple query language for advanced search.
|
||||||
|
You can search in tasks, comments, subtasks, links but also in the activity stream.
|
||||||
|
|
||||||
Example of query
|
Example of query
|
||||||
----------------
|
----------------
|
||||||
|
|
@ -12,23 +13,23 @@ This example will return all tasks assigned to me with a due date for tomorrow a
|
||||||
assigne:me due:tomorrow my title
|
assigne:me due:tomorrow my title
|
||||||
```
|
```
|
||||||
|
|
||||||
Search by task id or title
|
Global search
|
||||||
--------------------------
|
-------------
|
||||||
|
|
||||||
|
### Search by task id or title
|
||||||
|
|
||||||
- Search by task id: `#123`
|
- Search by task id: `#123`
|
||||||
- Search by task id and task title: `123`
|
- Search by task id and task title: `123`
|
||||||
- Search by task title: anything that doesn't match any search attributes
|
- Search by task title: anything that doesn't match any search attributes
|
||||||
|
|
||||||
Search by status
|
### Search by status
|
||||||
----------------
|
|
||||||
|
|
||||||
Attribute: **status**
|
Attribute: **status**
|
||||||
|
|
||||||
- Query to find open tasks: `status:open`
|
- Query to find open tasks: `status:open`
|
||||||
- Query to find closed tasks: `status:closed`
|
- Query to find closed tasks: `status:closed`
|
||||||
|
|
||||||
Search by assignee
|
### Search by assignee
|
||||||
------------------
|
|
||||||
|
|
||||||
Attribute: **assignee**
|
Attribute: **assignee**
|
||||||
|
|
||||||
|
|
@ -38,8 +39,7 @@ Attribute: **assignee**
|
||||||
- Query for unassigned tasks: `assignee:nobody`
|
- Query for unassigned tasks: `assignee:nobody`
|
||||||
- Query for my assigned tasks: `assignee:me`
|
- Query for my assigned tasks: `assignee:me`
|
||||||
|
|
||||||
Search by task creator
|
### Search by task creator
|
||||||
----------------------
|
|
||||||
|
|
||||||
Attribute: **creator**
|
Attribute: **creator**
|
||||||
|
|
||||||
|
|
@ -47,23 +47,20 @@ Attribute: **creator**
|
||||||
- Tasks created by John Doe: `creator:"John Doe"`
|
- Tasks created by John Doe: `creator:"John Doe"`
|
||||||
- Tasks created by the user id #1: `creator:1`
|
- Tasks created by the user id #1: `creator:1`
|
||||||
|
|
||||||
Search by subtask assignee
|
### Search by subtask assignee
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Attribute: **subtask:assignee**
|
Attribute: **subtask:assignee**
|
||||||
|
|
||||||
- Example: `subtask:assignee:"John Doe"`
|
- Example: `subtask:assignee:"John Doe"`
|
||||||
|
|
||||||
Search by color
|
### Search by color
|
||||||
---------------
|
|
||||||
|
|
||||||
Attribute: **color**
|
Attribute: **color**
|
||||||
|
|
||||||
- Query to search by color id: `color:blue`
|
- Query to search by color id: `color:blue`
|
||||||
- Query to search by color name: `color:"Deep Orange"`
|
- Query to search by color name: `color:"Deep Orange"`
|
||||||
|
|
||||||
Search by the due date
|
### Search by the due date
|
||||||
----------------------
|
|
||||||
|
|
||||||
Attribute: **due**
|
Attribute: **due**
|
||||||
|
|
||||||
|
|
@ -83,8 +80,7 @@ Operators supported with a date:
|
||||||
- Greater than or equal: **due:>=2015-06-29**
|
- Greater than or equal: **due:>=2015-06-29**
|
||||||
- Lower than or equal: **due:<=2015-06-29**
|
- Lower than or equal: **due:<=2015-06-29**
|
||||||
|
|
||||||
Search by modification date
|
### Search by modification date
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Attribute: **modified** or **updated**
|
Attribute: **modified** or **updated**
|
||||||
|
|
||||||
|
|
@ -94,29 +90,25 @@ There is also a filter by recently modified tasks: `modified:recently`.
|
||||||
|
|
||||||
This query will use the same value as the board highlight period configured in settings.
|
This query will use the same value as the board highlight period configured in settings.
|
||||||
|
|
||||||
Search by creation date
|
### Search by creation date
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Attribute: **created**
|
Attribute: **created**
|
||||||
|
|
||||||
Works in the same way as the modification date queries.
|
Works in the same way as the modification date queries.
|
||||||
|
|
||||||
Search by description
|
### Search by description
|
||||||
---------------------
|
|
||||||
|
|
||||||
Attribute: **description** or **desc**
|
Attribute: **description** or **desc**
|
||||||
|
|
||||||
Example: `description:"text search"`
|
Example: `description:"text search"`
|
||||||
|
|
||||||
Search by external reference
|
### Search by external reference
|
||||||
----------------------------
|
|
||||||
|
|
||||||
The task reference is an external id of your task, by example a ticket number from another software.
|
The task reference is an external id of your task, by example a ticket number from another software.
|
||||||
|
|
||||||
- Find tasks with a reference: `ref:1234` or `reference:TICKET-1234`
|
- Find tasks with a reference: `ref:1234` or `reference:TICKET-1234`
|
||||||
|
|
||||||
Search by category
|
### Search by category
|
||||||
------------------
|
|
||||||
|
|
||||||
Attribute: **category**
|
Attribute: **category**
|
||||||
|
|
||||||
|
|
@ -124,8 +116,7 @@ Attribute: **category**
|
||||||
- Find all tasks that have those categories: `category:"Bug" category:"Improvements"`
|
- Find all tasks that have those categories: `category:"Bug" category:"Improvements"`
|
||||||
- Find tasks with no category assigned: `category:none`
|
- Find tasks with no category assigned: `category:none`
|
||||||
|
|
||||||
Search by project
|
### Search by project
|
||||||
-----------------
|
|
||||||
|
|
||||||
Attribute: **project**
|
Attribute: **project**
|
||||||
|
|
||||||
|
|
@ -133,16 +124,14 @@ Attribute: **project**
|
||||||
- Find tasks by project id: `project:23`
|
- Find tasks by project id: `project:23`
|
||||||
- Find tasks for several projects: `project:"My project A" project:"My project B"`
|
- Find tasks for several projects: `project:"My project A" project:"My project B"`
|
||||||
|
|
||||||
Search by columns
|
### Search by columns
|
||||||
-----------------
|
|
||||||
|
|
||||||
Attribute: **column**
|
Attribute: **column**
|
||||||
|
|
||||||
- Find tasks by column name: `column:"Work in progress"`
|
- Find tasks by column name: `column:"Work in progress"`
|
||||||
- Find tasks for several columns: `column:"Backlog" column:ready`
|
- Find tasks for several columns: `column:"Backlog" column:ready`
|
||||||
|
|
||||||
Search by swim-lane
|
### Search by swim-lane
|
||||||
-------------------
|
|
||||||
|
|
||||||
Attribute: **swimlane**
|
Attribute: **swimlane**
|
||||||
|
|
||||||
|
|
@ -150,17 +139,41 @@ Attribute: **swimlane**
|
||||||
- Find tasks in the default swim-lane: `swimlane:default`
|
- 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 into several swim-lanes: `swimlane:"Version 1.2" swimlane:"Version 1.3"`
|
||||||
|
|
||||||
Search by task link
|
### Search by task link
|
||||||
------------------
|
|
||||||
|
|
||||||
Attribute: **link**
|
Attribute: **link**
|
||||||
|
|
||||||
- Find tasks by link name: `link:"is a milestone of"`
|
- Find tasks by link name: `link:"is a milestone of"`
|
||||||
- Find tasks into several links: `link:"is a milestone of" link:"relates to"`
|
- Find tasks into several links: `link:"is a milestone of" link:"relates to"`
|
||||||
|
|
||||||
Search by comment
|
### Search by comment
|
||||||
-----------------
|
|
||||||
|
|
||||||
Attribute: **comment**
|
Attribute: **comment**
|
||||||
|
|
||||||
- Find comments that contains this title: `comment:"My comment message"`
|
- Find comments that contains this title: `comment:"My comment message"`
|
||||||
|
|
||||||
|
Activity stream search
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
### Search events by task title
|
||||||
|
|
||||||
|
Attribute: **title** or none (default)
|
||||||
|
|
||||||
|
- Example: `title:"My task"`
|
||||||
|
- Search by task id: `#123`
|
||||||
|
|
||||||
|
### Search events by task status
|
||||||
|
|
||||||
|
Attribute: **status**
|
||||||
|
|
||||||
|
### Search by event creator
|
||||||
|
|
||||||
|
Attribute: **creator**
|
||||||
|
|
||||||
|
### Search by event creation date
|
||||||
|
|
||||||
|
Attribute: **created**
|
||||||
|
|
||||||
|
### Search events by project
|
||||||
|
|
||||||
|
Attribute: **project**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Kanboard\Filter\ProjectActivityCreationDateFilter;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\TaskFinder;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
class ProjectActivityCreationDateFilterTest extends Base
|
||||||
|
{
|
||||||
|
public function testWithToday()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('today');
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithYesterday()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('yesterday');
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(0, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithIsoDate()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter(date('Y-m-d'));
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithOperatorAndIsoDate()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('>='.date('Y-m-d'));
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('<'.date('Y-m-d'));
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(0, $events);
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('>'.date('Y-m-d'));
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(0, $events);
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreationDateFilter('>='.date('Y-m-d'));
|
||||||
|
$filter->setDateParser($this->container['dateParser']);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Kanboard\Filter\ProjectActivityCreatorFilter;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\TaskFinder;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
class ProjectActivityCreatorFilterTest extends Base
|
||||||
|
{
|
||||||
|
public function testWithUsername()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreatorFilter('admin');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithAnotherUsername()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreatorFilter('John Doe');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(0, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithCurrentUser()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreatorFilter('me');
|
||||||
|
$filter->setCurrentUserId(1);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithAnotherCurrentUser()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityCreatorFilter('me');
|
||||||
|
$filter->setCurrentUserId(2);
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(0, $events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Kanboard\Filter\ProjectActivityProjectNameFilter;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\TaskFinder;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
class ProjectActivityProjectNameFilterTest extends Base
|
||||||
|
{
|
||||||
|
public function testFilterByProjectName()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
$this->assertEquals(2, $projectModel->create(array('name' => 'P2')));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertEquals(2, $taskCreation->create(array('title' => 'Test', 'project_id' => 2)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(2, 2, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(2))));
|
||||||
|
|
||||||
|
$filter = new ProjectActivityProjectNameFilter('P1');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
$this->assertCount(1, $query->findAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Kanboard\Filter\ProjectActivityTaskStatusFilter;
|
||||||
|
use Kanboard\Model\Project;
|
||||||
|
use Kanboard\Model\ProjectActivity;
|
||||||
|
use Kanboard\Model\TaskCreation;
|
||||||
|
use Kanboard\Model\TaskFinder;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
use Kanboard\Model\TaskStatus;
|
||||||
|
|
||||||
|
require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
|
class ProjectActivityTaskStatusFilterTest extends Base
|
||||||
|
{
|
||||||
|
public function testFilterByTaskStatus()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$taskStatus = new TaskStatus($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
$this->assertEquals(2, $taskCreation->create(array('title' => 'Test', 'project_id' => 1)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 2, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(2))));
|
||||||
|
|
||||||
|
$this->assertTrue($taskStatus->close(1));
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityTaskStatusFilter('open');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
$this->assertEquals(2, $events[0]['task_id']);
|
||||||
|
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
$filter = new ProjectActivityTaskStatusFilter('closed');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
$this->assertEquals(1, $events[0]['task_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ require_once __DIR__.'/../Base.php';
|
||||||
|
|
||||||
class ProjectActivityTaskTitleFilterTest extends Base
|
class ProjectActivityTaskTitleFilterTest extends Base
|
||||||
{
|
{
|
||||||
public function testFilterByTaskId()
|
public function testWithFullTitle()
|
||||||
{
|
{
|
||||||
$taskFinder = new TaskFinder($this->container);
|
$taskFinder = new TaskFinder($this->container);
|
||||||
$taskCreation = new TaskCreation($this->container);
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
|
@ -31,4 +31,49 @@ class ProjectActivityTaskTitleFilterTest extends Base
|
||||||
$filter->withQuery($query)->apply();
|
$filter->withQuery($query)->apply();
|
||||||
$this->assertCount(1, $query->findAll());
|
$this->assertCount(1, $query->findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testWithPartialTitle()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test1', 'project_id' => 1)));
|
||||||
|
$this->assertEquals(2, $taskCreation->create(array('title' => 'Test2', 'project_id' => 1)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 2, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(2))));
|
||||||
|
|
||||||
|
$filter = new ProjectActivityTaskTitleFilter('test');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
$this->assertCount(2, $query->findAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWithId()
|
||||||
|
{
|
||||||
|
$taskFinder = new TaskFinder($this->container);
|
||||||
|
$taskCreation = new TaskCreation($this->container);
|
||||||
|
$projectModel = new Project($this->container);
|
||||||
|
$projectActivityModel = new ProjectActivity($this->container);
|
||||||
|
$query = $projectActivityModel->getQuery();
|
||||||
|
|
||||||
|
$this->assertEquals(1, $projectModel->create(array('name' => 'P1')));
|
||||||
|
|
||||||
|
$this->assertEquals(1, $taskCreation->create(array('title' => 'Test1', 'project_id' => 1)));
|
||||||
|
$this->assertEquals(2, $taskCreation->create(array('title' => 'Test2', 'project_id' => 1)));
|
||||||
|
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 1, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(1))));
|
||||||
|
$this->assertNotFalse($projectActivityModel->createEvent(1, 2, 1, Task::EVENT_CREATE, array('task' => $taskFinder->getById(2))));
|
||||||
|
|
||||||
|
$filter = new ProjectActivityTaskTitleFilter('#2');
|
||||||
|
$filter->withQuery($query)->apply();
|
||||||
|
|
||||||
|
$events = $query->findAll();
|
||||||
|
$this->assertCount(1, $events);
|
||||||
|
$this->assertEquals(2, $events[0]['task_id']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue