summaryrefslogtreecommitdiff
path: root/app/Model/ProjectDuplicationModel.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/Model/ProjectDuplicationModel.php')
-rw-r--r--app/Model/ProjectDuplicationModel.php161
1 files changed, 161 insertions, 0 deletions
diff --git a/app/Model/ProjectDuplicationModel.php b/app/Model/ProjectDuplicationModel.php
new file mode 100644
index 00000000..b67f8302
--- /dev/null
+++ b/app/Model/ProjectDuplicationModel.php
@@ -0,0 +1,161 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+use Kanboard\Core\Security\Role;
+
+/**
+ * Project Duplication
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ * @author Antonio Rabelo
+ */
+class ProjectDuplicationModel extends Base
+{
+ /**
+ * Get list of optional models to duplicate
+ *
+ * @access public
+ * @return string[]
+ */
+ public function getOptionalSelection()
+ {
+ return array('categoryModel', 'projectPermissionModel', 'actionModel', 'swimlaneModel', 'taskModel', 'projectMetadataModel');
+ }
+
+ /**
+ * Get list of all possible models to duplicate
+ *
+ * @access public
+ * @return string[]
+ */
+ public function getPossibleSelection()
+ {
+ return array('boardModel', 'categoryModel', 'projectPermissionModel', 'actionModel', 'swimlaneModel', 'taskModel', 'projectMetadataModel');
+ }
+
+ /**
+ * Get a valid project name for the duplication
+ *
+ * @access public
+ * @param string $name Project name
+ * @param integer $max_length Max length allowed
+ * @return string
+ */
+ public function getClonedProjectName($name, $max_length = 50)
+ {
+ $suffix = ' ('.t('Clone').')';
+
+ if (strlen($name.$suffix) > $max_length) {
+ $name = substr($name, 0, $max_length - strlen($suffix));
+ }
+
+ 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('projectPermissionModel', 'categoryModel', 'actionModel'), $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 === false) {
+ $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 === 'projectPermissionModel') {
+ 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
+ *
+ * @access private
+ * @param integer $src_project_id
+ * @param integer $owner_id
+ * @param string $name
+ * @param boolean $private
+ * @return integer
+ */
+ private function copy($src_project_id, $owner_id = 0, $name = null, $private = null)
+ {
+ $project = $this->projectModel->getById($src_project_id);
+ $is_private = empty($project['is_private']) ? 0 : 1;
+
+ $values = array(
+ 'name' => $name ?: $this->getClonedProjectName($project['name']),
+ 'is_active' => 1,
+ 'last_modified' => time(),
+ 'token' => '',
+ 'is_public' => 0,
+ 'is_private' => $private ? 1 : $is_private,
+ 'owner_id' => $owner_id,
+ );
+
+ if (! $this->db->table(ProjectModel::TABLE)->save($values)) {
+ return false;
+ }
+
+ return $this->db->getLastId();
+ }
+
+ /**
+ * Make sure that the creator of the duplicated project is alsp owner
+ *
+ * @access private
+ * @param integer $dst_project_id
+ * @param integer $owner_id
+ * @return boolean
+ */
+ private function makeOwnerManager($dst_project_id, $owner_id)
+ {
+ if ($owner_id > 0) {
+ $this->projectUserRoleModel->removeUser($dst_project_id, $owner_id);
+
+ if (! $this->projectUserRoleModel->addUser($dst_project_id, $owner_id, Role::PROJECT_MANAGER)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}