diff --git a/app/Controller/BaseController.php b/app/Controller/BaseController.php index 1dd7d3729..49f07e6b9 100644 --- a/app/Controller/BaseController.php +++ b/app/Controller/BaseController.php @@ -127,7 +127,7 @@ abstract class BaseController extends Base protected function getProject($project_id = 0) { $project_id = $this->request->getIntegerParam('project_id', $project_id); - $project = $this->projectModel->getByIdWithOwner($project_id); + $project = $this->projectModel->getByIdWithOwnerAndTaskCount($project_id); if (empty($project)) { throw new PageNotFoundException(); diff --git a/app/Controller/ProjectCreationController.php b/app/Controller/ProjectCreationController.php index cfc7ffe8a..ef49cb86f 100644 --- a/app/Controller/ProjectCreationController.php +++ b/app/Controller/ProjectCreationController.php @@ -97,7 +97,8 @@ class ProjectCreationController extends BaseController 'name' => $values['name'], 'is_private' => $values['is_private'], 'identifier' => $values['identifier'], - 'per_swimlane_task_limits' => $values['per_swimlane_task_limits'], + 'per_swimlane_task_limits' => array_key_exists('per_swimlane_task_limits', $values) ? $values['per_swimlane_task_limits'] : 0, + 'task_limit' => $values['task_limit'], ); return $this->projectModel->create($project, $this->userSession->getId(), true); diff --git a/app/Controller/SwimlaneController.php b/app/Controller/SwimlaneController.php index e6368b248..1a533ebbc 100644 --- a/app/Controller/SwimlaneController.php +++ b/app/Controller/SwimlaneController.php @@ -63,7 +63,7 @@ class SwimlaneController extends BaseController list($valid, $errors) = $this->swimlaneValidator->validateCreation($values); if ($valid) { - if ($this->swimlaneModel->create($project['id'], $values['name'], $values['description']) !== false) { + if ($this->swimlaneModel->create($project['id'], $values['name'], $values['description'], $values['task_limit']) !== false) { $this->flash->success(t('Your swimlane have been created successfully.')); $this->response->redirect($this->helper->url->to('SwimlaneController', 'index', array('project_id' => $project['id'])), true); return; diff --git a/app/Model/ProjectDuplicationModel.php b/app/Model/ProjectDuplicationModel.php index 4f79e72ee..a7de64fd8 100644 --- a/app/Model/ProjectDuplicationModel.php +++ b/app/Model/ProjectDuplicationModel.php @@ -160,6 +160,7 @@ class ProjectDuplicationModel extends Base 'priority_start' => $project['priority_start'], 'priority_end' => $project['priority_end'], 'per_swimlane_task_limits' => empty($project['per_swimlane_task_limits']) ? 0 : 1, + 'task_limit' => $project['task_limit'], 'identifier' => $identifier, ); diff --git a/app/Model/ProjectModel.php b/app/Model/ProjectModel.php index b6c113f73..74b91d172 100644 --- a/app/Model/ProjectModel.php +++ b/app/Model/ProjectModel.php @@ -79,6 +79,24 @@ class ProjectModel extends Base ->findOne(); } + /** + * Get a project by id with owner name and task count + * + * @access public + * @param integer $project_id Project id + * @return array + */ + public function getByIdWithOwnerAndTaskCount($project_id) + { + return $this->db->table(self::TABLE) + ->columns(self::TABLE.'.*', UserModel::TABLE.'.username AS owner_username', UserModel::TABLE.'.name AS owner_name', 'SUM(CAST('.TaskModel::TABLE.'.is_active AS INTEGER)) AS nb_active_tasks') + ->eq(self::TABLE.'.id', $project_id) + ->join(UserModel::TABLE, 'id', 'owner_id') + ->join(TaskModel::TABLE, 'project_id', 'id') + ->groupBy(self::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name') + ->findOne(); + } + /** * Get a project by the name * @@ -372,7 +390,7 @@ class ProjectModel extends Base $values['identifier'] = strtoupper($values['identifier']); } - $this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end')); + $this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end', 'task_limit')); if (! $this->db->table(self::TABLE)->save($values)) { $this->db->cancelTransaction(); @@ -459,7 +477,7 @@ class ProjectModel extends Base $values['per_swimlane_task_limits'] = empty($values['per_swimlane_task_limits']) ? 0 : 1; - $this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end')); + $this->helper->model->convertIntegerFields($values, array('priority_default', 'priority_start', 'priority_end', 'task_limit')); return $this->exists($values['id']) && $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); @@ -568,4 +586,19 @@ class ProjectModel extends Base ->eq('id', $project_id) ->save(array('is_public' => 0, 'token' => '')); } + + /** + * Return the task count for a project + * + * @access public + * @param integer $project_id Project id + * @return integer + */ + public function taskCount($project_id) + { + return $this->db->table(self::TABLE) + ->eq('id', $project_id)->exists() + ->join(ColumnModel::TABLE, 'id', 'project_id') + ->count(); + } } diff --git a/app/Model/SwimlaneModel.php b/app/Model/SwimlaneModel.php index 0d204ae28..869aec311 100644 --- a/app/Model/SwimlaneModel.php +++ b/app/Model/SwimlaneModel.php @@ -178,7 +178,7 @@ class SwimlaneModel extends Base ); $swimlanes = $this->db->table(self::TABLE) - ->columns('id', 'name', 'description', 'project_id', 'position', 'is_active') + ->columns('id', 'name', 'description', 'project_id', 'position', 'is_active', 'task_limit') ->subquery("SELECT COUNT(*) FROM ".TaskModel::TABLE." WHERE swimlane_id=".self::TABLE.".id AND is_active='1'", 'nb_open_tasks') ->subquery("SELECT COUNT(*) FROM ".TaskModel::TABLE." WHERE swimlane_id=".self::TABLE.".id AND is_active='0'", 'nb_closed_tasks') ->eq('project_id', $project_id) @@ -231,7 +231,7 @@ class SwimlaneModel extends Base * @param string $description * @return bool|int */ - public function create($projectId, $name, $description = '') + public function create($projectId, $name, $description = '', $task_limit = 0) { if (! $this->projectModel->exists($projectId)) { return 0; @@ -243,6 +243,7 @@ class SwimlaneModel extends Base 'description' => $description, 'position' => $this->getLastPosition($projectId), 'is_active' => 1, + 'task_limit' => $task_limit, )); } diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index b759ece8d..62a28d34d 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -8,7 +8,17 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 134; +const VERSION = 136; + +function version_136(PDO $pdo) +{ + $pdo->exec('ALTER TABLE `swimlanes` ADD COLUMN `task_limit` INT DEFAULT 0'); +} + +function version_135(PDO $pdo) +{ + $pdo->exec('ALTER TABLE `projects` ADD COLUMN `task_limit` INT DEFAULT 0'); +} function version_134(PDO $pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index e2d710346..cbb885067 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -8,7 +8,17 @@ use PDO; use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; -const VERSION = 112; +const VERSION = 114; + +function version_114(PDO $pdo) +{ + $pdo->exec('ALTER TABLE "swimlanes" ADD COLUMN task_limit INTEGER DEFAULT 0'); +} + +function version_113(PDO $pdo) +{ + $pdo->exec('ALTER TABLE "projects" ADD COLUMN task_limit INTEGER DEFAULT 0'); +} function version_112(PDO $pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index a24b87227..964d3032b 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -8,7 +8,17 @@ use Kanboard\Core\Security\Token; use Kanboard\Core\Security\Role; use PDO; -const VERSION = 121; +const VERSION = 123; + +function version_123(PDO $pdo) +{ + $pdo->exec('ALTER TABLE swimlanes ADD COLUMN task_limit INTEGER DEFAULT 0'); +} + +function version_122(PDO $pdo) +{ + $pdo->exec('ALTER TABLE projects ADD COLUMN task_limit INTEGER DEFAULT 0'); +} function version_121(PDO $pdo) { diff --git a/app/Template/board/table_container.php b/app/Template/board/table_container.php index a93e70013..bfa98eda9 100644 --- a/app/Template/board/table_container.php +++ b/app/Template/board/table_container.php @@ -1,4 +1,5 @@ -
= t('There is no column or swimlane activated in your project!') ?>
diff --git a/app/Template/board/table_swimlane.php b/app/Template/board/table_swimlane.php index 33c1cf26f..d58dbf43d 100644 --- a/app/Template/board/table_swimlane.php +++ b/app/Template/board/table_swimlane.php @@ -15,7 +15,11 @@ - (= $swimlane['nb_tasks'] ?>) + + (= $swimlane['nb_tasks'] ?>/= $swimlane['task_limit'] ?>) + + (= $swimlane['nb_tasks'] ?>) + diff --git a/app/Template/board/table_tasks.php b/app/Template/board/table_tasks.php index 1b846c731..f0defe21b 100644 --- a/app/Template/board/table_tasks.php +++ b/app/Template/board/table_tasks.php @@ -1,5 +1,5 @@ -= t('The project identifier is optional and must be alphanumeric, example: MYPROJECT.') ?>
- = $this->form->checkbox('per_swimlane_task_limits', t('Task limits apply to each swimlane individually'), 1, false) ?> + = $this->form->checkbox('per_swimlane_task_limits', t('Column task limits apply to each swimlane individually'), 1, false) ?> + + = $this->form->label(t('Task limit'), 'task_limit') ?> + = $this->form->number('task_limit', $values, $errors) ?> 1): ?> = $this->form->label(t('Create from another project'), 'src_project_id') ?> diff --git a/app/Template/project_edit/show.php b/app/Template/project_edit/show.php index 69bf860a5..d27b80a38 100644 --- a/app/Template/project_edit/show.php +++ b/app/Template/project_edit/show.php @@ -28,6 +28,9 @@ = $this->form->textEditor('description', $values, $errors, array('tabindex' => 4)) ?> = $this->form->checkbox('per_swimlane_task_limits', t('Task limits apply to each swimlane individually'), 1, $project['per_swimlane_task_limits'] == 1, '', array('tabindex' => 5)) ?> + + = $this->form->label(t('Task limit'), 'task_limit') ?> + = $this->form->number('task_limit', $values, $errors, array('tabindex' => 6)) ?> - = $this->modal->submitButtons(array('tabindex' => 12)) ?> + = $this->modal->submitButtons(array('tabindex' => 13)) ?> diff --git a/app/Template/project_view/show.php b/app/Template/project_view/show.php index d1a7c2258..45785c2aa 100644 --- a/app/Template/project_view/show.php +++ b/app/Template/project_view/show.php @@ -33,10 +33,12 @@ -