看板初始化提交

This commit is contained in:
zephyr
2026-06-01 21:23:12 -07:00
commit 27411ebedc
1827 changed files with 192340 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace Kanboard\Filter;
/**
* Base comparison filter class
*
* @package filter
*/
abstract class BaseComparisonFilter extends BaseFilter
{
/**
* 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 'eq';
}
/**
* Apply a comparison filter
*
* @access protected
* @param string $field
*/
protected function applyComparisonFilter($field)
{
$method = $this->parseOperator();
$this->query->$method($field, $this->value);
}
}
+103
View File
@@ -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;
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\DateParser;
/**
* Base date filter class
*
* @package filter
* @author Kamil Ściana
*/
abstract class BaseDateRangeFilter 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;
}
/**
* Apply a date filter
*
* @access protected
* @param string $field
*/
protected function applyDateFilter($field)
{
$dates = explode('..', $this->value);
if (count($dates)=== 2) {
$timestampFrom = $this->dateParser->getTimestamp($dates[0]." 00:00");
$timestampTo = $this->dateParser->getTimestamp($dates[1]." 00:00");
$this->query->gte($field, $timestampFrom);
$this->query->lte($field, $timestampTo + 86399);
}
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
namespace Kanboard\Filter;
use PicoDb\Table;
/**
* Base filter class
*
* @package filter
* @author Frederic Guillot
*/
abstract class BaseFilter
{
/**
* @var Table
*/
protected $query;
/**
* @var mixed
*/
protected $value;
/**
* BaseFilter constructor
*
* @access public
* @param mixed $value
*/
public function __construct($value = null)
{
$this->value = $value;
}
/**
* Get object instance
*
* @static
* @access public
* @param mixed $value
* @return static
*/
public static function getInstance($value = null)
{
return new static($value);
}
/**
* Set query
*
* @access public
* @param Table $query
* @return $this
*/
public function withQuery(Table $query)
{
$this->query = $query;
return $this;
}
/**
* Set the value
*
* @access public
* @param string $value
* @return $this
*/
public function withValue($value)
{
$this->value = $value;
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectActivityModel;
/**
* 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(ProjectActivityModel::TABLE.'.date_creation');
return $this;
}
}
@@ -0,0 +1,66 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectActivityModel;
/**
* 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 FilterInterface
*/
public function apply()
{
if ($this->value === 'me') {
$this->query->eq(ProjectActivityModel::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();
}
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by projectId
*
* @package filter
* @author Frederic Guillot
*/
class ProjectActivityProjectIdFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('project_id');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(ProjectActivityModel::TABLE.'.project_id', $this->value);
return $this;
}
}
@@ -0,0 +1,43 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by projectIds
*
* @package filter
* @author Frederic Guillot
*/
class ProjectActivityProjectIdsFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('projects');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (empty($this->value)) {
$this->query->eq(ProjectActivityModel::TABLE.'.project_id', 0);
} else {
$this->query->in(ProjectActivityModel::TABLE.'.project_id', $this->value);
}
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
/**
* 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(ProjectModel::TABLE.'.name', '%'.$this->value.'%');
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectActivityModel;
/**
* Filter activity events by taskId
*
* @package filter
* @author Frederic Guillot
*/
class ProjectActivityTaskIdFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('task_id');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(ProjectActivityModel::TABLE.'.task_id', $this->value);
return $this;
}
}
@@ -0,0 +1,43 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* 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(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN);
} elseif ($this->value === 'closed') {
$this->query->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_CLOSED);
}
return $this;
}
}
@@ -0,0 +1,25 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
/**
* Filter activity events by task title
*
* @package filter
* @author Frederic Guillot
*/
class ProjectActivityTaskTitleFilter extends TaskTitleFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('title');
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectGroupRoleModel;
/**
* Filter ProjectGroupRole users by project
*
* @package filter
* @author Frederic Guillot
*/
class ProjectGroupRoleProjectFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array();
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(ProjectGroupRoleModel::TABLE.'.project_id', $this->value);
return $this;
}
}
@@ -0,0 +1,44 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\GroupMemberModel;
use Kanboard\Model\ProjectGroupRoleModel;
use Kanboard\Model\UserModel;
/**
* Filter ProjectGroupRole users by username
*
* @package filter
* @author Frederic Guillot
*/
class ProjectGroupRoleUsernameFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array();
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query
->join(GroupMemberModel::TABLE, 'group_id', 'group_id', ProjectGroupRoleModel::TABLE)
->join(UserModel::TABLE, 'id', 'user_id', GroupMemberModel::TABLE)
->ilike(UserModel::TABLE.'.username', $this->value.'%');
return $this;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
/**
* Filter project by ids
*
* @package filter
* @author Frederic Guillot
*/
class ProjectIdsFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('project_ids');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (empty($this->value)) {
$this->query->eq(ProjectModel::TABLE.'.id', 0);
} else {
$this->query->in(ProjectModel::TABLE.'.id', $this->value);
}
return $this;
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
/**
* Filter project by status
*
* @package filter
* @author Frederic Guillot
*/
class ProjectStatusFilter 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 (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(ProjectModel::TABLE.'.is_active', $this->value);
} elseif ($this->value === 'inactive' || $this->value === 'closed' || $this->value === 'disabled') {
$this->query->eq(ProjectModel::TABLE.'.is_active', 0);
} else {
$this->query->eq(ProjectModel::TABLE.'.is_active', 1);
}
return $this;
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
/**
* Filter project by type
*
* @package filter
* @author Frederic Guillot
*/
class ProjectTypeFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('type');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(ProjectModel::TABLE.'.is_private', $this->value);
} elseif ($this->value === 'private') {
$this->query->eq(ProjectModel::TABLE.'.is_private', ProjectModel::TYPE_PRIVATE);
} else {
$this->query->eq(ProjectModel::TABLE.'.is_private', ProjectModel::TYPE_TEAM);
}
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectUserRoleModel;
/**
* Filter ProjectUserRole users by project
*
* @package filter
* @author Frederic Guillot
*/
class ProjectUserRoleProjectFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array();
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(ProjectUserRoleModel::TABLE.'.project_id', $this->value);
return $this;
}
}
@@ -0,0 +1,41 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\UserModel;
/**
* Filter ProjectUserRole users by username
*
* @package filter
* @author Frederic Guillot
*/
class ProjectUserRoleUsernameFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array();
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query
->join(UserModel::TABLE, 'id', 'user_id')
->ilike(UserModel::TABLE.'.username', $this->value.'%');
return $this;
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
use Kanboard\Model\UserModel;
/**
* Filter tasks by assignee
*
* @package filter
* @author Frederic Guillot
*/
class TaskAssigneeFilter 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('assignee');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(TaskModel::TABLE.'.owner_id', $this->value);
} else {
switch ($this->value) {
case 'me':
$this->query->eq(TaskModel::TABLE.'.owner_id', $this->currentUserId);
break;
case 'nobody':
$this->query->eq(TaskModel::TABLE.'.owner_id', 0);
break;
case 'anybody':
$this->query->gt(TaskModel::TABLE.'.owner_id', 0);
break;
default:
$this->query->beginOr();
$this->query->ilike(UserModel::TABLE.'.username', '%'.$this->value.'%');
$this->query->ilike(UserModel::TABLE.'.name', '%'.$this->value.'%');
$this->query->closeOr();
}
}
return $this;
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\CategoryModel;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by category
*
* @package filter
* @author Frederic Guillot
*/
class TaskCategoryFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('category');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->beginOr();
$this->query->eq(TaskModel::TABLE.'.category_id', $this->value);
$this->query->eq(CategoryModel::TABLE.'.name', $this->value);
$this->query->closeOr();
} elseif ($this->value === 'none') {
$this->query->eq(TaskModel::TABLE.'.category_id', 0);
} else {
$this->query->eq(CategoryModel::TABLE.'.name', $this->value);
}
return $this;
}
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ColorModel;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by color
*
* @package filter
* @author Frederic Guillot
*/
class TaskColorFilter extends BaseFilter implements FilterInterface
{
/**
* Color object
*
* @access private
* @var ColorModel
*/
private $colorModel;
/**
* Set color model object
*
* @access public
* @param ColorModel $colorModel
* @return TaskColorFilter
*/
public function setColorModel(ColorModel $colorModel)
{
$this->colorModel = $colorModel;
return $this;
}
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('color', 'colour');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(TaskModel::TABLE.'.color_id', $this->colorModel->find($this->value));
return $this;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ColumnModel;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by column
*
* @package filter
* @author Frederic Guillot
*/
class TaskColumnFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('column');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(TaskModel::TABLE.'.column_id', $this->value);
} else {
$this->query->eq(ColumnModel::TABLE.'.title', $this->value);
}
return $this;
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\CommentModel;
use Kanboard\Model\TaskModel;
use PicoDb\Database;
/**
* Filter tasks by comment
*
* @package filter
* @author Frederic Guillot
*/
class TaskCommentFilter extends BaseFilter implements FilterInterface
{
/**
* Database object
*
* @access private
* @var Database
*/
private $db;
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('comment');
}
/**
* Set database object
*
* @access public
* @param Database $db
* @return $this
*/
public function setDatabase(Database $db)
{
$this->db = $db;
return $this;
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->inSubquery(TaskModel::TABLE.'.id', $this->getSubQuery());
return $this;
}
/**
* Get task ids having this comment
*
* @access public
* @return array
*/
protected function getSubQuery()
{
return $this->db
->table(CommentModel::TABLE)
->columns(CommentModel::TABLE.'.task_id')
->ilike(CommentModel::TABLE.'.comment', '%'.$this->value.'%');
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by completion date
*
* @package filter
* @author Frederic Guillot
*/
class TaskCompletionDateFilter extends BaseDateFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('completed');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_completed');
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by completion date
*
* @package filter
* @author Kamil Ściana
*/
class TaskCompletionDateRangeFilter extends BaseDateRangeFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('completedRange');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_completed');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by creation date
*
* @package filter
* @author Frederic Guillot
*/
class TaskCreationDateFilter 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(TaskModel::TABLE.'.date_creation');
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by creation date
*
* @package filter
* @author Kamil Ściana
*/
class TaskCreationDateRangeFilter extends BaseDateRangeFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('createdRange');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_creation');
return $this;
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by creator
*
* @package filter
* @author Frederic Guillot
*/
class TaskCreatorFilter 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 FilterInterface
*/
public function apply()
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(TaskModel::TABLE.'.creator_id', $this->value);
} else {
switch ($this->value) {
case 'me':
$this->query->eq(TaskModel::TABLE.'.creator_id', $this->currentUserId);
break;
case 'nobody':
$this->query->eq(TaskModel::TABLE.'.creator_id', 0);
break;
case 'anybody':
$this->query->gt(TaskModel::TABLE.'.creator_id', 0);
break;
default:
$this->query->beginOr();
$this->query->ilike('uc.username', '%'.$this->value.'%');
$this->query->ilike('uc.name', '%'.$this->value.'%');
$this->query->closeOr();
}
}
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by description
*
* @package filter
* @author Frederic Guillot
*/
class TaskDescriptionFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('description', 'desc');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->ilike(TaskModel::TABLE.'.description', '%'.$this->value.'%');
return $this;
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by due date
*
* @package filter
* @author Frederic Guillot
*/
class TaskDueDateFilter extends BaseDateFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('due');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if ($this->value == "none") {
$this->query->eq(TaskModel::TABLE.'.date_due', 0);
} else {
$this->query->neq(TaskModel::TABLE.'.date_due', 0);
$this->query->notNull(TaskModel::TABLE.'.date_due');
$this->applyDateFilter(TaskModel::TABLE.'.date_due');
}
return $this;
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by due date range
*
* @package filter
* @author Frederic Guillot
*/
class TaskDueDateRangeFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array();
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->beginOr();
$this->query->isNull(TaskModel::TABLE.'.date_started');
$this->query->eq(TaskModel::TABLE.'.date_started', 0);
$this->query->closeOr();
$this->query->gte(TaskModel::TABLE.'.date_due', is_numeric($this->value[0]) ? $this->value[0] : strtotime($this->value[0]));
$this->query->lte(TaskModel::TABLE.'.date_due', is_numeric($this->value[1]) ? $this->value[1] : strtotime($this->value[1]));
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Exclude task ids
*
* @package filter
* @author Frederic Guillot
*/
class TaskIdExclusionFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('exclude');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->notin(TaskModel::TABLE.'.id', $this->value);
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by id
*
* @package filter
* @author Frederic Guillot
*/
class TaskIdFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('id');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->eq(TaskModel::TABLE.'.id', $this->value);
return $this;
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\LinkModel;
use Kanboard\Model\TaskModel;
use Kanboard\Model\TaskLinkModel;
use PicoDb\Database;
use PicoDb\Table;
/**
* Filter tasks by link name
*
* @package filter
* @author Frederic Guillot
*/
class TaskLinkFilter extends BaseFilter implements FilterInterface
{
/**
* Database object
*
* @access private
* @var Database
*/
private $db;
/**
* Set database object
*
* @access public
* @param Database $db
* @return TaskLinkFilter
*/
public function setDatabase(Database $db)
{
$this->db = $db;
return $this;
}
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('link');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->inSubquery(TaskModel::TABLE.'.id', $this->getSubQuery());
return $this;
}
/**
* Get subquery
*
* @access protected
* @return Table
*/
protected function getSubQuery()
{
return $this->db->table(TaskLinkModel::TABLE)
->columns(
TaskLinkModel::TABLE.'.task_id'
)
->join(LinkModel::TABLE, 'id', 'link_id', TaskLinkModel::TABLE)
->ilike(LinkModel::TABLE.'.label', $this->value);
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by modification date
*
* @package filter
* @author Frederic Guillot
*/
class TaskModificationDateFilter extends BaseDateFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('updated', 'modified');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_modification');
return $this;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by modification date
*
* @package filter
* @author Kamil Ściana
*/
class TaskModificationDateRangeFilter extends BaseDateRangeFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('updatedRange', 'modifiedRange');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_modification');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by modification date
*
* @package filter
* @author Frederic Guillot
*/
class TaskMovedDateFilter extends BaseDateFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('moved');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_moved');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by creation date
*
* @package filter
* @author Kamil Ściana
*/
class TaskMovedDateRangeFilter extends BaseDateRangeFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('movedRange');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_moved');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Class TaskPriorityFilter
*
* @package Kanboard\Filter
* @author Frederic Guillot
*/
class TaskPriorityFilter extends BaseComparisonFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('priority');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyComparisonFilter(TaskModel::TABLE.'.priority');
return $this;
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by project
*
* @package filter
* @author Frederic Guillot
*/
class TaskProjectFilter 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()
{
// Max integer value for Postgres is +2147483647
// See https://www.postgresql.org/docs/current/datatype-numeric.html
if (is_int($this->value) || ctype_digit((string) $this->value) && $this->value < 2147483647) {
$this->query->eq(TaskModel::TABLE.'.project_id', $this->value);
} else {
$this->query->ilike(ProjectModel::TABLE.'.name', $this->value);
}
return $this;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by project ids
*
* @package filter
* @author Frederic Guillot
*/
class TaskProjectsFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('projects');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (empty($this->value)) {
$this->query->eq(TaskModel::TABLE.'.project_id', 0);
} else {
$this->query->in(TaskModel::TABLE.'.project_id', $this->value);
}
return $this;
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by reference
*
* @package filter
* @author Frederic Guillot
*/
class TaskReferenceFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('reference', 'ref');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if ($this->value === 'none') {
$this->query->beginOr();
$this->query->eq(TaskModel::TABLE.'.reference', '');
$this->query->isNull(TaskModel::TABLE.'.reference');
$this->query->closeOr();
return $this;
}
if (strpos($this->value, '*') >= 0) {
$this->query->ilike(TaskModel::TABLE.'.reference', str_replace('*', '%', $this->value));
return $this;
}
$this->query->eq(TaskModel::TABLE.'.reference', $this->value);
return $this;
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Class TaskScoreFilter
*
* @package Kanboard\Filter
*/
class TaskScoreFilter extends BaseComparisonFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('score', 'complexity');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyComparisonFilter(TaskModel::TABLE.'.score');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by start date
*
* @package filter
* @author Frederic Guillot
*/
class TaskStartDateFilter extends BaseDateFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('started');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->applyDateFilter(TaskModel::TABLE.'.date_started');
return $this;
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Class TaskIdSearchFilter
*
* @package Kanboard\Filter
* @author Frederic Guillot
*/
class TaskStartsWithIdFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('starts_with_id');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->ilike('CAST('.TaskModel::TABLE.'.id AS CHAR(8))', $this->value.'%');
return $this;
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by status
*
* @package filter
* @author Frederic Guillot
*/
class TaskStatusFilter 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->value === 'closed') {
$this->query->eq(TaskModel::TABLE.'.is_active', $this->value === 'open' ? TaskModel::STATUS_OPEN : TaskModel::STATUS_CLOSED);
} elseif (is_int($this->value) || ctype_digit((string) $this->value)) {
$this->query->eq(TaskModel::TABLE.'.is_active', $this->value);
}
return $this;
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\SubtaskModel;
use Kanboard\Model\TaskModel;
use Kanboard\Model\UserModel;
use PicoDb\Database;
use PicoDb\Table;
/**
* Filter tasks by subtasks assignee
*
* @package filter
* @author Frederic Guillot
*/
class TaskSubtaskAssigneeFilter extends BaseFilter implements FilterInterface
{
/**
* Database object
*
* @access private
* @var Database
*/
private $db;
/**
* Current user id
*
* @access private
* @var int
*/
private $currentUserId = 0;
/**
* Set current user id
*
* @access public
* @param integer $userId
* @return TaskSubtaskAssigneeFilter
*/
public function setCurrentUserId($userId)
{
$this->currentUserId = $userId;
return $this;
}
/**
* Set database object
*
* @access public
* @param Database $db
* @return TaskSubtaskAssigneeFilter
*/
public function setDatabase(Database $db)
{
$this->db = $db;
return $this;
}
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('subtask:assignee');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->inSubquery(TaskModel::TABLE.'.id', $this->getSubQuery());
return $this;
}
/**
* Get subquery
*
* @access protected
* @return Table
*/
protected function getSubQuery()
{
$subquery = $this->db->table(SubtaskModel::TABLE)
->columns(SubtaskModel::TABLE.'.task_id')
->join(UserModel::TABLE, 'id', 'user_id', SubtaskModel::TABLE)
->neq(SubtaskModel::TABLE.'.status', SubtaskModel::STATUS_DONE);
return $this->applySubQueryFilter($subquery);
}
/**
* Apply subquery filter
*
* @access protected
* @param Table $subquery
* @return Table
*/
protected function applySubQueryFilter(Table $subquery)
{
if (is_int($this->value) || ctype_digit((string) $this->value)) {
$subquery->eq(SubtaskModel::TABLE.'.user_id', $this->value);
} else {
switch ($this->value) {
case 'me':
$subquery->eq(SubtaskModel::TABLE.'.user_id', $this->currentUserId);
break;
case 'nobody':
$subquery->eq(SubtaskModel::TABLE.'.user_id', 0);
break;
case 'anybody':
$subquery->gt(SubtaskModel::TABLE.'.user_id', 0);
break;
default:
$subquery->beginOr();
$subquery->ilike(UserModel::TABLE.'.username', $this->value.'%');
$subquery->ilike(UserModel::TABLE.'.name', '%'.$this->value.'%');
$subquery->closeOr();
}
}
return $subquery;
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\ProjectModel;
use Kanboard\Model\SwimlaneModel;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by swimlane
*
* @package filter
* @author Frederic Guillot
*/
class TaskSwimlaneFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('swimlane');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->ilike(SwimlaneModel::TABLE.'.name', $this->value);
return $this;
}
}
+87
View File
@@ -0,0 +1,87 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TagModel;
use Kanboard\Model\TaskModel;
use Kanboard\Model\TaskTagModel;
use PicoDb\Database;
/**
* Class TaskTagFilter
*
* @package Kanboard\Filter
* @author Frederic Guillot
*/
class TaskTagFilter extends BaseFilter implements FilterInterface
{
/**
* Database object
*
* @access private
* @var Database
*/
private $db;
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('tag');
}
/**
* Set database object
*
* @access public
* @param Database $db
* @return $this
*/
public function setDatabase(Database $db)
{
$this->db = $db;
return $this;
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if ($this->value === 'none') {
$sub_query = $this->getQueryOfTaskIdsWithoutTags();
} else {
$sub_query = $this->getQueryOfTaskIdsWithGivenTag();
}
$this->query->inSubquery(TaskModel::TABLE.'.id', $sub_query);
return $this;
}
protected function getQueryOfTaskIdsWithoutTags()
{
return $this->db
->table(TaskModel::TABLE)
->columns(TaskModel::TABLE . '.id')
->left(TaskTagModel::TABLE, 'tg', 'task_id', TaskModel::TABLE, 'id')
->isNull('tg.tag_id');
}
protected function getQueryOfTaskIdsWithGivenTag()
{
return $this->db
->table(TagModel::TABLE)
->columns(TaskTagModel::TABLE.'.task_id')
->ilike(TagModel::TABLE.'.name', '%'.$this->value.'%')
->join(TaskTagModel::TABLE, 'tag_id', 'id');
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
use Kanboard\Model\TaskModel;
/**
* Filter tasks by title
*
* @package filter
* @author Frederic Guillot
*/
class TaskTitleFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('title');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
if (ctype_digit((string) $this->value) || (strlen($this->value) > 1 && $this->value[0] === '#' && ctype_digit(substr($this->value, 1)))) {
$this->query->beginOr();
$this->query->eq(TaskModel::TABLE.'.id', str_replace('#', '', $this->value));
$this->query->ilike(TaskModel::TABLE.'.title', '%'.$this->value.'%');
$this->query->closeOr();
} else {
$this->query->ilike(TaskModel::TABLE.'.title', '%'.$this->value.'%');
}
return $this;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace Kanboard\Filter;
use Kanboard\Core\Filter\FilterInterface;
class UserNameFilter extends BaseFilter implements FilterInterface
{
/**
* Get search attribute
*
* @access public
* @return string[]
*/
public function getAttributes()
{
return array('name');
}
/**
* Apply filter
*
* @access public
* @return FilterInterface
*/
public function apply()
{
$this->query->beginOr()
->ilike('username', '%'.$this->value.'%')
->ilike('name', '%'.$this->value.'%')
->closeOr();
return $this;
}
}