Merge branch 'master' into sprint/220

This commit is contained in:
caoyanyi
2022-11-25 13:52:26 +08:00
3551 changed files with 419254 additions and 21908 deletions
+197 -44
View File
@@ -58,10 +58,9 @@ class testcaseModel extends model
->add('fromBug', $bugID)
->setDefault('openedBy', $this->app->user->account)
->setDefault('openedDate', $now)
->setIF($this->config->systemMode == 'new' and $this->app->tab == 'project', 'project', $this->session->project)
->setIF($this->app->tab == 'project', 'project', $this->session->project)
->setIF($this->app->tab == 'execution', 'execution', $this->session->execution)
->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion((int)$this->post->story))
->stripTags($this->config->testcase->editor->create['id'], $this->config->allowedTags)
->remove('steps,expects,files,labels,stepType,forceNotReview')
->setDefault('story', 0)
->cleanInt('story,product,branch,module')
@@ -78,7 +77,6 @@ class testcaseModel extends model
/* Value of story may be showmore. */
$case->story = (int)$case->story;
$case = $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->create['id'], $this->post->uid);
$this->dao->insert(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->create->requiredFields, 'notempty')->checkFlow()->exec();
if(!$this->dao->isError())
{
@@ -97,8 +95,8 @@ class testcaseModel extends model
$step->parent = ($step->type == 'item') ? $parentStepID : 0;
$step->case = $caseID;
$step->version = 1;
$step->desc = htmlSpecialString($stepDesc);
$step->expect = $step->type == 'group' ? '' : htmlSpecialString($data->expects[$stepID]);
$step->desc = rtrim(htmlSpecialString($stepDesc));
$step->expect = $step->type == 'group' ? '' : rtrim(htmlSpecialString($data->expects[$stepID]));
$this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec();
if($step->type == 'group') $parentStepID = $this->dao->lastInsertID();
if($step->type == 'step') $parentStepID = 0;
@@ -138,6 +136,12 @@ class testcaseModel extends model
$pri = 3;
foreach($cases->title as $i => $title)
{
if(empty($title) and $this->common->checkValidRow('testcase', $cases, $i))
{
dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->testcase->title);
return false;
}
$module = $cases->module[$i] == 'ditto' ? $module : $cases->module[$i];
$story = $cases->story[$i] == 'ditto' ? $story : $cases->story[$i];
$type = $cases->type[$i] == 'ditto' ? $type : $cases->type[$i];
@@ -159,7 +163,7 @@ class testcaseModel extends model
$data[$i] = new stdclass();
$data[$i]->product = $productID;
if($this->config->systemMode == 'new' && $this->app->tab == 'project') $data[$i]->project = $this->session->project;
if($this->app->tab == 'project') $data[$i]->project = $this->session->project;
$data[$i]->branch = $cases->branch[$i];
$data[$i]->module = $cases->module[$i];
$data[$i]->type = $cases->type[$i];
@@ -659,16 +663,16 @@ class testcaseModel extends model
*/
public function getByAssignedTo($account, $orderBy = 'id_desc', $pager = null, $auto = 'no')
{
return $this->dao->select('t1.task,t1.case,t1.version,t1.assignedTo,t1.lastRunner,t1.lastRunDate,t1.lastRunResult,t1.status,t2.id as id,t2.project,t2.pri,t2.title,t2.type,t2.openedBy,t2.color,t2.product,t2.branch,t2.module,t2.status,t3.name as taskName')->from(TABLE_TESTRUN)->alias('t1')
return $this->dao->select('t1.id as run, t1.task,t1.case,t1.version,t1.assignedTo,t1.lastRunner,t1.lastRunDate,t1.lastRunResult,t1.status as lastRunStatus,t2.id as id,t2.project,t2.pri,t2.title,t2.type,t2.openedBy,t2.color,t2.product,t2.branch,t2.module,t2.status,t2.story,t2.storyVersion,t3.name as taskName')->from(TABLE_TESTRUN)->alias('t1')
->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id')
->leftJoin(TABLE_TESTTASK)->alias('t3')->on('t1.task = t3.id')
->where('t1.assignedTo')->eq($account)
->andWhere('t3.deleted')->eq(0)
->andWhere('t2.deleted')->eq(0)
->andWhere('t3.status')->ne('done')
->beginIF($auto != 'skip' and $auto != 'unit')->andWhere('t2.auto')->ne('unit')->fi()
->beginIF(strpos($auto, 'skip') === false and $auto != 'unit')->andWhere('t2.auto')->ne('unit')->fi()
->beginIF($auto == 'unit')->andWhere('t2.auto')->eq('unit')->fi()
->orderBy($orderBy)->page($pager)->fetchAll('id');
->orderBy($orderBy)->page($pager)->fetchAll(strpos($auto, 'run') !== false? 'run' : 'id');
}
/**
@@ -741,6 +745,24 @@ class testcaseModel extends model
->fetchAll('id');
}
/**
* Get case pairs by product id and branch.
*
* @param int $productID
* @param int|string $branch
* @access public
* @return void
*/
public function getPairsByProduct($productID, $branch = 0)
{
return $this->dao->select('id, concat_ws(":", id, title) as title')->from(TABLE_CASE)
->where('deleted')->eq(0)
->andWhere('product')->eq($productID)
->beginIF($branch)->andWhere('branch')->in($branch)->fi()
->orderBy('id_desc')
->fetchPairs();
}
/**
* Get cases of a story.
*
@@ -817,6 +839,7 @@ class testcaseModel extends model
->add('lastEditedDate', $now)
->setDefault('story,branch', 0)
->setDefault('stage', '')
->setDefault('deleteFiles', array())
->join('stage', ',')
->join('linkCase', ',')
->setForce('status', $status)
@@ -829,13 +852,10 @@ class testcaseModel extends model
if($oldCase->lib != 0)
{
/* Remove the require field named story when the case is a lib case.*/
$requiredFieldsArr = explode(',', $requiredFields);
$fieldIndex = array_search('story', $requiredFieldsArr);
array_splice($requiredFieldsArr, $fieldIndex, 1);
$requiredFields = implode(',', $requiredFieldsArr);
$requiredFields = str_replace(',story,', ',', ",$requiredFields,");
}
$case = $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->edit['id'], $this->post->uid);
$this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($requiredFields, 'notempty')->checkFlow()->where('id')->eq((int)$caseID)->exec();
$this->dao->update(TABLE_CASE)->data($case, 'deleteFiles')->autoCheck()->batchCheck($requiredFields, 'notempty')->checkFlow()->where('id')->eq((int)$caseID)->exec();
if(!$this->dao->isError())
{
$this->updateCase2Project($oldCase, $case, $caseID);
@@ -865,8 +885,8 @@ class testcaseModel extends model
$step->parent = ($step->type == 'item') ? $parentStepID : 0;
$step->case = $caseID;
$step->version = $version;
$step->desc = htmlSpecialString($stepDesc);
$step->expect = $step->type == 'group' ? '' : htmlSpecialString($data->expects[$stepID]);
$step->desc = rtrim(htmlSpecialString($stepDesc));
$step->expect = $step->type == 'group' ? '' : rtrim(htmlSpecialString($data->expects[$stepID]));
$this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec();
if($step->type == 'group') $parentStepID = $this->dao->lastInsertID();
if($step->type == 'step') $parentStepID = 0;
@@ -942,6 +962,8 @@ class testcaseModel extends model
}
}
}
$this->file->processFile4Object('testcase', $oldCase, $case);
return common::createChanges($oldCase, $case);
}
}
@@ -1089,15 +1111,15 @@ class testcaseModel extends model
if($data->pris[$caseID] == 'ditto') $data->pris[$caseID] = isset($prev['pri']) ? $prev['pri'] : 3;
if($data->modules[$caseID] == 'ditto') $data->modules[$caseID] = isset($prev['module']) ? $prev['module'] : 0;
if($data->types[$caseID] == 'ditto') $data->types[$caseID] = isset($prev['type']) ? $prev['type'] : '';
if($data->story[$caseID] == '') $data->story[$caseID] = 0;
if($data->story[$caseID] == '') $data->story[$caseID] = 0;
if($data->story[$caseID] == 'ditto') $data->story[$caseID] = isset($prev['story']) ? $prev['story'] : 0;
if(isset($data->branches[$caseID]) and $data->branches[$caseID] == 'ditto') $data->branches[$caseID] = isset($prev['branch']) ? $prev['branch'] : 0;
if($data->story[$caseID] == 'ditto') $data->story[$caseID] = isset($prev['story']) ? $prev['story'] : 0;
$prev['pri'] = $data->pris[$caseID];
$prev['type'] = $data->types[$caseID];
$prev['story'] = $data->story[$caseID];
$prev['branch'] = $data->branches[$caseID];
$prev['module'] = $data->modules[$caseID];
if(isset($data->branches)) $prev['branch'] = $data->branches[$caseID];
}
/* Initialize cases from the post data.*/
@@ -1109,7 +1131,6 @@ class testcaseModel extends model
$case->lastEditedBy = $this->app->user->account;
$case->lastEditedDate = $now;
$case->pri = $data->pris[$caseID];
$case->branch = $data->branches[$caseID];
$case->module = $data->modules[$caseID];
$case->status = $data->statuses[$caseID];
$case->story = $data->story[$caseID];
@@ -1119,6 +1140,7 @@ class testcaseModel extends model
$case->keywords = $data->keywords[$caseID];
$case->type = $data->types[$caseID];
$case->stage = empty($data->stages[$caseID]) ? '' : implode(',', $data->stages[$caseID]);
if(isset($data->branches[$caseID])) $case->branch = $data->branches[$caseID];
foreach($extendFields as $extendField)
{
@@ -1161,7 +1183,7 @@ class testcaseModel extends model
unset($oldCase->steps);
$allChanges[$caseID] = common::createChanges($oldCase, $case);
if($case->branch and isset($testtasks[$caseID]))
if(!empty($case->branch) and isset($testtasks[$caseID]))
{
foreach($testtasks[$caseID] as $taskID => $testtask)
{
@@ -1343,10 +1365,12 @@ class testcaseModel extends model
*/
public static function isClickable($case, $action, $module = 'testcase')
{
global $config;
$action = strtolower($action);
if($module == 'testcase' && $action == 'createbug') return $case->caseFails > 0;
if($module == 'testcase' && $action == 'review') return isset($case->caseStatus) ? $case->caseStatus == 'wait' : $case->status == 'wait';
if($module == 'testcase' && $action == 'createbug') return $case->caseFails > 0;
if($module == 'testcase' && $action == 'review') return isset($case->caseStatus) ? $case->caseStatus == 'wait' : $case->status == 'wait';
return true;
}
@@ -1453,7 +1477,15 @@ class testcaseModel extends model
$cases[$key] = $caseData;
$line++;
}
if(!empty($fieldNames)) dao::$errors = sprintf($this->lang->testcase->noRequireTip, implode(',', $fieldNames));
if(!empty($fieldNames))
{
$tipContent = '';
foreach($requiredFields as $field)
{
if(isset($fieldNames[$field])) $tipContent .= ",{$fieldNames[$field]}";
}
dao::$errors = sprintf($this->lang->testcase->noRequireTip, trim($tipContent, ','));
}
if(dao::isError()) return false;
@@ -1558,7 +1590,7 @@ class testcaseModel extends model
}
else
{
if($this->config->systemMode == 'new' && $this->app->tab == 'project') $caseData->project = $this->session->project;
if($this->app->tab == 'project') $caseData->project = $this->session->project;
$caseData->version = 1;
$caseData->openedBy = $this->app->user->account;
$caseData->openedDate = $now;
@@ -1929,14 +1961,23 @@ class testcaseModel extends model
*/
public function buildSearchForm($productID, $products, $queryID, $actionURL, $projectID = 0)
{
$product = ($this->app->tab == 'project' and empty($productID)) ? $products : array($productID => $products[$productID]) + array('all' => $this->lang->testcase->allProduct);
$this->config->testcase->search['params']['product']['values'] = $product;
$productList = array();
if($this->app->tab == 'project' and empty($productID))
{
$productList = $products;
}
else
{
$productList = array('all' => $this->lang->all);
if(isset($products[$productID])) $productList = array($productID => $products[$productID]) + $productList;
}
$this->config->testcase->search['params']['product']['values'] = array('') + $productList;
$module = $this->loadModel('tree')->getOptionMenu($productID, 'case', 0);
if(!$productID)
{
$module = array();
foreach($products as $id => $product) $module += $this->loadModel('tree')->getOptionMenu($id, 'case', 0);
foreach($products as $id => $name) $module += $this->loadModel('tree')->getOptionMenu($id, 'case', 0);
}
$this->config->testcase->search['params']['module']['values'] = $module;
@@ -1949,8 +1990,9 @@ class testcaseModel extends model
}
else
{
$productInfo = $this->loadModel('product')->getByID($productID);
$this->config->testcase->search['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$productInfo->type]);
$this->app->loadLang('branch');
$product = $this->loadModel('product')->getByID($productID);
$this->config->testcase->search['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
$this->config->testcase->search['params']['branch']['values'] = array('' => '', '0' => $this->lang->branch->main) + $this->loadModel('branch')->getPairs($productID, '', $projectID) + array('all' => $this->lang->branch->all);
}
if(!$this->config->testcase->needReview) unset($this->config->testcase->search['params']['status']['values']['wait']);
@@ -2133,14 +2175,15 @@ class testcaseModel extends model
/**
* Append bugs and results.
*
* @param array $cases
* @param string $type
* @param int $cases
* @param string $type
* @param array $caseIdlist
* @access public
* @return array
* @return void
*/
public function appendData($cases, $type = 'case')
public function appendData($cases, $type = 'case', $caseIdlist = array())
{
$caseIdList = array_keys($cases);
if(empty($caseIdlist)) $caseIdList = array_keys($cases);
if($type == 'case')
{
$caseBugs = $this->dao->select('count(*) as count, `case`')->from(TABLE_BUG)->where('`case`')->in($caseIdList)->andWhere('deleted')->eq(0)->groupBy('`case`')->fetchPairs('case', 'count');
@@ -2267,9 +2310,10 @@ class testcaseModel extends model
$data->order = ++ $lastOrder;
$this->dao->insert(TABLE_PROJECTCASE)->data($data)->exec();
$objectType = $objectInfo[$projectID]->type;
$object = $objectInfo[$projectID];
$objectType = $object->type;
if($objectType == 'project') $this->action->create('case', $caseID, 'linked2project', '', $projectID);
if(in_array($objectType, array('sprint', 'stage'))) $this->action->create('case', $caseID, 'linked2execution', '', $projectID);
if(in_array($objectType, array('sprint', 'stage')) and $object->multiple) $this->action->create('case', $caseID, 'linked2execution', '', $projectID);
}
}
@@ -2406,7 +2450,6 @@ class testcaseModel extends model
if(!empty($_POST['title']) and $case->title != $this->post->title) $stepChanged = true;
if(!empty($_POST['precondition']) and $case->precondition != $this->post->precondition) $stepChanged = true;
if(!empty($_POST['labels'][0])) $stepChanged = true;
return array($stepChanged, $status);
}
@@ -2450,13 +2493,13 @@ class testcaseModel extends model
{
$menu .= $this->buildMenu('testtask', 'runCase', "$extraParams&version=$case->currentVersion", $case, 'view', 'play', '', 'showinonlybody', false, "data-width='95%'");
$menu .= $this->buildMenu('testtask', 'results', "$extraParams&version=$case->version", $case, 'view', '', '', 'showinonlybody', false, "data-width='95%'");
$menu .= $this->buildMenu('testcase', 'importToLib', $params, $case, 'view', 'assets', '', 'showinonlybody iframe', true, "data-width='500px'");
if(!isonlybody()) $menu .= $this->buildMenu('testcase', 'importToLib', $params, $case, 'view', 'assets', '', 'showinonlybody iframe', true, "data-width='500px'");
}
else
{
$menu .= $this->buildMenu('testtask', 'runCase', "$extraParams&version=$case->currentVersion", $case, 'view', 'play', '', 'showinonlybody iframe', false, "data-width='95%'");
$menu .= $this->buildMenu('testtask', 'results', "$extraParams&version=$case->version", $case, 'view', '', '', 'showinonlybody iframe', false, "data-width='95%'");
$menu .= $this->buildMenu('testcase', 'importToLib', $params, $case, 'view', 'assets', '', 'showinonlybody iframe', true, "data-width='500px'");
if(!isonlybody()) $menu .= $this->buildMenu('testcase', 'importToLib', $params, $case, 'view', 'assets', '', 'showinonlybody iframe', true, "data-width='500px'");
}
if($case->caseFails > 0)
{
@@ -2465,7 +2508,7 @@ class testcaseModel extends model
}
if($this->config->testcase->needReview || !empty($this->config->testcase->forceReview))
{
$menu .= $this->buildMenu('testcase', 'review', $params, $case, 'view', '', '', 'iframe', '', '', $this->lang->testcase->reviewAB);
$menu .= $this->buildMenu('testcase', 'review', $params, $case, 'view', '', '', 'showinonlybody iframe', '', '', $this->lang->testcase->reviewAB);
}
}
else
@@ -2518,12 +2561,12 @@ class testcaseModel extends model
if($case->needconfirm || $case->browseType == 'needconfirm')
{
return $this->buildMenu('testcase', 'confirmstorychange', $params, $case, 'browse', 'confirm', 'hiddenwin', '', '', '', $this->lang->confirm);
return $this->buildMenu('testcase', 'confirmstorychange', $params, $case, 'browse', 'ok', 'hiddenwin', '', '', '', $this->lang->confirm);
}
$menu .= $this->buildMenu('testtask', 'results', "runID=0&$params", $case, 'browse', '', '', 'iframe', true, "data-width='95%'");
$menu .= $this->buildMenu('testtask', 'runCase', "runID=0&$params&version=$case->version", $case, 'browse', 'play', '', 'runCase iframe', false, "data-width='95%'");
if($case->auto == 'auto') $menu .= $this->buildMenu('testcase', 'showScript', $params, $case, 'browse', 'file-code', '', 'runCase iframe', false);
$menu .= $this->buildMenu('testtask', 'results', "runID=0&$params", $case, 'browse', '', '', 'iframe', true, "data-width='95%'");
$editParams = $params;
if($this->app->tab == 'project') $editParams .= "&comment=false&projectID={$this->session->project}";
@@ -2532,11 +2575,121 @@ class testcaseModel extends model
if($this->config->testcase->needReview || !empty($this->config->testcase->forceReview))
{
common::printIcon('testcase', 'review', $params, $case, 'browse', 'glasses', '', 'iframe');
common::printIcon('testcase', 'review', $params, $case, 'browse', 'glasses', '', 'showinonlybody iframe');
}
$menu .= $this->buildMenu('testcase', 'createBug', "product=$case->product&branch=$case->branch&extra=caseID=$case->id,version=$case->version,runID=", $case, 'browse', 'bug', '', 'iframe', '', "data-width='90%'");
$menu .= $this->buildMenu('testcase', 'create', "productID=$case->product&branch=$case->branch&moduleID=$case->module&from=testcase&param=$case->id", $case, 'browse', 'copy');
return $menu;
}
/**
* processDatas
*
* @param array $datas
* @access public
* @return void
*/
public function processDatas($datas)
{
if(isset($datas->datas)) $datas = $datas->datas;
$columnKey = array();
$caseData = array();
$stepData = array();
$stepVars = 0;
foreach($datas as $row => $cellValue)
{
foreach($cellValue as $field => $value)
{
if($field != 'stepDesc' and $field != 'stepExpect') continue;
if($field == 'stepDesc' or $field == 'stepExpect')
{
$steps = $value;
if(strpos($value, "\n"))
{
$steps = explode("\n", $value);
}
elseif(strpos($value, "\r"))
{
$steps = explode("\r", $value);
}
if(is_string($steps)) $steps = explode("\n", $steps);
$stepKey = str_replace('step', '', strtolower($field));
$caseStep = array();
foreach($steps as $step)
{
$trimedStep = trim($step);
if(empty($trimedStep)) continue;
if(preg_match('/^(([0-9]+)\.[0-9]+)([.、]{1})/U', $step, $out) and ($field == 'stepDesc' or ($field == 'stepExpect' and isset($stepData[$row]['desc'][$out[1]]))))
{
$num = $out[1];
$parent = $out[2];
$sign = $out[3];
$signbit = $sign == '.' ? 1 : 3;
$step = trim(substr($step, strlen($num) + $signbit));
if(!empty($step)) $caseStep[$num]['content'] = $step;
$caseStep[$num]['type'] = 'item';
$caseStep[$parent]['type'] = 'group';
}
elseif(preg_match('/^([0-9]+)([.、]{1})/U', $step, $out) and ($field == 'stepDesc' or ($field == 'stepExpect' and isset($stepData[$row]['desc'][$out[1]]))))
{
$num = $out[1];
$sign = $out[2];
$signbit = $sign == '.' ? 1 : 3;
$step = trim(substr($step, strpos($step, $sign) + $signbit));
if(!empty($step)) $caseStep[$num]['content'] = $step;
$caseStep[$num]['type'] = 'step';
}
elseif(isset($num))
{
if(!isset($caseStep[$num]['content'])) $caseStep[$num]['content'] = '';
if(!isset($caseStep[$num]['type'])) $caseStep[$num]['type'] = 'step';
$caseStep[$num]['content'] .= "\n" . $step;
}
else
{
if($field == 'stepDesc')
{
$num = 1;
$caseStep[$num]['content'] = $step;
$caseStep[$num]['type'] = 'step';
}
if($field == 'stepExpect' and isset($stepData[$row]['desc']))
{
end($stepData[$row]['desc']);
$num = key($stepData[$row]['desc']); $caseStep[$num]['content'] = $step;
}
}
}
unset($num);
unset($sign);
$stepVars += count($caseStep, COUNT_RECURSIVE) - count($caseStep);
$stepData[$row][$stepKey] = $caseStep;
}
}
}
return $stepData;
}
/**
* Get modules for datatable.
*
* @param int $productID
* @access public
* @return void
*/
public function getDatatableModules($productID)
{
$branches = $this->loadModel('branch')->getPairs($productID);
$modules = $this->loadModel('tree')->getOptionMenu($productID, 'case', '');
if(count($branches) <= 1) return $modules;
foreach($branches as $branchID => $branchName) $modules += $this->tree->getOptionMenu($productID, 'case', 0, $branchID);
return $modules;
}
}