Project cloning/duplication (pull-request #196)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,6 +32,7 @@
|
||||
######################
|
||||
.buildpath
|
||||
.project
|
||||
/.settings/
|
||||
|
||||
# OS generated files #
|
||||
######################
|
||||
@@ -52,4 +53,4 @@ Thumbs.db
|
||||
# App specific #
|
||||
################
|
||||
config.php
|
||||
data/files
|
||||
data/files
|
||||
|
||||
@@ -13,6 +13,27 @@ use Core\Translator;
|
||||
*/
|
||||
class Project extends Base
|
||||
{
|
||||
|
||||
/**
|
||||
* Clone Project
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @access public
|
||||
*/
|
||||
public function duplicate()
|
||||
{
|
||||
$this->checkCSRFParam();
|
||||
$project_id = $this->request->getIntegerParam('project_id');
|
||||
|
||||
if ($project_id && $this->project->duplicate($project_id)) {
|
||||
$this->session->flash(t('Project cloned successfully.'));
|
||||
} else {
|
||||
$this->session->flashError(t('Unable to clone this project.'));
|
||||
}
|
||||
|
||||
$this->response->redirect('?controller=project');
|
||||
}
|
||||
|
||||
/**
|
||||
* Task export
|
||||
*
|
||||
|
||||
@@ -398,4 +398,8 @@ return array(
|
||||
'Completion date' => 'Abschlussdatum',
|
||||
'Webhook URL for task creation' => 'Webhook URL zur Aufgabenerstellung',
|
||||
'Webhook URL for task modification' => 'Webhook URL zur Aufgabenänderung',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -397,4 +397,8 @@ return array(
|
||||
// 'Completion date' => '',
|
||||
// 'Webhook URL for task creation' => '',
|
||||
// 'Webhook URL for task modification' => '',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -397,4 +397,8 @@ return array(
|
||||
'Completion date' => 'Valmistumispäivä',
|
||||
'Webhook URL for task creation' => 'Webhook URL tehtävän luomiselle',
|
||||
'Webhook URL for task modification' => 'Webhook URL tehtävän muokkaamiselle',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -395,4 +395,8 @@ return array(
|
||||
'Completion date' => 'Date de complétion',
|
||||
'Webhook URL for task creation' => 'URL du webhook pour la création de tâche',
|
||||
'Webhook URL for task modification' => 'URL du webhook pour la modification de tâche',
|
||||
'Clone' => 'Clone',
|
||||
'Clone Project' => 'Cloner le projet',
|
||||
'Project cloned successfully.' => 'Projet cloné avec succès.',
|
||||
'Unable to clone this project.' => 'Impossible de cloner ce projet.',
|
||||
);
|
||||
|
||||
@@ -398,4 +398,8 @@ return array(
|
||||
// 'Completion date' => '',
|
||||
// 'Webhook URL for task creation' => '',
|
||||
// 'Webhook URL for task modification' => '',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -395,4 +395,8 @@ return array(
|
||||
// 'Completion date' => '',
|
||||
// 'Webhook URL for task creation' => '',
|
||||
// 'Webhook URL for task modification' => '',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -397,4 +397,8 @@ return array(
|
||||
// 'Completion date' => '',
|
||||
// 'Webhook URL for task creation' => '',
|
||||
// 'Webhook URL for task modification' => '',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -403,4 +403,8 @@ return array(
|
||||
// 'Completion date' => '',
|
||||
// 'Webhook URL for task creation' => '',
|
||||
// 'Webhook URL for task modification' => '',
|
||||
// 'Clone' => '',
|
||||
// 'Clone Project' => '',
|
||||
// 'Project cloned successfully.' => '',
|
||||
// 'Unable to clone this project.' => '',
|
||||
);
|
||||
|
||||
@@ -377,6 +377,212 @@ class Project extends Base
|
||||
return $this->filterListByAccess($this->getListByStatus(self::ACTIVE), $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a project from another one.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_id Project Id
|
||||
* @return integer Cloned Project Id
|
||||
*/
|
||||
public function createProjectFromAnotherProject($project_id)
|
||||
{
|
||||
// Recover the template project data
|
||||
$project = $this->getById($project_id);
|
||||
|
||||
// Create a Clone project
|
||||
$clone_project = array(
|
||||
'name' => $project['name'].' ('.t('Clone').')',
|
||||
'is_active' => true,
|
||||
'last_modified' => 0,
|
||||
'token' => Security::generateToken(),
|
||||
);
|
||||
|
||||
// Register the cloned project
|
||||
if (! $this->db->table(self::TABLE)->save($clone_project)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the cloned project Id
|
||||
return $this->db->getConnection()->getLastId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Board Columns from a project to another one.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_from Project Template
|
||||
* @return integer $project_to Project that receives the copy
|
||||
* @return boolean
|
||||
*/
|
||||
public function copyBoardFromAnotherProject($project_from, $project_to)
|
||||
{
|
||||
$boardModel = new Board($this->db, $this->event);
|
||||
$columns = $this->db->table(Board::TABLE)->eq('project_id', $project_from)->asc('position')->findAllByColumn('title');
|
||||
return $boardModel->create($project_to, $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Categories from a project to another one.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_from Project Template
|
||||
* @return integer $project_to Project that receives the copy
|
||||
* @return boolean
|
||||
*/
|
||||
public function copyCategoriesFromAnotherProject($project_from, $project_to)
|
||||
{
|
||||
$categoryModel = new Category($this->db, $this->event);
|
||||
$categoriesTemplate = $categoryModel->getAll($project_from);
|
||||
|
||||
foreach ($categoriesTemplate as $category) {
|
||||
|
||||
unset($category['id']);
|
||||
$category['project_id'] = $project_to;
|
||||
|
||||
if (! $categoryModel->create($category)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy User Access from a project to another one.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_from Project Template
|
||||
* @return integer $project_to Project that receives the copy
|
||||
* @return boolean
|
||||
*/
|
||||
public function copyUserAccessFromAnotherProject($project_from, $project_to)
|
||||
{
|
||||
$usersList = $this->getAllowedUsers($project_from);
|
||||
|
||||
foreach ($usersList as $id => $userName) {
|
||||
if (! $this->allowUser($project_to, $id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Actions and related Actions Parameters from a project to another one.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_from Project Template
|
||||
* @return integer $project_to Project that receives the copy
|
||||
* @return boolean
|
||||
*/
|
||||
public function copyActionsFromAnotherProject($project_from, $project_to)
|
||||
{
|
||||
$actionModel = new Action($this->db, $this->event);
|
||||
$actionTemplate = $actionModel->getAllByProject($project_from);
|
||||
|
||||
foreach ($actionTemplate as $action) {
|
||||
|
||||
unset($action['id']);
|
||||
$action['project_id'] = $project_to;
|
||||
$actionParams = $action['params'];
|
||||
unset($action['params']);
|
||||
|
||||
if (! $this->db->table(Action::TABLE)->save($action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$action_clone_id = $this->db->getConnection()->getLastId();
|
||||
|
||||
foreach ($actionParams as $param) {
|
||||
unset($param['id']);
|
||||
$param['value'] = $this->resolveValueParamToClonedAction($param, $project_to);
|
||||
$param['action_id'] = $action_clone_id;
|
||||
|
||||
if (! $this->db->table(Action::TABLE_PARAMS)->save($param)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve type of action value from a project to the respective value in another project.
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $param A action parameter
|
||||
* @return integer $project_to Project to find the corresponding values
|
||||
* @return mixed The corresponding values from $project_to
|
||||
*/
|
||||
private function resolveValueParamToClonedAction($param, $project_to)
|
||||
{
|
||||
switch($param['name']) {
|
||||
case 'project_id':
|
||||
return $project_to;
|
||||
case 'category_id':
|
||||
$categoryModel = new Category($this->db, $this->event);
|
||||
$categoryTemplate = $categoryModel->getById($param['value']);
|
||||
$categoryFromNewProject = $this->db->table(Category::TABLE)->eq('project_id', $project_to)->eq('name', $categoryTemplate['name'])->findOne();
|
||||
return $categoryFromNewProject['id'];
|
||||
case 'column_id':
|
||||
$boardModel = new Board($this->db, $this->event);
|
||||
$boardTemplate = $boardModel->getColumn($param['value']);
|
||||
$boardFromNewProject = $this->db->table(Board::TABLE)->eq('project_id', $project_to)->eq('title', $boardTemplate['title'])->findOne();
|
||||
return $boardFromNewProject['id'];
|
||||
default:
|
||||
return $param['value'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone a project
|
||||
*
|
||||
* @author Antonio Rabelo
|
||||
* @param integer $project_id Project Id
|
||||
* @return integer Cloned Project Id
|
||||
*/
|
||||
public function duplicate($project_id)
|
||||
{
|
||||
$this->db->startTransaction();
|
||||
|
||||
// Get the cloned project Id
|
||||
$clone_project_id = $this->createProjectFromAnotherProject($project_id);
|
||||
if (! $clone_project_id) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone Board
|
||||
if (! $this->copyBoardFromAnotherProject($project_id, $clone_project_id)) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone Categories
|
||||
if (! $this->copyCategoriesFromAnotherProject($project_id, $clone_project_id)) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone Allowed Users
|
||||
if (! $this->copyUserAccessFromAnotherProject($project_id, $clone_project_id)) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone Actions
|
||||
if (! $this->copyActionsFromAnotherProject($project_id, $clone_project_id)) {
|
||||
$this->db->cancelTransaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->db->closeTransaction();
|
||||
|
||||
return (int) $clone_project_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a project
|
||||
*
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
<li>
|
||||
<a href="?controller=project&action=export&project_id=<?= $project['id'] ?>"><?= t('Tasks Export') ?></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?controller=project&action=duplicate&project_id=<?= $project['id'].Helper\param_csrf() ?>"><?= t('Clone Project') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<?php endif ?>
|
||||
|
||||
Reference in New Issue
Block a user