When creating a new project, have the possibility to select another project to duplicate

This commit is contained in:
Frederic Guillot 2016-01-31 17:46:19 -05:00
parent 1500ff92b2
commit fc21d3873e
30 changed files with 694 additions and 342 deletions

View File

@ -10,6 +10,7 @@ Breaking changes:
New features:
* When creating a new project, have the possibility to select another project to duplicate
* Add a "Me" button to assignee form element
* Add external links for tasks with plugin api
* Add project owner (Directly Responsible Individual)

View File

@ -1,6 +1,6 @@
BUILD_DIR = /tmp
CSS_APP = $(addprefix assets/css/src/, $(addsuffix .css, base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown screenshot filters gantt))
CSS_APP = $(addprefix assets/css/src/, $(addsuffix .css, base links title table form button alert tooltip header board task comment subtask markdown listing activity dashboard pagination popover confirm sidebar responsive dropdown screenshot filters gantt project))
CSS_PRINT = $(addprefix assets/css/src/, $(addsuffix .css, print links table board task comment subtask markdown))
CSS_VENDOR = $(addprefix assets/css/vendor/, $(addsuffix .css, jquery-ui.min jquery-ui-timepicker-addon.min chosen.min fullcalendar.min font-awesome.min c3.min))

View File

@ -11,18 +11,19 @@ use Symfony\Component\Console\Command\Command;
* @package console
* @author Frederic Guillot
*
* @property \Kanboard\Model\Notification $notification
* @property \Kanboard\Model\Project $project
* @property \Kanboard\Model\ProjectPermission $projectPermission
* @property \Kanboard\Model\ProjectAnalytic $projectAnalytic
* @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
* @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
* @property \Kanboard\Model\SubtaskExport $subtaskExport
* @property \Kanboard\Model\OverdueNotification $overdueNotification
* @property \Kanboard\Model\Task $task
* @property \Kanboard\Model\TaskExport $taskExport
* @property \Kanboard\Model\TaskFinder $taskFinder
* @property \Kanboard\Model\Transition $transition
* @property \Kanboard\Model\Notification $notification
* @property \Kanboard\Model\Project $project
* @property \Kanboard\Model\ProjectPermission $projectPermission
* @property \Kanboard\Model\ProjectAnalytic $projectAnalytic
* @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
* @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
* @property \Kanboard\Model\SubtaskExport $subtaskExport
* @property \Kanboard\Model\OverdueNotification $overdueNotification
* @property \Kanboard\Model\Task $task
* @property \Kanboard\Model\TaskExport $taskExport
* @property \Kanboard\Model\TaskFinder $taskFinder
* @property \Kanboard\Model\Transition $transition
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
*/
abstract class Base extends Command
{

View File

@ -171,14 +171,15 @@ class Project extends Base
$project = $this->getProject();
if ($this->request->getStringParam('duplicate') === 'yes') {
$values = array_keys($this->request->getValues());
if ($this->projectDuplication->duplicate($project['id'], $values) !== false) {
$project_id = $this->projectDuplication->duplicate($project['id'], array_keys($this->request->getValues()), $this->userSession->getId());
if ($project_id !== false) {
$this->flash->success(t('Project cloned successfully.'));
} else {
$this->flash->failure(t('Unable to clone this project.'));
}
$this->response->redirect($this->helper->url->to('project', 'index'));
$this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id)));
}
$this->response->html($this->projectLayout('project/duplicate', array(
@ -240,57 +241,4 @@ class Project extends Base
'title' => t('Project activation')
)));
}
/**
* Display a form to create a new project
*
* @access public
*/
public function create(array $values = array(), array $errors = array())
{
$is_private = isset($values['is_private']) && $values['is_private'] == 1;
$this->response->html($this->template->layout('project/new', array(
'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'values' => $values,
'errors' => $errors,
'is_private' => $is_private,
'title' => $is_private ? t('New private project') : t('New project'),
)));
}
/**
* Display a form to create a private project
*
* @access public
*/
public function createPrivate(array $values = array(), array $errors = array())
{
$values['is_private'] = 1;
$this->create($values, $errors);
}
/**
* Validate and save a new project
*
* @access public
*/
public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->projectValidator->validateCreation($values);
if ($valid) {
$project_id = $this->project->create($values, $this->userSession->getId(), true);
if ($project_id > 0) {
$this->flash->success(t('Your project have been created successfully.'));
$this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id)));
}
$this->flash->failure(t('Unable to create your project.'));
}
$this->create($values, $errors);
}
}

View File

@ -0,0 +1,126 @@
<?php
namespace Kanboard\Controller;
/**
* Project Creation Controller
*
* @package controller
* @author Frederic Guillot
*/
class ProjectCreation extends Base
{
/**
* Display a form to create a new project
*
* @access public
*/
public function create(array $values = array(), array $errors = array())
{
$is_private = isset($values['is_private']) && $values['is_private'] == 1;
$projects_list = array(0 => t('Do not duplicate anything')) + $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$this->response->html($this->template->layout('project_creation/create', array(
'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'values' => $values,
'errors' => $errors,
'is_private' => $is_private,
'projects_list' => $projects_list,
'title' => $is_private ? t('New private project') : t('New project'),
)));
}
/**
* Display a form to create a private project
*
* @access public
*/
public function createPrivate(array $values = array(), array $errors = array())
{
$values['is_private'] = 1;
$this->create($values, $errors);
}
/**
* Validate and save a new project
*
* @access public
*/
public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->projectValidator->validateCreation($values);
if ($valid) {
$project_id = $this->createOrDuplicate($values);
if ($project_id > 0) {
$this->flash->success(t('Your project have been created successfully.'));
return $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id)));
}
$this->flash->failure(t('Unable to create your project.'));
}
$this->create($values, $errors);
}
/**
* Create or duplicate a project
*
* @access private
* @param array $values
* @return boolean|integer
*/
private function createOrDuplicate(array $values)
{
if ($values['src_project_id'] == 0) {
return $this->createNewProject($values);
}
return $this->duplicateNewProject($values);
}
/**
* Save a new project
*
* @access private
* @param array $values
* @return boolean|integer
*/
private function createNewProject(array $values)
{
$project = array(
'name' => $values['name'],
'is_private' => $values['is_private'],
);
return $this->project->create($project, $this->userSession->getId(), true);
}
/**
* Creatte from another project
*
* @access private
* @param array $values
* @return boolean|integer
*/
private function duplicateNewProject(array $values)
{
$selection = array();
foreach ($this->projectDuplication->getOptionalSelection() as $item) {
if (isset($values[$item]) && $values[$item] == 1) {
$selection[] = $item;
}
}
return $this->projectDuplication->duplicate(
$values['src_project_id'],
$selection,
$this->userSession->getId(),
$values['name'],
$values['is_private'] == 1
);
}
}

View File

@ -89,11 +89,11 @@ class ProjectEdit extends Base
{
if ($redirect === 'edit') {
if (isset($values['is_private'])) {
if (! $this->helper->user->hasProjectAccess('project', 'create', $project['id'])) {
if (! $this->helper->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])) {
unset($values['is_private']);
}
} elseif ($project['is_private'] == 1 && ! isset($values['is_private'])) {
if ($this->helper->user->hasProjectAccess('project', 'create', $project['id'])) {
if ($this->helper->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])) {
$values += array('is_private' => 0);
}
}

View File

@ -12,6 +12,24 @@ use Kanboard\Core\Security\Role;
*/
class ProjectPermission extends Base
{
/**
* Permissions are only available for team projects
*
* @access protected
* @param integer $project_id Default project id
* @return array
*/
protected function getProject($project_id = 0)
{
$project = parent::getProject($project_id);
if ($project['is_private'] == 1) {
$this->forbidden();
}
return $project;
}
/**
* Show all permissions
*
@ -62,6 +80,7 @@ class ProjectPermission extends Base
*/
public function addUser()
{
$project = $this->getProject();
$values = $this->request->getValues();
if ($this->projectUserRole->addUser($values['project_id'], $values['user_id'], $values['role'])) {
@ -70,7 +89,7 @@ class ProjectPermission extends Base
$this->flash->failure(t('Unable to update this project.'));
}
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $values['project_id'])));
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id'])));
}
/**
@ -81,19 +100,16 @@ class ProjectPermission extends Base
public function removeUser()
{
$this->checkCSRFParam();
$project = $this->getProject();
$user_id = $this->request->getIntegerParam('user_id');
$values = array(
'project_id' => $this->request->getIntegerParam('project_id'),
'user_id' => $this->request->getIntegerParam('user_id'),
);
if ($this->projectUserRole->removeUser($values['project_id'], $values['user_id'])) {
if ($this->projectUserRole->removeUser($project['id'], $user_id)) {
$this->flash->success(t('Project updated successfully.'));
} else {
$this->flash->failure(t('Unable to update this project.'));
}
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $values['project_id'])));
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id'])));
}
/**
@ -103,10 +119,10 @@ class ProjectPermission extends Base
*/
public function changeUserRole()
{
$project_id = $this->request->getIntegerParam('project_id');
$project = $this->getProject();
$values = $this->request->getJson();
if (! empty($project_id) && ! empty($values) && $this->projectUserRole->changeUserRole($project_id, $values['id'], $values['role'])) {
if (! empty($project) && ! empty($values) && $this->projectUserRole->changeUserRole($project['id'], $values['id'], $values['role'])) {
$this->response->json(array('status' => 'ok'));
} else {
$this->response->json(array('status' => 'error'));
@ -120,19 +136,20 @@ class ProjectPermission extends Base
*/
public function addGroup()
{
$project = $this->getProject();
$values = $this->request->getValues();
if (empty($values['group_id']) && ! empty($values['external_id'])) {
$values['group_id'] = $this->group->create($values['name'], $values['external_id']);
}
if ($this->projectGroupRole->addGroup($values['project_id'], $values['group_id'], $values['role'])) {
if ($this->projectGroupRole->addGroup($project['id'], $values['group_id'], $values['role'])) {
$this->flash->success(t('Project updated successfully.'));
} else {
$this->flash->failure(t('Unable to update this project.'));
}
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $values['project_id'])));
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id'])));
}
/**
@ -143,19 +160,16 @@ class ProjectPermission extends Base
public function removeGroup()
{
$this->checkCSRFParam();
$project = $this->getProject();
$group_id = $this->request->getIntegerParam('group_id');
$values = array(
'project_id' => $this->request->getIntegerParam('project_id'),
'group_id' => $this->request->getIntegerParam('group_id'),
);
if ($this->projectGroupRole->removeGroup($values['project_id'], $values['group_id'])) {
if ($this->projectGroupRole->removeGroup($project['id'], $group_id)) {
$this->flash->success(t('Project updated successfully.'));
} else {
$this->flash->failure(t('Unable to update this project.'));
}
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $values['project_id'])));
$this->response->redirect($this->helper->url->to('ProjectPermission', 'index', array('project_id' => $project['id'])));
}
/**
@ -165,10 +179,10 @@ class ProjectPermission extends Base
*/
public function changeGroupRole()
{
$project_id = $this->request->getIntegerParam('project_id');
$project = $this->getProject();
$values = $this->request->getJson();
if (! empty($project_id) && ! empty($values) && $this->projectGroupRole->changeGroupRole($project_id, $values['id'], $values['role'])) {
if (! empty($project) && ! empty($values) && $this->projectGroupRole->changeGroupRole($project['id'], $values['id'], $values['role'])) {
$this->response->json(array('status' => 'ok'));
} else {
$this->response->json(array('status' => 'error'));

View File

@ -109,7 +109,7 @@ class Taskduplication extends Base
private function chooseDestination(array $task, $template)
{
$values = array();
$projects_list = $this->projectUserRole->getProjectsByUser($this->userSession->getId(), array(ProjectModel::ACTIVE));
$projects_list = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
unset($projects_list[$task['project_id']]);

View File

@ -120,8 +120,6 @@ class ExternalLinkManager extends Base
*/
public function find()
{
$provider = null;
if ($this->userInputType === self::TYPE_AUTO) {
$provider = $this->findProvider();
} else {

View File

@ -2,6 +2,8 @@
namespace Kanboard\Model;
use Kanboard\Core\Security\Role;
/**
* Project Duplication
*
@ -11,6 +13,28 @@ namespace Kanboard\Model;
*/
class ProjectDuplication extends Base
{
/**
* Get list of optional models to duplicate
*
* @access public
* @return array
*/
public function getOptionalSelection()
{
return array('category', 'projectPermission', 'action', 'swimlane', 'task');
}
/**
* Get list of all possible models to duplicate
*
* @access public
* @return array
*/
public function getPossibleSelection()
{
return array('board', 'category', 'projectPermission', 'action', 'swimlane', 'task');
}
/**
* Get a valid project name for the duplication
*
@ -30,79 +54,107 @@ class ProjectDuplication extends Base
return $name.$suffix;
}
/**
* Clone a project with all settings
*
* @param integer $src_project_id Project Id
* @param array $selection Selection of optional project parts to duplicate
* @param integer $owner_id Owner of the project
* @param string $name Name of the project
* @param boolean $private Force the project to be private
* @return integer Cloned Project Id
*/
public function duplicate($src_project_id, $selection = array('projectPermission', 'category', 'action'), $owner_id = 0, $name = null, $private = null)
{
$this->db->startTransaction();
// Get the cloned project Id
$dst_project_id = $this->copy($src_project_id, $owner_id, $name, $private);
if (! $dst_project_id) {
$this->db->cancelTransaction();
return false;
}
// Clone Columns, Categories, Permissions and Actions
foreach ($this->getPossibleSelection() as $model) {
// Skip if optional part has not been selected
if (in_array($model, $this->getOptionalSelection()) && ! in_array($model, $selection)) {
continue;
}
// Skip permissions for private projects
if ($private && $model === 'projectPermission') {
continue;
}
if (! $this->$model->duplicate($src_project_id, $dst_project_id)) {
$this->db->cancelTransaction();
return false;
}
}
if (! $this->makeOwnerManager($dst_project_id, $owner_id)) {
$this->db->cancelTransaction();
return false;
}
$this->db->closeTransaction();
return (int) $dst_project_id;
}
/**
* Create a project from another one
*
* @param integer $project_id Project Id
* @return integer Cloned Project Id
* @access private
* @param integer $src_project_id
* @param integer $owner_id
* @param string $name
* @param boolean $private
* @return integer
*/
public function copy($project_id)
private function copy($src_project_id, $owner_id = 0, $name = null, $private = null)
{
$project = $this->project->getById($project_id);
$project = $this->project->getById($src_project_id);
$is_private = empty($project['is_private']) ? 0 : 1;
$values = array(
'name' => $this->getClonedProjectName($project['name']),
'is_active' => true,
'last_modified' => 0,
'name' => $name ?: $this->getClonedProjectName($project['name']),
'is_active' => 1,
'last_modified' => time(),
'token' => '',
'is_public' => 0,
'is_private' => empty($project['is_private']) ? 0 : 1,
'is_private' => $private ? 1 : $is_private,
'owner_id' => $owner_id,
);
if (! $this->db->table(Project::TABLE)->save($values)) {
return 0;
return false;
}
return $this->db->getLastId();
}
/**
* Clone a project with all settings
* Make sure that the creator of the duplicated project is alsp owner
*
* @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
* @access private
* @param integer $dst_project_id
* @param integer $owner_id
* @return boolean
*/
public function duplicate($project_id, $part_selection = array('category', 'action'))
private function makeOwnerManager($dst_project_id, $owner_id)
{
$this->db->startTransaction();
if ($owner_id > 0) {
$this->projectUserRole->removeUser($dst_project_id, $owner_id);
// Get the cloned project Id
$clone_project_id = $this->copy($project_id);
if (! $clone_project_id) {
$this->db->cancelTransaction();
return false;
}
// 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();
if (! $this->projectUserRole->addUser($dst_project_id, $owner_id, Role::PROJECT_MANAGER)) {
return false;
}
}
$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;
return true;
}
}

View File

@ -199,4 +199,25 @@ class Task extends Base
return round(($position * 100) / count($columns), 1);
}
/**
* Helper method to duplicate all tasks to another project
*
* @access public
* @param integer $src_project_id
* @param integer $dst_project_id
* @return boolean
*/
public function duplicate($src_project_id, $dst_project_id)
{
$task_ids = $this->taskFinder->getAllIds($src_project_id, array(Task::STATUS_OPEN, Task::STATUS_CLOSED));
foreach ($task_ids as $task_id) {
if (! $this->taskDuplication->duplicateToProject($task_id, $dst_project_id)) {
return false;
}
}
return true;
}
}

View File

@ -179,6 +179,23 @@ class TaskFinder extends Base
->findAll();
}
/**
* Get all tasks for a given project and status
*
* @access public
* @param integer $project_id
* @param array $status
* @return array
*/
public function getAllIds($project_id, array $status = array(Task::STATUS_OPEN))
{
return $this->db
->table(Task::TABLE)
->eq(Task::TABLE.'.project_id', $project_id)
->in(Task::TABLE.'.is_active', $status)
->findAllByColumn('id');
}
/**
* Get overdue tasks query
*

View File

@ -128,8 +128,7 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('Gantt', array('projects', 'saveProjectDate'), Role::APP_MANAGER);
$acl->add('Group', '*', Role::APP_ADMIN);
$acl->add('Link', '*', Role::APP_ADMIN);
$acl->add('Project', array('users', 'allowEverybody', 'allow', 'role', 'revoke', 'create'), Role::APP_MANAGER);
$acl->add('ProjectPermission', '*', Role::APP_USER);
$acl->add('ProjectCreation', 'create', Role::APP_MANAGER);
$acl->add('Projectuser', '*', Role::APP_MANAGER);
$acl->add('Twofactor', 'disable', Role::APP_ADMIN);
$acl->add('UserImport', '*', Role::APP_ADMIN);

View File

@ -43,10 +43,12 @@ class RouteProvider implements ServiceProviderInterface
$container['route']->addRoute('search', 'search', 'index');
$container['route']->addRoute('search/:search', 'search', 'index');
// ProjectCreation routes
$container['route']->addRoute('project/create', 'ProjectCreation', 'create');
$container['route']->addRoute('project/create/private', 'ProjectCreation', 'createPrivate');
// Project routes
$container['route']->addRoute('projects', 'project', 'index');
$container['route']->addRoute('project/create', 'project', 'create');
$container['route']->addRoute('project/create/private', 'project', 'createPrivate');
$container['route']->addRoute('project/:project_id', 'project', 'show');
$container['route']->addRoute('p/:project_id', 'project', 'show');
$container['route']->addRoute('project/:project_id/customer-filter', 'customfilter', 'index');

View File

@ -1,15 +1,15 @@
<section id="main">
<div class="page-header page-header-mobile">
<ul>
<?php if ($this->user->hasAccess('project', 'create')): ?>
<?php if ($this->user->hasAccess('ProjectCreation', 'create')): ?>
<li>
<i class="fa fa-plus fa-fw"></i>
<?= $this->url->link(t('New project'), 'project', 'create') ?>
<?= $this->url->link(t('New project'), 'ProjectCreation', 'create') ?>
</li>
<?php endif ?>
<li>
<i class="fa fa-lock fa-fw"></i>
<?= $this->url->link(t('New private project'), 'project', 'createPrivate') ?>
<?= $this->url->link(t('New private project'), 'ProjectCreation', 'createPrivate') ?>
</li>
<li>
<i class="fa fa-search fa-fw"></i>

View File

@ -1,12 +1,6 @@
<section id="main">
<div class="page-header">
<ul>
<?php if ($this->user->hasAccess('project', 'create')): ?>
<li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'project', 'create') ?></li>
<?php endif ?>
<li>
<i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'project', 'create', array('private' => 1)) ?>
</li>
<li>
<i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('Projects list'), 'project', 'index') ?>
</li>

View File

@ -31,14 +31,26 @@
</select>
</li>
<?php endif ?>
<li>
<li class="user-links">
<?php if ($this->user->hasNotifications()): ?>
<span class="notification">
<?= $this->url->link('<i class="fa fa-bell web-notification-icon"></i>', 'app', 'notifications', array('user_id' => $this->user->getId()), false, '', t('Unread notifications')) ?>
</span>
<?php endif ?>
<span class="dropdown">
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-plus fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<?php if ($this->user->hasAccess('ProjectCreation', 'create')): ?>
<li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'ProjectCreation', 'create') ?></li>
<?php endif ?>
<li>
<i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'ProjectCreation', 'createPrivate') ?>
</li>
</ul>
</div>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-user fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li class="no-hover"><strong><?= $this->e($this->user->getFullname()) ?></strong></li>
@ -46,7 +58,7 @@
<li><?= $this->url->link(t('My profile'), 'user', 'show', array('user_id' => $this->user->getId())) ?></li>
<li><?= $this->url->link(t('Logout'), 'auth', 'logout') ?></li>
</ul>
</span>
</div>
</li>
</ul>
</nav>

View File

@ -10,13 +10,17 @@
<?= $this->form->csrf() ?>
<?php if ($project['is_private'] == 0): ?>
<?= $this->form->checkbox('projectPermission', t('Permissions'), 1, true) ?>
<?php endif ?>
<?= $this->form->checkbox('category', t('Categories'), 1, true) ?>
<?= $this->form->checkbox('action', t('Actions'), 1, true) ?>
<?= $this->form->checkbox('swimlane', t('Swimlanes'), 1, false) ?>
<?= $this->form->checkbox('task', t('Tasks'), 1, false) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Duplicate') ?>" class="btn btn-red"/>
<input type="submit" value="<?= t('Duplicate') ?>" class="btn btn-red">
<?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
</div>
</form>

View File

@ -1,10 +1,6 @@
<section id="main">
<div class="page-header">
<ul>
<?php if ($this->user->hasAccess('project', 'create')): ?>
<li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'project', 'create') ?></li>
<?php endif ?>
<li><i class="fa fa-lock fa-fw"></i><?= $this->url->link(t('New private project'), 'project', 'createPrivate') ?></li>
<?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
<li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'projectuser', 'managers') ?></li>
<?php endif ?>

View File

@ -1,24 +0,0 @@
<section id="main">
<div class="page-header">
<ul>
<li><i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('All projects'), 'project', 'index') ?></li>
</ul>
</div>
<form method="post" action="<?= $this->url->href('project', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('is_private', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
<?= t('or') ?> <?= $this->url->link(t('cancel'), 'project', 'index') ?>
</div>
</form>
<?php if (isset($is_private) && $is_private): ?>
<div class="alert alert-info">
<p><?= t('There is no user management for private projects.') ?></p>
</div>
<?php endif ?>
</section>

View File

@ -0,0 +1,42 @@
<section id="main">
<div class="page-header">
<ul>
<li><i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('All projects'), 'project', 'index') ?></li>
</ul>
</div>
<form class="form-popover" id="project-creation-form" method="post" action="<?= $this->url->href('ProjectCreation', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('is_private', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
<?php if (count($projects_list) > 1): ?>
<?= $this->form->label(t('Create from another project'), 'src_project_id') ?>
<?= $this->form->select('src_project_id', $projects_list, $values) ?>
<?php endif ?>
<div class="project-creation-options" <?= isset($values['src_project_id']) && $values['src_project_id'] > 0 ? '' : 'style="display: none"' ?>>
<p class="alert"><?= t('Which parts of the project do you want to duplicate?') ?></p>
<?php if (! $is_private): ?>
<?= $this->form->checkbox('projectPermission', t('Permissions'), 1, true) ?>
<?php endif ?>
<?= $this->form->checkbox('category', t('Categories'), 1, true) ?>
<?= $this->form->checkbox('action', t('Actions'), 1, true) ?>
<?= $this->form->checkbox('swimlane', t('Swimlanes'), 1, true) ?>
<?= $this->form->checkbox('task', t('Tasks'), 1, false) ?>
</div>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue">
</div>
</form>
<?php if ($is_private): ?>
<div class="alert alert-info">
<p><?= t('There is no user management for private projects.') ?></p>
</div>
<?php endif ?>
</section>

View File

@ -24,7 +24,7 @@
<?= $this->form->select('owner_id', $owners, $values, $errors) ?>
</div>
<?php if ($this->user->hasProjectAccess('project', 'create', $project['id'])): ?>
<?php if ($this->user->hasProjectAccess('ProjectCreation', 'create', $project['id'])): ?>
<hr>
<?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
<p class="form-help"><?= t('Private projects do not have users and groups management.') ?></p>

View File

@ -1,13 +1,6 @@
<section id="main">
<div class="page-header">
<ul>
<?php if ($this->user->hasAccess('project', 'create')): ?>
<li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New project'), 'project', 'create') ?></li>
<?php endif ?>
<li>
<i class="fa fa-lock fa-fw"></i>
<?= $this->url->link(t('New private project'), 'project', 'create', array('private' => 1)) ?>
</li>
<li>
<i class="fa fa-folder fa-fw"></i>
<?= $this->url->link(t('Projects list'), 'project', 'index') ?>

File diff suppressed because one or more lines are too long

View File

@ -55,6 +55,11 @@ nav .active a {
color: #d40000;
}
/* user links on the left */
header .user-links .dropdown {
margin-left: 15px;
}
/* title tooltip */
header h1 .tooltip {
opacity: 0.3;

View File

@ -0,0 +1,8 @@
.project-creation-options {
max-width: 500px;
border-left: 3px dotted #efefef;
margin-top: 20px;
padding-left: 15px;
padding-bottom: 5px;
padding-top: 5px;
}

File diff suppressed because one or more lines are too long

View File

@ -15,4 +15,14 @@ Project.prototype.listen = function() {
})
});
});
$('#project-creation-form #form-src_project_id').on('change', function() {
var srcProjectId = $(this).val();
if (srcProjectId == 0) {
$(".project-creation-options").hide();
} else {
$(".project-creation-options").show();
}
});
};

View File

@ -36,8 +36,8 @@ class UserHelperTest extends Base
);
$this->assertTrue($helper->hasAccess('user', 'create'));
$this->assertTrue($helper->hasAccess('project', 'create'));
$this->assertTrue($helper->hasAccess('project', 'createPrivate'));
$this->assertTrue($helper->hasAccess('ProjectCreation', 'create'));
$this->assertTrue($helper->hasAccess('ProjectCreation', 'createPrivate'));
}
public function testHasAccessForManagers()
@ -50,8 +50,8 @@ class UserHelperTest extends Base
);
$this->assertFalse($helper->hasAccess('user', 'create'));
$this->assertTrue($helper->hasAccess('project', 'create'));
$this->assertTrue($helper->hasAccess('project', 'createPrivate'));
$this->assertTrue($helper->hasAccess('ProjectCreation', 'create'));
$this->assertTrue($helper->hasAccess('ProjectCreation', 'createPrivate'));
}
public function testHasAccessForUsers()
@ -64,8 +64,8 @@ class UserHelperTest extends Base
);
$this->assertFalse($helper->hasAccess('user', 'create'));
$this->assertFalse($helper->hasAccess('project', 'create'));
$this->assertTrue($helper->hasAccess('project', 'createPrivate'));
$this->assertFalse($helper->hasAccess('ProjectCreation', 'create'));
$this->assertTrue($helper->hasAccess('ProjectCreation', 'createPrivate'));
}
public function testHasProjectAccessForAdmins()

View File

@ -6,8 +6,11 @@ use Kanboard\Model\Action;
use Kanboard\Model\Project;
use Kanboard\Model\Category;
use Kanboard\Model\ProjectUserRole;
use Kanboard\Model\ProjectGroupRole;
use Kanboard\Model\ProjectDuplication;
use Kanboard\Model\User;
use Kanboard\Model\Group;
use Kanboard\Model\GroupMember;
use Kanboard\Model\Swimlane;
use Kanboard\Model\Task;
use Kanboard\Model\TaskCreation;
@ -16,7 +19,14 @@ use Kanboard\Core\Security\Role;
class ProjectDuplicationTest extends Base
{
public function testProjectName()
public function testGetSelections()
{
$projectDuplicationModel = new ProjectDuplication($this->container);
$this->assertCount(5, $projectDuplicationModel->getOptionalSelection());
$this->assertCount(6, $projectDuplicationModel->getPossibleSelection());
}
public function testGetClonedProjectName()
{
$pd = new ProjectDuplication($this->container);
@ -29,19 +39,6 @@ class ProjectDuplicationTest extends Base
$this->assertEquals(str_repeat('a', 42).' (Clone)', $pd->getClonedProjectName(str_repeat('a', 60)));
}
public function testCopyProjectWithLongName()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(1, $p->create(array('name' => str_repeat('a', 50))));
$this->assertEquals(2, $pd->duplicate(1));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals(str_repeat('a', 42).' (Clone)', $project['name']);
}
public function testClonePublicProject()
{
$p = new Project($this->container);
@ -53,8 +50,10 @@ class ProjectDuplicationTest extends Base
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Public (Clone)', $project['name']);
$this->assertEquals(1, $project['is_active']);
$this->assertEquals(0, $project['is_private']);
$this->assertEquals(0, $project['is_public']);
$this->assertEquals(0, $project['owner_id']);
$this->assertEmpty($project['token']);
}
@ -62,6 +61,7 @@ class ProjectDuplicationTest extends Base
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$pp = new ProjectUserRole($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Private', 'is_private' => 1), 1, true));
$this->assertEquals(2, $pd->duplicate(1));
@ -69,14 +69,112 @@ class ProjectDuplicationTest extends Base
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Private (Clone)', $project['name']);
$this->assertEquals(1, $project['is_active']);
$this->assertEquals(1, $project['is_private']);
$this->assertEquals(0, $project['is_public']);
$this->assertEquals(0, $project['owner_id']);
$this->assertEmpty($project['token']);
$pp = new ProjectUserRole($this->container);
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 1));
}
$this->assertEquals(array(1 => 'admin'), $pp->getAssignableUsers(1));
$this->assertEquals(array(1 => 'admin'), $pp->getAssignableUsers(2));
public function testCloneSharedProject()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Shared')));
$this->assertTrue($p->update(array('id' => 1, 'is_public' => 1, 'token' => 'test')));
$project = $p->getById(1);
$this->assertEquals('test', $project['token']);
$this->assertEquals(1, $project['is_public']);
$this->assertEquals(2, $pd->duplicate(1));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Shared (Clone)', $project['name']);
$this->assertEquals('', $project['token']);
$this->assertEquals(0, $project['is_public']);
}
public function testCloneInactiveProject()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Inactive')));
$this->assertTrue($p->update(array('id' => 1, 'is_active' => 0)));
$project = $p->getById(1);
$this->assertEquals(0, $project['is_active']);
$this->assertEquals(2, $pd->duplicate(1));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Inactive (Clone)', $project['name']);
$this->assertEquals(1, $project['is_active']);
}
public function testCloneProjectWithOwner()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$projectUserRoleModel = new ProjectUserRole($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Owner')));
$project = $p->getById(1);
$this->assertEquals(0, $project['owner_id']);
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission'), 1));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Owner (Clone)', $project['name']);
$this->assertEquals(1, $project['owner_id']);
$this->assertEquals(Role::PROJECT_MANAGER, $projectUserRoleModel->getUserRole(2, 1));
}
public function testCloneProjectWithDifferentName()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Owner')));
$project = $p->getById(1);
$this->assertEquals(0, $project['owner_id']);
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission'), 1, 'Foobar'));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Foobar', $project['name']);
$this->assertEquals(1, $project['owner_id']);
}
public function testCloneProjectAndForceItToBePrivate()
{
$p = new Project($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(1, $p->create(array('name' => 'Owner')));
$project = $p->getById(1);
$this->assertEquals(0, $project['owner_id']);
$this->assertEquals(0, $project['is_private']);
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission'), 1, 'Foobar', true));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('Foobar', $project['name']);
$this->assertEquals(1, $project['owner_id']);
$this->assertEquals(1, $project['is_private']);
}
public function testCloneProjectWithCategories()
@ -98,16 +196,9 @@ class ProjectDuplicationTest extends Base
$this->assertEquals('P1 (Clone)', $project['name']);
$categories = $c->getAll(2);
$this->assertNotempty($categories);
$this->assertEquals(3, count($categories));
$this->assertEquals(4, $categories[0]['id']);
$this->assertCount(3, $categories);
$this->assertEquals('C1', $categories[0]['name']);
$this->assertEquals(5, $categories[1]['id']);
$this->assertEquals('C2', $categories[1]['name']);
$this->assertEquals(6, $categories[2]['id']);
$this->assertEquals('C3', $categories[2]['name']);
}
@ -119,28 +210,115 @@ class ProjectDuplicationTest extends Base
$u = new User($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(2, $u->create(array('username' => 'unittest1', 'password' => 'unittest')));
$this->assertEquals(3, $u->create(array('username' => 'unittest2', 'password' => 'unittest')));
$this->assertEquals(4, $u->create(array('username' => 'unittest3', 'password' => 'unittest')));
$this->assertEquals(2, $u->create(array('username' => 'user1')));
$this->assertEquals(3, $u->create(array('username' => 'user2')));
$this->assertEquals(4, $u->create(array('username' => 'user3')));
$this->assertEquals(1, $p->create(array('name' => 'P1')));
$this->assertTrue($pp->addUser(1, 2, Role::PROJECT_MEMBER));
$this->assertTrue($pp->addUser(1, 2, Role::PROJECT_MANAGER));
$this->assertTrue($pp->addUser(1, 3, Role::PROJECT_MEMBER));
$this->assertTrue($pp->addUser(1, 4, Role::PROJECT_MANAGER));
$this->assertEquals(Role::PROJECT_MEMBER, $pp->getUserRole(1, 2));
$this->assertEquals(Role::PROJECT_MEMBER, $pp->getUserRole(1, 3));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(1, 4));
$this->assertTrue($pp->addUser(1, 4, Role::PROJECT_VIEWER));
$this->assertEquals(2, $pd->duplicate(1));
$project = $p->getById(2);
$this->assertNotEmpty($project);
$this->assertEquals('P1 (Clone)', $project['name']);
$this->assertEquals(3, count($pp->getUsers(2)));
$this->assertEquals(Role::PROJECT_MEMBER, $pp->getUserRole(2, 2));
$this->assertCount(3, $pp->getUsers(2));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 2));
$this->assertEquals(Role::PROJECT_MEMBER, $pp->getUserRole(2, 3));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 4));
$this->assertEquals(Role::PROJECT_VIEWER, $pp->getUserRole(2, 4));
}
public function testCloneProjectWithUsersAndOverrideOwner()
{
$p = new Project($this->container);
$c = new Category($this->container);
$pp = new ProjectUserRole($this->container);
$u = new User($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(2, $u->create(array('username' => 'user1')));
$this->assertEquals(1, $p->create(array('name' => 'P1'), 2));
$project = $p->getById(1);
$this->assertEquals(2, $project['owner_id']);
$this->assertTrue($pp->addUser(1, 2, Role::PROJECT_MANAGER));
$this->assertTrue($pp->addUser(1, 1, Role::PROJECT_MEMBER));
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission'), 1));
$this->assertCount(2, $pp->getUsers(2));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 2));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 1));
$project = $p->getById(2);
$this->assertEquals(1, $project['owner_id']);
}
public function testCloneTeamProjectToPrivatProject()
{
$p = new Project($this->container);
$c = new Category($this->container);
$pp = new ProjectUserRole($this->container);
$u = new User($this->container);
$pd = new ProjectDuplication($this->container);
$this->assertEquals(2, $u->create(array('username' => 'user1')));
$this->assertEquals(3, $u->create(array('username' => 'user2')));
$this->assertEquals(1, $p->create(array('name' => 'P1'), 2));
$project = $p->getById(1);
$this->assertEquals(2, $project['owner_id']);
$this->assertEquals(0, $project['is_private']);
$this->assertTrue($pp->addUser(1, 2, Role::PROJECT_MANAGER));
$this->assertTrue($pp->addUser(1, 1, Role::PROJECT_MEMBER));
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission'), 3, 'My private project', true));
$this->assertCount(1, $pp->getUsers(2));
$this->assertEquals(Role::PROJECT_MANAGER, $pp->getUserRole(2, 3));
$project = $p->getById(2);
$this->assertEquals(3, $project['owner_id']);
$this->assertEquals(1, $project['is_private']);
}
public function testCloneProjectWithGroups()
{
$p = new Project($this->container);
$c = new Category($this->container);
$pd = new ProjectDuplication($this->container);
$userModel = new User($this->container);
$groupModel = new Group($this->container);
$groupMemberModel = new GroupMember($this->container);
$projectGroupRoleModel = new ProjectGroupRole($this->container);
$projectUserRoleModel = new ProjectUserRole($this->container);
$this->assertEquals(1, $p->create(array('name' => 'P1')));
$this->assertEquals(1, $groupModel->create('G1'));
$this->assertEquals(2, $groupModel->create('G2'));
$this->assertEquals(3, $groupModel->create('G3'));
$this->assertEquals(2, $userModel->create(array('username' => 'user1')));
$this->assertEquals(3, $userModel->create(array('username' => 'user2')));
$this->assertEquals(4, $userModel->create(array('username' => 'user3')));
$this->assertTrue($groupMemberModel->addUser(1, 2));
$this->assertTrue($groupMemberModel->addUser(2, 3));
$this->assertTrue($groupMemberModel->addUser(3, 4));
$this->assertTrue($projectGroupRoleModel->addGroup(1, 1, Role::PROJECT_MANAGER));
$this->assertTrue($projectGroupRoleModel->addGroup(1, 2, Role::PROJECT_MEMBER));
$this->assertTrue($projectGroupRoleModel->addGroup(1, 3, Role::PROJECT_VIEWER));
$this->assertEquals(2, $pd->duplicate(1));
$this->assertCount(3, $projectGroupRoleModel->getGroups(2));
$this->assertEquals(Role::PROJECT_MANAGER, $projectUserRoleModel->getUserRole(2, 2));
$this->assertEquals(Role::PROJECT_MEMBER, $projectUserRoleModel->getUserRole(2, 3));
$this->assertEquals(Role::PROJECT_VIEWER, $projectUserRoleModel->getUserRole(2, 4));
}
public function testCloneProjectWithActionTaskAssignCurrentUser()
@ -199,68 +377,6 @@ class ProjectDuplicationTest extends Base
$this->assertEquals(5, $actions[0]['params']['category_id']);
}
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(array('project_id' => 1, 'name' => 'S1')));
$this->assertEquals(2, $s->create(array('project_id' => 1, 'name' => 'S2')));
$this->assertEquals(3, $s->create(array('project_id' => 1, 'name' => '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->assertNotFalse($pd->duplicate(1, array('category', 'action', 'swimlane', 'task')));
$project = $p->getByName('P1 (Clone)');
$this->assertNotFalse($project);
$project_id = $project['id'];
// Check if Swimlanes have been duplicated
$swimlanes = $s->getAll($project_id);
$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']);
$new_default = $s->getDefault($project_id);
$this->assertEquals('New Default', $new_default['default_swimlane']);
// Check if Tasks have been duplicated
$tasks = $tf->getAll($project_id);
$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']);
$p->remove($project_id);
$this->assertFalse($p->exists($project_id));
$this->assertCount(0, $s->getAll($project_id));
$this->assertCount(0, $tf->getAll($project_id));
}
public function testCloneProjectWithSwimlanes()
{
$p = new Project($this->container);
@ -269,30 +385,22 @@ class ProjectDuplicationTest extends Base
$tc = new TaskCreation($this->container);
$tf = new TaskFinder($this->container);
$this->assertEquals(1, $p->create(array('name' => 'P1')));
$this->assertEquals(1, $p->create(array('name' => 'P1', 'default_swimlane' => 'New Default')));
// create initial swimlanes
$this->assertEquals(1, $s->create(array('project_id' => 1, 'name' => 'S1')));
$this->assertEquals(2, $s->create(array('project_id' => 1, 'name' => 'S2')));
$this->assertEquals(3, $s->create(array('project_id' => 1, 'name' => 'S3')));
$default_swimlane1 = $s->getDefault(1);
$default_swimlane1['default_swimlane'] = 'New Default';
// create initial tasks
$this->assertEquals(1, $tc->create(array('title' => 'T0', 'project_id' => 1, 'swimlane_id' => 0)));
$this->assertEquals(2, $tc->create(array('title' => 'T1', 'project_id' => 1, 'swimlane_id' => 1)));
$this->assertEquals(3, $tc->create(array('title' => 'T2', 'project_id' => 1, 'swimlane_id' => 2)));
$this->assertEquals(4, $tc->create(array('title' => 'T3', 'project_id' => 1, 'swimlane_id' => 3)));
$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->assertNotFalse($pd->duplicate(1, array('category', 'action', 'swimlane')));
$project = $p->getByName('P1 (Clone)');
$this->assertNotFalse($project);
$project_id = $project['id'];
$swimlanes = $s->getAll($project_id);
$this->assertEquals(2, $pd->duplicate(1, array('category', 'swimlane')));
$swimlanes = $s->getAll(2);
$this->assertCount(3, $swimlanes);
$this->assertEquals(4, $swimlanes[0]['id']);
$this->assertEquals('S1', $swimlanes[0]['name']);
@ -300,11 +408,12 @@ class ProjectDuplicationTest extends Base
$this->assertEquals('S2', $swimlanes[1]['name']);
$this->assertEquals(6, $swimlanes[2]['id']);
$this->assertEquals('S3', $swimlanes[2]['name']);
$new_default = $s->getDefault($project_id);
$this->assertEquals('New Default', $new_default['default_swimlane']);
// Check if Tasks have NOT been duplicated
$this->assertCount(0, $tf->getAll($project_id));
$swimlane = $s->getDefault(2);
$this->assertEquals('New Default', $swimlane['default_swimlane']);
// Check if tasks are NOT been duplicated
$this->assertCount(0, $tf->getAll(2));
}
public function testCloneProjectWithTasks()
@ -317,38 +426,62 @@ class ProjectDuplicationTest extends Base
$this->assertEquals(1, $p->create(array('name' => 'P1')));
// create initial tasks
$this->assertEquals(1, $tc->create(array('title' => 'T1', 'project_id' => 1, 'column_id' => 1)));
$this->assertEquals(2, $tc->create(array('title' => 'T2', 'project_id' => 1, 'column_id' => 2)));
$this->assertEquals(3, $tc->create(array('title' => 'T3', 'project_id' => 1, 'column_id' => 3)));
$this->assertEquals(2, $pd->duplicate(1, array('category', 'action', 'task')));
// Check if Tasks have been duplicated
$tasks = $tf->getAll(2);
$this->assertCount(3, $tasks);
$this->assertEquals('T1', $tasks[0]['title']);
$this->assertEquals('T2', $tasks[1]['title']);
$this->assertEquals('T3', $tasks[2]['title']);
}
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', 'default_swimlane' => 'New Default')));
// create initial swimlanes
$this->assertEquals(1, $s->create(array('project_id' => 1, 'name' => 'S1')));
$this->assertEquals(2, $s->create(array('project_id' => 1, 'name' => 'S2')));
$this->assertEquals(3, $s->create(array('project_id' => 1, 'name' => 'S3')));
$default_swimlane1 = $s->getDefault(1);
$default_swimlane1['default_swimlane'] = 'New Default';
$this->assertTrue($s->updateDefault($default_swimlane1));
//create initial tasks
// 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->assertNotFalse($pd->duplicate(1, array('category', 'action', 'task')));
$project = $p->getByName('P1 (Clone)');
$this->assertNotFalse($project);
$project_id = $project['id'];
$this->assertEquals(2, $pd->duplicate(1, array('projectPermission', 'swimlane', 'task')));
// Check if Swimlanes have NOT been duplicated
$this->assertCount(0, $s->getAll($project_id));
// 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']);
$swimlane = $s->getDefault(2);
$this->assertEquals('New Default', $swimlane['default_swimlane']);
// Check if Tasks have been duplicated
$tasks = $tf->getAll($project_id);
$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']);
}
}