From 9a661a5e9ede5fc699f573179683b7db973a2fe0 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Mon, 11 Jan 2016 21:47:51 -0500 Subject: Move subtask validator methods --- app/Model/Subtask.php | 90 +-------------------------------------------------- 1 file changed, 1 insertion(+), 89 deletions(-) (limited to 'app/Model/Subtask.php') diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php index 664e41e1..0e039bb3 100644 --- a/app/Model/Subtask.php +++ b/app/Model/Subtask.php @@ -4,11 +4,9 @@ namespace Kanboard\Model; use PicoDb\Database; use Kanboard\Event\SubtaskEvent; -use SimpleValidator\Validator; -use SimpleValidator\Validators; /** - * Subtask model + * Subtask Model * * @package model * @author Frederic Guillot @@ -451,90 +449,4 @@ class Subtask extends Base } }); } - - /** - * Validate creation - * - * @access public - * @param array $values Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateCreation(array $values) - { - $rules = array( - new Validators\Required('task_id', t('The task id is required')), - new Validators\Required('title', t('The title is required')), - ); - - $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); - - return array( - $v->execute(), - $v->getErrors() - ); - } - - /** - * Validate modification - * - * @access public - * @param array $values Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateModification(array $values) - { - $rules = array( - new Validators\Required('id', t('The subtask id is required')), - new Validators\Required('task_id', t('The task id is required')), - new Validators\Required('title', t('The title is required')), - ); - - $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); - - return array( - $v->execute(), - $v->getErrors() - ); - } - - /** - * Validate API modification - * - * @access public - * @param array $values Form values - * @return array $valid, $errors [0] = Success or not, [1] = List of errors - */ - public function validateApiModification(array $values) - { - $rules = array( - new Validators\Required('id', t('The subtask id is required')), - new Validators\Required('task_id', t('The task id is required')), - ); - - $v = new Validator($values, array_merge($rules, $this->commonValidationRules())); - - return array( - $v->execute(), - $v->getErrors() - ); - } - - /** - * Common validation rules - * - * @access private - * @return array - */ - private function commonValidationRules() - { - return array( - new Validators\Integer('id', t('The subtask id must be an integer')), - new Validators\Integer('task_id', t('The task id must be an integer')), - new Validators\MaxLength('title', t('The maximum length is %d characters', 255), 255), - new Validators\Integer('user_id', t('The user id must be an integer')), - new Validators\Integer('status', t('The status must be an integer')), - new Validators\Numeric('time_estimated', t('The time must be a numeric value')), - new Validators\Numeric('time_spent', t('The time must be a numeric value')), - ); - } } -- cgit v1.2.3 From 0bc51620c731e7cfd10db5e064fc04693205b21c Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 31 Jan 2016 19:51:59 -0500 Subject: Add unit tests for last automatic actions --- app/Controller/Taskduplication.php | 2 - app/Model/Category.php | 11 +- app/Model/LastLogin.php | 16 +-- app/Model/ProjectDuplication.php | 6 +- app/Model/Subtask.php | 8 +- app/Model/SubtaskTimeTracking.php | 10 +- app/Model/Swimlane.php | 143 +++++++++++++------------ tests/units/Action/TaskCloseNoActivityTest.php | 43 ++++++++ tests/units/Action/TaskEmailNoActivityTest.php | 103 ++++++++++++++++++ 9 files changed, 248 insertions(+), 94 deletions(-) create mode 100644 tests/units/Action/TaskCloseNoActivityTest.php create mode 100644 tests/units/Action/TaskEmailNoActivityTest.php (limited to 'app/Model/Subtask.php') diff --git a/app/Controller/Taskduplication.php b/app/Controller/Taskduplication.php index a41183a7..2362ae42 100644 --- a/app/Controller/Taskduplication.php +++ b/app/Controller/Taskduplication.php @@ -2,8 +2,6 @@ namespace Kanboard\Controller; -use Kanboard\Model\Project as ProjectModel; - /** * Task Duplication controller * diff --git a/app/Model/Category.php b/app/Model/Category.php index 58cee738..883fc282 100644 --- a/app/Model/Category.php +++ b/app/Model/Category.php @@ -193,11 +193,12 @@ class Category extends Base */ public function duplicate($src_project_id, $dst_project_id) { - $categories = $this->db->table(self::TABLE) - ->columns('name') - ->eq('project_id', $src_project_id) - ->asc('name') - ->findAll(); + $categories = $this->db + ->table(self::TABLE) + ->columns('name') + ->eq('project_id', $src_project_id) + ->asc('name') + ->findAll(); foreach ($categories as $category) { $category['project_id'] = $dst_project_id; diff --git a/app/Model/LastLogin.php b/app/Model/LastLogin.php index f5be020e..a1734819 100644 --- a/app/Model/LastLogin.php +++ b/app/Model/LastLogin.php @@ -39,14 +39,14 @@ class LastLogin extends Base $this->cleanup($user_id); return $this->db - ->table(self::TABLE) - ->insert(array( - 'auth_type' => $auth_type, - 'user_id' => $user_id, - 'ip' => $ip, - 'user_agent' => substr($user_agent, 0, 255), - 'date_creation' => time(), - )); + ->table(self::TABLE) + ->insert(array( + 'auth_type' => $auth_type, + 'user_id' => $user_id, + 'ip' => $ip, + 'user_agent' => substr($user_agent, 0, 255), + 'date_creation' => time(), + )); } /** diff --git a/app/Model/ProjectDuplication.php b/app/Model/ProjectDuplication.php index 16e4f7c2..9c5f80ad 100644 --- a/app/Model/ProjectDuplication.php +++ b/app/Model/ProjectDuplication.php @@ -17,7 +17,7 @@ class ProjectDuplication extends Base * Get list of optional models to duplicate * * @access public - * @return array + * @return string[] */ public function getOptionalSelection() { @@ -28,7 +28,7 @@ class ProjectDuplication extends Base * Get list of all possible models to duplicate * * @access public - * @return array + * @return string[] */ public function getPossibleSelection() { @@ -71,7 +71,7 @@ class ProjectDuplication extends Base // Get the cloned project Id $dst_project_id = $this->copy($src_project_id, $owner_id, $name, $private); - if (! $dst_project_id) { + if ($dst_project_id === false) { $this->db->cancelTransaction(); return false; } diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php index 0e039bb3..1e989ad5 100644 --- a/app/Model/Subtask.php +++ b/app/Model/Subtask.php @@ -435,10 +435,10 @@ class Subtask extends Base return $this->db->transaction(function (Database $db) use ($src_task_id, $dst_task_id) { $subtasks = $db->table(Subtask::TABLE) - ->columns('title', 'time_estimated', 'position') - ->eq('task_id', $src_task_id) - ->asc('position') - ->findAll(); + ->columns('title', 'time_estimated', 'position') + ->eq('task_id', $src_task_id) + ->asc('position') + ->findAll(); foreach ($subtasks as &$subtask) { $subtask['task_id'] = $dst_task_id; diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php index a741dbb5..b766b542 100644 --- a/app/Model/SubtaskTimeTracking.php +++ b/app/Model/SubtaskTimeTracking.php @@ -302,11 +302,11 @@ class SubtaskTimeTracking extends Base { $hook = 'model:subtask-time-tracking:calculate:time-spent'; $start_time = $this->db - ->table(self::TABLE) - ->eq('subtask_id', $subtask_id) - ->eq('user_id', $user_id) - ->eq('end', 0) - ->findOneColumn('start'); + ->table(self::TABLE) + ->eq('subtask_id', $subtask_id) + ->eq('user_id', $user_id) + ->eq('end', 0) + ->findOneColumn('start'); if (empty($start_time)) { return 0; diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php index e5124e8e..6b0dcdc5 100644 --- a/app/Model/Swimlane.php +++ b/app/Model/Swimlane.php @@ -96,10 +96,11 @@ class Swimlane extends Base */ public function getDefault($project_id) { - $result = $this->db->table(Project::TABLE) - ->eq('id', $project_id) - ->columns('id', 'default_swimlane', 'show_default_swimlane') - ->findOne(); + $result = $this->db + ->table(Project::TABLE) + ->eq('id', $project_id) + ->columns('id', 'default_swimlane', 'show_default_swimlane') + ->findOne(); if ($result['default_swimlane'] === 'Default swimlane') { $result['default_swimlane'] = t($result['default_swimlane']); @@ -117,10 +118,11 @@ class Swimlane extends Base */ public function getAll($project_id) { - return $this->db->table(self::TABLE) - ->eq('project_id', $project_id) - ->orderBy('position', 'asc') - ->findAll(); + return $this->db + ->table(self::TABLE) + ->eq('project_id', $project_id) + ->orderBy('position', 'asc') + ->findAll(); } /** @@ -133,9 +135,10 @@ class Swimlane extends Base */ public function getAllByStatus($project_id, $status = self::ACTIVE) { - $query = $this->db->table(self::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', $status); + $query = $this->db + ->table(self::TABLE) + ->eq('project_id', $project_id) + ->eq('is_active', $status); if ($status == self::ACTIVE) { $query->asc('position'); @@ -155,17 +158,19 @@ class Swimlane extends Base */ public function getSwimlanes($project_id) { - $swimlanes = $this->db->table(self::TABLE) - ->columns('id', 'name', 'description') - ->eq('project_id', $project_id) - ->eq('is_active', self::ACTIVE) - ->orderBy('position', 'asc') - ->findAll(); - - $default_swimlane = $this->db->table(Project::TABLE) - ->eq('id', $project_id) - ->eq('show_default_swimlane', 1) - ->findOneColumn('default_swimlane'); + $swimlanes = $this->db + ->table(self::TABLE) + ->columns('id', 'name', 'description') + ->eq('project_id', $project_id) + ->eq('is_active', self::ACTIVE) + ->orderBy('position', 'asc') + ->findAll(); + + $default_swimlane = $this->db + ->table(Project::TABLE) + ->eq('id', $project_id) + ->eq('show_default_swimlane', 1) + ->findOneColumn('default_swimlane'); if ($default_swimlane) { if ($default_swimlane === 'Default swimlane') { @@ -200,11 +205,12 @@ class Swimlane extends Base $swimlanes[0] = $default === 'Default swimlane' ? t($default) : $default; } - return $swimlanes + $this->db->hashtable(self::TABLE) - ->eq('project_id', $project_id) - ->in('is_active', $only_active ? array(self::ACTIVE) : array(self::ACTIVE, self::INACTIVE)) - ->orderBy('position', 'asc') - ->getAll('id', 'name'); + return $swimlanes + $this->db + ->hashtable(self::TABLE) + ->eq('project_id', $project_id) + ->in('is_active', $only_active ? array(self::ACTIVE) : array(self::ACTIVE, self::INACTIVE)) + ->orderBy('position', 'asc') + ->getAll('id', 'name'); } /** @@ -232,9 +238,10 @@ class Swimlane extends Base */ public function update(array $values) { - return $this->db->table(self::TABLE) - ->eq('id', $values['id']) - ->update($values); + return $this->db + ->table(self::TABLE) + ->eq('id', $values['id']) + ->update($values); } /** @@ -247,12 +254,12 @@ class Swimlane extends Base public function updateDefault(array $values) { return $this->db - ->table(Project::TABLE) - ->eq('id', $values['id']) - ->update(array( - 'default_swimlane' => $values['default_swimlane'], - 'show_default_swimlane' => $values['show_default_swimlane'], - )); + ->table(Project::TABLE) + ->eq('id', $values['id']) + ->update(array( + 'default_swimlane' => $values['default_swimlane'], + 'show_default_swimlane' => $values['show_default_swimlane'], + )); } /** @@ -264,10 +271,11 @@ class Swimlane extends Base */ public function getLastPosition($project_id) { - return $this->db->table(self::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', 1) - ->count() + 1; + return $this->db + ->table(self::TABLE) + ->eq('project_id', $project_id) + ->eq('is_active', 1) + ->count() + 1; } /** @@ -281,12 +289,12 @@ class Swimlane extends Base public function disable($project_id, $swimlane_id) { $result = $this->db - ->table(self::TABLE) - ->eq('id', $swimlane_id) - ->update(array( - 'is_active' => self::INACTIVE, - 'position' => 0, - )); + ->table(self::TABLE) + ->eq('id', $swimlane_id) + ->update(array( + 'is_active' => self::INACTIVE, + 'position' => 0, + )); if ($result) { // Re-order positions @@ -307,12 +315,12 @@ class Swimlane extends Base public function enable($project_id, $swimlane_id) { return $this->db - ->table(self::TABLE) - ->eq('id', $swimlane_id) - ->update(array( - 'is_active' => self::ACTIVE, - 'position' => $this->getLastPosition($project_id), - )); + ->table(self::TABLE) + ->eq('id', $swimlane_id) + ->update(array( + 'is_active' => self::ACTIVE, + 'position' => $this->getLastPosition($project_id), + )); } /** @@ -353,11 +361,12 @@ class Swimlane extends Base public function updatePositions($project_id) { $position = 0; - $swimlanes = $this->db->table(self::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', 1) - ->asc('position') - ->findAllByColumn('id'); + $swimlanes = $this->db + ->table(self::TABLE) + ->eq('project_id', $project_id) + ->eq('is_active', 1) + ->asc('position') + ->findAllByColumn('id'); if (! $swimlanes) { return false; @@ -365,8 +374,8 @@ class Swimlane extends Base foreach ($swimlanes as $swimlane_id) { $this->db->table(self::TABLE) - ->eq('id', $swimlane_id) - ->update(array('position' => ++$position)); + ->eq('id', $swimlane_id) + ->update(array('position' => ++$position)); } return true; @@ -383,10 +392,10 @@ class Swimlane extends Base public function moveDown($project_id, $swimlane_id) { $swimlanes = $this->db->hashtable(self::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', self::ACTIVE) - ->asc('position') - ->getAll('id', 'position'); + ->eq('project_id', $project_id) + ->eq('is_active', self::ACTIVE) + ->asc('position') + ->getAll('id', 'position'); $positions = array_flip($swimlanes); @@ -416,10 +425,10 @@ class Swimlane extends Base public function moveUp($project_id, $swimlane_id) { $swimlanes = $this->db->hashtable(self::TABLE) - ->eq('project_id', $project_id) - ->eq('is_active', self::ACTIVE) - ->asc('position') - ->getAll('id', 'position'); + ->eq('project_id', $project_id) + ->eq('is_active', self::ACTIVE) + ->asc('position') + ->getAll('id', 'position'); $positions = array_flip($swimlanes); diff --git a/tests/units/Action/TaskCloseNoActivityTest.php b/tests/units/Action/TaskCloseNoActivityTest.php new file mode 100644 index 00000000..b6e04c47 --- /dev/null +++ b/tests/units/Action/TaskCloseNoActivityTest.php @@ -0,0 +1,43 @@ +container); + $taskCreationModel = new TaskCreation($this->container); + $taskFinderModel = new TaskFinder($this->container); + + $this->assertEquals(1, $projectModel->create(array('name' => 'test1'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + + $this->container['db']->table(Task::TABLE)->eq('id', 1)->update(array('date_modification' => strtotime('-10days'))); + + $tasks = $taskFinderModel->getAll(1); + $event = new TaskListEvent(array('tasks' => $tasks, 'project_id' => 1)); + + $action = new TaskCloseNoActivity($this->container); + $action->setProjectId(1); + $action->setParam('duration', 2); + + $this->assertTrue($action->execute($event, Task::EVENT_DAILY_CRONJOB)); + + $task = $taskFinderModel->getById(1); + $this->assertNotEmpty($task); + $this->assertEquals(0, $task['is_active']); + + $task = $taskFinderModel->getById(2); + $this->assertNotEmpty($task); + $this->assertEquals(1, $task['is_active']); + } +} diff --git a/tests/units/Action/TaskEmailNoActivityTest.php b/tests/units/Action/TaskEmailNoActivityTest.php new file mode 100644 index 00000000..af4baed5 --- /dev/null +++ b/tests/units/Action/TaskEmailNoActivityTest.php @@ -0,0 +1,103 @@ +container); + $projectModel = new Project($this->container); + $taskCreationModel = new TaskCreation($this->container); + $taskFinderModel = new TaskFinder($this->container); + + $this->assertEquals(2, $userModel->create(array('username' => 'test', 'email' => 'chuck@norris', 'name' => 'Chuck Norris'))); + $this->assertEquals(1, $projectModel->create(array('name' => 'test1'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + + $this->container['db']->table(Task::TABLE)->eq('id', 1)->update(array('date_modification' => strtotime('-10days'))); + + $tasks = $taskFinderModel->getAll(1); + $event = new TaskListEvent(array('tasks' => $tasks, 'project_id' => 1)); + + $action = new TaskEmailNoActivity($this->container); + $action->setProjectId(1); + $action->setParam('user_id', 2); + $action->setParam('subject', 'Old tasks'); + $action->setParam('duration', 2); + + $this->container['emailClient'] + ->expects($this->once()) + ->method('send') + ->with('chuck@norris', 'Chuck Norris', 'Old tasks', $this->anything()); + + $this->assertTrue($action->execute($event, Task::EVENT_DAILY_CRONJOB)); + } + + public function testUserWithNoEmail() + { + $userModel = new User($this->container); + $projectModel = new Project($this->container); + $taskCreationModel = new TaskCreation($this->container); + $taskFinderModel = new TaskFinder($this->container); + + $this->assertEquals(2, $userModel->create(array('username' => 'test', 'name' => 'Chuck Norris'))); + $this->assertEquals(1, $projectModel->create(array('name' => 'test1'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + + $this->container['db']->table(Task::TABLE)->eq('id', 1)->update(array('date_modification' => strtotime('-10days'))); + + $tasks = $taskFinderModel->getAll(1); + $event = new TaskListEvent(array('tasks' => $tasks, 'project_id' => 1)); + + $action = new TaskEmailNoActivity($this->container); + $action->setProjectId(1); + $action->setParam('user_id', 2); + $action->setParam('subject', 'Old tasks'); + $action->setParam('duration', 2); + + $this->container['emailClient'] + ->expects($this->never()) + ->method('send'); + + $this->assertFalse($action->execute($event, Task::EVENT_DAILY_CRONJOB)); + } + + public function testTooRecent() + { + $userModel = new User($this->container); + $projectModel = new Project($this->container); + $taskCreationModel = new TaskCreation($this->container); + $taskFinderModel = new TaskFinder($this->container); + + $this->assertEquals(2, $userModel->create(array('username' => 'test', 'email' => 'chuck@norris', 'name' => 'Chuck Norris'))); + $this->assertEquals(1, $projectModel->create(array('name' => 'test1'))); + $this->assertEquals(1, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + $this->assertEquals(2, $taskCreationModel->create(array('project_id' => 1, 'title' => 'test'))); + + $tasks = $taskFinderModel->getAll(1); + $event = new TaskListEvent(array('tasks' => $tasks, 'project_id' => 1)); + + $action = new TaskEmailNoActivity($this->container); + $action->setProjectId(1); + $action->setParam('user_id', 2); + $action->setParam('subject', 'Old tasks'); + $action->setParam('duration', 2); + + $this->container['emailClient'] + ->expects($this->never()) + ->method('send'); + + $this->assertFalse($action->execute($event, Task::EVENT_DAILY_CRONJOB)); + } +} -- cgit v1.2.3 From 0f2b46dd6a9a1dc17768de2c415f382df95142e8 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Thu, 4 Feb 2016 21:38:53 -0500 Subject: Do not refresh the whole page when changing subtask status (work in progress) --- ChangeLog | 1 + app/Controller/Base.php | 20 +++- app/Controller/Comment.php | 2 +- app/Controller/Subtask.php | 111 --------------------- app/Controller/SubtaskRestriction.php | 61 +++++++++++ app/Controller/SubtaskStatus.php | 28 ++++++ app/Helper/Subtask.php | 38 +++---- app/Model/Subtask.php | 7 +- app/ServiceProvider/AuthenticationProvider.php | 2 + app/Template/app/subtasks.php | 2 +- app/Template/board/tooltip_subtasks.php | 15 ++- app/Template/subtask/icons.php | 7 -- app/Template/subtask/menu.php | 4 +- app/Template/subtask/restriction_change_status.php | 19 ---- app/Template/subtask/show.php | 77 +------------- app/Template/subtask/table.php | 69 +++++++++++++ app/Template/subtask_restriction/popover.php | 17 ++++ app/Template/task/show.php | 5 +- assets/js/app.js | 2 +- assets/js/src/App.js | 13 +++ assets/js/src/Tooltip.js | 15 --- tests/units/Model/SubtaskTest.php | 12 +-- 22 files changed, 258 insertions(+), 269 deletions(-) create mode 100644 app/Controller/SubtaskRestriction.php create mode 100644 app/Controller/SubtaskStatus.php delete mode 100644 app/Template/subtask/icons.php delete mode 100644 app/Template/subtask/restriction_change_status.php create mode 100644 app/Template/subtask/table.php create mode 100644 app/Template/subtask_restriction/popover.php (limited to 'app/Model/Subtask.php') diff --git a/ChangeLog b/ChangeLog index 7e4bdad6..7a95ae1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ New features: Improvements: +* Do not refresh the whole page when changing subtask status (work in progress) * Add dropdown menu with inline popup for all task actions * Change sidebar style * Change task summary layout diff --git a/app/Controller/Base.php b/app/Controller/Base.php index a80b3528..c55ad9ad 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -214,8 +214,7 @@ abstract class Base extends \Kanboard\Core\Base $project = $this->project->getByIdWithOwner($project_id); if (empty($project)) { - $this->flash->failure(t('Project not found.')); - $this->response->redirect($this->helper->url->to('project', 'index')); + $this->notfound(); } return $project; @@ -242,6 +241,23 @@ abstract class Base extends \Kanboard\Core\Base return $user; } + /** + * Get the current subtask + * + * @access protected + * @return array + */ + protected function getSubtask() + { + $subtask = $this->subtask->getById($this->request->getIntegerParam('subtask_id')); + + if (empty($subtask)) { + $this->notfound(); + } + + return $subtask; + } + /** * Common method to get project filters * diff --git a/app/Controller/Comment.php b/app/Controller/Comment.php index 2ad3f379..da3213e0 100644 --- a/app/Controller/Comment.php +++ b/app/Controller/Comment.php @@ -107,7 +107,7 @@ class Comment extends Base public function update() { $task = $this->getTask(); - $comment = $this->getComment(); + $this->getComment(); $values = $this->request->getValues(); list($valid, $errors) = $this->commentValidator->validateModification($values); diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php index 9fe15c9d..f8798906 100644 --- a/app/Controller/Subtask.php +++ b/app/Controller/Subtask.php @@ -2,8 +2,6 @@ namespace Kanboard\Controller; -use Kanboard\Model\Subtask as SubtaskModel; - /** * Subtask controller * @@ -12,23 +10,6 @@ use Kanboard\Model\Subtask as SubtaskModel; */ class Subtask extends Base { - /** - * Get the current subtask - * - * @access private - * @return array - */ - private function getSubtask() - { - $subtask = $this->subtask->getById($this->request->getIntegerParam('subtask_id')); - - if (empty($subtask)) { - $this->notfound(); - } - - return $subtask; - } - /** * Show list of subtasks */ @@ -181,98 +162,6 @@ class Subtask extends Base $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); } - /** - * Change status to the next status: Toto -> In Progress -> Done - * - * @access public - */ - public function toggleStatus() - { - $task = $this->getTask(); - $subtask = $this->getSubtask(); - $redirect = $this->request->getStringParam('redirect', 'task'); - - $this->subtask->toggleStatus($subtask['id']); - - if ($redirect === 'board') { - $this->sessionStorage->hasSubtaskInProgress = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); - - $this->response->html($this->template->render('board/tooltip_subtasks', array( - 'subtasks' => $this->subtask->getAll($task['id']), - 'task' => $task, - ))); - } - - $this->toggleRedirect($task, $redirect); - } - - /** - * Handle subtask restriction (popover) - * - * @access public - */ - public function subtaskRestriction() - { - $task = $this->getTask(); - $subtask = $this->getSubtask(); - - $this->response->html($this->template->render('subtask/restriction_change_status', array( - 'status_list' => array( - SubtaskModel::STATUS_TODO => t('Todo'), - SubtaskModel::STATUS_DONE => t('Done'), - ), - 'subtask_inprogress' => $this->subtask->getSubtaskInProgress($this->userSession->getId()), - 'subtask' => $subtask, - 'task' => $task, - 'redirect' => $this->request->getStringParam('redirect'), - ))); - } - - /** - * Change status of the in progress subtask and the other subtask - * - * @access public - */ - public function changeRestrictionStatus() - { - $task = $this->getTask(); - $subtask = $this->getSubtask(); - $values = $this->request->getValues(); - - // Change status of the previous in progress subtask - $this->subtask->update(array( - 'id' => $values['id'], - 'status' => $values['status'], - )); - - // Set the current subtask to in pogress - $this->subtask->update(array( - 'id' => $subtask['id'], - 'status' => SubtaskModel::STATUS_INPROGRESS, - )); - - $this->toggleRedirect($task, $values['redirect']); - } - - /** - * Redirect to the right page - * - * @access private - */ - private function toggleRedirect(array $task, $redirect) - { - switch ($redirect) { - case 'board': - $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id']))); - case 'dashboard': - $this->response->redirect($this->helper->url->to('app', 'index')); - case 'subtask': - $this->response->redirect($this->helper->url->to('subtask', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); - default: - $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'subtasks')); - } - } - /** * Move subtask position * diff --git a/app/Controller/SubtaskRestriction.php b/app/Controller/SubtaskRestriction.php new file mode 100644 index 00000000..56024867 --- /dev/null +++ b/app/Controller/SubtaskRestriction.php @@ -0,0 +1,61 @@ +getTask(); + $subtask = $this->getSubtask(); + + $this->response->html($this->template->render('subtask_restriction/popover', array( + 'status_list' => array( + SubtaskModel::STATUS_TODO => t('Todo'), + SubtaskModel::STATUS_DONE => t('Done'), + ), + 'subtask_inprogress' => $this->subtask->getSubtaskInProgress($this->userSession->getId()), + 'subtask' => $subtask, + 'task' => $task, + ))); + } + + /** + * Change status of the in progress subtask and the other subtask + * + * @access public + */ + public function update() + { + $task = $this->getTask(); + $subtask = $this->getSubtask(); + $values = $this->request->getValues(); + + // Change status of the previous "in progress" subtask + $this->subtask->update(array( + 'id' => $values['id'], + 'status' => $values['status'], + )); + + // Set the current subtask to "in progress" + $this->subtask->update(array( + 'id' => $subtask['id'], + 'status' => SubtaskModel::STATUS_INPROGRESS, + )); + + $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])), true); + } +} diff --git a/app/Controller/SubtaskStatus.php b/app/Controller/SubtaskStatus.php new file mode 100644 index 00000000..efe8a974 --- /dev/null +++ b/app/Controller/SubtaskStatus.php @@ -0,0 +1,28 @@ + In Progress -> Done + * + * @access public + */ + public function change() + { + $task = $this->getTask(); + $subtask = $this->getSubtask(); + + $status = $this->subtask->toggleStatus($subtask['id']); + $subtask['status'] = $status; + + $this->response->html($this->helper->subtask->toggleStatus($subtask, $task['project_id'])); + } +} diff --git a/app/Helper/Subtask.php b/app/Helper/Subtask.php index 5b8d7d90..38074b78 100644 --- a/app/Helper/Subtask.php +++ b/app/Helper/Subtask.php @@ -10,38 +10,40 @@ namespace Kanboard\Helper; */ class Subtask extends \Kanboard\Core\Base { + public function getTitle(array $subtask) + { + if ($subtask['status'] == 0) { + $html = ''; + } elseif ($subtask['status'] == 1) { + $html = ''; + } else { + $html = ''; + } + + return $html.$this->helper->e($subtask['title']); + } + /** * Get the link to toggle subtask status * * @access public * @param array $subtask - * @param string $redirect * @param integer $project_id * @return string */ - public function toggleStatus(array $subtask, $redirect, $project_id = 0) + public function toggleStatus(array $subtask, $project_id) { - if ($project_id > 0 && ! $this->helper->user->hasProjectAccess('subtask', 'edit', $project_id)) { - return trim($this->template->render('subtask/icons', array('subtask' => $subtask))) . $this->helper->e($subtask['title']); + if (! $this->helper->user->hasProjectAccess('subtask', 'edit', $project_id)) { + return $this->getTitle($subtask); } + $params = array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']); + if ($subtask['status'] == 0 && isset($this->sessionStorage->hasSubtaskInProgress) && $this->sessionStorage->hasSubtaskInProgress) { - return $this->helper->url->link( - trim($this->template->render('subtask/icons', array('subtask' => $subtask))) . $this->helper->e($subtask['title']), - 'subtask', - 'subtaskRestriction', - array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'redirect' => $redirect), - false, - 'popover task-board-popover' - ); + return $this->helper->url->link($this->getTitle($subtask), 'SubtaskRestriction', 'popover', $params, false, 'popover'); } - return $this->helper->url->link( - trim($this->template->render('subtask/icons', array('subtask' => $subtask))) . $this->helper->e($subtask['title']), - 'subtask', - 'toggleStatus', - array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'redirect' => $redirect) - ); + return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatus', 'change', $params, false, 'ajax-replace'); } public function selectTitle(array $values, array $errors = array(), array $attributes = array()) diff --git a/app/Model/Subtask.php b/app/Model/Subtask.php index 1e989ad5..14853941 100644 --- a/app/Model/Subtask.php +++ b/app/Model/Subtask.php @@ -353,15 +353,16 @@ class Subtask extends Base * * @access public * @param integer $subtask_id - * @return bool + * @return boolean|integer */ public function toggleStatus($subtask_id) { $subtask = $this->getById($subtask_id); + $status = ($subtask['status'] + 1) % 3; $values = array( 'id' => $subtask['id'], - 'status' => ($subtask['status'] + 1) % 3, + 'status' => $status, 'task_id' => $subtask['task_id'], ); @@ -369,7 +370,7 @@ class Subtask extends Base $values['user_id'] = $this->userSession->getId(); } - return $this->update($values); + return $this->update($values) ? $status : false; } /** diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php index dac73160..4196a470 100644 --- a/app/ServiceProvider/AuthenticationProvider.php +++ b/app/ServiceProvider/AuthenticationProvider.php @@ -83,6 +83,8 @@ class AuthenticationProvider implements ServiceProviderInterface $acl->add('ProjectEdit', '*', Role::PROJECT_MANAGER); $acl->add('Projectuser', '*', Role::PROJECT_MANAGER); $acl->add('Subtask', '*', Role::PROJECT_MEMBER); + $acl->add('SubtaskRestriction', '*', Role::PROJECT_MEMBER); + $acl->add('SubtaskStatus', '*', Role::PROJECT_MEMBER); $acl->add('Swimlane', '*', Role::PROJECT_MANAGER); $acl->add('Task', 'remove', Role::PROJECT_MEMBER); $acl->add('Taskcreation', '*', Role::PROJECT_MEMBER); diff --git a/app/Template/app/subtasks.php b/app/Template/app/subtasks.php index b4c87bab..f72f21fb 100644 --- a/app/Template/app/subtasks.php +++ b/app/Template/app/subtasks.php @@ -24,7 +24,7 @@ url->link($this->e($subtask['task_name']), 'task', 'show', array('task_id' => $subtask['task_id'], 'project_id' => $subtask['project_id'])) ?> - subtask->toggleStatus($subtask, 'dashboard') ?> + subtask->toggleStatus($subtask, $subtask['project_id']) ?> diff --git a/app/Template/board/tooltip_subtasks.php b/app/Template/board/tooltip_subtasks.php index 5e48fcf4..65b7ce4d 100644 --- a/app/Template/board/tooltip_subtasks.php +++ b/app/Template/board/tooltip_subtasks.php @@ -1,7 +1,12 @@ -
+ - subtask->toggleStatus($subtask, 'board', $task['project_id']) ?> - e(empty($subtask['username']) ? '' : ' ['.$this->user->getFullname($subtask).']') ?> -
+ + + + - +
+ subtask->toggleStatus($subtask, $task['project_id']) ?> + + e($subtask['username'] ?: $this->user->getFullname($subtask)) ?> +
diff --git a/app/Template/subtask/icons.php b/app/Template/subtask/icons.php deleted file mode 100644 index 1f31d51f..00000000 --- a/app/Template/subtask/icons.php +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/Template/subtask/menu.php b/app/Template/subtask/menu.php index f14b09b2..878ad68c 100644 --- a/app/Template/subtask/menu.php +++ b/app/Template/subtask/menu.php @@ -3,12 +3,12 @@