diff options
-rw-r--r-- | app/Action/TaskDuplicateAnotherProject.php | 3 | ||||
-rw-r--r-- | app/Controller/Task.php | 33 | ||||
-rw-r--r-- | app/Model/SubTask.php | 53 | ||||
-rw-r--r-- | app/Model/Task.php | 55 | ||||
-rw-r--r-- | app/Schema/Mysql.php | 2 | ||||
-rw-r--r-- | app/Schema/Postgres.php | 2 | ||||
-rw-r--r-- | app/Schema/Sqlite.php | 2 | ||||
-rw-r--r-- | app/Templates/task_duplicate_project.php | 24 | ||||
-rw-r--r-- | app/Templates/task_sidebar.php | 1 | ||||
-rw-r--r-- | docs/automatic-actions.markdown | 9 | ||||
-rw-r--r-- | tests/units/Base.php | 1 | ||||
-rw-r--r-- | tests/units/SubtaskTest.php | 56 | ||||
-rw-r--r-- | tests/units/TaskTest.php | 9 |
13 files changed, 205 insertions, 45 deletions
diff --git a/app/Action/TaskDuplicateAnotherProject.php b/app/Action/TaskDuplicateAnotherProject.php index 7ef0f6ab..0f14cbed 100644 --- a/app/Action/TaskDuplicateAnotherProject.php +++ b/app/Action/TaskDuplicateAnotherProject.php @@ -73,7 +73,8 @@ class TaskDuplicateAnotherProject extends Base { if ($data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id')) { - $this->task->duplicateToAnotherProject($data['task_id'], $this->getParam('project_id')); + $task = $this->task->getById($data['task_id']); + $this->task->duplicateToAnotherProject($this->getParam('project_id'), $task); return true; } diff --git a/app/Controller/Task.php b/app/Controller/Task.php index 6936185f..35ef6965 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -433,6 +433,26 @@ class Task extends Base */ public function move() { + $this->toAnotherProject('move'); + } + + /** + * Duplicate a task to another project + * + * @access public + */ + public function copy() + { + $this->toAnotherProject('duplicate'); + } + + /** + * Common methods between the actions "move" and "copy" + * + * @access private + */ + private function toAnotherProject($action) + { $task = $this->getTask(); $values = $task; $errors = array(); @@ -446,23 +466,24 @@ class Task extends Base list($valid, $errors) = $this->task->validateProjectModification($values); if ($valid) { - if ($this->task->moveToAnotherProject($values['project_id'], $task)) { - $this->session->flash(t('Task updated successfully.')); - $this->response->redirect('?controller=task&action=show&task_id='.$values['id']); + $task_id = $this->task->{$action.'ToAnotherProject'}($values['project_id'], $task); + if ($task_id) { + $this->session->flash(t('Task created successfully.')); + $this->response->redirect('?controller=task&action=show&task_id='.$task_id); } else { - $this->session->flashError(t('Unable to update your task.')); + $this->session->flashError(t('Unable to create your task.')); } } } - $this->response->html($this->taskLayout('task_move_project', array( + $this->response->html($this->taskLayout('task_'.$action.'_project', array( 'values' => $values, 'errors' => $errors, 'task' => $task, 'projects_list' => $projects_list, 'menu' => 'tasks', - 'title' => t('Move the task to another project') + 'title' => t(ucfirst($action).' the task to another project') ))); } } diff --git a/app/Model/SubTask.php b/app/Model/SubTask.php index 9f2941c5..011c58e7 100644 --- a/app/Model/SubTask.php +++ b/app/Model/SubTask.php @@ -121,13 +121,12 @@ class SubTask extends Base } /** - * Create + * Prepare data before insert/update * * @access public * @param array $values Form values - * @return bool */ - public function create(array $values) + public function prepare(array &$values) { if (isset($values['another_subtask'])) { unset($values['another_subtask']); @@ -140,7 +139,18 @@ class SubTask extends Base if (isset($values['time_spent']) && empty($values['time_spent'])) { $values['time_spent'] = 0; } + } + /** + * Create + * + * @access public + * @param array $values Form values + * @return bool + */ + public function create(array $values) + { + $this->prepare($values); $result = $this->db->table(self::TABLE)->save($values); if ($result) { @@ -160,14 +170,7 @@ class SubTask extends Base */ public function update(array $values) { - if (isset($values['time_estimated']) && empty($values['time_estimated'])) { - $values['time_estimated'] = 0; - } - - if (isset($values['time_spent']) && empty($values['time_spent'])) { - $values['time_spent'] = 0; - } - + $this->prepare($values); $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); if ($result) { @@ -190,6 +193,34 @@ class SubTask extends Base } /** + * Duplicate all subtasks to another task + * + * @access public + * @param integer $src_task_id Source task id + * @param integer $dst_task_id Destination task id + * @return bool + */ + public function duplicate($src_task_id, $dst_task_id) + { + $subtasks = $this->db->table(self::TABLE) + ->columns('title', 'time_estimated') + ->eq('task_id', $src_task_id) + ->findAll(); + + foreach ($subtasks as &$subtask) { + + $subtask['task_id'] = $dst_task_id; + $subtask['time_spent'] = 0; + + if (! $this->db->table(self::TABLE)->save($subtask)) { + return false; + } + } + + return true; + } + + /** * Validate creation/modification * * @access public diff --git a/app/Model/Task.php b/app/Model/Task.php index 64f3b74c..30c1781b 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -306,43 +306,54 @@ class Task extends Base * Duplicate a task to another project (always copy to the first column) * * @access public - * @param integer $task_id Task id * @param integer $project_id Destination project id + * @param array $task Task data * @return boolean */ - public function duplicateToAnotherProject($task_id, $project_id) + public function duplicateToAnotherProject($project_id, array $task) { $this->db->startTransaction(); - // Get the original task - $task = $this->getById($task_id); - - // Cleanup data - unset($task['id']); - unset($task['date_completed']); - // Assign new values - $task['date_creation'] = time(); - $task['owner_id'] = 0; - $task['category_id'] = 0; - $task['is_active'] = 1; - $task['column_id'] = $this->board->getFirstColumn($project_id); - $task['project_id'] = $project_id; - $task['position'] = $this->countByColumnId($task['project_id'], $task['column_id']); + $values = array(); + $values['title'] = $task['title']; + $values['description'] = $task['description']; + $values['date_creation'] = time(); + $values['date_modification'] = $values['date_creation']; + $values['date_due'] = $task['date_due']; + $values['color_id'] = $task['color_id']; + $values['project_id'] = $project_id; + $values['column_id'] = $this->board->getFirstColumn($project_id); + $values['owner_id'] = 0; + $values['creator_id'] = $task['creator_id']; + $values['position'] = $this->countByColumnId($project_id, $values['column_id']); + $values['score'] = $task['score']; + $values['category_id'] = 0; + + // Check if the assigned user is allowed for the new project + if ($task['owner_id'] && $this->project->isUserAllowed($project_id, $task['owner_id'])) { + $values['owner_id'] = $task['owner_id']; + } // Save task - if (! $this->db->table(self::TABLE)->save($task)) { + if (! $this->db->table(self::TABLE)->save($values)) { $this->db->cancelTransaction(); return false; } $task_id = $this->db->getConnection()->getLastId(); + // Duplicate subtasks + if (! $this->subTask->duplicate($task['id'], $task_id)) { + $this->db->cancelTransaction(); + return false; + } + $this->db->closeTransaction(); // Trigger events - $this->event->trigger(self::EVENT_CREATE_UPDATE, array('task_id' => $task_id) + $task); - $this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $task); + $this->event->trigger(self::EVENT_CREATE_UPDATE, array('task_id' => $task_id) + $values); + $this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $values); return $task_id; } @@ -584,7 +595,11 @@ class Task extends Base $values['position'] = $this->countByColumnId($project_id, $values['column_id']); $values['project_id'] = $project_id; - return $this->db->table(self::TABLE)->eq('id', $task['id'])->update($values); + if ($this->db->table(self::TABLE)->eq('id', $task['id'])->update($values)) { + return $task['id']; + } + + return false; } /** diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index ca4bbbae..9b202a69 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -57,7 +57,7 @@ function version_18($pdo) status INT DEFAULT 0, time_estimated INT DEFAULT 0, time_spent INT DEFAULT 0, - task_id INT, + task_id INT NOT NULL, user_id INT, PRIMARY KEY (id), FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index ac27f786..99774a55 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -143,7 +143,7 @@ function version_1($pdo) status SMALLINT DEFAULT 0, time_estimated INTEGER DEFAULT 0, time_spent INTEGER DEFAULT 0, - task_id INTEGER, + task_id INTEGER NOT NULL, user_id INTEGER, FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE ); diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index fed9aaf8..21b6ed4d 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -57,7 +57,7 @@ function version_18($pdo) status INTEGER DEFAULT 0, time_estimated INTEGER DEFAULT 0, time_spent INTEGER DEFAULT 0, - task_id INTEGER, + task_id INTEGER NOT NULL, user_id INTEGER, FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE )" diff --git a/app/Templates/task_duplicate_project.php b/app/Templates/task_duplicate_project.php new file mode 100644 index 00000000..86d2114a --- /dev/null +++ b/app/Templates/task_duplicate_project.php @@ -0,0 +1,24 @@ +<div class="page-header"> + <h2><?= t('Duplicate the task to another project') ?></h2> +</div> + +<?php if (empty($projects_list)): ?> + <p class="alert"><?= t('No project') ?></p> +<?php else: ?> + + <form method="post" action="?controller=task&action=copy&task_id=<?= $task['id'] ?>&project_id=<?= $task['project_id'] ?>" autocomplete="off"> + + <?= Helper\form_csrf() ?> + + <?= Helper\form_hidden('id', $values) ?> + <?= Helper\form_label(t('Project'), 'project_id') ?> + <?= Helper\form_select('project_id', $projects_list, $values, $errors) ?><br/> + + <div class="form-actions"> + <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/> + <?= t('or') ?> + <a href="?controller=task&action=show&task_id=<?= $task['id'] ?>"><?= t('cancel') ?></a> + </div> + </form> + +<?php endif ?>
\ No newline at end of file diff --git a/app/Templates/task_sidebar.php b/app/Templates/task_sidebar.php index ba9d7a86..43170aa6 100644 --- a/app/Templates/task_sidebar.php +++ b/app/Templates/task_sidebar.php @@ -10,6 +10,7 @@ <li><a href="?controller=file&action=create&task_id=<?= $task['id'] ?>"><?= t('Attach a document') ?></a></li> <li><a href="?controller=task&action=duplicate&project_id=<?= $task['project_id'] ?>&task_id=<?= $task['id'] ?>"><?= t('Duplicate') ?></a></li> <li><a href="?controller=task&action=move&project_id=<?= $task['project_id'] ?>&task_id=<?= $task['id'] ?>"><?= t('Move to another project') ?></a></li> + <li><a href="?controller=task&action=copy&project_id=<?= $task['project_id'] ?>&task_id=<?= $task['id'] ?>"><?= t('Duplicate to another project') ?></a></li> <li> <?php if ($task['is_active'] == 1): ?> <a href="?controller=task&action=confirmClose&task_id=<?= $task['id'] ?>"><?= t('Close this task') ?></a> diff --git a/docs/automatic-actions.markdown b/docs/automatic-actions.markdown index e903e0b1..6d46b053 100644 --- a/docs/automatic-actions.markdown +++ b/docs/automatic-actions.markdown @@ -33,6 +33,7 @@ List of available actions - Assign the task to a specific user - Assign the task to the person who does the action - Duplicate the task to another project +- Move the task to another project - Assign a color to a specific user - Assign automatically a color based on a category - Assign automatically a category based on a color @@ -68,6 +69,14 @@ Let's say we have two projects "Customer orders" and "Production", once the orde - Choose the action: **Duplicate the task to another project** - Define the action parameters: **Column = Validated** and **Project = Production** +### When a task is moved to the last column, move the exact same task to another project + +Let's say we have two projects "Ideas" and "Development", once the idea is validated, swap it to the "Development" project. + +- Choose the event: **Move a task to another column** +- Choose the action: **Move the task to another project** +- Define the action parameters: **Column = Validated** and **Project = Development** + ### I want to assign automatically a color to the user Bob - Choose the event: **Task creation** diff --git a/tests/units/Base.php b/tests/units/Base.php index fad5d074..7d8a075f 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -39,6 +39,7 @@ require_once __DIR__.'/../../app/Model/User.php'; require_once __DIR__.'/../../app/Model/Board.php'; require_once __DIR__.'/../../app/Model/Action.php'; require_once __DIR__.'/../../app/Model/Category.php'; +require_once __DIR__.'/../../app/Model/SubTask.php'; require_once __DIR__.'/../../app/Action/Base.php'; require_once __DIR__.'/../../app/Action/TaskClose.php'; diff --git a/tests/units/SubtaskTest.php b/tests/units/SubtaskTest.php new file mode 100644 index 00000000..a74ee60a --- /dev/null +++ b/tests/units/SubtaskTest.php @@ -0,0 +1,56 @@ +<?php + +require_once __DIR__.'/Base.php'; + +use Model\Task; +use Model\SubTask; +use Model\Project; +use Model\Category; +use Model\User; + +class SubTaskTest extends Base +{ + public function testDuplicate() + { + $t = new Task($this->registry); + $s = new SubTask($this->registry); + $p = new Project($this->registry); + + // We create a project + $this->assertEquals(1, $p->create(array('name' => 'test1'))); + + // We create 2 tasks + $this->assertEquals(1, $t->create(array('title' => 'test 1', 'project_id' => 1, 'column_id' => 1, 'owner_id' => 1))); + $this->assertEquals(2, $t->create(array('title' => 'test 2', 'project_id' => 1, 'column_id' => 1, 'owner_id' => 0))); + + // We create many subtasks for the first task + $this->assertEquals(1, $s->create(array('title' => 'subtask #1', 'task_id' => 1, 'time_estimated' => 5, 'time_spent' => 3, 'status' => 1))); + $this->assertEquals(2, $s->create(array('title' => 'subtask #2', 'task_id' => 1, 'time_estimated' => 0, 'time_spent' => 0, 'status' => 2, 'user_id' => 1))); + + // We duplicate our subtasks + $this->assertTrue($s->duplicate(1, 2)); + $subtasks = $s->getAll(2); + + $this->assertNotFalse($subtasks); + $this->assertNotEmpty($subtasks); + $this->assertEquals(2, count($subtasks)); + + $this->assertEquals('subtask #1', $subtasks[0]['title']); + $this->assertEquals('subtask #2', $subtasks[1]['title']); + + $this->assertEquals(2, $subtasks[0]['task_id']); + $this->assertEquals(2, $subtasks[1]['task_id']); + + $this->assertEquals(5, $subtasks[0]['time_estimated']); + $this->assertEquals(0, $subtasks[1]['time_estimated']); + + $this->assertEquals(0, $subtasks[0]['time_spent']); + $this->assertEquals(0, $subtasks[1]['time_spent']); + + $this->assertEquals(0, $subtasks[0]['status']); + $this->assertEquals(0, $subtasks[1]['status']); + + $this->assertEquals(0, $subtasks[0]['user_id']); + $this->assertEquals(0, $subtasks[1]['user_id']); + } +} diff --git a/tests/units/TaskTest.php b/tests/units/TaskTest.php index 66f82016..064f30b0 100644 --- a/tests/units/TaskTest.php +++ b/tests/units/TaskTest.php @@ -170,15 +170,16 @@ class TaskTest extends Base // We create a task $this->assertEquals(1, $t->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1, 'owner_id' => 1, 'category_id' => 1))); + $task = $t->getById(1); // We duplicate our task to the 2nd project - $this->assertEquals(2, $t->duplicateToAnotherProject(1, 2)); + $this->assertEquals(2, $t->duplicateToAnotherProject(2, $task)); $this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); // Check the values of the duplicated task $task = $t->getById(2); $this->assertNotEmpty($task); - $this->assertEquals(0, $task['owner_id']); + $this->assertEquals(1, $task['owner_id']); $this->assertEquals(0, $task['category_id']); $this->assertEquals(2, $task['project_id']); $this->assertEquals('test', $task['title']); @@ -204,7 +205,7 @@ class TaskTest extends Base // We duplicate our task to the 2nd project $task = $t->getById(1); - $this->assertTrue($t->moveToAnotherProject(2, $task)); + $this->assertEquals(1, $t->moveToAnotherProject(2, $task)); //$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE)); // Check the values of the duplicated task @@ -222,7 +223,7 @@ class TaskTest extends Base // The owner should be reseted $task = $t->getById(2); - $this->assertTrue($t->moveToAnotherProject(2, $task)); + $this->assertEquals(2, $t->moveToAnotherProject(2, $task)); $task = $t->getById(2); $this->assertNotEmpty($task); |