diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/Controller/Project.php | 21 | ||||
-rw-r--r-- | app/Locales/de_DE/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/es_ES/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/fi_FI/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/fr_FR/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/pl_PL/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/pt_BR/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/sv_SE/translations.php | 4 | ||||
-rw-r--r-- | app/Locales/zh_CN/translations.php | 4 | ||||
-rw-r--r-- | app/Model/Project.php | 206 | ||||
-rw-r--r-- | app/Templates/project_index.php | 3 |
11 files changed, 262 insertions, 0 deletions
diff --git a/app/Controller/Project.php b/app/Controller/Project.php index 8c21801b..0d430b44 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -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 * diff --git a/app/Locales/de_DE/translations.php b/app/Locales/de_DE/translations.php index 551a7580..73aed160 100644 --- a/app/Locales/de_DE/translations.php +++ b/app/Locales/de_DE/translations.php @@ -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.' => '', ); diff --git a/app/Locales/es_ES/translations.php b/app/Locales/es_ES/translations.php index 37b4e231..a8a8024c 100644 --- a/app/Locales/es_ES/translations.php +++ b/app/Locales/es_ES/translations.php @@ -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.' => '', ); diff --git a/app/Locales/fi_FI/translations.php b/app/Locales/fi_FI/translations.php index caf768fb..801ec5c1 100644 --- a/app/Locales/fi_FI/translations.php +++ b/app/Locales/fi_FI/translations.php @@ -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.' => '', ); diff --git a/app/Locales/fr_FR/translations.php b/app/Locales/fr_FR/translations.php index 72e56111..552060c5 100644 --- a/app/Locales/fr_FR/translations.php +++ b/app/Locales/fr_FR/translations.php @@ -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.', ); diff --git a/app/Locales/pl_PL/translations.php b/app/Locales/pl_PL/translations.php index c9c6a0e5..41e7f80a 100644 --- a/app/Locales/pl_PL/translations.php +++ b/app/Locales/pl_PL/translations.php @@ -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.' => '', ); diff --git a/app/Locales/pt_BR/translations.php b/app/Locales/pt_BR/translations.php index 793c30e6..95ea11b5 100644 --- a/app/Locales/pt_BR/translations.php +++ b/app/Locales/pt_BR/translations.php @@ -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.' => '', ); diff --git a/app/Locales/sv_SE/translations.php b/app/Locales/sv_SE/translations.php index 3cd6525a..68248b72 100644 --- a/app/Locales/sv_SE/translations.php +++ b/app/Locales/sv_SE/translations.php @@ -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.' => '', ); diff --git a/app/Locales/zh_CN/translations.php b/app/Locales/zh_CN/translations.php index 6f519981..1d759336 100644 --- a/app/Locales/zh_CN/translations.php +++ b/app/Locales/zh_CN/translations.php @@ -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.' => '', ); diff --git a/app/Model/Project.php b/app/Model/Project.php index 5d3f01b9..f598c96f 100644 --- a/app/Model/Project.php +++ b/app/Model/Project.php @@ -378,6 +378,212 @@ class Project extends Base } /** + * 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 * * @access public diff --git a/app/Templates/project_index.php b/app/Templates/project_index.php index 097ebd1f..dc71033f 100644 --- a/app/Templates/project_index.php +++ b/app/Templates/project_index.php @@ -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 ?> |