Implemented Changes to Project Duplication to include Swimlanes and Tasks.
ProjectDuplication::duplicate accepts additional param of type array now. Array includes which optional parts to duplicate. Optional parts are: 'swimlane', 'category', 'task', 'action'.
This commit is contained in:
parent
24300f828a
commit
e5ea361255
|
|
@ -297,7 +297,7 @@ class Project extends Base
|
|||
/**
|
||||
* Duplicate a project
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @author Antonio Rabelo & Michael Lüpkes
|
||||
* @access public
|
||||
*/
|
||||
public function duplicate()
|
||||
|
|
@ -305,10 +305,8 @@ class Project extends Base
|
|||
$project = $this->getProject();
|
||||
|
||||
if ($this->request->getStringParam('duplicate') === 'yes') {
|
||||
|
||||
$this->checkCSRFParam();
|
||||
|
||||
if ($this->projectDuplication->duplicate($project['id'])) {
|
||||
$values = array_keys($this->request->getValues());
|
||||
if ($this->projectDuplication->duplicate($project['id'], $values)) {
|
||||
$this->session->flash(t('Project cloned successfully.'));
|
||||
} else {
|
||||
$this->session->flashError(t('Unable to clone this project.'));
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use Pimple\Container;
|
|||
* @property \Model\Swimlane $swimlane
|
||||
* @property \Model\Task $task
|
||||
* @property \Model\TaskCreation $taskCreation
|
||||
* @property \Model\TaskDuplication $taskDuplication
|
||||
* @property \Model\TaskExport $taskExport
|
||||
* @property \Model\TaskFinder $taskFinder
|
||||
* @property \Model\TaskHistory $taskHistory
|
||||
|
|
|
|||
|
|
@ -59,10 +59,11 @@ class ProjectDuplication extends Base
|
|||
/**
|
||||
* Clone a project with all settings
|
||||
*
|
||||
* @param integer $project_id Project Id
|
||||
* @param integer $project_id Project Id
|
||||
* @param array $part_selection Selection of optional project parts to duplicate. Possible options: 'swimlane', 'action', 'category', 'task'
|
||||
* @return integer Cloned Project Id
|
||||
*/
|
||||
public function duplicate($project_id)
|
||||
public function duplicate($project_id, $part_selection = array('category', 'action'))
|
||||
{
|
||||
$this->db->startTransaction();
|
||||
|
||||
|
|
@ -74,7 +75,14 @@ class ProjectDuplication extends Base
|
|||
return false;
|
||||
}
|
||||
|
||||
foreach (array('board', 'category', 'projectPermission', 'action') as $model) {
|
||||
// Clone Columns, Categories, Permissions and Actions
|
||||
$optional_parts = array('swimlane', 'action', 'category');
|
||||
foreach (array('board', 'category', 'projectPermission', 'action', 'swimlane') as $model) {
|
||||
|
||||
// Skip if optional part has not been selected
|
||||
if (in_array($model, $optional_parts) && ! in_array($model, $part_selection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->$model->duplicate($project_id, $clone_project_id)) {
|
||||
$this->db->cancelTransaction();
|
||||
|
|
@ -82,8 +90,21 @@ class ProjectDuplication extends Base
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
$this->db->closeTransaction();
|
||||
|
||||
//* Clone Tasks if in $part_selection
|
||||
|
||||
if(in_array('task', $part_selection)) {
|
||||
$tasks = $this->taskFinder->getAll($project_id);
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
if (!$this->taskDuplication->duplicateToProject($task['id'], $clone_project_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (int) $clone_project_id;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ class Swimlane extends Base
|
|||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param string $name
|
||||
* @return bool
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function create($project_id, $name)
|
||||
{
|
||||
|
|
@ -412,6 +412,37 @@ class Swimlane extends Base
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate Swimlane to project
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_from Project Template
|
||||
* @param integer $project_to Project that receives the copy
|
||||
* @return integer|boolean
|
||||
*/
|
||||
|
||||
public function duplicate($project_from, $project_to)
|
||||
{
|
||||
$swimlanes = $this->getAll($project_from);
|
||||
|
||||
foreach ($swimlanes as $swimlane) {
|
||||
|
||||
unset($swimlane['id']);
|
||||
$swimlane['project_id'] = $project_to;
|
||||
|
||||
if (! $this->db->table(self::TABLE)->save($swimlane)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$default_swimlane = $this->getDefault($project_from);
|
||||
$default_swimlane['id'] = $project_to;
|
||||
|
||||
$this->updateDefault($default_swimlane);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate creation
|
||||
*
|
||||
|
|
|
|||
|
|
@ -4,11 +4,20 @@
|
|||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info">
|
||||
<?= t('Do you really want to duplicate this project: "%s"?', $project['name']) ?>
|
||||
<?= t('Which parts of the project do you want to duplicate?') ?>
|
||||
</p>
|
||||
<form method="post" action="<?= $this->u('project', 'duplicate', array('project_id' => $project['id'], 'duplicate' => 'yes')) ?>" autocomplete="off">
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->a(t('Yes'), 'project', 'duplicate', array('project_id' => $project['id'], 'duplicate' => 'yes'), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?> <?= $this->a(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
|
||||
</div>
|
||||
<?= $this->formCsrf() ?>
|
||||
|
||||
<?= $this->formCheckbox('category', t('Categories'), 1, true) ?>
|
||||
<?= $this->formCheckbox('action', t('Actions'), 1, true) ?>
|
||||
<?= $this->formCheckbox('swimlane', t('Swimlanes'), 1, true) ?>
|
||||
<?= $this->formCheckbox('task', t('Tasks'), 1, true) ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Duplicate') ?>" class="btn btn-red"/>
|
||||
<?= t('or') ?> <?= $this->a(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -11,6 +11,8 @@ date_default_timezone_set('UTC');
|
|||
|
||||
abstract class Base extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (DB_DRIVER === 'mysql') {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ use Model\Category;
|
|||
use Model\ProjectPermission;
|
||||
use Model\ProjectDuplication;
|
||||
use Model\User;
|
||||
use Model\Swimlane;
|
||||
use Model\Task;
|
||||
use Model\TaskCreation;
|
||||
use Model\Acl;
|
||||
use Model\Board;
|
||||
use Model\TaskFinder;
|
||||
|
||||
class ProjectDuplicationTest extends Base
|
||||
{
|
||||
|
|
@ -203,4 +203,114 @@ class ProjectDuplicationTest extends Base
|
|||
$this->assertEquals('blue', $actions[0]['params'][0]['value']);
|
||||
$this->assertEquals(5, $actions[0]['params'][1]['value']);
|
||||
}
|
||||
|
||||
public function testCloneProjectWithSwimlanesAndTasks()
|
||||
{
|
||||
$p = new Project($this->container);
|
||||
$pd = new ProjectDuplication($this->container);
|
||||
$s = new Swimlane($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'P1')));
|
||||
|
||||
// create initial swimlanes
|
||||
$this->assertEquals(1, $s->create(1, 'S1'));
|
||||
$this->assertEquals(2, $s->create(1, 'S2'));
|
||||
$this->assertEquals(3, $s->create(1, 'S3'));
|
||||
|
||||
$default_swimlane1 = $s->getDefault(1);
|
||||
$default_swimlane1['default_swimlane'] = 'New Default';
|
||||
|
||||
$this->assertTrue($s->updateDefault($default_swimlane1));
|
||||
|
||||
//create initial tasks
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'T1', 'project_id' => 1, 'column_id' => 1, 'owner_id' => 1)));
|
||||
$this->assertEquals(2, $tc->create(array('title' => 'T2', 'project_id' => 1, 'column_id' => 2, 'owner_id' => 1)));
|
||||
$this->assertEquals(3, $tc->create(array('title' => 'T3', 'project_id' => 1, 'column_id' => 3, 'owner_id' => 1)));
|
||||
|
||||
$this->container['dispatcher']->addListener(Task::EVENT_CREATE_UPDATE, function() {});
|
||||
$this->container['dispatcher']->addListener(Task::EVENT_CREATE, function() {});
|
||||
|
||||
$this->assertEquals(2, $pd->duplicate(1, array('category', 'action', 'swimlane', 'task')));
|
||||
|
||||
// Check if Swimlanes have been duplicated
|
||||
$swimlanes = $s->getAll(2);
|
||||
|
||||
$this->assertCount(3, $swimlanes);
|
||||
$this->assertEquals(4, $swimlanes[0]['id']);
|
||||
$this->assertEquals('S1', $swimlanes[0]['name']);
|
||||
$this->assertEquals(5, $swimlanes[1]['id']);
|
||||
$this->assertEquals('S2', $swimlanes[1]['name']);
|
||||
$this->assertEquals(6, $swimlanes[2]['id']);
|
||||
$this->assertEquals('S3', $swimlanes[2]['name']);
|
||||
$this->assertEquals('New Default', $s->getDefault(2)['default_swimlane']);
|
||||
|
||||
// Check if Tasks have been duplicated
|
||||
|
||||
$tasks = $tf->getAll(2);
|
||||
|
||||
$this->assertCount(3, $tasks);
|
||||
$this->assertEquals(4, $tasks[0]['id']);
|
||||
$this->assertEquals('T1', $tasks[0]['title']);
|
||||
$this->assertEquals(5, $tasks[1]['id']);
|
||||
$this->assertEquals('T2', $tasks[1]['title']);
|
||||
$this->assertEquals(6, $tasks[2]['id']);
|
||||
$this->assertEquals('T3', $tasks[2]['title']);
|
||||
|
||||
// Drop project
|
||||
unset($tasks);
|
||||
unset($swimlanes);
|
||||
|
||||
$p->remove(2);
|
||||
|
||||
$this->assertFalse($p->exists(2));
|
||||
$this->assertCount(0, $s->getAll(2));
|
||||
$this->assertCount(0, $tf->getAll(2));
|
||||
|
||||
// Check duplication with Swimlanes only
|
||||
$this->assertEquals(2, $pd->duplicate(1, array('category', 'action', 'swimlane')));
|
||||
|
||||
// Check if Swimlanes have been duplicated
|
||||
$swimlanes = $s->getAll(2);
|
||||
|
||||
$this->assertCount(3, $swimlanes);
|
||||
$this->assertEquals(4, $swimlanes[0]['id']);
|
||||
$this->assertEquals('S1', $swimlanes[0]['name']);
|
||||
$this->assertEquals(5, $swimlanes[1]['id']);
|
||||
$this->assertEquals('S2', $swimlanes[1]['name']);
|
||||
$this->assertEquals(6, $swimlanes[2]['id']);
|
||||
$this->assertEquals('S3', $swimlanes[2]['name']);
|
||||
$this->assertEquals('New Default', $s->getDefault(2)['default_swimlane']);
|
||||
|
||||
// Check if Tasks have NOT been duplicated
|
||||
$this->assertCount(0, $tf->getAll(2));
|
||||
|
||||
// Drop project
|
||||
unset($tasks);
|
||||
unset($swimlanes);
|
||||
|
||||
$p->remove(2);
|
||||
|
||||
$this->assertFalse($p->exists(2));
|
||||
$this->assertCount(0, $s->getAll(2));
|
||||
$this->assertCount(0, $tf->getAll(2));
|
||||
|
||||
// Check duplication with Tasks only
|
||||
$this->assertEquals(2, $pd->duplicate(1, array('category', 'action', 'task')));
|
||||
|
||||
// Check if Swimlanes have NOT been duplicated
|
||||
$this->assertCount(0, $s->getAll(2));
|
||||
|
||||
// Check if Tasks have been duplicated
|
||||
$tasks = $tf->getAll(2);
|
||||
|
||||
$this->assertCount(3, $tasks);
|
||||
$this->assertEquals(4, $tasks[0]['id']);
|
||||
$this->assertEquals('T1', $tasks[0]['title']);
|
||||
$this->assertEquals(5, $tasks[1]['id']);
|
||||
$this->assertEquals('T2', $tasks[1]['title']);
|
||||
$this->assertEquals(6, $tasks[2]['id']);
|
||||
$this->assertEquals('T3', $tasks[2]['title']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -375,4 +375,34 @@ class SwimlaneTest extends Base
|
|||
$this->assertEquals(0, $swimlane['is_active']);
|
||||
$this->assertEquals(0, $swimlane['position']);
|
||||
}
|
||||
|
||||
public function testDuplicateSwimlane()
|
||||
{
|
||||
$p = new Project($this->container);
|
||||
$s = new Swimlane($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'P1')));
|
||||
$this->assertEquals(2, $p->create(array('name' => 'P2')));
|
||||
$this->assertEquals(1, $s->create(1, 'S1'));
|
||||
$this->assertEquals(2, $s->create(1, 'S2'));
|
||||
$this->assertEquals(3, $s->create(1, 'S3'));
|
||||
|
||||
$default_swimlane1 = $s->getDefault(1);
|
||||
$default_swimlane1['default_swimlane'] = 'New Default';
|
||||
|
||||
$this->assertTrue($s->updateDefault($default_swimlane1));
|
||||
|
||||
$this->assertTrue($s->duplicate(1, 2));
|
||||
|
||||
$swimlanes = $s->getAll(2);
|
||||
|
||||
$this->assertCount(3, $swimlanes);
|
||||
$this->assertEquals(4, $swimlanes[0]['id']);
|
||||
$this->assertEquals('S1', $swimlanes[0]['name']);
|
||||
$this->assertEquals(5, $swimlanes[1]['id']);
|
||||
$this->assertEquals('S2', $swimlanes[1]['name']);
|
||||
$this->assertEquals(6, $swimlanes[2]['id']);
|
||||
$this->assertEquals('S3', $swimlanes[2]['name']);
|
||||
$this->assertEquals('New Default', $s->getDefault(2)['default_swimlane']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue