diff --git a/db/update4.0.beta1.sql b/db/update4.0.beta1.sql new file mode 100644 index 0000000000..af6faa0047 --- /dev/null +++ b/db/update4.0.beta1.sql @@ -0,0 +1,7 @@ +INSERT INTO `zt_groupPriv` (`company`, `group`, `module`, `method`) VALUES +(1, 1, 'bug', 'batchEdit'), +(1, 2, 'bug', 'batchEdit'), +(1, 3, 'bug', 'batchEdit'), +(1, 4, 'bug', 'batchEdit'), +(1, 5, 'bug', 'batchEdit'); + diff --git a/module/bug/control.php b/module/bug/control.php index 384aaf15be..87c393b2d3 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -455,6 +455,81 @@ class bug extends control $this->display(); } + /** + * Batch edit bug. + * + * @param string $from example:bugBrowse, bugBatchEdit. + * @param int $productID + * @param string $orderBy + * @access public + * @return void + */ + public function batchEdit($from = '', $productID = 0, $orderBy = '') + { + if($from == 'bugBrowse') + { + /* Initialize vars.*/ + if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc'; + $editedBugs = array(); + $allBugs = $this->dao->select('*')->from(TABLE_BUG)->alias('t1')->where($this->session->bugQueryCondition)->orderBy($orderBy)->fetchAll('id'); + $bugIDList = $this->post->bugIDList ? $this->post->bugIDList : array(); + $product = $this->product->getByID($productID); + $columns = 9; + $showSuhosinInfo = false; + + /* Set product menu. */ + $this->bug->setMenu($this->products, $productID); + + /* Initialize the tasks whose need to edited. */ + foreach($allBugs as $bug) if(in_array($bug->id, $bugIDList)) $editedBugs[$bug->id] = $bug; + + /* Judge whether the editedTasks is too large. */ + $showSuhosinInfo = $this->loadModel('common')->judgeSuhosinSetting(count($editedBugs), $columns); + + /* Set the sessions. */ + $this->app->session->set('showSuhosinInfo', $showSuhosinInfo); + + /* Assign. */ + $this->view->header['title'] = $product->name . $this->lang->colon . $this->lang->bug->batchEdit; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->common; + $this->view->position[] = $this->lang->bug->batchEdit; + + if($showSuhosinInfo) $this->view->suhosinInfo = $this->lang->suhosinInfo; + $this->view->productID = $productID; + $this->view->editedBugs = $editedBugs; + $this->view->users = $this->user->getPairs('nodeleted'); + + $this->display(); + } + elseif($from == 'bugBatchEdit') + { + $allChanges = $this->bug->batchUpdate(); + + foreach($allChanges as $bugID => $changes) + { + $actionID = $this->action->create('bug', $bugID, 'Edited'); + $this->action->logHistory($actionID, $changes); + $this->sendmail($bugID, $actionID); + + $bug = $this->bug->getById($bugID); + if($bug->toTask != 0) + { + foreach($changes as $change) + { + if($change['field'] == 'status') + { + $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); + $cancelURL = $this->server->HTTP_REFERER; + die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->task), $confirmURL, $cancelURL, 'parent', 'parent')); + } + } + } + } + die(js::locate($this->session->bugList, 'parent')); + } + } + /** * Update assign of bug. * diff --git a/module/bug/js/batchedit.js b/module/bug/js/batchedit.js new file mode 100644 index 0000000000..0b26083423 --- /dev/null +++ b/module/bug/js/batchedit.js @@ -0,0 +1,18 @@ +/** + * Set duplicate field. + * + * @param string $resolution + * @access public + * @return void + */ +function setDuplicate(resolution, bugID) +{ + if(resolution == 'duplicate') + { + $('#duplicateBugBox' + bugID).show(); + } + else + { + $('#duplicateBugBox' + bugID).hide(); + } +} diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php index 9625512552..ca6094af73 100644 --- a/module/bug/lang/en.php +++ b/module/bug/lang/en.php @@ -69,6 +69,7 @@ $lang->bug->index = 'Index'; $lang->bug->create = 'Create Bug'; $lang->bug->confirmBug = 'Confirm Bug'; $lang->bug->edit = 'Edit Bug'; +$lang->bug->batchEdit = 'Batch edit'; $lang->bug->assignTo = 'Assign'; $lang->bug->browse = 'Browse Bug'; $lang->bug->view = 'Bug Info'; diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index a032cd4038..d511de10fb 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -69,6 +69,7 @@ $lang->bug->index = '首页'; $lang->bug->create = '创建'; $lang->bug->confirmBug = '确认'; $lang->bug->edit = '编辑'; +$lang->bug->batchEdit = '批量编辑'; $lang->bug->assignTo = '指派'; $lang->bug->browse = 'Bug列表'; $lang->bug->view = 'Bug详情'; diff --git a/module/bug/model.php b/module/bug/model.php index 75efdbcfef..1738d6f67f 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -193,6 +193,86 @@ class bugModel extends model if(!dao::isError()) return common::createChanges($oldBug, $bug); } + /** + * Batch update bugs. + * + * @access public + * @return array + */ + public function batchUpdate() + { + $bugs = array(); + $allChanges = array(); + $now = helper::now(); + $bugIDList = $this->post->bugIDList ? $this->post->bugIDList : array(); + + /* Adjust whether the post data is complete, if not, remove the last element of $bugIDList. */ + if($this->session->showSuhosinInfo) array_pop($bugIDList); + + if(!empty($bugIDList)) + { + /* Initialize bugs from the post data.*/ + foreach($bugIDList as $bugID) + { + $oldBug = $this->getByID($bugID); + + $bug->lastEditedBy = $this->app->user->account; + $bug->lastEditedDate = $now; + $bug->type = $this->post->types[$bugID]; + $bug->severity = $this->post->severities[$bugID]; + $bug->pri = $this->post->pris[$bugID]; + $bug->status = $this->post->statuses[$bugID]; + $bug->title = htmlspecialchars($this->post->titles[$bugID]); + $bug->assignedTo = $this->post->assignedTos[$bugID]; + $bug->resolvedBy = $this->post->resolvedBys[$bugID]; + $bug->resolution = $this->post->resolutions[$bugID]; + $bug->duplicateBug = $this->post->duplicateBugs[$bugID] ? $this->post->duplicateBugs[$bugID] : $oldBug->duplicateBug; + + if($bug->assignedTo != $oldBug->assignedTo) $bug->assignedDate = $now; + if($bug->resolvedBy != '' or $bug->resolution != '') $bug->resolvedDate = $now; + if($bug->resolution != '' and $bug->resolvedBy == '') $bug->resolvedBy = $this->app->user->account; + if($bug->resolution != '') + { + $bug->status = 'resolved'; + $bug->confirmed = 1; + } + if($bug->resolution != '' and $bug->assignedTo == '') + { + $bug->assignedTo = $oldBug->openedBy; + $bug->assignedDate = $now; + } + + $bugs[$bugID] = $bug; + unset($bug); + } + + /* Update bugs. */ + foreach($bugs as $bugID => $bug) + { + $oldBug = $this->getByID($bugID); + + $this->dao->update(TABLE_BUG)->data($bug) + ->autoCheck() + ->batchCheck($this->config->bug->edit->requiredFields, 'notempty') + ->checkIF($bug->resolvedBy, 'resolution', 'notempty') + ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') + ->where('id')->eq((int)$bugID) + ->exec(); + + if(!dao::isError()) + { + $allChanges[$bugID] = common::createChanges($oldBug, $bug); + } + else + { + die(js::error('bug#' . $bugID . dao::getError(true))); + } + } + } + + return $allChanges; + } + /** * Assign a bug to a user again. * diff --git a/module/bug/view/batchedit.html.php b/module/bug/view/batchedit.html.php new file mode 100644 index 0000000000..bbbce2b0ca --- /dev/null +++ b/module/bug/view/batchedit.html.php @@ -0,0 +1,59 @@ + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
"> + + + + + + + + + + + + + + + type != 'designchange') unset($this->lang->bug->typeList['designchange']); + if($bug->type != 'newfeature') unset($this->lang->bug->typeList['newfeature']); + if($bug->type != 'trackthings') unset($this->lang->bug->typeList['trackthings']); + ?> + + + + + + + + + + + + + + + + +
bug->common . $lang->colon . $lang->bug->batchEdit;?>
idAB;?>bug->type;?>bug->severityAB;?>bug->pri;?> bug->title;?>bug->assignedTo;?>bug->status;?>bug->resolvedByAB;?>bug->resolutionAB;?>
id . html::hidden("bugIDList[$bug->id]", $bug->id);?>id]", $lang->bug->typeList, $bug->type, 'class=select-1');?>id]", (array)$lang->bug->severityList, $bug->severity, 'class=select-1');?>id]", (array)$lang->bug->priList, $bug->pri, 'class=select-1');?>id]", $bug->title, 'class=text-1'); echo "*";?>id]", $users, $bug->assignedTo, 'class=select-1');?>id]", (array)$lang->bug->statusList, $bug->status, 'class=select-1');?>id]", $users, $bug->resolvedBy, 'class=select-1');?> +
id]", $this->lang->bug->resolutionList, $bug->resolution, "class=w-80px onchange=setDuplicate(this.value,$bug->id)");?>
+
id;?>' resolution != 'duplicate') echo "style='display:none'";?>>id]", '', "class=w-40px placeholder='{$lang->bug->duplicateBug}'");?>
+
+
+ diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php index e079e27e74..ff8cb8741a 100644 --- a/module/bug/view/browse.html.php +++ b/module/bug/view/browse.html.php @@ -23,7 +23,6 @@ var customed = ;
" . $lang->bug->moduleBugs . " "; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . ""; @@ -32,6 +31,7 @@ var customed = ; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unclosed¶m=0"), $lang->bug->unclosed) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . ""; echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->bug->needConfirm) . ""; echo "{$lang->bug->byQuery} "; ?> @@ -46,118 +46,131 @@ var customed = ;
'>
- - - + +
-
-
- -
- tree->manage);?> - tree->fix, 'hiddenwin');?> +
'> + + + - - + + id");?> + + + + + + confirmed;?> + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + + cookie->windowWidth >= $this->config->wideSize ? 12 : 9;?> + + + +
+
+
+ +
+ tree->manage);?> + tree->fix, 'hiddenwin');?> +
- -
- recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - + + + - -
idAB);?> bug->severityAB);?> priAB);?> + recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + - + - cookie->windowWidth >= $this->config->wideSize):?> - - + cookie->windowWidth >= $this->config->wideSize):?> + + - - - - - + + + + + - cookie->windowWidth >= $this->config->wideSize):?> - - + cookie->windowWidth >= $this->config->wideSize):?> + + - - - + + + - cookie->windowWidth >= $this->config->wideSize):?> - - + cookie->windowWidth >= $this->config->wideSize):?> + + - - - - - - - id");?> - - - - - - confirmed;?> - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - - cookie->windowWidth >= $this->config->wideSize ? 12 : 9;?> - + + - -
idAB);?> bug->severityAB);?> priAB);?>bug->title);?>bug->title);?>bug->statusAB);?>bug->statusAB);?>bug->story);?>actions;?>openedByAB);?>bug->story);?>actions;?>openedByAB);?> bug->openedDateAB);?> bug->openedDateAB);?>assignedToAB);?>bug->resolvedByAB);?>bug->resolutionAB);?>assignedToAB);?>bug->resolvedByAB);?>bug->resolutionAB);?> bug->resolvedDateAB);?> bug->resolvedDateAB);?>actions;?>
id));?>severity;?>'>severity;?>bug->priList[$bug->pri];?>'>bug->priList[$bug->pri];?>[{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>bug->statusList[$bug->status];?>createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin')?>openedBy];?>openedDate, 5, 11)?>assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>resolvedDate, 5, 11)?> - id"; - common::printIcon('bug', 'resolve', $params, $bug, 'list'); - common::printIcon('bug', 'close', $params, $bug, 'list'); - common::printIcon('bug', 'edit', $params, $bug, 'list'); - common::printIcon('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $bug, 'list', 'copy'); - ?> -
show();?>actions;?>
-
+ +
+ + id));?> + severity;?>'>severity;?>bug->priList[$bug->pri];?>'>bug->priList[$bug->pri];?>[{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>bug->statusList[$bug->status];?>createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin')?>openedBy];?>openedDate, 5, 11)?>assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>resolvedDate, 5, 11)?> + id"; + common::printIcon('bug', 'resolve', $params, $bug, 'list'); + common::printIcon('bug', 'close', $params, $bug, 'list'); + common::printIcon('bug', 'edit', $params, $bug, 'list'); + common::printIcon('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $bug, 'list', 'copy'); + ?> +
+
+ bug->batchEdit); + ?> +
+
show();?>
+
+
+ diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index b2bbc45b32..552b5e7078 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -179,7 +179,7 @@ $lang->build->menu = $lang->project->menu; /* QA视图菜单设置。*/ $lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); +$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report,batchedit', 'subModule' => 'tree'); $lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); $lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index eed6833001..c334d486ee 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -323,6 +323,7 @@ $lang->resource->bug->create = 'create'; $lang->resource->bug->confirmBug = 'confirmBug'; $lang->resource->bug->view = 'view'; $lang->resource->bug->edit = 'edit'; +$lang->resource->bug->batchEdit = 'batchEdit'; $lang->resource->bug->assignTo = 'assignTo'; $lang->resource->bug->resolve = 'resolve'; $lang->resource->bug->activate = 'activate';