1014 lines
41 KiB
PHP
1014 lines
41 KiB
PHP
<?php
|
|
/**
|
|
* The control file of upgrade module of ZenTaoPMS.
|
|
*
|
|
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
|
|
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
|
* @package upgrade
|
|
* @version $Id: control.php 5119 2013-07-12 08:06:42Z wyd621@gmail.com $
|
|
* @link http://www.zentao.net
|
|
*/
|
|
class upgrade extends control
|
|
{
|
|
/**
|
|
* The index page.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function index()
|
|
{
|
|
/* Locate to index page of my module, if upgrade.php does not exist. */
|
|
$upgradeFile = $this->app->wwwRoot . 'upgrade.php';
|
|
if(!file_exists($upgradeFile)) $this->locate($this->createLink('my', 'index'));
|
|
|
|
$this->upgrade->deleteTmpModel();
|
|
|
|
$systemMode = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=mode');
|
|
if(empty($systemMode) && !isset($this->config->qcVersion))
|
|
{
|
|
/* Judge upgrade step. */
|
|
$upgradeStep = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=upgradeStep');
|
|
if($upgradeStep == 'mergeProgram') $this->locate(inlink('mergeProgram'));
|
|
}
|
|
if(version_compare($this->config->installedVersion, '6.4', '<=')) $this->locate(inlink('license'));
|
|
$this->locate(inlink('backup'));
|
|
}
|
|
|
|
/**
|
|
* Check agree license.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function license()
|
|
{
|
|
if($this->get->agree == true) $this->locate(inlink('backup'));
|
|
|
|
$clientLang = $this->app->getClientLang();
|
|
$licenseCN = file_get_contents($this->app->getBasePath() . 'doc/LICENSE.CN');
|
|
$licenseEN = file_get_contents($this->app->getBasePath() . 'doc/LICENSE.EN');
|
|
|
|
$license = $licenseEN . $licenseCN;
|
|
if($clientLang == 'zh-cn' or $clientLang == 'zh-tw') $license = $licenseCN . $licenseEN;
|
|
|
|
$this->view->title = $this->lang->upgrade->common;
|
|
$this->view->license = $license;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Backup.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function backup()
|
|
{
|
|
$this->session->set('upgrading', true);
|
|
|
|
$this->view->title = $this->lang->upgrade->common;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Select the version of old zentao.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function selectVersion()
|
|
{
|
|
$version = str_replace(array(' ', '.'), array('', '_'), $this->config->installedVersion);
|
|
$version = strtolower($version);
|
|
|
|
if($this->config->visions == ',lite,')
|
|
{
|
|
$installedVersion = str_replace('.', '_', $this->config->installedVersion);
|
|
$version = array_search($installedVersion, $this->config->upgrade->liteVersion);
|
|
|
|
foreach($this->lang->upgrade->fromVersions as $key => $value)
|
|
{
|
|
if(strpos($key, 'lite') === false) unset($this->lang->upgrade->fromVersions[$key]);
|
|
}
|
|
|
|
$this->config->version = ($this->config->edition == 'biz' ? 'LiteVIP' : 'Lite') . $this->config->liteVersion;
|
|
}
|
|
|
|
$this->view->title = $this->lang->upgrade->common . $this->lang->colon . $this->lang->upgrade->selectVersion;
|
|
$this->view->position[] = $this->lang->upgrade->common;
|
|
$this->view->version = $version;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Confirm the version.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function confirm()
|
|
{
|
|
if(strpos($this->post->fromVersion, 'lite') !== false) $this->post->fromVersion = $this->config->upgrade->liteVersion[$this->post->fromVersion];
|
|
|
|
$this->session->set('step', '');
|
|
$this->view->title = $this->lang->upgrade->confirm;
|
|
$this->view->position[] = $this->lang->upgrade->common;
|
|
$this->view->confirm = $this->upgrade->getConfirm($this->post->fromVersion);
|
|
$this->view->fromVersion = $this->post->fromVersion;
|
|
/* When sql is empty then skip it. */
|
|
if(empty($this->view->confirm)) $this->locate(inlink('execute', "fromVersion={$this->post->fromVersion}"));
|
|
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Execute the upgrading.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function execute($fromVersion = '')
|
|
{
|
|
$this->session->set('step', '');
|
|
|
|
$this->view->title = $this->lang->upgrade->result;
|
|
$this->view->position[] = $this->lang->upgrade->common;
|
|
|
|
$result = $this->upgrade->deleteFiles();
|
|
if($result)
|
|
{
|
|
$this->view->result = 'fail';
|
|
$this->view->errors = $result;
|
|
|
|
return $this->display();
|
|
}
|
|
|
|
$fromVersion = isset($_POST['fromVersion']) ? $this->post->fromVersion : $fromVersion;
|
|
if(strpos($fromVersion, 'lite') !== false) $fromVersion = $this->config->upgrade->liteVersion[$fromVersion];
|
|
$this->upgrade->execute($fromVersion);
|
|
|
|
if(!$this->upgrade->isError())
|
|
{
|
|
$systemMode = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=mode');
|
|
|
|
/* Delete all patch actions if upgrade success. */
|
|
$this->loadModel('action')->deleteByType('patch');
|
|
|
|
$openVersion = $this->upgrade->getOpenVersion(str_replace('.', '_', $fromVersion));
|
|
$selectMode = true;
|
|
|
|
if($systemMode == 'classic')
|
|
{
|
|
$this->loadModel('setting')->setItem('system.common.global.mode', 'light');
|
|
|
|
$programID = $this->loadModel('program')->createDefaultProgram();
|
|
$this->loadModel('setting')->setItem('system.common.global.defaultProgram', $programID);
|
|
|
|
/* Set default program for product and project with no program. */
|
|
$this->upgrade->relateDefaultProgram($programID);
|
|
|
|
$_POST['projectType'] = 'execution';
|
|
$this->upgrade->upgradeInProjectMode($programID, $systemMode);
|
|
|
|
$this->upgrade->computeObjectMembers();
|
|
$this->upgrade->initUserView();
|
|
$this->upgrade->setDefaultPriv();
|
|
$this->dao->update(TABLE_CONFIG)->set('value')->eq('0_0')->where('`key`')->eq('productProject')->exec();
|
|
|
|
$hourPoint = $this->loadModel('setting')->getItem('owner=system&module=custom&key=hourPoint');
|
|
if(empty($hourPoint)) $this->setting->setItem('system.custom.hourPoint', 0);
|
|
|
|
$sprints = $this->dao->select('id')->from(TABLE_PROJECT)->where('type')->eq('sprint')->fetchAll('id');
|
|
$this->dao->update(TABLE_ACTION)->set('objectType')->eq('execution')->where('objectID')->in(array_keys($sprints))->andWhere('objectType')->eq('project')->exec();
|
|
|
|
$this->loadModel('custom')->disableFeaturesByMode('light');
|
|
|
|
$selectMode = false;
|
|
}
|
|
if(version_compare($openVersion, '15_0_rc1', '>=') and $systemMode == 'new')
|
|
{
|
|
$this->loadModel('setting')->setItem('system.common.global.mode', 'ALM');
|
|
if(empty($this->config->URAndSR)) $this->setting->setItem('system.common.closedFeatures', 'productUR');
|
|
$selectMode = false;
|
|
}
|
|
if(version_compare($openVersion, '18_0_beta1', '>=')) $selectMode = false;
|
|
|
|
if($selectMode) $this->locate(inlink('to18Guide', "fromVersion=$fromVersion"));
|
|
|
|
$this->locate(inlink('afterExec', "fromVersion=$fromVersion"));
|
|
}
|
|
|
|
$this->view->result = 'sqlFail';
|
|
$this->view->errors = $this->upgrade->getError();
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Guide to 18 version.
|
|
*
|
|
* @param string $fromVersion
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function to18Guide($fromVersion)
|
|
{
|
|
if($_POST)
|
|
{
|
|
$mode = fixer::input('post')->get('mode');
|
|
$this->loadModel('setting')->setItem('system.common.global.mode', $mode);
|
|
$this->loadModel('custom')->disableFeaturesByMode($mode);
|
|
|
|
/* Update sprint concept. */
|
|
$sprintConcept = 0;
|
|
if(isset($this->config->custom->sprintConcept))
|
|
{
|
|
if($this->config->custom->sprintConcept == 2) $sprintConcept = 1;
|
|
}
|
|
elseif(isset($this->config->custom->productProject))
|
|
{
|
|
list($productConcept, $projectConcept) = explode('_', $this->config->custom->productProject);
|
|
if($projectConcept == 2) $sprintConcept = 1;
|
|
}
|
|
$this->setting->setItem('system.custom.sprintConcept', $sprintConcept);
|
|
|
|
$openVersion = $this->upgrade->getOpenVersion(str_replace('.', '_', $fromVersion));
|
|
if($mode == 'light')
|
|
{
|
|
$programID = $this->loadModel('program')->createDefaultProgram();
|
|
$this->loadModel('setting')->setItem('system.common.global.defaultProgram', $programID);
|
|
|
|
/* Set default program for product and project with no program. */
|
|
$this->upgrade->relateDefaultProgram($programID);
|
|
|
|
}
|
|
|
|
$this->locate(inlink('selectMergeMode', "fromVersion=$fromVersion&mode=$mode"));
|
|
}
|
|
|
|
list($disabledFeatures, $enabledScrumFeatures, $disabledScrumFeatures) = $this->loadModel('custom')->computeFeatures();
|
|
|
|
$this->view->title = $this->lang->custom->selectUsage;
|
|
$this->view->edition = $this->config->edition;
|
|
$this->view->disabledFeatures = $disabledFeatures;
|
|
$this->view->enabledScrumFeatures = $enabledScrumFeatures;
|
|
$this->view->disabledScrumFeatures = $disabledScrumFeatures;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Merge program.
|
|
*
|
|
* @param string $type
|
|
* @param int $programID
|
|
* @param string $projectType project|execution
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function mergeProgram($type = 'productline', $programID = 0, $projectType = 'project')
|
|
{
|
|
set_time_limit(0);
|
|
|
|
$this->session->set('upgrading', true);
|
|
$this->app->loadLang('program');
|
|
$this->app->loadLang('project');
|
|
$this->app->loadLang('product');
|
|
$this->app->loadConfig('execution');
|
|
|
|
if($_POST)
|
|
{
|
|
$projectType = isset($_POST['projectType']) ? $_POST['projectType'] : 'project';
|
|
if($type == 'productline')
|
|
{
|
|
$linkedProducts = array();
|
|
$linkedSprints = array();
|
|
$unlinkSprints = array();
|
|
$sprintProducts = array();
|
|
$singleProducts = array();
|
|
|
|
/* Compute checked products and sprints, unchecked products and sprints. */
|
|
foreach($_POST['products'] as $lineID => $products)
|
|
{
|
|
foreach($products as $productID)
|
|
{
|
|
$linkedProducts[$productID] = $productID;
|
|
|
|
if(isset($_POST['sprints'][$lineID][$productID]))
|
|
{
|
|
foreach($_POST['sprints'][$lineID][$productID] as $sprintID)
|
|
{
|
|
$linkedSprints[$sprintID] = $sprintID;
|
|
$sprintProducts[$sprintID] = $productID;
|
|
unset($_POST['sprintIdList'][$lineID][$productID][$sprintID]);
|
|
}
|
|
$unlinkSprints[$productID] = $this->post->sprintIdList[$lineID][$productID];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Create Program. */
|
|
list($programID, $projectList, $lineID) = $this->upgrade->createProgram($linkedProducts, $linkedSprints);
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
|
|
/* Process merged products and projects. */
|
|
if($_POST['projectType'] == 'execution')
|
|
{
|
|
/* Use historical projects as execution upgrades. */
|
|
$this->upgrade->processMergedData($programID, $projectList, $lineID, $linkedProducts, $linkedSprints);
|
|
}
|
|
else
|
|
{
|
|
/* Use historical projects as project upgrades. */
|
|
$singleProducts = array_diff($linkedProducts, $sprintProducts);
|
|
foreach($linkedSprints as $sprint)
|
|
{
|
|
$this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, array($sprintProducts[$sprint] => $sprintProducts[$sprint]), array($sprint => $sprint));
|
|
}
|
|
}
|
|
|
|
/* When upgrading historical data as a project, handle products that are not linked with the project. */
|
|
if(!empty($singleProducts)) $this->upgrade->computeProductAcl($singleProducts, $programID, $lineID);
|
|
|
|
/* Process unlinked sprint and product. */
|
|
foreach($linkedProducts as $productID => $product)
|
|
{
|
|
if((isset($unlinkSprints[$productID]) and empty($unlinkSprints[$productID])) || !isset($unlinkSprints[$productID])) $this->dao->update(TABLE_PRODUCT)->set('line')->eq($lineID)->where('id')->eq($productID)->exec();
|
|
}
|
|
}
|
|
elseif($type == 'product')
|
|
{
|
|
$linkedProducts = array();
|
|
$linkedSprints = array();
|
|
$unlinkSprints = array();
|
|
$sprintProducts = array();
|
|
$singleProducts = array();
|
|
foreach($_POST['products'] as $productID)
|
|
{
|
|
$linkedProducts[$productID] = $productID;
|
|
|
|
if(isset($_POST['sprints'][$productID]))
|
|
{
|
|
foreach($_POST['sprints'][$productID] as $sprintID)
|
|
{
|
|
$linkedSprints[$sprintID] = $sprintID;
|
|
$sprintProducts[$sprintID] = $productID;
|
|
unset($_POST['sprintIdList'][$productID][$sprintID]);
|
|
}
|
|
$unlinkSprints += $this->post->sprintIdList[$productID];
|
|
}
|
|
}
|
|
|
|
/* Create Program. */
|
|
list($programID, $projectList, $lineID) = $this->upgrade->createProgram($linkedProducts, $linkedSprints);
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
|
|
/* Process productline. */
|
|
$this->dao->delete()->from(TABLE_MODULE)->where('`root`')->eq(0)->andWhere('`type`')->eq('line')->exec();
|
|
|
|
/* Process merged products and projects. */
|
|
if($_POST['projectType'] == 'execution')
|
|
{
|
|
/* Use historical projects as execution upgrades. */
|
|
$this->upgrade->processMergedData($programID, $projectList, $lineID, $linkedProducts, $linkedSprints);
|
|
}
|
|
else
|
|
{
|
|
/* Use historical projects as project upgrades. */
|
|
$singleProducts = array_diff($linkedProducts, $sprintProducts);
|
|
foreach($linkedSprints as $sprint)
|
|
{
|
|
$this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, array($sprintProducts[$sprint] => $sprintProducts[$sprint]), array($sprint => $sprint));
|
|
}
|
|
}
|
|
|
|
/* When upgrading historical data as a project, handle products that are not linked with the project. */
|
|
if(!empty($singleProducts)) $this->upgrade->computeProductAcl($singleProducts, $programID, $lineID);
|
|
}
|
|
elseif($type == 'sprint')
|
|
{
|
|
$linkedSprints = $this->post->sprints;
|
|
|
|
/* Create Program. */
|
|
list($programID, $projectList, $lineID) = $this->upgrade->createProgram(array(), $linkedSprints);
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
|
|
if($_POST['projectType'] == 'execution')
|
|
{
|
|
/* Use historical projects as execution upgrades. */
|
|
$this->upgrade->processMergedData($programID, $projectList, $lineID, array(), $linkedSprints);
|
|
}
|
|
else
|
|
{
|
|
/* Use historical projects as project upgrades. */
|
|
foreach($linkedSprints as $sprint)
|
|
{
|
|
$this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, array(), array($sprint => $sprint));
|
|
}
|
|
}
|
|
}
|
|
elseif($type == 'moreLink')
|
|
{
|
|
$linkedSprints = $this->post->sprints;
|
|
|
|
/* Create Program. */
|
|
list($programID, $projectList, $lineID) = $this->upgrade->createProgram(array(), $linkedSprints);
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
|
|
if($_POST['projectType'] == 'execution')
|
|
{
|
|
/* Use historical projects as execution upgrades. */
|
|
$this->upgrade->processMergedData($programID, $projectList, $lineID, array(), $linkedSprints);
|
|
}
|
|
else
|
|
{
|
|
/* Use historical projects as project upgrades. */
|
|
foreach($linkedSprints as $sprint)
|
|
{
|
|
$this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, array(), array($sprint => $sprint));
|
|
}
|
|
}
|
|
|
|
/* If is more-link sprints, and as project upgrade, set old relation into new project. */
|
|
$projectProducts = $this->dao->select('product,project,branch,plan')->from(TABLE_PROJECTPRODUCT)
|
|
->where('project')->in($linkedSprints)
|
|
->fetchAll();
|
|
foreach($projectProducts as $projectProduct)
|
|
{
|
|
$data = new stdclass();
|
|
$data->project = $_POST['projectType'] == 'execution' ? $projectList : $projectList[$projectProduct->project];
|
|
$data->product = $projectProduct->product;
|
|
$data->plan = $projectProduct->plan;
|
|
$data->branch = $projectProduct->branch;
|
|
|
|
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
|
|
}
|
|
}
|
|
|
|
return print(js::locate($this->createLink('upgrade', 'mergeProgram', "type=$type&programID=$programID&projectType=$projectType"), 'parent'));
|
|
}
|
|
|
|
/* Get no merged product and project count. */
|
|
$noMergedProductCount = $this->dao->select('count(*) as count')->from(TABLE_PRODUCT)->where('program')->eq(0)->andWhere('vision')->eq('rnd')->fetch('count');
|
|
$noMergedSprintCount = $this->dao->select('count(*) as count')->from(TABLE_PROJECT)->where('vision')->eq('rnd')->andWhere('project')->eq(0)->andWhere('type')->eq('sprint')->andWhere('deleted')->eq(0)->fetch('count');
|
|
|
|
/* When all products and projects merged then finish and locate afterExec page. */
|
|
if(empty($noMergedProductCount) and empty($noMergedSprintCount))
|
|
{
|
|
$this->upgrade->computeObjectMembers();
|
|
$this->upgrade->initUserView();
|
|
$this->upgrade->setDefaultPriv();
|
|
$this->dao->update(TABLE_CONFIG)->set('value')->eq('0_0')->where('`key`')->eq('productProject')->exec();
|
|
|
|
/* Set defult hourPoint. */
|
|
$hourPoint = $this->loadModel('setting')->getItem('owner=system&module=custom&key=hourPoint');
|
|
if(empty($hourPoint)) $this->setting->setItem('system.custom.hourPoint', 0);
|
|
|
|
/* Update sprints history. */
|
|
$sprints = $this->dao->select('id')->from(TABLE_PROJECT)->where('type')->eq('sprint')->fetchAll('id');
|
|
$this->dao->update(TABLE_ACTION)->set('objectType')->eq('execution')->where('objectID')->in(array_keys($sprints))->andWhere('objectType')->eq('project')->exec();
|
|
return print(js::locate($this->createLink('upgrade', 'mergeRepo')));
|
|
}
|
|
|
|
$this->view->noMergedProductCount = $noMergedProductCount;
|
|
$this->view->noMergedSprintCount = $noMergedSprintCount;
|
|
|
|
$systemMode = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=mode');
|
|
|
|
$this->loadModel('project');
|
|
$this->view->type = $type;
|
|
|
|
/* Get products and projects group by product line. */
|
|
if($type == 'productline')
|
|
{
|
|
$productlines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq(0)->orderBy('id_desc')->fetchAll('id');
|
|
|
|
$noMergedProducts = $this->dao->select('*')->from(TABLE_PRODUCT)->where('line')->in(array_keys($productlines))->andWhere('vision')->eq('rnd')->orderBy('id_desc')->fetchAll('id');
|
|
if(empty($productlines) || empty($noMergedProducts)) $this->locate($this->createLink('upgrade', 'mergeProgram', "type=product&programID=0&projectType=$projectType"));
|
|
|
|
$noMergedSprints = $this->dao->select('t1.*')->from(TABLE_PROJECT)->alias('t1')
|
|
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id=t2.project')
|
|
->where('t1.project')->eq(0)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere('t1.vision')->eq('rnd')
|
|
->andWhere('t1.type')->eq('sprint')
|
|
->andWhere('t2.product')->in(array_keys($noMergedProducts))
|
|
->orderBy('t1.id_desc')
|
|
->fetchAll('id');
|
|
|
|
/* Remove sprint than linked more than two products */
|
|
$sprintProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($noMergedSprints))->fetchGroup('project', 'product');
|
|
foreach($sprintProducts as $sprintID => $products)
|
|
{
|
|
if(count($products) > 1) unset($noMergedSprints[$sprintID]);
|
|
}
|
|
|
|
/* Group product by product line. */
|
|
$lineGroups = array();
|
|
foreach($noMergedProducts as $product) $lineGroups[$product->line][$product->id] = $product;
|
|
|
|
/* Group sprint by product. */
|
|
$productGroups = array();
|
|
foreach($noMergedSprints as $sprint)
|
|
{
|
|
$sprintProduct = zget($sprintProducts, $sprint->id, array());
|
|
if(empty($sprintProduct)) continue;
|
|
|
|
$productID = key($sprintProduct);
|
|
$productGroups[$productID][$sprint->id] = $sprint;
|
|
}
|
|
|
|
foreach($productlines as $line)
|
|
{
|
|
if(!isset($lineGroups[$line->id])) unset($productlines[$line->id]);
|
|
}
|
|
|
|
$this->view->productlines = $productlines;
|
|
$this->view->lineGroups = $lineGroups;
|
|
$this->view->productGroups = $productGroups;
|
|
}
|
|
|
|
/* Get projects group by product. */
|
|
if($type == 'product')
|
|
{
|
|
$noMergedSprints = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
|
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
|
|
->where('t2.model')->eq('')
|
|
->andWhere('t2.project')->eq(0)
|
|
->andWhere('t2.vision')->eq('rnd')
|
|
->andWhere('t2.deleted')->eq(0)
|
|
->andWhere('t2.type')->eq('sprint')
|
|
->fetchAll('id');
|
|
|
|
/* Remove project than linked more than two products */
|
|
$sprintProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($noMergedSprints))->fetchGroup('project', 'product');
|
|
$productGroup = array();
|
|
foreach($sprintProducts as $sprintID => $products)
|
|
{
|
|
if(count($products) > 1)
|
|
{
|
|
unset($noMergedSprints[$sprintID]);
|
|
$productGroup[] = array_keys($products);
|
|
}
|
|
}
|
|
|
|
/* Get products that are not merged by sprints. */
|
|
$noMergedProducts = array();
|
|
if($noMergedSprints)
|
|
{
|
|
$noMergedProducts = $this->dao->select('t1.*')->from(TABLE_PRODUCT)->alias('t1')
|
|
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id=t2.product')
|
|
->where('t2.project')->in(array_keys($noMergedSprints))
|
|
->andWhere('t1.vision')->eq('rnd')
|
|
->fetchAll('id');
|
|
}
|
|
|
|
/* Add products without sprints. */
|
|
$noMergedProducts += $this->dao->select('*')->from(TABLE_PRODUCT)->where('program')->eq(0)->andWhere('vision')->eq('rnd')->fetchAll('id');
|
|
|
|
if(empty($noMergedProducts)) $this->locate($this->createLink('upgrade', 'mergeProgram', "type=sprint&programID=0&projectType=$projectType"));
|
|
|
|
/* Group project by product. */
|
|
$productGroups = array();
|
|
foreach($noMergedSprints as $sprint)
|
|
{
|
|
$sprintProduct = zget($sprintProducts, $sprint->id, array());
|
|
if(empty($sprintProduct)) continue;
|
|
|
|
$productID = key($sprintProduct);
|
|
$productGroups[$productID][$sprint->id] = $sprint;
|
|
}
|
|
|
|
$this->view->noMergedProducts = $noMergedProducts;
|
|
$this->view->productGroups = $productGroups;
|
|
}
|
|
|
|
/* Get no merged projects than is not linked product. */
|
|
if($type == 'sprint')
|
|
{
|
|
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)
|
|
->where('project')->eq(0)
|
|
->andWhere('vision')->eq('rnd')
|
|
->andWhere('type')->eq('sprint')
|
|
->andWhere('deleted')->eq(0)
|
|
->orderBy('id_desc')
|
|
->fetchAll('id');
|
|
|
|
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($noMergedSprints))->fetchGroup('project', 'product');
|
|
foreach($projectProducts as $sprintID => $products) unset($noMergedSprints[$sprintID]);
|
|
|
|
if(empty($noMergedSprints)) $this->locate($this->createLink('upgrade', 'mergeProgram', "type=moreLink"));
|
|
|
|
$this->view->noMergedSprints = $noMergedSprints;
|
|
if(!$programID && $systemMode == 'light') $programID = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=defaultProgram');
|
|
}
|
|
|
|
/* Get no merged projects that link more then two products. */
|
|
if($type == 'moreLink')
|
|
{
|
|
$noMergedSprints = $this->dao->select('*')->from(TABLE_PROJECT)
|
|
->where('project')->eq(0)
|
|
->andWhere('vision')->eq('rnd')
|
|
->andWhere('type')->eq('sprint')
|
|
->andWhere('deleted')->eq(0)
|
|
->orderBy('id_desc')
|
|
->fetchAll('id');
|
|
|
|
$projectProducts = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)
|
|
->where('project')->in(array_keys($noMergedSprints))
|
|
->fetchGroup('project', 'product');
|
|
|
|
$productPairs = array();
|
|
foreach($projectProducts as $sprintID => $products)
|
|
{
|
|
foreach($products as $productID => $data) $productPairs[$productID] = $productID;
|
|
}
|
|
|
|
$projects = $this->dao->select('t1.*,t2.product as productID')->from(TABLE_PROJECT)->alias('t1')
|
|
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id=t2.project')
|
|
->where('t2.product')->in($productPairs)
|
|
->andWhere('t1.vision')->eq('rnd')
|
|
->andWhere('t1.type')->eq('project')
|
|
->fetchAll('productID');
|
|
|
|
foreach($noMergedSprints as $sprintID => $sprint)
|
|
{
|
|
$products = zget($projectProducts, $sprintID, array());
|
|
foreach($products as $productID => $data)
|
|
{
|
|
$project = zget($projects, $productID, '');
|
|
if($project) $sprint->projects[$project->id] = $project->name;
|
|
}
|
|
|
|
if(!isset($sprint->projects)) $sprint->projects = $this->dao->select('id,name')->from(TABLE_PROJECT)->where('type')->eq('project')->andWhere('vision')->eq('rnd')->fetchPairs();
|
|
}
|
|
|
|
$this->view->noMergedSprints = $noMergedSprints;
|
|
}
|
|
|
|
$programs = $this->upgrade->getProgramPairs();
|
|
$currentProgramID = $programID ? $programID : key($programs);
|
|
|
|
$this->view->title = $this->lang->upgrade->mergeProgram;
|
|
$this->view->programs = $programs;
|
|
$this->view->programID = $programID;
|
|
$this->view->projects = array('' => '') + $this->upgrade->getProjectPairsByProgram($currentProgramID);
|
|
$this->view->lines = $currentProgramID ? array('' => '') + $this->loadModel('product')->getLinePairs($currentProgramID) : array('' => '');
|
|
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noempty');
|
|
$this->view->groups = $this->loadModel('group')->getPairs();
|
|
$this->view->systemMode = $systemMode;
|
|
$this->view->projectType = $projectType;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Select the merge mode when upgrading to zentaopms 18.0.
|
|
*
|
|
* @param string $fromVersion
|
|
* @param string $mode light | ALM
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function selectMergeMode($fromVersion, $mode = 'light')
|
|
{
|
|
if($_POST)
|
|
{
|
|
$mergeMode = $this->post->projectType;
|
|
if($mergeMode == 'manually') $this->locate(inlink('mergeProgram'));
|
|
|
|
if($mode == 'light') $programID = $this->loadModel('setting')->getItem('owner=system&module=common§ion=global&key=defaultProgram');
|
|
if($mode == 'ALM') $programID = $this->loadModel('program')->createDefaultProgram();
|
|
|
|
if($mergeMode == 'project') $this->upgrade->upgradeInProjectMode($programID);
|
|
if($mergeMode == 'execution') $this->upgrade->upgradeInExecutionMode($programID);
|
|
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
|
|
$this->upgrade->computeObjectMembers();
|
|
$this->upgrade->initUserView();
|
|
$this->upgrade->setDefaultPriv();
|
|
$this->dao->update(TABLE_CONFIG)->set('value')->eq('0_0')->where('`key`')->eq('productProject')->exec();
|
|
|
|
$hourPoint = $this->loadModel('setting')->getItem('owner=system&module=custom&key=hourPoint');
|
|
if(empty($hourPoint)) $this->setting->setItem('system.custom.hourPoint', 0);
|
|
|
|
$sprints = $this->dao->select('id')->from(TABLE_PROJECT)->where('type')->eq('sprint')->fetchAll('id');
|
|
$this->dao->update(TABLE_ACTION)->set('objectType')->eq('execution')->where('objectID')->in(array_keys($sprints))->andWhere('objectType')->eq('project')->exec();
|
|
|
|
if(dao::isError()) return print(js::error(dao::getError()));
|
|
$this->locate(inlink('afterExec', "fromVersion=$fromVersion"));
|
|
}
|
|
$this->view->title = $this->lang->upgrade->selectMergeMode;
|
|
$this->view->fromVersion = $fromVersion;
|
|
$this->view->systemMode = $mode;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Rename object in upgrade.
|
|
*
|
|
* @param string $type project|product|execution
|
|
* @param string $duplicateList
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function renameObject($type = 'project', $duplicateList = '')
|
|
{
|
|
$this->app->loadLang($type);
|
|
if($_POST)
|
|
{
|
|
foreach($this->post->project as $projectID => $projectName)
|
|
{
|
|
if(!$projectName) continue;
|
|
$this->dao->update(TABLE_PROJECT)->set('name')->eq($projectName)->where('id')->eq($projectID)->exec();
|
|
}
|
|
|
|
return print(js::reload('parent.parent', ''));
|
|
}
|
|
|
|
$objectGroup = array();
|
|
if($type == 'project' or $type == 'execution')
|
|
{
|
|
$objectGroup = $this->dao->select('id,name')->from(TABLE_PROJECT)
|
|
->where('id')->in($duplicateList)
|
|
->fetchGroup('name');
|
|
}
|
|
|
|
$this->view->type = $type;
|
|
$this->view->objectGroup = $objectGroup;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Merge Repos.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function mergeRepo()
|
|
{
|
|
if($_POST)
|
|
{
|
|
$this->upgrade->mergeRepo();
|
|
return print(js::locate($this->createLink('upgrade', 'mergeRepo'), 'parent'));
|
|
}
|
|
|
|
$repoes = $this->dao->select('id, name')->from(TABLE_REPO)->where('deleted')->eq(0)->andWhere('product')->eq('')->fetchPairs();
|
|
$products = $this->dao->select('id, name')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchPairs();
|
|
if(empty($repoes) or empty($products))
|
|
{
|
|
$this->dao->delete()->from(TABLE_BLOCK)->exec();
|
|
$this->dao->delete()->from(TABLE_CONFIG)->where('`key`')->eq('blockInited')->exec();
|
|
$this->loadModel('setting')->deleteItems('owner=system&module=common§ion=global&key=upgradeStep');
|
|
return print(js::locate($this->createLink('upgrade', 'afterExec', "fromVersion=&processed=no")));
|
|
}
|
|
|
|
$this->view->title = $this->lang->upgrade->mergeRepo;
|
|
$this->view->repoes = $repoes;
|
|
$this->view->products = $products;
|
|
$this->view->programs = $this->dao->select('id, name')->from(TABLE_PROGRAM)->where('deleted')->eq(0)->andWhere('type')->eq('program')->fetchPairs();
|
|
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Get the project of the program it belongs to.
|
|
*
|
|
* @param int $programID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxGetProjectPairsByProgram($programID = 0)
|
|
{
|
|
$projects = array('' => '') + $this->upgrade->getProjectPairsByProgram($programID);
|
|
echo html::select('projects', $projects, '', 'class="form-control prj-exist" onchange="getProgramStatus(\'project\', this.value)"');
|
|
}
|
|
|
|
/**
|
|
* Get the lines of the program it belongs to.
|
|
*
|
|
* @param int $programID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxGetLinesPairsByProgram($programID = 0)
|
|
{
|
|
$lines = array('' => '');
|
|
if((int)$programID) $lines += $this->loadModel('product')->getLinePairs($programID);
|
|
echo html::select('lines', $lines, '', 'class="form-control line-exist"');
|
|
}
|
|
|
|
/**
|
|
* After execute.
|
|
*
|
|
* @param string $fromVersion
|
|
* @param string $processed
|
|
* @param string $skipMoveFile
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function afterExec($fromVersion, $processed = 'no', $skipMoveFile = 'no')
|
|
{
|
|
$alterSQL = $this->upgrade->checkConsistency($this->config->version);
|
|
if(!empty($alterSQL))
|
|
{
|
|
$this->view->title = $this->lang->upgrade->consistency;
|
|
$this->view->alterSQL = $alterSQL;
|
|
return print($this->display('upgrade', 'consistency'));
|
|
}
|
|
|
|
$extFiles = $this->upgrade->getExtFiles();
|
|
if(!empty($extFiles) and $skipMoveFile == 'no') return print(js::locate(inlink('moveExtFiles', "fromVersion=$fromVersion")));
|
|
|
|
$response = $this->upgrade->removeEncryptedDir();
|
|
if($response['result'] == 'fail')
|
|
{
|
|
$this->view->title = $this->lang->upgrade->common;
|
|
$this->view->errors = $response['command'];
|
|
$this->view->result = 'fail';
|
|
|
|
return $this->display('upgrade', 'execute');
|
|
}
|
|
|
|
unset($_SESSION['user']);
|
|
|
|
if($processed == 'no')
|
|
{
|
|
$this->app->loadLang('install');
|
|
$this->view->title = $this->lang->upgrade->result;
|
|
$this->view->position[] = $this->lang->upgrade->common;
|
|
|
|
$needProcess = $this->upgrade->checkProcess();
|
|
$this->view->needProcess = $needProcess;
|
|
$this->view->fromVersion = $fromVersion;
|
|
$this->display();
|
|
}
|
|
if(empty($needProcess) or $processed == 'yes')
|
|
{
|
|
$this->loadModel('setting')->updateVersion($this->config->version);
|
|
|
|
$installFile = $this->app->getAppRoot() . 'www/install.php';
|
|
$upgradeFile = $this->app->getAppRoot() . 'www/upgrade.php';
|
|
if(file_exists($installFile)) @unlink($installFile);
|
|
if(file_exists($upgradeFile)) @unlink($upgradeFile);
|
|
unset($_SESSION['upgrading']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Consistency.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function consistency($netConnect = true)
|
|
{
|
|
set_time_limit(0);
|
|
$alterSQL = $this->upgrade->checkConsistency();
|
|
if(empty($alterSQL))
|
|
{
|
|
if(!$netConnect) $this->locate(inlink('selectVersion'));
|
|
$this->locate(inlink('checkExtension'));
|
|
}
|
|
|
|
$this->view->title = $this->lang->upgrade->consistency;
|
|
$this->view->alterSQL = $alterSQL;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Check extension.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function checkExtension()
|
|
{
|
|
$this->loadModel('extension');
|
|
$extensions = $this->extension->getLocalExtensions('installed');
|
|
if(empty($extensions)) $this->locate(inlink('selectVersion'));
|
|
|
|
$versions = array();
|
|
foreach($extensions as $code => $extension) $versions[$code] = $extension->version;
|
|
|
|
$incompatibleExts = $this->extension->checkIncompatible($versions);
|
|
$extensionsName = array();
|
|
if(empty($incompatibleExts)) $this->locate(inlink('selectVersion'));
|
|
|
|
$removeCommands = array();
|
|
foreach($incompatibleExts as $extension)
|
|
{
|
|
$this->extension->updateExtension($extension, array('status' => 'deactivated'));
|
|
$removeCommands[$extension] = $this->extension->removePackage($extension);
|
|
$extensionsName[$extension] = $extensions[$extension]->name;
|
|
}
|
|
|
|
$data = '';
|
|
if($extensionsName)
|
|
{
|
|
$data .= "<h3>{$this->lang->upgrade->forbiddenExt}</h3>";
|
|
$data .= '<ul>';
|
|
foreach($extensionsName as $extension => $extensionName)
|
|
{
|
|
$data .= "<li>$extensionName";
|
|
if($removeCommands[$extension]) $data .= '<p>'. $this->lang->extension->unremovedFiles . '</p> <p>' . join('<br />', $removeCommands[$extension]) . '</p>';
|
|
$data .= '</li>';
|
|
}
|
|
$data .= '</ul>';
|
|
}
|
|
|
|
$this->view->title = $this->lang->upgrade->checkExtension;
|
|
$this->view->data = $data;
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* Ajax update file.
|
|
*
|
|
* @param string $type
|
|
* @param int $lastID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxUpdateFile($type = '', $lastID = 0)
|
|
{
|
|
set_time_limit(0);
|
|
$this->app->loadLang('search');
|
|
$result = $this->upgrade->updateFileObjectID($type, $lastID);
|
|
$response = array();
|
|
if($result['type'] == 'finish')
|
|
{
|
|
$response['result'] = 'finished';
|
|
$response['type'] = $type;
|
|
$response['count'] = $result['count'];
|
|
$response['message'] = $this->lang->search->buildSuccessfully;
|
|
}
|
|
else
|
|
{
|
|
$response['result'] = 'continue';
|
|
$response['next'] = inlink('ajaxUpdateFile', "type={$result['type']}&lastID={$result['lastID']}");
|
|
$response['count'] = $result['count'];
|
|
$response['type'] = $type;
|
|
$response['nextType'] = $result['type'];
|
|
$response['message'] = zget($this->lang->searchObjects, $result['type']) . " <span class='{$result['type']}-num'>0</span>";
|
|
}
|
|
echo json_encode($response);
|
|
}
|
|
|
|
/**
|
|
* Ajax get product name.
|
|
*
|
|
* @param int $productID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxGetProductName($productID)
|
|
{
|
|
echo $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('name');
|
|
}
|
|
|
|
/**
|
|
* Ajax get program status.
|
|
*
|
|
* @param int $projectID
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function ajaxGetProgramStatus($programID)
|
|
{
|
|
echo $this->dao->select('status')->from(TABLE_PROGRAM)->where('id')->eq($programID)->fetch('status');
|
|
}
|
|
|
|
/**
|
|
* Move Extent files.
|
|
*
|
|
* @param string $fromVersion
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function moveExtFiles($fromVersion)
|
|
{
|
|
$command = '';
|
|
$result = 'success';
|
|
if(strtolower($this->server->request_method) == 'post')
|
|
{
|
|
if(!empty($_POST['files']))
|
|
{
|
|
$response = $this->upgrade->moveExtFiles();
|
|
$result = $response['result'];
|
|
if($result == 'fail') $command = $response['command'];
|
|
}
|
|
|
|
if($result == 'success') $this->locate($this->inlink('afterExec', "fromVersion=$fromVersion&processed=no&skipMoveFile=yes"));
|
|
}
|
|
|
|
$this->view->title = $this->lang->upgrade->common;
|
|
$this->view->files = $this->upgrade->getExtFiles();
|
|
$this->view->result = $result;
|
|
$this->view->command = $command;
|
|
$this->view->fromVersion = $fromVersion;
|
|
|
|
$this->display();
|
|
}
|
|
}
|