From 4ebd5e6cc12f161b887474b871742dba87f030d0 Mon Sep 17 00:00:00 2001 From: zhujinyong Date: Sun, 21 Mar 2021 17:44:25 +0800 Subject: [PATCH] + Add qa, bug, testcase, testtask of project module. --- module/bug/model.php | 65 ++++++++++ module/common/lang/menu.php | 16 +-- module/project/control.php | 176 ++++++++++++++++++++++++++ module/project/view/bug.html.php | 164 ++++++++++++++++++++++++ module/project/view/qa.html.php | 2 + module/project/view/testcase.html.php | 78 ++++++++++++ module/project/view/testtask.html.php | 146 +++++++++++++++++++++ module/story/control.php | 13 +- module/testcase/model.php | 22 ++++ module/testtask/model.php | 22 ++++ 10 files changed, 692 insertions(+), 12 deletions(-) create mode 100644 module/project/view/bug.html.php create mode 100644 module/project/view/qa.html.php create mode 100644 module/project/view/testcase.html.php create mode 100644 module/project/view/testtask.html.php diff --git a/module/bug/model.php b/module/bug/model.php index b296aa536a..affbee0cdc 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1396,6 +1396,71 @@ class bugModel extends model return $bugs; } + /** + * Get bugs of a project. + * + * @param int $projectID + * @param int $build + * @param string $type + * @param int $param + * @param string $orderBy + * @param string $excludeBugs + * @param object $pager + * @access public + * @return array + */ + public function getProjectBugs($projectID, $build = 0, $type = '', $param = 0, $orderBy = 'id_desc', $excludeBugs = '', $pager = null) + { + $type = strtolower($type); + if($type == 'bysearch') + { + $queryID = (int)$param; + $products = $this->loadModel('project')->getProducts($projectID); + + if($this->session->projectBugQuery == false) $this->session->set('projectBugQuery', ' 1 = 1'); + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('projectBugQuery', $query->sql); + $this->session->set('projectBugForm', $query->form); + } + } + + $allProduct = "`product` = 'all'"; + $bugQuery = $this->session->projectBugQuery; + if(strpos($this->session->projectBugQuery, $allProduct) !== false) + { + $bugQuery = str_replace($allProduct, '1', $this->session->projectBugQuery); + } + + $bugs = $this->dao->select('*')->from(TABLE_BUG) + ->where($bugQuery) + ->andWhere('project')->eq((int)$projectID) + ->andWhere('deleted')->eq(0) + ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + } + else + { + $bugs = $this->dao->select('*')->from(TABLE_BUG) + ->where('deleted')->eq(0) + ->beginIF(empty($build))->andWhere('project')->eq($projectID)->fi() + ->beginIF($type == 'unresolved')->andWhere('status')->eq('active')->fi() + ->beginIF($type == 'noclosed')->andWhere('status')->ne('closed')->fi() + ->beginIF($build)->andWhere("CONCAT(',', openedBuild, ',') like '%,$build,%'")->fi() + ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi() + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug'); + + return $bugs; + } + /** * Get bugs of a execution. * diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index fb9ad14a91..5f72d3a4cf 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -148,7 +148,7 @@ $lang->scrum->menu->index = array('link' => "{$lang->dashboard}|project|inde $lang->scrum->menu->execution = array('link' => "$lang->executionCommon|project|execution|projectID=%s"); $lang->scrum->menu->story = array('link' => "$lang->SRCommon|projectstory|story|projectID=%s", 'alias' => 'story,track'); $lang->scrum->menu->doc = array('link' => "{$lang->doc->common}|doc|objectLibs|type=project&objectID=%s", 'subModule' => 'doc'); -$lang->scrum->menu->qa = array('link' => "{$lang->qa->common}|qa|index", 'subModule' => 'testcase,testtask'); +$lang->scrum->menu->qa = array('link' => "{$lang->qa->common}|project|qa|projectID=%s", 'subModule' => 'testcase,testtask,bug', 'alias' => 'bug,testtask,testcase'); $lang->scrum->menu->devops = array('link' => "{$lang->devops->common}|repo|browse"); $lang->scrum->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s"); $lang->scrum->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease'); @@ -169,14 +169,10 @@ $lang->scrum->menuOrder[48] = 'dynamic'; $lang->scrum->menuOrder[50] = 'settings'; $lang->scrum->menu->qa['subMenu'] = new stdclass(); -$lang->scrum->menu->qa['subMenu']->index = array('link' => "$lang->dashboard|qa|index"); -$lang->scrum->menu->qa['subMenu']->bug = array('link' => "{$lang->bug->common}|bug|browse|productID=%s", 'subModule' => 'bug'); -$lang->scrum->menu->qa['subMenu']->testcase = array('link' => "{$lang->testcase->shortCommon}|testcase|browse|productID=%s", 'subModule' => 'testsuite,testcase,caselib'); -$lang->scrum->menu->qa['subMenu']->testtask = array('link' => "{$lang->testtask->common}|testtask|browse|productID=%s", 'subModule' => 'testtask', 'class' => 'dropdown dropdown-hover'); - -$lang->scrum->menu->qa['subMenu']->testtask['subMenu'] = new stdclass(); -$lang->scrum->menu->qa['subMenu']->testtask['subMenu']->testtask = array('link' => "{$lang->testtask->common}|testtask|browse|productID=%s"); -$lang->scrum->menu->qa['subMenu']->testtask['subMenu']->report = array('link' => "{$lang->testreport->shortCommon}|testreport|browse|productID=%s"); +$lang->scrum->menu->qa['subMenu']->index = array('link' => "$lang->dashboard|project|qa|projectID=%s"); +$lang->scrum->menu->qa['subMenu']->bug = array('link' => "{$lang->bug->common}|project|bug|projectID=%s", 'subModule' => 'bug'); +$lang->scrum->menu->qa['subMenu']->testcase = array('link' => "{$lang->testcase->shortCommon}|project|testcase|projectID=%s", 'subModule' => 'testsuite,testcase,caselib'); +$lang->scrum->menu->qa['subMenu']->testtask = array('link' => "{$lang->testtask->common}|project|testtask|projectID=%s", 'subModule' => 'testtask', 'class' => 'dropdown dropdown-hover'); $lang->scrum->menu->settings['subMenu'] = new stdclass(); $lang->scrum->menu->settings['subMenu']->view = array('link' => "$lang->overview|project|view|project=%s", 'alias' => 'edit'); @@ -197,7 +193,7 @@ $lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectst $lang->waterfall->menu->design = array('link' => "$lang->design|design|browse|product=0&project=%s"); $lang->waterfall->menu->repo = array('link' => "{$lang->devops->common}|repo|browse|"); $lang->waterfall->menu->track = array('link' => "$lang->track|projectstory|track", 'alias' => 'track'); -$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|qa|index"); +$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|project|qa|projectID=%s", 'subModule' => 'testcase,testtask,bug', 'alias' => 'bug,testtask,testcase'); $lang->waterfall->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse", 'subModule' => 'projectrelease'); $lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s"); $lang->waterfall->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s"); diff --git a/module/project/control.php b/module/project/control.php index e0b43508db..6033f94b7c 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -664,6 +664,182 @@ class project extends control $this->locate($this->createLink('execution', 'all', "status=all&projectID=$projectID", '', false)); } + /** + * Project qa dashboard. + * + * @param int $projectID + * @access public + * @return void + */ + public function qa($projectID = 0) + { + $this->project->setMenu($projectID); + $this->view->title = $this->lang->project->qa; + $this->display(); + } + + /** + * Project bug list. + * + * @param int $projectID + * @param string $orderBy + * @param int $build + * @param string $type + * @param int $param + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function bug($projectID = 0, $orderBy = 'status,id_desc', $build = 0, $type = 'all', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Load these two models. */ + $this->loadModel('bug'); + $this->loadModel('user'); + + /* Save session. */ + $this->session->set('bugList', $this->app->getURI(true), 'qa'); + $this->project->setMenu($projectID); + + $project = $this->project->getByID($projectID); + $type = strtolower($type); + $queryID = ($type == 'bysearch') ? (int)$param : 0; + $products = $this->project->getProducts($projectID); + $productID = key($products); // Get the first product for creating bug. + $branchID = isset($products[$productID]) ? $products[$productID]->branch : 0; + + /* Header and position. */ + $title = $project->name . $this->lang->colon . $this->lang->bug->common; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->bug->common; + + /* Load pager and get bugs, user. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + $sort = $this->loadModel('common')->appendOrder($orderBy); + $bugs = $this->bug->getProjectBugs($projectID, $build, $type, $param, $sort, '', $pager); + $users = $this->user->getPairs('noletter'); + + /* team member pairs. */ + $memberPairs = array(); + $memberPairs[] = ""; + foreach($this->view->teamMembers as $key => $member) + { + $memberPairs[$key] = $member->realname; + } + + /* Build the search form. */ + $actionURL = $this->createLink('project', 'bug', "projectID=$projectID&orderBy=$orderBy&build=$build&type=bysearch&queryID=myQueryID"); + $this->execution->buildBugSearchForm($products, $queryID, $actionURL); + + /* Assign. */ + $this->view->title = $title; + $this->view->position = $position; + $this->view->bugs = $bugs; + $this->view->tabID = 'bug'; + $this->view->build = $this->loadModel('build')->getById($build); + $this->view->buildID = $this->view->build ? $this->view->build->id : 0; + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->users = $users; + $this->view->productID = $productID; + $this->view->branchID = empty($this->view->build->branch) ? $branchID : $this->view->build->branch; + $this->view->memberPairs = $memberPairs; + $this->view->type = $type; + $this->view->param = $param; + + $this->display(); + } + + /** + * Project case list. + * + * @param int $projectID + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function testcase($projectID = 0, $type = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $this->loadModel('testcase'); + $this->loadModel('testtask'); + + $this->project->setMenu($projectID); + + $products = $this->project->getProducts($projectID); + $productID = key($products); // Get the first product for creating testcase. + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $cases = $this->loadModel('testcase')->getProjectCases($projectID, $orderBy, $pager, $type); + $cases = $this->testcase->appendData($cases, 'run'); + + $this->view->title = $this->lang->execution->testcase; + $this->view->projectID = $projectID; + $this->view->productID = $productID; + $this->view->cases = $cases; + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + $this->view->type = $type; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->execution = $this->execution->getByID($executionID); + + $this->display(); + } + + /** + * Project test task list. + * + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function testtask($projectID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $this->loadModel('testtask'); + + /* Save session. */ + $this->session->set('testtaskList', $this->app->getURI(true), 'qa'); + + $this->project->setMenu($projectID); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $productTasks = array(); + + $project = $this->project->getByID($projectID); + $tasks = $this->testtask->getProjectTasks($projectID, $orderBy, $pager); + foreach($tasks as $key => $task) $productTasks[$task->product][] = $task; + + $this->view->title = $project->name . $this->lang->colon . $this->lang->project->common; + $this->view->position[] = html::a($this->createLink('project', 'testtask', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->testtask->common; + $this->view->project = $project; + $this->view->projectID = $projectID; + $this->view->projectName = $project->name; + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->tasks = $productTasks; + $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); + $this->view->products = $this->loadModel('product')->getPairs('', 0); + $this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable. + + $this->display(); + } + /** * Browse builds of a project. * diff --git a/module/project/view/bug.html.php b/module/project/view/bug.html.php new file mode 100644 index 0000000000..e1970283e3 --- /dev/null +++ b/module/project/view/bug.html.php @@ -0,0 +1,164 @@ + + * @package execution + * @version $Id: bug.html.php 4894 2013-06-25 01:28:39Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + +
+
+ +
+

+ bug->noBug;?> + + createLink('bug', 'create', "productID=$productID&branch=$branchID&extra=executionID=$execution->id"), " " . $lang->bug->create, '', "class='btn btn-info'");?> + +

+
+ +
+ + + id}&orderBy=%s&build=$buildID&type=$type¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + bug->severityList as $severityKey => $severityValue) + { + if(!empty($severityKey) and (string)$severityKey != (string)$severityValue) + { + $hasCustomSeverity = true; + break; + } + } + ?> + + + + + + + + + + + + + + + + +
+ +
+ +
+ + idAB);?> +
bug->severityAB);?> priAB);?> bug->title);?> openedByAB);?>assignedToAB);?>bug->resolvedBy);?>bug->resolutionAB);?>actions;?>
+ + id => ''), '', $arrtibute) . html::a(helper::createLink('bug', 'view', "bugID=$bug->id"), sprintf('%03d', $bug->id));?> + + id);?> + + + + ' title='bug->severityList, $bug->severity);?>' data-severity='severity;?>'>bug->severityList, $bug->severity, $bug->severity);?> + + ' title='bug->severityList, $bug->severity);?>' data-severity='severity;?>'> + + pri?>' title='bug->priList, $bug->pri, $bug->pri)?>'>bug->priList, $bug->pri, $bug->pri)?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title, null, "style='color: $bug->color'");?>openedBy, $bug->openedBy);?>bug->printAssignedHtml($bug, $users);?>resolvedBy, $bug->resolvedBy);?>bug->resolutionList, $bug->resolution);?> + id"; + common::printIcon('bug', 'confirmBug', $params, $bug, 'list', 'ok', '', 'iframe', true); + common::printIcon('bug', 'resolve', $params, $bug, 'list', 'checked', '', 'iframe', true); + common::printIcon('bug', 'close', $params, $bug, 'list', '', '', 'iframe', true); + common::printIcon('bug', 'create', "product=$bug->product&branch=$bug->branch&extra=$params", $bug, 'list', 'copy'); + common::printIcon('bug', 'edit', $params, $bug, 'list'); + } + ?> +
+
+ + + diff --git a/module/project/view/qa.html.php b/module/project/view/qa.html.php new file mode 100644 index 0000000000..679560fa37 --- /dev/null +++ b/module/project/view/qa.html.php @@ -0,0 +1,2 @@ + + diff --git a/module/project/view/testcase.html.php b/module/project/view/testcase.html.php new file mode 100644 index 0000000000..c10a65da74 --- /dev/null +++ b/module/project/view/testcase.html.php @@ -0,0 +1,78 @@ + + +
+ +
+

+ testcase->noCase;?> + + id", '', '', '', true), " " . $lang->testcase->create, '', "class='btn btn-info' data-app='execution'");?> + +

+
+ +
+ + recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?> + + + + + + + + + + + + + + + + + case : $case->id; + $runID = $type == 'assigntome' ? $case->id : 0; + $canBeChanged = common::canBeChanged('testcase', $case); + ?> + + + + version";?> + task";?> + + + + + + + + + + + +
idAB);?> priAB);?> testcase->title);?> typeAB);?> openedByAB);?> testtask->lastRunAccount);?> testtask->lastRunTime);?> testtask->lastRunResult);?>statusAB);?> actions;?>
+ id); ?> + pri?>' title='testcase->priList, $case->pri, $case->pri);?>'>testcase->priList, $case->pri, $case->pri)?>createLink('testcase', 'view', $params, '', '', $case->project), $case->title, null, "style='color: $case->color' data-group='project'");?>testcase->typeList, $case->type);?>openedBy);?>lastRunner);?>lastRunDate)) echo date(DT_MONTHTIME1, strtotime($case->lastRunDate));?>lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?>processStatus('testcase', $case);?> + product&branch=$case->branch&extra=caseID=$caseID,version=$case->version,runID=$runID", $case, 'list', 'bug', '', '', '', '', '', $case->project); + common::printIcon('testcase', 'create', "productID=$case->product&branch=$case->branch&moduleID=$case->module&from=testcase¶m=$caseID", $case, 'list', 'copy', '', '', '', '', '', $case->project); + common::printIcon('testtask', 'runCase', "runID=$runID&caseID=$caseID&version=$case->version", '', 'list', 'play', '', 'iframe', true, "data-width='95%'", '', $case->project); + common::printIcon('testtask', 'results', "runID=$runID&caseID=$caseID", '', 'list', 'list-alt', '', 'iframe', true, "data-width='95%'", '', $case->project); + common::printIcon('testcase', 'edit', "caseID=$caseID", $case, 'list', 'edit', '', '', '', '', '', $case->project); + } + ?> +
+
+ +
+ diff --git a/module/project/view/testtask.html.php b/module/project/view/testtask.html.php new file mode 100644 index 0000000000..5d4629f5c6 --- /dev/null +++ b/module/project/view/testtask.html.php @@ -0,0 +1,146 @@ + + * @package testtask + * @version $Id: browse.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $ + * @link http://www.zentao.net + */ +?> + +testtask->confirmDelete)?> + +
+ +
+

+ testtask->noTesttask;?> + + createLink('testtask', 'create', "product=0&execution=$executionID"), " " . $lang->testtask->create, '', "class='btn btn-info'");?> + +

+
+ +
+ + + recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?> + + '> + + + + + + + + + + + + + $productTasks):?> + + + > + + + + + + + + + + processStatus('testtask', $task);?> + + + + + + + + + + +
testtask->product);?> + +
+ +
+ + idAB);?> +
testtask->name);?>testtask->build);?>testtask->owner);?>testtask->begin);?>testtask->end);?>statusAB);?>actions;?>
+ +
testtask->allTasks;?>
+
+ + id => sprintf('%03d', $task->id)));?> + + id);?> + + createLink('testtask', 'view', "taskID=$task->id"), $task->name);?>build == 'trunk' || empty($task->buildName)) ? $lang->trunk : html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName);?>owner);?>begin?>end?> + + + id", $task, 'list', 'sitemap'); + common::printIcon('testtask', 'linkCase', "taskID=$task->id", $task, 'list', 'link'); + common::printIcon('testreport', 'browse', "objectID=$task->product&objectType=product&extra=$task->id", $task, 'list','flag'); + common::printIcon('testtask', 'edit', "taskID=$task->id", $task, 'list'); + if(common::hasPriv('testtask', 'delete', $task)) + { + $deleteURL = $this->createLink('testtask', 'delete', "taskID=$task->id&confirm=yes"); + echo html::a("javascript:ajaxDelete(\"$deleteURL\", \"taskList\", confirmDelete)", '', '', "class='btn' title='{$lang->testtask->delete}'"); + } + } + ?> +
+ +
+ +
+ diff --git a/module/story/control.php b/module/story/control.php index 75804d3cb3..0c237c1c33 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -846,9 +846,18 @@ class story extends control /* Set the menu. */ $from = $this->app->openApp; - if($from == 'execution' or $from == 'project') + if($from == 'execution') { - commonModel::setAppObjectID($from, $param); + $executions = $this->loadModel('execution')->getPairs(0, 'all', 'nocode'); + $this->execution->setMenu($execution, $param); + } + elseif($from == 'project') + { + $this->loadModel('project')->setMenu($param); + } + elseif($from == 'product') + { + $this->product->setMenu($story->product, $story->branch); } $this->executeHooks($storyID); diff --git a/module/testcase/model.php b/module/testcase/model.php index 9a26738d6f..98fe6a9405 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -264,6 +264,28 @@ class testcaseModel extends model ->fetchAll('id'); } + /** + * Get project cases. + * + * @param int $projectID + * @param string $orderBy + * @param object $pager + * @param string $browseType + * @access public + * @return array + */ + public function getProjectCases($projectID, $orderBy = 'id_desc', $pager = null, $browseType = '') + { + return $this->dao->select('distinct t1.*, t2.*')->from(TABLE_PROJECTCASE)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') + ->where('t1.project')->eq((int)$projectID) + ->beginIF($browseType != 'all')->andWhere('t2.status')->eq($browseType)->fi() + ->andWhere('t2.deleted')->eq('0') + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + } + /** * Get execution cases. * diff --git a/module/testtask/model.php b/module/testtask/model.php index 7633d2199a..6540a6e289 100644 --- a/module/testtask/model.php +++ b/module/testtask/model.php @@ -139,6 +139,28 @@ class testtaskModel extends model return $tasks; } + /** + * Get test tasks of a project. + * + * @param int $projectID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getProjectTasks($projectID, $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('t1.*, t2.name AS buildName') + ->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.build = t2.id') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t1.auto')->ne('unit') + ->andWhere('t1.deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + } + /** * Get test tasks of a execution. *