From e5ea36125536b5ac8f8a7e31c2602e9bd1b52075 Mon Sep 17 00:00:00 2001 From: Michael Lüpkes Date: Tue, 3 Feb 2015 11:16:10 +0100 Subject: 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'. --- app/Controller/Project.php | 8 +-- app/Model/Base.php | 1 + app/Model/ProjectDuplication.php | 27 +++++++- app/Model/Swimlane.php | 33 +++++++++- app/Template/project/duplicate.php | 19 ++++-- tests/units/Base.php | 2 + tests/units/ProjectDuplicationTest.php | 114 ++++++++++++++++++++++++++++++++- tests/units/SwimlaneTest.php | 30 +++++++++ 8 files changed, 218 insertions(+), 16 deletions(-) diff --git a/app/Controller/Project.php b/app/Controller/Project.php index 8178ab5f..842ed6e8 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -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.')); diff --git a/app/Model/Base.php b/app/Model/Base.php index 785785a7..e29588a2 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -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 diff --git a/app/Model/ProjectDuplication.php b/app/Model/ProjectDuplication.php index 11a606d7..5adc1b4c 100644 --- a/app/Model/ProjectDuplication.php +++ b/app/Model/ProjectDuplication.php @@ -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; } } diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php index 71b95ae9..c9bc43e1 100644 --- a/app/Model/Swimlane.php +++ b/app/Model/Swimlane.php @@ -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 * diff --git a/app/Template/project/duplicate.php b/app/Template/project/duplicate.php index fc704b1e..b6184220 100644 --- a/app/Template/project/duplicate.php +++ b/app/Template/project/duplicate.php @@ -4,11 +4,20 @@

- +

+
-
- a(t('Yes'), 'project', 'duplicate', array('project_id' => $project['id'], 'duplicate' => 'yes'), true, 'btn btn-red') ?> - a(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?> -
+ formCsrf() ?> + + formCheckbox('category', t('Categories'), 1, true) ?> + formCheckbox('action', t('Actions'), 1, true) ?> + formCheckbox('swimlane', t('Swimlanes'), 1, true) ?> + formCheckbox('task', t('Tasks'), 1, true) ?> + +
+ + a(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?> +
+
\ No newline at end of file diff --git a/tests/units/Base.php b/tests/units/Base.php index b216aff4..311d3cdf 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -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') { diff --git a/tests/units/ProjectDuplicationTest.php b/tests/units/ProjectDuplicationTest.php index ab50b9f1..9ddc8f89 100644 --- a/tests/units/ProjectDuplicationTest.php +++ b/tests/units/ProjectDuplicationTest.php @@ -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']); + } } diff --git a/tests/units/SwimlaneTest.php b/tests/units/SwimlaneTest.php index bda0f590..0694f08a 100644 --- a/tests/units/SwimlaneTest.php +++ b/tests/units/SwimlaneTest.php @@ -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']); + } } -- cgit v1.2.3 From 644f511df286aa2ef032fc8d4361df654ea71968 Mon Sep 17 00:00:00 2001 From: Michael Lüpkes Date: Tue, 3 Feb 2015 11:28:38 +0100 Subject: Fix for syntax unsupported in PHP 5.3 --- tests/units/ProjectDuplicationTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/units/ProjectDuplicationTest.php b/tests/units/ProjectDuplicationTest.php index 9ddc8f89..bb8e0408 100644 --- a/tests/units/ProjectDuplicationTest.php +++ b/tests/units/ProjectDuplicationTest.php @@ -244,7 +244,8 @@ class ProjectDuplicationTest extends Base $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']); + $new_default = $s->getDefault(2); + $this->assertEquals('New Default', $new_default['default_swimlane']); // Check if Tasks have been duplicated @@ -261,6 +262,7 @@ class ProjectDuplicationTest extends Base // Drop project unset($tasks); unset($swimlanes); + unset($new_default); $p->remove(2); @@ -281,7 +283,8 @@ class ProjectDuplicationTest extends Base $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']); + $new_default = $s->getDefault(2); + $this->assertEquals('New Default', $new_default['default_swimlane']); // Check if Tasks have NOT been duplicated $this->assertCount(0, $tf->getAll(2)); @@ -289,6 +292,7 @@ class ProjectDuplicationTest extends Base // Drop project unset($tasks); unset($swimlanes); + unset($new_default); $p->remove(2); -- cgit v1.2.3 From 4bf6e6d5c4efe811f722aeccbc8dfa02426772ec Mon Sep 17 00:00:00 2001 From: Michael Lüpkes Date: Tue, 3 Feb 2015 11:32:51 +0100 Subject: Another fix for 5.3 syntax (see above) --- tests/units/SwimlaneTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/units/SwimlaneTest.php b/tests/units/SwimlaneTest.php index 0694f08a..37226613 100644 --- a/tests/units/SwimlaneTest.php +++ b/tests/units/SwimlaneTest.php @@ -403,6 +403,7 @@ class SwimlaneTest extends Base $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']); + $new_default = $s->getDefault(2); + $this->assertEquals('New Default', $new_default['default_swimlane']); } } -- cgit v1.2.3