Merge branch 'sprint/170' into 'sprint/170_hufangzhou_43891_new'

# Conflicts:
#   module/branch/control.php
This commit is contained in:
李玉春
2021-11-08 05:53:39 +00:00
15 changed files with 173 additions and 45 deletions
+4 -4
View File
@@ -5,7 +5,7 @@
*
* The author disclaims copyright to this source code. In place of
* a legal notice, here is a blessing:
*
*
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
@@ -15,7 +15,7 @@ helper::import(dirname(dirname(__FILE__)) . '/base/filter/filter.class.php');
/**
* validater类,检查数据是否符合规则。
* The validater class, checking data by rules.
*
*
* @package framework
*/
class validater extends baseValidater
@@ -25,7 +25,7 @@ class validater extends baseValidater
/**
* fixer类,处理数据。
* fixer class, to fix data types.
*
*
* @package framework
*/
class fixer extends baseFixer
@@ -60,7 +60,7 @@ class fixer extends baseFixer
}
if($canImplode) $this->data->$field = implode(',', $value);
}
if(isset($flowFields[$field]) and $flowFields[$field]->control == 'textarea') $this->skipSpecial($field);
if(isset($flowFields[$field]) and ($flowFields[$field]->control == 'textarea' or $flowFields[$field]->control == 'richtext')) $this->skipSpecial($field);
$this->specialChars($field);
}
+7 -9
View File
@@ -66,16 +66,14 @@ class branch extends control
*/
public function ajaxGetDropMenu($productID, $branch = 0, $module, $method, $extra = '')
{
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
$this->view->productID = $productID;
$this->view->projectID = $this->session->project;
$this->view->module = $module;
$this->view->method = $method;
$this->view->extra = $extra;
$branches = $this->branch->getPairs($productID, 'all');
$statusList = $this->dao->select('id,status')->from(TABLE_BRANCH)->where('product')->eq($productID)->fetchPairs();
$branches = $this->branch->getPairs($productID);
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
$this->view->productID = $productID;
$this->view->projectID = $this->session->project;
$this->view->module = $module;
$this->view->method = $method;
$this->view->extra = $extra;
$this->view->branches = $branches;
$this->view->currentBranchID = $branch;
$this->view->branchesPinyin = common::convert2Pinyin($branches);
+5 -1
View File
@@ -89,8 +89,12 @@ class branchModel extends model
{
$product = $this->loadModel('product')->getById($productID);
if(!$product or $product->type == 'normal') return array();
$branches = array('0' => $this->lang->branch->main) + $branches;
}
$branches = array('all' => $this->lang->branch->all, '0' => $this->lang->branch->main) + $branches;
if(strpos($params, 'all') !== false)
{
$branches = array('all' => $this->lang->branch->all) + $branches;
}
return $branches;
}
+1 -1
View File
@@ -226,7 +226,7 @@ class bug extends control
$this->view->moduleID = $moduleID;
$this->view->memberPairs = $this->user->getPairs('noletter|nodeleted');
$this->view->branch = $branch;
$this->view->branches = $this->loadModel('branch')->getPairs($productID, 'noempty');
$this->view->branches = $this->loadModel('branch')->getPairs($productID);
$this->view->executions = $executions;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
$this->view->stories = $storyList;
+1 -1
View File
@@ -89,7 +89,7 @@
<td class="c-pri"><span class='label-pri <?php echo 'label-pri-' . $task->pri;?>' title='<?php echo zget($lang->task->priList, $task->pri);?>'><?php echo zget($lang->task->priList, $task->pri);?></span></td>
<td class='c-name <?php if(!empty($task->children)) echo 'has-child';?>' title='<?php echo $task->name?>'>
<?php if(!empty($task->team)) echo '<span class="label label-badge label-light">' . $this->lang->task->multipleAB . '</span> ';?>
<?php if($task->parent > 0) echo '<span class="label label-badge label-light">' . $this->lang->task->childrenAB . '</span> ';?>
<?php if($task->parent > 0) echo '<span class="label label-badge label-light">' . $this->lang->task->childrenAB . '</span> ' . html::a($this->createLink('task', 'view', "taskID=$task->parent", '', '', $task->project), $task->parentName) . ' / ';?>
<?php echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', '', $task->project), $task->name, null, "style='color: $task->color' data-group='execution'");?>
<?php if(!empty($task->children)) echo '<a class="task-toggle" data-id="' . $task->id . '"><i class="icon icon-angle-double-right"></i></a>';?>
</td>
+2 -2
View File
@@ -413,7 +413,7 @@ class productplan extends control
else
{
$this->config->product->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($plan->product, 'noempty');
$branches = array('' => '', $this->loadModel('branch')->getPairs($plan->product);
if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]);
$this->config->product->search['params']['branch']['values'] = $branches;
}
@@ -554,7 +554,7 @@ class productplan extends control
else
{
$this->config->bug->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty');
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID);
if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]);
$this->config->bug->search['params']['branch']['values'] = $branches;
}
+39 -1
View File
@@ -237,7 +237,6 @@ class productplanModel extends model
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
->where('product')->in($product)
->andWhere('deleted')->eq(0)
->andWhere('end')->ge($date)
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
->beginIF($skipParent)->andWhere('parent')->ne(-1)->fi()
->orderBy('begin desc')
@@ -319,6 +318,45 @@ class productplanModel extends model
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('parent')->eq((int)$planID)->andWhere('deleted')->eq('0')->fetchAll();
}
/**
* Get plan list by story id list.
*
* @param string|array $storyIdList
* @access public
* @return array
*/
public function getPlansByStories($storyIdList)
{
if(empty($storyIdList)) return array();
return $this->dao->select('t1.id as storyID, t3.*')->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_PLANSTORY)->alias('t2')->on('t1.id=t2.story')
->leftJoin(TABLE_PRODUCTPLAN)->alias('t3')->on('t2.plan=t3.id')
->where('t1.id')->in($storyIdList)
->fetchGroup('storyID', 'id');
}
/**
* Get branch plan pairs.
*
* @param int $productID
* @access public
* @return array
*/
public function getBranchPlanPairs($productID)
{
$plans = $this->dao->select('branch,id,title,begin,end')->from(TABLE_PRODUCTPLAN)
->where('deleted')->eq(0)
->andWhere('product')->eq($productID)
->fetchAll('id');
$planPairs = array();
foreach($plans as $planID => $plan)
{
$planPairs[$plan->branch][$planID] = $plan->title . ' [' . $plan->begin . '~' . $plan->end . ']';
}
return $planPairs;
}
/**
* Create a plan.
*
+57 -11
View File
@@ -626,6 +626,7 @@ class story extends control
$this->view->stories = $stories;
$this->view->users = $users;
$this->view->product = $product;
$this->view->plans = $this->loadModel('productplan')->getPairsForStory($story->product, $story->branch, true);
$this->view->products = $myProducts + $othersProducts;
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product);
$this->view->reviewers = implode(',', $reviewerList);
@@ -705,15 +706,12 @@ class story extends control
$product = $this->product->getByID($productID);
$branchProduct = $product->type == 'normal' ? false : true;
/* Set modules and productPlans. */
$modules = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
$modules = array('ditto' => $this->lang->story->ditto) + $modules;
$productPlans = $this->productplan->getPairs($productID, $branch, '', true);
$productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans;
/* Set modules. */
$modules = array('ditto' => $this->lang->story->ditto) + $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
$this->view->modules = $modules;
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id);
$this->view->productPlans = $productPlans;
$this->view->plans = $this->productplan->getBranchPlanPairs($productID);
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name);
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit;
}
@@ -1376,14 +1374,55 @@ class story extends control
* Batch change branch.
*
* @param int $branchID
* @param string $confirm yes|no
* @param string $storyIdList
* @access public
* @return void
*/
public function batchChangeBranch($branchID)
public function batchChangeBranch($branchID, $confirm = '', $storyIdList = '')
{
$storyIdList = !empty($_POST['storyIdList']) ? $this->post->storyIdList : die(js::locate($this->session->storyList, 'parent'));
if(!empty($_POST['storyIdList'])) $storyIdList = $_POST['storyIdList'];
$storyIdList = !empty($storyIdList) ? $storyIdList : die(js::locate($this->session->storyList, 'parent'));
$plans = $this->loadModel('productplan')->getPlansByStories($storyIdList);
if(empty($confirm))
{
$stories = $this->story->getByList($storyIdList);
$normalStotyIdList = '';
$conflictStoryIdList = '';
$conflictStoryArray = array();
/* Determine whether there is a conflict between the branch of the story and the linked plan. */
foreach($storyIdList as $storyID)
{
if($stories[$storyID]->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID]))
{
foreach($plans[$storyID] as $plan)
{
if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID)
{
$conflictStoryIdList .= '[' . $storyID . ']';
$conflictStoryArray[] = $storyID;
break;
}
}
}
}
/* Prompt the user whether to continue to modify the conflicting stories branch. */
if($conflictStoryIdList)
{
$normalStotyIdList = array_diff($storyIdList, $conflictStoryArray);
$normalStotyIdList = implode(',', $normalStotyIdList);
$storyIdList = implode(',', $storyIdList);
$confirmURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=yes&storyIdList=$storyIdList");
$cancelURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=no&storyIdList=$normalStotyIdList");
die(js::confirm(sprintf($this->lang->story->confirmChangeBranch, $conflictStoryIdList ), $confirmURL, $cancelURL));
}
}
if(is_string($storyIdList)) $storyIdList = array_filter(explode(',', $storyIdList));
$storyIdList = array_unique($storyIdList);
$allChanges = $this->story->batchChangeBranch($storyIdList, $branchID);
$allChanges = $this->story->batchChangeBranch($storyIdList, $branchID, $confirm, $plans);
if(dao::isError()) die(js::error(dao::getError()));
foreach($allChanges as $storyID => $changes)
{
@@ -1771,7 +1810,7 @@ class story extends control
* @access public
* @return void
*/
public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1)
public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1, $executionID = 0)
{
if($moduleID)
{
@@ -1787,7 +1826,14 @@ class story extends control
$storyStatus = array_keys($storyStatus);
}
$stories = $this->story->getProductStoryPairs($productID, $branch ? "0,$branch" : $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent);
if($executionID)
{
$stories = $this->story->getExecutionStoryPairs($executionID, $productID, $branch, $moduleID, $type);
}
else
{
$stories = $this->story->getProductStoryPairs($productID, $branch ? "0,$branch" : $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent);
}
$storyID = isset($stories[$storyID]) ? $storyID : 0;
$select = html::select('story', empty($stories) ? array('' => '') : $stories, $storyID, "class='form-control'");
+1
View File
@@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved
$lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.';
$lang->story->estimateMustBeNumber = 'Estimate value must be number.';
$lang->story->estimateMustBePlus = 'Estimated value cannot be negative';
$lang->story->confirmChangeBranch = $lang->SRCommon . ' %s is linked to the plan of its linked branch. If the branch is edited, ' . $lang->SRCommon . ' will be removed from the plan of its linked branch. Do you want to continue edit ' . $lang->SRCommon . '?';
$lang->story->form = new stdclass();
$lang->story->form->area = 'Scope';
+1
View File
@@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "修改父{$lang->SRCommon}的所属产品
$lang->story->changeTips = '该软件需求关联的用户需求有变更,点击“不变更”忽略此条变更,点击“变更”来进行该软件需求的变更。';
$lang->story->estimateMustBeNumber = '估算值必须是数字';
$lang->story->estimateMustBePlus = '估算值不能是负数';
$lang->story->confirmChangeBranch = $lang->SRCommon . '%s已关联在之前所属分支的计划中,调整分支后,' . $lang->SRCommon . '将从之前所属分支的计划中移除,请确认是否继续修改上述' . $lang->SRCommon . '的分支。';
$lang->story->form = new stdclass();
$lang->story->form->area = "该{$lang->SRCommon}所属范围";
+37 -3
View File
@@ -1619,6 +1619,7 @@ class storyModel extends model
foreach($storyIdList as $storyID)
{
$oldStory = $oldStories[$storyID];
if($oldStory->branch != BRANCH_MAIN and $oldStory->branch != $plan->branch and $plan->branch != BRANCH_MAIN) continue;
/* Ignore parent story, closed story and story linked to this plan already. */
if($oldStory->parent < 0) continue;
@@ -1674,10 +1675,12 @@ class storyModel extends model
*
* @param array $storyIdList
* @param int $branchID
* @param string $confirm
* @param array $plans
* @access public
* @return void
* @return array
*/
public function batchChangeBranch($storyIdList, $branchID)
public function batchChangeBranch($storyIdList, $branchID, $confirm = '', $plans = array())
{
$now = helper::now();
$allChanges = array();
@@ -1692,7 +1695,38 @@ class storyModel extends model
$story->branch = $branchID;
$this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq((int)$storyID)->exec();
if(!dao::isError()) $allChanges[$storyID] = common::createChanges($oldStory, $story);
if(!dao::isError())
{
if($confirm == 'yes')
{
$planIdList = '';
$conflictPlanIdList = '';
/* Determine whether there is a conflict between the branch of the story and the linked plan. */
if($oldStory->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID]))
{
foreach($plans[$storyID] as $planID => $plan)
{
if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID)
{
$conflictPlanIdList .= $planID . ',';
}
else
{
$planIdList .= $planID . ',';
}
}
/* If there is a conflict in the linked plan when the branch story to be modified, the linked with the conflicting plan will be removed. */
if($conflictPlanIdList)
{
$story->plan = $planIdList;
$this->dao->delete()->from(TABLE_PLANSTORY)->where('story')->eq($storyID)->andWhere('plan')->in($conflictPlanIdList)->exec();
$this->dao->update(TABLE_STORY)->set('plan')->eq($planIdList)->where('id')->eq($storyID)->exec();
}
}
}
$allChanges[$storyID] = common::createChanges($oldStory, $story);
}
}
return $allChanges;
}
+12
View File
@@ -100,6 +100,18 @@ foreach(explode(',', $showFields) as $field)
<?php echo html::select("modules[$storyID]", $modules, $story->module, "class='form-control chosen'");?>
</td>
<td class='text-left<?php echo zget($visibleFields, 'plan', ' hidden')?>'>
<?php
$productPlans = array();
if($story->branch != BRANCH_MAIN)
{
$productPlans = zget($plans, $story->branch) + zget($plans, 0);
}
else
{
foreach($plans as $branchPlan) $productPlans += $branchPlan;
}
?>
<?php if($this->session->currentProductType == 'normal') $productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans;?>
<?php echo html::select("plans[$storyID]", $productPlans, $story->plan, "class='form-control chosen'");?>
</td>
<td title='<?php echo $story->title?>'>
+5 -3
View File
@@ -428,13 +428,15 @@ class testcase extends control
if(empty($moduleID)) $moduleID = $story->module;
}
$currentModuleID = (int)$moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
$currentModuleID = $moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
/* Get the status of stories are not closed. */
$storyStatus = $this->lang->story->statusList;
unset($storyStatus['closed']);
$modules = array();
if($currentModuleID)
{
$productModules = $this->tree->getOptionMenu($productID, 'story');
$currentModuleID = array_key_exists($currentModuleID,$productModules) ? $currentModuleID : 0;
$modules = $this->loadModel('tree')->getStoryModule($currentModuleID);
$modules = $this->tree->getAllChildID($modules);
}
@@ -453,11 +455,11 @@ class testcase extends control
$this->view->title = $title;
$this->view->position = $position;
$this->view->projectID = isset($projectID) ? $projectID : '';
$this->view->projectID = isset($projectID) ? $projectID : 0;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch);
$this->view->currentModuleID = $currentModuleID ? $currentModuleID : (int)$this->cookie->lastCaseModule;
$this->view->currentModuleID = $currentModuleID;
$this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('testcase', 'browse', "productID=$productID") : '';
$this->view->stories = $stories;
$this->view->caseTitle = $caseTitle;
+1 -8
View File
@@ -124,14 +124,7 @@ function setStories()
productID = $('#product').val();
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
if(tab == 'execution')
{
link = createLink('story', 'ajaxGetExecutionStories', 'executionID=' + executionID + '&productID=' + productID + '&branch' + branch + '&moduleID=' + moduleID + '&storyID=0');
}
else
{
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50');
}
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50' + '&executionID' + executionID);
$.get(link, function(stories)
{
-1
View File
@@ -17,7 +17,6 @@
<?php js::set('lblAfter', $lang->testcase->insertAfter);?>
<?php js::set('isonlybody', isonlybody());?>
<?php js::set('executionID', $projectID);?>
<?php js::set('tab', $this->app->tab);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>