<?php namespace Kanboard\Model; use Kanboard\Core\Security\Role; /** * Project Duplication * * @package model * @author Frederic Guillot * @author Antonio Rabelo */ class ProjectDuplication extends Base { /** * Get list of optional models to duplicate * * @access public * @return string[] */ public function getOptionalSelection() { return array('category', 'projectPermission', 'action', 'swimlane', 'task'); } /** * Get list of all possible models to duplicate * * @access public * @return string[] */ public function getPossibleSelection() { return array('board', 'category', 'projectPermission', 'action', 'swimlane', 'task'); } /** * 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('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 === 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 === '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 * * @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->project->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(Project::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->projectUserRole->removeUser($dst_project_id, $owner_id); if (! $this->projectUserRole->addUser($dst_project_id, $owner_id, Role::PROJECT_MANAGER)) { return false; } } return true; } }