Filter refactoring
This commit is contained in:
@@ -76,6 +76,7 @@ class AvatarFile extends Base
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param array $file
|
||||
* @return boolean
|
||||
*/
|
||||
public function uploadFile($user_id, array $file)
|
||||
{
|
||||
|
||||
@@ -31,28 +31,4 @@ abstract class Base extends \Kanboard\Core\Base
|
||||
return (int) $db->getLastId();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build SQL condition for a given time range
|
||||
*
|
||||
* @access protected
|
||||
* @param string $start_time Start timestamp
|
||||
* @param string $end_time End timestamp
|
||||
* @param string $start_column Start column name
|
||||
* @param string $end_column End column name
|
||||
* @return string
|
||||
*/
|
||||
protected function getCalendarCondition($start_time, $end_time, $start_column, $end_column)
|
||||
{
|
||||
$start_column = $this->db->escapeIdentifier($start_column);
|
||||
$end_column = $this->db->escapeIdentifier($end_column);
|
||||
|
||||
$conditions = array(
|
||||
"($start_column >= '$start_time' AND $start_column <= '$end_time')",
|
||||
"($start_column <= '$start_time' AND $end_column >= '$start_time')",
|
||||
"($start_column <= '$start_time' AND ($end_column = '0' OR $end_column IS NULL))",
|
||||
);
|
||||
|
||||
return $start_column.' IS NOT NULL AND '.$start_column.' > 0 AND ('.implode(' OR ', $conditions).')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,20 @@ class Project extends Base
|
||||
*/
|
||||
const INACTIVE = 0;
|
||||
|
||||
/**
|
||||
* Value for private project
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const TYPE_PRIVATE = 1;
|
||||
|
||||
/**
|
||||
* Value for team project
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const TYPE_TEAM = 0;
|
||||
|
||||
/**
|
||||
* Get a project by the id
|
||||
*
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
use PicoDb\Table;
|
||||
|
||||
/**
|
||||
* Project activity model
|
||||
*
|
||||
@@ -133,12 +135,12 @@ class ProjectActivity extends Base
|
||||
* Common function to return events
|
||||
*
|
||||
* @access public
|
||||
* @param \PicoDb\Table $query PicoDb Query
|
||||
* @param Table $query PicoDb Query
|
||||
* @param integer $start Timestamp of earliest activity
|
||||
* @param integer $end Timestamp of latest activity
|
||||
* @return array
|
||||
*/
|
||||
private function getEvents(\PicoDb\Table $query, $start, $end)
|
||||
private function getEvents(Table $query, $start, $end)
|
||||
{
|
||||
if (! is_null($start)) {
|
||||
$query->gte('date_creation', $start);
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* Project Group Role Filter
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectGroupRoleFilter extends Base
|
||||
{
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* @access protected
|
||||
* @var \PicoDb\Table
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* Initialize filter
|
||||
*
|
||||
* @access public
|
||||
* @return UserFilter
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->query = $this->db->table(ProjectGroupRole::TABLE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all results of the filter
|
||||
*
|
||||
* @access public
|
||||
* @param string $column
|
||||
* @return array
|
||||
*/
|
||||
public function findAll($column = '')
|
||||
{
|
||||
if ($column !== '') {
|
||||
return $this->query->asc($column)->findAllByColumn($column);
|
||||
}
|
||||
|
||||
return $this->query->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PicoDb query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by project id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return ProjectUserRoleFilter
|
||||
*/
|
||||
public function filterByProjectId($project_id)
|
||||
{
|
||||
$this->query->eq(ProjectGroupRole::TABLE.'.project_id', $project_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by username
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return ProjectUserRoleFilter
|
||||
*/
|
||||
public function startWithUsername($input)
|
||||
{
|
||||
$this->query
|
||||
->join(GroupMember::TABLE, 'group_id', 'group_id', ProjectGroupRole::TABLE)
|
||||
->join(User::TABLE, 'id', 'user_id', GroupMember::TABLE)
|
||||
->ilike(User::TABLE.'.username', $input.'%');
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,10 @@
|
||||
namespace Kanboard\Model;
|
||||
|
||||
use Kanboard\Core\Security\Role;
|
||||
use Kanboard\Filter\ProjectGroupRoleProjectFilter;
|
||||
use Kanboard\Filter\ProjectGroupRoleUsernameFilter;
|
||||
use Kanboard\Filter\ProjectUserRoleProjectFilter;
|
||||
use Kanboard\Filter\ProjectUserRoleUsernameFilter;
|
||||
|
||||
/**
|
||||
* Project Permission
|
||||
@@ -53,8 +57,18 @@ class ProjectPermission extends Base
|
||||
*/
|
||||
public function findUsernames($project_id, $input)
|
||||
{
|
||||
$userMembers = $this->projectUserRoleFilter->create()->filterByProjectId($project_id)->startWithUsername($input)->findAll('username');
|
||||
$groupMembers = $this->projectGroupRoleFilter->create()->filterByProjectId($project_id)->startWithUsername($input)->findAll('username');
|
||||
$userMembers = $this->projectUserRoleQuery
|
||||
->withFilter(new ProjectUserRoleProjectFilter($project_id))
|
||||
->withFilter(new ProjectUserRoleUsernameFilter($input))
|
||||
->getQuery()
|
||||
->findAllByColumn('username');
|
||||
|
||||
$groupMembers = $this->projectGroupRoleQuery
|
||||
->withFilter(new ProjectGroupRoleProjectFilter($project_id))
|
||||
->withFilter(new ProjectGroupRoleUsernameFilter($input))
|
||||
->getQuery()
|
||||
->findAllByColumn('username');
|
||||
|
||||
$members = array_unique(array_merge($userMembers, $groupMembers));
|
||||
|
||||
sort($members);
|
||||
|
||||
@@ -251,8 +251,8 @@ class ProjectUserRole extends Base
|
||||
/**
|
||||
* Copy user access from a project to another one
|
||||
*
|
||||
* @param integer $project_src_id Project Template
|
||||
* @return integer $project_dst_id Project that receives the copy
|
||||
* @param integer $project_src_id
|
||||
* @param integer $project_dst_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function duplicate($project_src_id, $project_dst_id)
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* Project User Role Filter
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectUserRoleFilter extends Base
|
||||
{
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* @access protected
|
||||
* @var \PicoDb\Table
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* Initialize filter
|
||||
*
|
||||
* @access public
|
||||
* @return UserFilter
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->query = $this->db->table(ProjectUserRole::TABLE);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all results of the filter
|
||||
*
|
||||
* @access public
|
||||
* @param string $column
|
||||
* @return array
|
||||
*/
|
||||
public function findAll($column = '')
|
||||
{
|
||||
if ($column !== '') {
|
||||
return $this->query->asc($column)->findAllByColumn($column);
|
||||
}
|
||||
|
||||
return $this->query->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PicoDb query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by project id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return ProjectUserRoleFilter
|
||||
*/
|
||||
public function filterByProjectId($project_id)
|
||||
{
|
||||
$this->query->eq(ProjectUserRole::TABLE.'.project_id', $project_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by username
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return ProjectUserRoleFilter
|
||||
*/
|
||||
public function startWithUsername($input)
|
||||
{
|
||||
$this->query
|
||||
->join(User::TABLE, 'id', 'user_id')
|
||||
->ilike(User::TABLE.'.username', $input.'%');
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ abstract class Setting extends Base
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
abstract public function prepare(array $values);
|
||||
|
||||
@@ -145,94 +145,6 @@ class SubtaskTimeTracking extends Base
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user calendar events
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @param string $start ISO-8601 format
|
||||
* @param string $end
|
||||
* @return array
|
||||
*/
|
||||
public function getUserCalendarEvents($user_id, $start, $end)
|
||||
{
|
||||
$hook = 'model:subtask-time-tracking:calendar:events';
|
||||
$events = $this->getUserQuery($user_id)
|
||||
->addCondition($this->getCalendarCondition(
|
||||
$this->dateParser->getTimestampFromIsoFormat($start),
|
||||
$this->dateParser->getTimestampFromIsoFormat($end),
|
||||
'start',
|
||||
'end'
|
||||
))
|
||||
->findAll();
|
||||
|
||||
if ($this->hook->exists($hook)) {
|
||||
$events = $this->hook->first($hook, array(
|
||||
'user_id' => $user_id,
|
||||
'events' => $events,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
));
|
||||
}
|
||||
|
||||
return $this->toCalendarEvents($events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project calendar events
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @return array
|
||||
*/
|
||||
public function getProjectCalendarEvents($project_id, $start, $end)
|
||||
{
|
||||
$result = $this
|
||||
->getProjectQuery($project_id)
|
||||
->addCondition($this->getCalendarCondition(
|
||||
$this->dateParser->getTimestampFromIsoFormat($start),
|
||||
$this->dateParser->getTimestampFromIsoFormat($end),
|
||||
'start',
|
||||
'end'
|
||||
))
|
||||
->findAll();
|
||||
|
||||
return $this->toCalendarEvents($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a record set to calendar events
|
||||
*
|
||||
* @access private
|
||||
* @param array $rows
|
||||
* @return array
|
||||
*/
|
||||
private function toCalendarEvents(array $rows)
|
||||
{
|
||||
$events = array();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$user = isset($row['username']) ? ' ('.($row['user_fullname'] ?: $row['username']).')' : '';
|
||||
|
||||
$events[] = array(
|
||||
'id' => $row['id'],
|
||||
'subtask_id' => $row['subtask_id'],
|
||||
'title' => t('#%d', $row['task_id']).' '.$row['subtask_title'].$user,
|
||||
'start' => date('Y-m-d\TH:i:s', $row['start']),
|
||||
'end' => date('Y-m-d\TH:i:s', $row['end'] ?: time()),
|
||||
'backgroundColor' => $this->color->getBackgroundColor($row['color_id']),
|
||||
'borderColor' => $this->color->getBorderColor($row['color_id']),
|
||||
'textColor' => 'black',
|
||||
'url' => $this->helper->url->to('task', 'show', array('task_id' => $row['task_id'], 'project_id' => $row['project_id'])),
|
||||
'editable' => false,
|
||||
);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a timer is started for this use and subtask
|
||||
*
|
||||
|
||||
@@ -1,745 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* Task Filter
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskFilter extends Base
|
||||
{
|
||||
/**
|
||||
* Filters mapping
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $filters = array(
|
||||
'T_ASSIGNEE' => 'filterByAssignee',
|
||||
'T_COLOR' => 'filterByColors',
|
||||
'T_DUE' => 'filterByDueDate',
|
||||
'T_UPDATED' => 'filterByModificationDate',
|
||||
'T_CREATED' => 'filterByCreationDate',
|
||||
'T_TITLE' => 'filterByTitle',
|
||||
'T_STATUS' => 'filterByStatusName',
|
||||
'T_DESCRIPTION' => 'filterByDescription',
|
||||
'T_CATEGORY' => 'filterByCategoryName',
|
||||
'T_PROJECT' => 'filterByProjectName',
|
||||
'T_COLUMN' => 'filterByColumnName',
|
||||
'T_REFERENCE' => 'filterByReference',
|
||||
'T_SWIMLANE' => 'filterBySwimlaneName',
|
||||
'T_LINK' => 'filterByLinkName',
|
||||
);
|
||||
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* @access public
|
||||
* @var \PicoDb\Table
|
||||
*/
|
||||
public $query;
|
||||
|
||||
/**
|
||||
* Apply filters according to the search input
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function search($input)
|
||||
{
|
||||
$tree = $this->lexer->map($this->lexer->tokenize($input));
|
||||
$this->query = $this->taskFinder->getExtendedQuery();
|
||||
|
||||
if (empty($tree)) {
|
||||
$this->filterByTitle($input);
|
||||
}
|
||||
|
||||
foreach ($tree as $filter => $value) {
|
||||
$method = $this->filters[$filter];
|
||||
$this->$method($value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new query
|
||||
*
|
||||
* @access public
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->query = $this->db->table(Task::TABLE);
|
||||
$this->query->left(User::TABLE, 'ua', 'id', Task::TABLE, 'owner_id');
|
||||
$this->query->left(User::TABLE, 'uc', 'id', Task::TABLE, 'creator_id');
|
||||
|
||||
$this->query->columns(
|
||||
Task::TABLE.'.*',
|
||||
'ua.email AS assignee_email',
|
||||
'ua.name AS assignee_name',
|
||||
'ua.username AS assignee_username',
|
||||
'uc.email AS creator_email',
|
||||
'uc.username AS creator_username'
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new subtask query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function createSubtaskQuery()
|
||||
{
|
||||
return $this->db->table(Subtask::TABLE)
|
||||
->columns(
|
||||
Subtask::TABLE.'.user_id',
|
||||
Subtask::TABLE.'.task_id',
|
||||
User::TABLE.'.name',
|
||||
User::TABLE.'.username'
|
||||
)
|
||||
->join(User::TABLE, 'id', 'user_id', Subtask::TABLE)
|
||||
->neq(Subtask::TABLE.'.status', Subtask::STATUS_DONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new link query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function createLinkQuery()
|
||||
{
|
||||
return $this->db->table(TaskLink::TABLE)
|
||||
->columns(
|
||||
TaskLink::TABLE.'.task_id',
|
||||
Link::TABLE.'.label'
|
||||
)
|
||||
->join(Link::TABLE, 'id', 'link_id', TaskLink::TABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the filter
|
||||
*
|
||||
* @access public
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
$filter = new static($this->container);
|
||||
$filter->query = clone($this->query);
|
||||
$filter->query->condition = clone($this->query->condition);
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude a list of task_id
|
||||
*
|
||||
* @access public
|
||||
* @param integer[] $task_ids
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function excludeTasks(array $task_ids)
|
||||
{
|
||||
$this->query->notin(Task::TABLE.'.id', $task_ids);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $task_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterById($task_id)
|
||||
{
|
||||
if ($task_id > 0) {
|
||||
$this->query->eq(Task::TABLE.'.id', $task_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by reference
|
||||
*
|
||||
* @access public
|
||||
* @param string $reference
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByReference($reference)
|
||||
{
|
||||
if (! empty($reference)) {
|
||||
$this->query->eq(Task::TABLE.'.reference', $reference);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by title
|
||||
*
|
||||
* @access public
|
||||
* @param string $title
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByDescription($title)
|
||||
{
|
||||
$this->query->ilike(Task::TABLE.'.description', '%'.$title.'%');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by title or id if the string is like #123 or an integer
|
||||
*
|
||||
* @access public
|
||||
* @param string $title
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByTitle($title)
|
||||
{
|
||||
if (ctype_digit($title) || (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1)))) {
|
||||
$this->query->beginOr();
|
||||
$this->query->eq(Task::TABLE.'.id', str_replace('#', '', $title));
|
||||
$this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
|
||||
$this->query->closeOr();
|
||||
} else {
|
||||
$this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by a list of project id
|
||||
*
|
||||
* @access public
|
||||
* @param array $project_ids
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByProjects(array $project_ids)
|
||||
{
|
||||
$this->query->in(Task::TABLE.'.project_id', $project_ids);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by project id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByProject($project_id)
|
||||
{
|
||||
if ($project_id > 0) {
|
||||
$this->query->eq(Task::TABLE.'.project_id', $project_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by project name
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of project name
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByProjectName(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($values as $project) {
|
||||
if (ctype_digit($project)) {
|
||||
$this->query->eq(Task::TABLE.'.project_id', $project);
|
||||
} else {
|
||||
$this->query->ilike(Project::TABLE.'.name', $project);
|
||||
}
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by swimlane name
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of swimlane name
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterBySwimlaneName(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($values as $swimlane) {
|
||||
if ($swimlane === 'default') {
|
||||
$this->query->eq(Task::TABLE.'.swimlane_id', 0);
|
||||
} else {
|
||||
$this->query->ilike(Swimlane::TABLE.'.name', $swimlane);
|
||||
$this->query->addCondition(Task::TABLE.'.swimlane_id=0 AND '.Project::TABLE.'.default_swimlane '.$this->db->getDriver()->getOperator('ILIKE')." '$swimlane'");
|
||||
}
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by category id
|
||||
*
|
||||
* @access public
|
||||
* @param integer $category_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByCategory($category_id)
|
||||
{
|
||||
if ($category_id >= 0) {
|
||||
$this->query->eq(Task::TABLE.'.category_id', $category_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by category
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of assignees
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByCategoryName(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($values as $category) {
|
||||
if ($category === 'none') {
|
||||
$this->query->eq(Task::TABLE.'.category_id', 0);
|
||||
} else {
|
||||
$this->query->eq(Category::TABLE.'.name', $category);
|
||||
}
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by assignee
|
||||
*
|
||||
* @access public
|
||||
* @param integer $owner_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByOwner($owner_id)
|
||||
{
|
||||
if ($owner_id >= 0) {
|
||||
$this->query->eq(Task::TABLE.'.owner_id', $owner_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by assignee names
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of assignees
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByAssignee(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($values as $assignee) {
|
||||
switch ($assignee) {
|
||||
case 'me':
|
||||
$this->query->eq(Task::TABLE.'.owner_id', $this->userSession->getId());
|
||||
break;
|
||||
case 'nobody':
|
||||
$this->query->eq(Task::TABLE.'.owner_id', 0);
|
||||
break;
|
||||
default:
|
||||
$this->query->ilike(User::TABLE.'.username', '%'.$assignee.'%');
|
||||
$this->query->ilike(User::TABLE.'.name', '%'.$assignee.'%');
|
||||
}
|
||||
}
|
||||
|
||||
$this->filterBySubtaskAssignee($values);
|
||||
|
||||
$this->query->closeOr();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by subtask assignee names
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of assignees
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterBySubtaskAssignee(array $values)
|
||||
{
|
||||
$subtaskQuery = $this->createSubtaskQuery();
|
||||
$subtaskQuery->beginOr();
|
||||
|
||||
foreach ($values as $assignee) {
|
||||
if ($assignee === 'me') {
|
||||
$subtaskQuery->eq(Subtask::TABLE.'.user_id', $this->userSession->getId());
|
||||
} else {
|
||||
$subtaskQuery->ilike(User::TABLE.'.username', '%'.$assignee.'%');
|
||||
$subtaskQuery->ilike(User::TABLE.'.name', '%'.$assignee.'%');
|
||||
}
|
||||
}
|
||||
|
||||
$subtaskQuery->closeOr();
|
||||
|
||||
$this->query->in(Task::TABLE.'.id', $subtaskQuery->findAllByColumn('task_id'));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by color
|
||||
*
|
||||
* @access public
|
||||
* @param string $color_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByColor($color_id)
|
||||
{
|
||||
if ($color_id !== '') {
|
||||
$this->query->eq(Task::TABLE.'.color_id', $color_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by colors
|
||||
*
|
||||
* @access public
|
||||
* @param array $colors
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByColors(array $colors)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($colors as $color) {
|
||||
$this->filterByColor($this->color->find($color));
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by column
|
||||
*
|
||||
* @access public
|
||||
* @param integer $column_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByColumn($column_id)
|
||||
{
|
||||
if ($column_id >= 0) {
|
||||
$this->query->eq(Task::TABLE.'.column_id', $column_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by column name
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of column name
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByColumnName(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
foreach ($values as $project) {
|
||||
$this->query->ilike(Column::TABLE.'.title', $project);
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by swimlane
|
||||
*
|
||||
* @access public
|
||||
* @param integer $swimlane_id
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterBySwimlane($swimlane_id)
|
||||
{
|
||||
if ($swimlane_id >= 0) {
|
||||
$this->query->eq(Task::TABLE.'.swimlane_id', $swimlane_id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by status name
|
||||
*
|
||||
* @access public
|
||||
* @param string $status
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByStatusName($status)
|
||||
{
|
||||
if ($status === 'open' || $status === 'closed') {
|
||||
$this->filterByStatus($status === 'open' ? Task::STATUS_OPEN : Task::STATUS_CLOSED);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by status
|
||||
*
|
||||
* @access public
|
||||
* @param integer $is_active
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByStatus($is_active)
|
||||
{
|
||||
if ($is_active >= 0) {
|
||||
$this->query->eq(Task::TABLE.'.is_active', $is_active);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by link
|
||||
*
|
||||
* @access public
|
||||
* @param array $values List of links
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByLinkName(array $values)
|
||||
{
|
||||
$this->query->beginOr();
|
||||
|
||||
$link_query = $this->createLinkQuery()->in(Link::TABLE.'.label', $values);
|
||||
$matching_task_ids = $link_query->findAllByColumn('task_id');
|
||||
if (empty($matching_task_ids)) {
|
||||
$this->query->eq(Task::TABLE.'.id', 0);
|
||||
} else {
|
||||
$this->query->in(Task::TABLE.'.id', $matching_task_ids);
|
||||
}
|
||||
|
||||
$this->query->closeOr();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by due date
|
||||
*
|
||||
* @access public
|
||||
* @param string $date ISO8601 date format
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByDueDate($date)
|
||||
{
|
||||
$this->query->neq(Task::TABLE.'.date_due', 0);
|
||||
$this->query->notNull(Task::TABLE.'.date_due');
|
||||
return $this->filterWithOperator(Task::TABLE.'.date_due', $date, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by due date (range)
|
||||
*
|
||||
* @access public
|
||||
* @param string $start
|
||||
* @param string $end
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByDueDateRange($start, $end)
|
||||
{
|
||||
$this->query->gte('date_due', $this->dateParser->getTimestampFromIsoFormat($start));
|
||||
$this->query->lte('date_due', $this->dateParser->getTimestampFromIsoFormat($end));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter by start date (range)
|
||||
*
|
||||
* @access public
|
||||
* @param string $start
|
||||
* @param string $end
|
||||
* @return TaskFilter
|
||||
*/
|
||||
public function filterByStartDateRange($start, $end)
|
||||
{
|
||||
$this->query->addCondition($this->getCalendarCondition(
|
||||
$this->dateParser->getTimestampFromIsoFormat($start),
|
||||
$this->dateParser->getTimestampFromIsoFormat($end),
|
||||
'date_started',
|
||||
'date_completed'
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function filterByCreationDateRange($start, $end)
|
||||
{
|
||||
$this->query->addCondition($this->getCalendarCondition(
|
||||
$this->dateParser->getTimestampFromIsoFormat($start),
|
||||
$this->dateParser->getTimestampFromIsoFormat($end),
|
||||
'date_creation',
|
||||
'date_completed'
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return array
|
||||
*/
|
||||
public function findAll()
|
||||
{
|
||||
return $this->query->asc(Task::TABLE.'.id')->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PicoDb query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get swimlanes and tasks to display the board
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getBoard($project_id)
|
||||
{
|
||||
$tasks = $this->filterByProject($project_id)->query->asc(Task::TABLE.'.position')->findAll();
|
||||
|
||||
return $this->board->getBoard($project_id, function ($project_id, $column_id, $swimlane_id) use ($tasks) {
|
||||
return array_filter($tasks, function (array $task) use ($column_id, $swimlane_id) {
|
||||
return $task['column_id'] == $column_id && $task['swimlane_id'] == $swimlane_id;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter with an operator
|
||||
*
|
||||
* @access public
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @param boolean $is_date
|
||||
* @return TaskFilter
|
||||
*/
|
||||
private function filterWithOperator($field, $value, $is_date)
|
||||
{
|
||||
$operators = array(
|
||||
'<=' => 'lte',
|
||||
'>=' => 'gte',
|
||||
'<' => 'lt',
|
||||
'>' => 'gt',
|
||||
);
|
||||
|
||||
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);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -362,6 +362,27 @@ class TaskFinder extends Base
|
||||
return $rq->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get iCal query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getICalQuery()
|
||||
{
|
||||
return $this->db->table(Task::TABLE)
|
||||
->left(User::TABLE, 'ua', 'id', Task::TABLE, 'owner_id')
|
||||
->left(User::TABLE, 'uc', 'id', Task::TABLE, 'creator_id')
|
||||
->columns(
|
||||
Task::TABLE.'.*',
|
||||
'ua.email AS assignee_email',
|
||||
'ua.name AS assignee_name',
|
||||
'ua.username AS assignee_username',
|
||||
'uc.email AS creator_email',
|
||||
'uc.username AS creator_username'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count all tasks for a given project and status
|
||||
*
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* User Filter
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class UserFilter extends Base
|
||||
{
|
||||
/**
|
||||
* Search query
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $input;
|
||||
|
||||
/**
|
||||
* Query
|
||||
*
|
||||
* @access protected
|
||||
* @var \PicoDb\Table
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* Initialize filter
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return UserFilter
|
||||
*/
|
||||
public function create($input)
|
||||
{
|
||||
$this->query = $this->db->table(User::TABLE);
|
||||
$this->input = $input;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter users by name or username
|
||||
*
|
||||
* @access public
|
||||
* @return UserFilter
|
||||
*/
|
||||
public function filterByUsernameOrByName()
|
||||
{
|
||||
$this->query->beginOr()
|
||||
->ilike('username', '%'.$this->input.'%')
|
||||
->ilike('name', '%'.$this->input.'%')
|
||||
->closeOr();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all results of the filter
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function findAll()
|
||||
{
|
||||
return $this->query->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PicoDb query
|
||||
*
|
||||
* @access public
|
||||
* @return \PicoDb\Table
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user