Add the possibility to duplicate a task to another project

This commit is contained in:
Frédéric Guillot 2014-09-01 19:36:40 -08:00
parent e496554654
commit e6d0658a0e
13 changed files with 205 additions and 45 deletions

View File

@ -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;
}

View File

@ -432,6 +432,26 @@ class Task extends Base
* @access public
*/
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;
@ -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')
)));
}
}

View File

@ -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) {
@ -189,6 +192,34 @@ class SubTask extends Base
return $this->db->table(self::TABLE)->eq('id', $subtask_id)->remove();
}
/**
* 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
*

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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
);

View File

@ -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
)"

View File

@ -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&amp;action=copy&amp;task_id=<?= $task['id'] ?>&amp;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&amp;action=show&amp;task_id=<?= $task['id'] ?>"><?= t('cancel') ?></a>
</div>
</form>
<?php endif ?>

View File

@ -10,6 +10,7 @@
<li><a href="?controller=file&amp;action=create&amp;task_id=<?= $task['id'] ?>"><?= t('Attach a document') ?></a></li>
<li><a href="?controller=task&amp;action=duplicate&amp;project_id=<?= $task['project_id'] ?>&amp;task_id=<?= $task['id'] ?>"><?= t('Duplicate') ?></a></li>
<li><a href="?controller=task&amp;action=move&amp;project_id=<?= $task['project_id'] ?>&amp;task_id=<?= $task['id'] ?>"><?= t('Move to another project') ?></a></li>
<li><a href="?controller=task&amp;action=copy&amp;project_id=<?= $task['project_id'] ?>&amp;task_id=<?= $task['id'] ?>"><?= t('Duplicate to another project') ?></a></li>
<li>
<?php if ($task['is_active'] == 1): ?>
<a href="?controller=task&amp;action=confirmClose&amp;task_id=<?= $task['id'] ?>"><?= t('Close this task') ?></a>

View File

@ -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**

View File

@ -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';

View File

@ -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']);
}
}

View File

@ -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);