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
+ */
+?>
+
+
+
+
+ id", " " . $lang->bug->export, '', "class='btn btn-link export'");?>
+ id", " " . $lang->bug->create, '', "class='btn btn-primary'");?>
+
+
+
+
+
+
+
+ bug->noBug;?>
+
+ createLink('bug', 'create', "productID=$productID&branch=$branchID&extra=executionID=$execution->id"), " " . $lang->bug->create, '', "class='btn btn-info'");?>
+
+
+
+
+