diff --git a/module/bug/config/form.php b/module/bug/config/form.php index d68222e790..1432aca3ba 100644 --- a/module/bug/config/form.php +++ b/module/bug/config/form.php @@ -40,6 +40,43 @@ $config->bug->form->create['status'] = array('required' => false, 'type' => 's $config->bug->form->create['issueKey'] = array('required' => false, 'type' => 'string', 'default' => ''); $config->bug->form->create['uid'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit = array(); +$config->bug->form->edit['title'] = array('required' => true, 'type' => 'string', 'filter' => 'trim'); +$config->bug->form->edit['openedBuild'] = array('required' => true, 'type' => 'array', 'filter' => 'join'); +$config->bug->form->edit['product'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['branch'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['project'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['execution'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['plan'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['module'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['story'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['task'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['case'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['testtask'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['duplicateBug'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->bug->form->edit['severity'] = array('required' => false, 'type' => 'int', 'default' => 3); +$config->bug->form->edit['pri'] = array('required' => false, 'type' => 'int', 'default' => 3); +$config->bug->form->edit['type'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['status'] = array('required' => false, 'type' => 'string', 'default' => 'active'); +$config->bug->form->edit['keywords'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['steps'] = array('required' => false, 'type' => 'string', 'default' => $lang->bug->tplStep . $lang->bug->tplResult . $lang->bug->tplExpect); +$config->bug->form->edit['resolution'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['resolvedBuild'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['assignedTo'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['feedbackBy'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['resolvedBy'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['closedBy'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['notifyEmail'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['uid'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->bug->form->edit['os'] = array('required' => false, 'type' => 'array', 'default' => array(''), 'filter' => 'join'); +$config->bug->form->edit['browser'] = array('required' => false, 'type' => 'array', 'default' => array(''), 'filter' => 'join'); +$config->bug->form->edit['linkBug'] = array('required' => false, 'type' => 'array', 'default' => array(''), 'filter' => 'join'); +$config->bug->form->edit['mailto'] = array('required' => false, 'type' => 'array', 'default' => array(''), 'filter' => 'join'); +$config->bug->form->edit['deadline'] = array('required' => false, 'type' => 'date', 'default' => NULL); +$config->bug->form->edit['resolvedDate'] = array('required' => false, 'type' => 'date', 'default' => NULL); +$config->bug->form->edit['closedDate'] = array('required' => false, 'type' => 'date', 'default' => NULL); +$config->bug->form->edit['lastEditedDate'] = array('required' => false, 'type' => 'date', 'default' => helper::now()); + global $app; $config->bug->form->close = array(); $config->bug->form->close['status'] = array('required' => false, 'type' => 'string', 'default' => 'closed'); @@ -49,4 +86,4 @@ $config->bug->form->close['lastEditedBy'] = array('required' => false, 'type' $config->bug->form->close['lastEditedDate'] = array('required' => false, 'type' => 'string', 'default' => helper::now()); $config->bug->form->close['closedBy'] = array('required' => false, 'type' => 'string', 'default' => $app->user->account); $config->bug->form->close['closedDate'] = array('required' => false, 'type' => 'string', 'default' => helper::now()); -$config->bug->form->close['comment'] = array('required' => false, 'type' => 'string', 'default' => '');; +$config->bug->form->close['comment'] = array('required' => false, 'type' => 'string', 'default' => ''); diff --git a/module/bug/control.php b/module/bug/control.php index 5cba0d8513..28e17b20b4 100755 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -12,6 +12,7 @@ class bug extends control { /** + * 所有产品。 * All products. * * @var array @@ -20,6 +21,7 @@ class bug extends control public $products = array(); /** + * 当前项目编号。 * Project id. * * @var int @@ -28,16 +30,25 @@ class bug extends control public $projectID = 0; /** - * Construct function, load some modules auto. + * 构造函数 + + * 1.加载其他模块model类。 + * 2.获取产品,并输出到视图 + + * The construct function. + * + * 1. Load model of other modules. + * 2. Get products and assign to view. * * @param string $moduleName * @param string $methodName * @access public * @return void */ - public function __construct($moduleName = '', $methodName = '') + public function __construct(string $moduleName = '', string $methodName = '') { parent::__construct($moduleName, $methodName); + $this->loadModel('product'); $this->loadModel('tree'); $this->loadModel('user'); @@ -48,27 +59,28 @@ class bug extends control /* Get product data. */ $products = array(); - $objectID = 0; - $tab = ($this->app->tab == 'project' or $this->app->tab == 'execution') ? $this->app->tab : 'qa'; if(!isonlybody()) { - if($this->app->tab == 'project' or $this->app->tab == 'execution') + $tab = ($this->app->tab == 'project' or $this->app->tab == 'execution') ? $this->app->tab : 'qa'; + $mode = (strpos(',create,edit,', ",{$this->app->methodName},") !== false and empty($this->config->CRProduct)) ? 'noclosed' : ''; + $objectID = ($tab == 'project' or $tab == 'execution') ? $this->session->{$tab} : 0; + if($tab == 'project' or $tab == 'execution') { - $objectID = $this->app->tab == 'project' ? $this->session->project : $this->session->execution; - $products = $this->product->getProducts($objectID, 'all', '', false); + $products = $this->product->getProducts($objectID, $mode, $orderBy = '', $withBranch = false); } else { - $mode = ($this->app->methodName == 'create' and empty($this->config->CRProduct)) ? 'noclosed' : ''; - $products = $this->product->getPairs($mode, 0, '', 'all'); + $products = $this->product->getPairs($mode, $programID = 0, $append = '', $shadow = 'all'); } + if(empty($products) and !helper::isAjaxRequest()) return print($this->locate($this->createLink('product', 'showErrorNone', "moduleName=$tab&activeMenu=bug&objectID=$objectID"))); } else { - $mode = (empty($this->config->CRProduct)) ? 'noclosed' : ''; + $mode = empty($this->config->CRProduct) ? 'noclosed' : ''; $products = $this->product->getPairs($mode, 0, '', 'all'); } + $this->view->products = $this->products = $products; } @@ -645,259 +657,46 @@ class bug extends control } /** + * 更新bug信息。 * Edit a bug. * - * @param int $bugID - * @param bool $comment + * @param string $bugID + * @param bool $comment true|false * @param string $kanbanGroup * @access public * @return void */ - public function edit($bugID, $comment = false, $kanbanGroup = 'default') + public function edit(string $bugID, bool $comment = false, string $kanbanGroup = 'default') { if(!empty($_POST)) { + $oldBug = $this->bug->getByID($bugID); + + $formData = form::data($this->config->bug->form->edit); + $bug = $this->bugZen->prepareEditExtras($formData, $oldBug); + if(!$bug) return $this->send($this->bugZen->errorEdit()); + $changes = array(); - $files = array(); - if($comment == false) + if(!$comment) { - $changes = $this->bug->update($bugID); - if(dao::isError()) - { - if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'error', 'message' => dao::getError())); - return print(js::error(dao::getError())); - } + $changes = $this->bug->update($bug, $oldBug); + if(!$changes) return $this->send($this->bugZen->errorEdit()); } - if($this->post->comment != '' or !empty($changes)) - { - $action = !empty($changes) ? 'Edited' : 'Commented'; - $actionID = $this->action->create('bug', $bugID, $action, $this->post->comment); - $this->action->logHistory($actionID, $changes); - } - - if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'data' => $bugID)); - $bug = $this->bug->getById($bugID); + $this->bugZen->processAfterEdit($bugID, $this->post->comment, $changes); $this->executeHooks($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; - return print(js::confirm(sprintf($this->lang->bug->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent')); - } - } - } - if(isonlybody()) - { - $execution = $this->loadModel('execution')->getByID($bug->execution); - if($this->app->tab == 'execution') - { - $execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all'; - $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; - - if(isset($execution->type) and $execution->type == 'kanban') - { - $rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue); - $kanbanData = json_encode($kanbanData); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)")); - } - else - { - $taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue); - $kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData); - $kanbanData = $kanbanData[$kanbanType]; - $kanbanData = json_encode($kanbanData); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)")); - } - } - else - { - return print(js::closeModal('parent.parent')); - } - } - return print(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + return $this->send($this->bugZen->responseAfterEdit($bugID, $changes, $kanbanGroup)); } - /* Get the info of bug, current product and modue. */ - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $executionID = $bug->execution; - $projectID = $bug->project; - $currentModuleID = $bug->module; - $product = $this->loadModel('product')->getByID($productID); - $execution = $this->loadModel('execution')->getByID($executionID); + $bug = $this->bug->getByID($bugID); + $this->bug->checkBugExecutionPriv($bug); - if(!isset($this->products[$bug->product])) - { - $this->products[$bug->product] = $product->name; - $this->view->products = $this->products; - } + $this->bugZen->setEditMenu($bug); - /* Set the menu. */ - if($this->app->tab == 'project') $this->loadModel('project')->setMenu($bug->project); - if($this->app->tab == 'execution') $this->loadModel('execution')->setMenu($bug->execution); - if($this->app->tab == 'qa') $this->qa->setMenu($this->products, $productID, $bug->branch); - if($this->app->tab == 'devops') - { - session_write_close(); - - $repos = $this->loadModel('repo')->getRepoPairs('project', $bug->project); - $this->repo->setMenu($repos); - - $this->lang->navGroup->bug = 'devops'; - } - - /* Unset discarded types. */ - foreach($this->config->bug->discardedTypes as $type) - { - if($bug->type != $type) unset($this->lang->bug->typeList[$type]); - } - - if($this->app->tab == 'qa') - { - $this->view->products = $this->config->CRProduct ? $this->products : $this->product->getPairs('noclosed'); - } - if($this->app->tab == 'project') - { - $products = array(); - $productList = $this->config->CRProduct ? $this->product->getOrderedProducts('all', 40, $bug->project) : $this->product->getOrderedProducts('normal', 40, $bug->project); - foreach($productList as $productInfo) $products[$productInfo->id] = $productInfo->name; - - $this->view->products = $products; - } - - /* Set header and position. */ - $this->view->title = $this->lang->bug->edit . "BUG #$bug->id $bug->title - " . $this->products[$productID]; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->edit; - - /* Assign. */ - $allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty'); - if($executionID) - { - $openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $executionID, 'execution'); - } - elseif($projectID) - { - $openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $projectID, 'project'); - } - else - { - $openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased'); - } - - /* Set the openedBuilds list. */ - $oldOpenedBuilds = array(); - $bugOpenedBuilds = explode(',', $bug->openedBuild); - foreach($bugOpenedBuilds as $buildID) - { - if(isset($allBuilds[$buildID])) $oldOpenedBuilds[$buildID] = $allBuilds[$buildID]; - } - $openedBuilds = $openedBuilds + $oldOpenedBuilds; - - /* Set the resolvedBuilds list. */ - $oldResolvedBuild = array(); - if(($bug->resolvedBuild) and isset($allBuilds[$bug->resolvedBuild])) $oldResolvedBuild[$bug->resolvedBuild] = $allBuilds[$bug->resolvedBuild]; - - $projectID = $this->lang->navGroup->bug == 'project' ? $this->session->project : 0; - - if($this->app->tab == 'execution' or $this->app->tab == 'project') - { - $objectID = $this->app->tab == 'project' ? $bug->project : $bug->execution; - } - - /* Display status of branch. */ - $branches = $this->loadModel('branch')->getList($productID, isset($objectID) ? $objectID : 0, 'all'); - $branchOption = array(); - $branchTagOption = array(); - foreach($branches as $branchInfo) - { - $branchOption[$branchInfo->id] = $branchInfo->name; - $branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''); - } - if(!isset($branchTagOption[$bug->branch])) - { - $bugBranch = $this->branch->getById($bug->branch, $bug->product, ''); - $branchTagOption[$bug->branch] = $bug->branch == BRANCH_MAIN ? $bugBranch : ($bugBranch->name . ($bugBranch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '')); - } - - $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $bug->branch); - if(!isset($moduleOptionMenu[$bug->module])) $moduleOptionMenu += $this->tree->getModulesName($bug->module); - - $cases = $this->loadmodel('testcase')->getPairsByProduct($bug->product, array(0, $bug->branch)); - - /* Get assigned to member. */ - if($bug->execution) - { - $assignedToList = $this->user->getTeamMemberPairs($bug->execution, 'execution'); - } - elseif($bug->project) - { - $assignedToList = $this->loadModel('project')->getTeamMemberPairs($bug->project); - } - else - { - $assignedToList = $this->bug->getProductMemberPairs($bug->product, $bug->branch); - $assignedToList = array_filter($assignedToList); - if(empty($assignedToList)) $assignedToList = $this->user->getPairs('devfirst|noclosed'); - } - if($bug->assignedTo and !isset($assignedToList[$bug->assignedTo]) and $bug->assignedTo != 'closed') - { - /* Fix bug #28378. */ - $assignedTo = $this->user->getById($bug->assignedTo); - $assignedToList[$bug->assignedTo] = $assignedTo->realname; - } - if($bug->status == 'closed') $assignedToList['closed'] = 'Closed'; - - $branch = $product->type == 'branch' ? ($bug->branch > 0 ? $bug->branch . ',0' : '0') : ''; - $productBugs = $this->bug->getProductBugPairs($productID, $branch); - unset($productBugs[$bugID]); - - $executions = array(0 => '') + $this->product->getExecutionPairsByProduct($bug->product, $bug->branch, 'id_desc', $bug->project); - if(!empty($bug->execution) and empty($executions[$bug->execution])) $executions[$execution->id] = $execution->name . "({$this->lang->bug->deleted})"; - - $projects = array(0 => '') + $this->product->getProjectPairsByProduct($productID, $bug->branch); - if(!empty($bug->project) and empty($projects[$bug->project])) - { - $project = $this->loadModel('project')->getByID($bug->project); - $projects[$project->id] = $project->name . "({$this->lang->bug->deleted})"; - } - - if($product->shadow) $this->view->project = $this->loadModel('project')->getByShadowProduct($bug->product); - - $this->view->bug = $bug; - $this->view->product = $product; - $this->view->execution = $execution; - $this->view->productBugs = $productBugs; - $this->view->productName = $this->products[$productID]; - $this->view->plans = $this->loadModel('productplan')->getPairs($productID, $bug->branch, '', true); - $this->view->projects = $projects; - $this->view->projectExecutionPairs = $this->loadModel('project')->getProjectExecutionPairs(); - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->view->currentModuleID = $currentModuleID; - $this->view->executions = $executions; - $this->view->stories = $bug->execution ? $this->story->getExecutionStoryPairs($bug->execution) : $this->story->getProductStoryPairs($bug->product, $bug->branch, 0, 'all', 'id_desc', 0, 'full', 'story', false); - $this->view->branchOption = $branchOption; - $this->view->branchTagOption = $branchTagOption; - $this->view->tasks = $this->task->getExecutionTaskPairs($bug->execution); - $this->view->testtasks = $this->loadModel('testtask')->getPairs($bug->product, $bug->execution, $bug->testtask); - $this->view->users = $this->user->getPairs('', "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy,$bug->openedBy"); - $this->view->assignedToList = $assignedToList; - $this->view->cases = array('' => '') + $cases; - $this->view->openedBuilds = $openedBuilds; - $this->view->resolvedBuilds = array('' => '') + $openedBuilds + $oldResolvedBuild; - $this->view->actions = $this->action->getList('bug', $bugID); - - $this->display(); + $this->bugZen->buildEditForm($bug); } /** diff --git a/module/bug/model.php b/module/bug/model.php index b10ecc54ec..975cf0e1a8 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -174,7 +174,7 @@ class bugModel extends model foreach($extendFields as $extendField) { $bug->{$extendField->field} = $this->post->{$extendField->field}[$i]; - if(is_array($bug->{$extendField->field})) $bug->{$extendField->field} = join(',', $bug->{$extendField->field}); + if(is_array($bug->{$extendField->field})) $bug->{$extendField->field} = implode(',', $bug->{$extendField->field}); $bug->{$extendField->field} = htmlSpecialString($bug->{$extendField->field}); } @@ -397,7 +397,7 @@ class bugModel extends model * @access public * @return object|false */ - public function getByID(int $bugID, bool $setImgSize = false): object|false + public function getByID(string $bugID, bool $setImgSize = false): object|false { $bug = $this->bugTao->fetchBugInfo($bugID); if(!$bug) return false; @@ -532,121 +532,33 @@ class bugModel extends model } /** + * 更新bug信息。 * Update a bug. * - * @param int $bugID + * @param object $bug + * @param object $oldBug * @access public - * @return void + * @return array|false */ - public function update($bugID) + public function update(object $bug, object $oldBug): array|false { - $oldBug = $this->getById($bugID); - if(!empty($_POST['lastEditedDate']) and $oldBug->lastEditedDate != $this->post->lastEditedDate) - { - dao::$errors[] = $this->lang->error->editedByOther; - return false; - } - $now = helper::now(); - $bug = fixer::input('post') - ->add('id', $bugID) - ->cleanInt('product,module,severity,project,execution,story,task,branch') - ->stripTags($this->config->bug->editor->edit['id'], $this->config->allowedTags) - ->setDefault('module,execution,story,task,duplicateBug,branch', 0) - ->setDefault('product', $oldBug->product) - ->setDefault('openedBuild', '') - ->setDefault('os', '') - ->setDefault('browser', '') - ->setDefault('plan', 0) - ->setDefault('deadline', '0000-00-00') - ->setDefault('resolvedDate', '') - ->setDefault('lastEditedBy', $this->app->user->account) - ->setDefault('mailto', '') - ->setDefault('deleteFiles', array()) - ->add('lastEditedDate', $now) - ->setIF(strpos($this->config->bug->edit->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline) - ->join('openedBuild', ',') - ->join('mailto', ',') - ->join('linkBug', ',') - ->join('os', ',') - ->join('browser', ',') - ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) - ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) - ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) - ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) - ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) - ->setIF($this->post->assignedTo == '' and $oldBug->status == 'closed', 'assignedTo', 'closed') - ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') - ->setIF($this->post->resolution != '', 'confirmed', 1) - ->setIF($this->post->resolution != '' and $this->post->resolution != 'duplicate', 'duplicateBug', 0) - ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->setIF(!$this->post->linkBug, 'linkBug', '') - ->setIF($this->post->case === '', 'case', 0) - ->remove('comment,files,labels,uid,contactListMenu') - ->get(); - - $bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->edit['id'], $this->post->uid); $this->dao->update(TABLE_BUG)->data($bug, 'deleteFiles') ->autoCheck() ->batchCheck($this->config->bug->edit->requiredFields, 'notempty') ->checkIF($bug->resolvedBy, 'resolution', 'notempty') ->checkIF($bug->closedBy, 'resolution', 'notempty') - ->checkIF($bug->notifyEmail, 'notifyEmail', 'email') + ->checkIF($bug->notifyEmail,'notifyEmail', 'email') ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') ->checkIF($bug->resolution == 'fixed', 'resolvedBuild','notempty') ->checkFlow() - ->where('id')->eq((int)$bugID) + ->where('id')->eq($bug->id) ->exec(); - if(!dao::isError()) - { - /* Link bug to build and release. */ - if($bug->resolution == 'fixed' and !empty($bug->resolvedBuild) and $oldBug->resolvedBuild != $bug->resolvedBuild) - { - if(!empty($oldBug->resolvedBuild)) $this->loadModel('build')->unlinkBug($oldBug->resolvedBuild, (int)$bugID); - $this->linkBugToBuild($bugID, $bug->resolvedBuild); - } + if(dao::isError()) return false; - if($bug->plan != $oldBug->plan) - { - $this->loadModel('action'); - if(!empty($oldBug->plan)) $this->action->create('productplan', $oldBug->plan, 'unlinkbug', '', $bugID); - if(!empty($bug->plan)) $this->action->create('productplan', $bug->plan, 'linkbug', '', $bugID); - } + if(!$this->bugTao->afterUpdate($bug, $oldBug)) return false; - $linkBugs = explode(',', $bug->linkBug); - $oldLinkBugs = explode(',', $oldBug->linkBug); - $addBugs = array_diff($linkBugs, $oldLinkBugs); - $removeBugs = array_diff($oldLinkBugs, $linkBugs); - $changeBugs = array_merge($addBugs, $removeBugs); - $changeBugs = $this->dao->select('id,linkbug')->from(TABLE_BUG)->where('id')->in(array_filter($changeBugs))->fetchPairs(); - foreach($changeBugs as $changeBugID => $changeBug) - { - if(in_array($changeBugID, $addBugs) and empty($changeBug)) $this->dao->update(TABLE_BUG)->set('linkBug')->eq($bugID)->where('id')->eq((int)$changeBugID)->exec(); - if(in_array($changeBugID, $addBugs) and !empty($changeBug)) $this->dao->update(TABLE_BUG)->set('linkBug')->eq("$changeBug,$bugID")->where('id')->eq((int)$changeBugID)->exec(); - if(in_array($changeBugID, $removeBugs)) - { - $linkBugs = explode(',', $changeBug); - unset($linkBugs[array_search($bugID, $linkBugs)]); - $this->dao->update(TABLE_BUG)->set('linkBug')->eq(implode(',', $linkBugs))->where('id')->eq((int)$changeBugID)->exec(); - } - } - - if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bugID); - - if($bug->execution and $bug->status != $oldBug->status) $this->loadModel('kanban')->updateLane($bug->execution, 'bug'); - - if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldBug->feedback) $this->loadModel('feedback')->updateStatus('bug', $oldBug->feedback, $bug->status, $oldBug->status); - - $this->file->processFile4Object('bug', $oldBug, $bug); - return common::createChanges($oldBug, $bug); - } + return common::createChanges($oldBug, $bug); } /** @@ -739,7 +651,7 @@ class bugModel extends model foreach($extendFields as $extendField) { $bug->{$extendField->field} = $this->post->{$extendField->field}[$bugID]; - if(is_array($bug->{$extendField->field})) $bug->{$extendField->field} = join(',', $bug->{$extendField->field}); + if(is_array($bug->{$extendField->field})) $bug->{$extendField->field} = implode(',', $bug->{$extendField->field}); $bug->{$extendField->field} = htmlSpecialString($bug->{$extendField->field}); } @@ -846,7 +758,7 @@ class bugModel extends model { $postFieldData = $this->post->{$extendField->field}; - if(is_array($postFieldData[$bugID])) $postFieldData[$bugID] = join(',', $postFieldData[$bugID]); + if(is_array($postFieldData[$bugID])) $postFieldData[$bugID] = implode(',', $postFieldData[$bugID]); $activateBugs[$bugID][$extendField->field] = htmlSpecialString($postFieldData[$bugID]); } @@ -1524,7 +1436,7 @@ class bugModel extends model $builds = $this->loadModel('build')->getBuildPairs(array_unique($productIdList), 'all', $params = ''); /* Process the openedBuild and resolvedBuild fields. */ - foreach($bugs as $key => $bug) + foreach($bugs as $bug) { $openBuildIdList = explode(',', $bug->openedBuild); $openedBuild = ''; @@ -1618,7 +1530,7 @@ class bugModel extends model } else { - if($this->session->$queryName == false) $this->session->set($queryName, ' 1 = 1'); + if($this->session->$queryName === false) $this->session->set($queryName, ' 1 = 1'); } $query = $this->session->$queryName; $query = preg_replace('/`(\w+)`/', 't1.`$1`', $query); @@ -1711,7 +1623,7 @@ class bugModel extends model if($type == 'bysearch') { $queryID = (int)$param; - if($this->session->projectBugQuery == false) $this->session->set('projectBugQuery', ' 1 = 1'); + if($this->session->projectBugQuery === false) $this->session->set('projectBugQuery', ' 1 = 1'); if($queryID) { $query = $this->loadModel('search')->getQuery($queryID); @@ -1782,7 +1694,7 @@ class bugModel extends model if($type == 'bysearch') { $queryID = (int)$param; - if($this->session->executionBugQuery == false) $this->session->set('executionBugQuery', ' 1 = 1'); + if($this->session->executionBugQuery === false) $this->session->set('executionBugQuery', ' 1 = 1'); if($queryID) { $query = $this->loadModel('search')->getQuery($queryID); @@ -1818,7 +1730,7 @@ class bugModel extends model { if($build) $conditions[] = "FIND_IN_SET('$build', t1.openedBuild)"; } - $condition = join(' OR ', $conditions); + $condition = implode(' OR ', $conditions); $condition = "($condition)"; } $bugs = $this->dao->select("t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, IF(t1.`severity` = 0, {$this->config->maxPriValue}, t1.`severity`) as severityOrder")->from(TABLE_BUG)->alias('t1') @@ -1876,7 +1788,7 @@ class bugModel extends model ->andWhere('t1.date')->lt($minBegin) ->fetchPairs('id', 'id'); - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('deleted')->eq(0) + return $this->dao->select('*')->from(TABLE_BUG)->where('deleted')->eq(0) ->andWhere('product')->eq($productID) ->andWhere('toStory')->eq(0) ->andWhere('openedDate')->ge($minBegin) @@ -1887,8 +1799,6 @@ class bugModel extends model ->beginIF($branch !== '')->andWhere('branch')->in("0,$branch")->fi() ->page($pager) ->fetchAll(); - - return $bugs; } /** @@ -1976,7 +1886,7 @@ class bugModel extends model $condition .= " OR (`execution` = '{$execution->id}' AND openedDate < '{$execution->begin}')"; } - $bugs = $this->dao->select('*')->from(TABLE_BUG) + return $this->dao->select('*')->from(TABLE_BUG) ->where('resolvedDate')->ge($minBegin) ->andWhere('resolution')->ne('postponed') ->andWhere('product')->eq($productID) @@ -1987,7 +1897,6 @@ class bugModel extends model ->orderBy('openedDate ASC') ->page($pager) ->fetchAll('id'); - return $bugs; } /** @@ -2394,7 +2303,7 @@ class bugModel extends model { $datas = $this->dao->select('pri AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->reportCondition())->groupBy('name')->orderBy('value DESC')->fetchAll('name'); if(!$datas) return array(); - foreach($datas as $status => $data) $data->name = $this->lang->bug->report->bugsPerPri->graph->xAxisName . ':' . zget($this->lang->bug->priList, $data->name); + foreach($datas as $data) $data->name = $this->lang->bug->report->bugsPerPri->graph->xAxisName . ':' . zget($this->lang->bug->priList, $data->name); return $datas; } @@ -2528,7 +2437,7 @@ class bugModel extends model } else { - if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); + if($this->session->bugQuery === false) $this->session->set('bugQuery', ' 1 = 1'); } $bugQuery = $this->getBugQuery($this->session->bugQuery); @@ -2557,7 +2466,7 @@ class bugModel extends model if($branch !== 'all' and strpos($bugQuery, '`branch` =') === false) $bugQuery .= " AND `branch` in('0','$branch')"; if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery); - $bugs = $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder, IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder")->from(TABLE_BUG)->where($bugQuery) + return $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder, IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder")->from(TABLE_BUG)->where($bugQuery) ->beginIF(!$this->app->user->admin)->andWhere('execution')->in('0,' . $this->app->user->view->sprints)->fi() ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi() @@ -2570,8 +2479,8 @@ class bugModel extends model ->andWhere('deleted')->eq(0) ->beginIF(!$this->app->user->admin)->andWhere('project')->in('0,' . $this->app->user->view->projects)->fi() - ->orderBy($orderBy)->page($pager)->fetchAll(); - return $bugs; + ->orderBy($orderBy)->page($pager) + ->fetchAll(); } /** @@ -2749,13 +2658,13 @@ class bugModel extends model public function linkBugToBuild($bugs, $resolvedBuild) { if(empty($resolvedBuild) or $resolvedBuild == 'trunk') return true; - if(is_array($bugs)) $bugs = join(',', $bugs); + if(is_array($bugs)) $bugs = implode(',', $bugs); $build = $this->dao->select('id,product,bugs')->from(TABLE_BUILD)->where('id')->eq($resolvedBuild)->fetch(); $buildBugs = $build->bugs . ',' . $bugs; $buildBugs = explode(',', trim($buildBugs, ',')); $buildBugs = array_unique($buildBugs); - $this->dao->update(TABLE_BUILD)->set('bugs')->eq(join(',', $buildBugs))->where('id')->eq($resolvedBuild)->exec(); + $this->dao->update(TABLE_BUILD)->set('bugs')->eq(implode(',', $buildBugs))->where('id')->eq($resolvedBuild)->exec(); $release = $this->dao->select('id,bugs')->from(TABLE_RELEASE)->where('product')->eq($build->product)->andWhere("(FIND_IN_SET('$resolvedBuild', build) or shadow = $resolvedBuild)")->andWhere('deleted')->eq('0')->fetch(); if($release) @@ -2763,7 +2672,7 @@ class bugModel extends model $releaseBugs = $release->bugs . ',' . $bugs; $releaseBugs = explode(',', trim($releaseBugs, ',')); $releaseBugs = array_unique($releaseBugs); - $this->dao->update(TABLE_RELEASE)->set('bugs')->eq(join(',', $releaseBugs))->where('id')->eq($release->id)->exec(); + $this->dao->update(TABLE_RELEASE)->set('bugs')->eq(implode(',', $releaseBugs))->where('id')->eq($release->id)->exec(); } return true; diff --git a/module/bug/tao.php b/module/bug/tao.php index 722ae958e2..4cccf81dc0 100644 --- a/module/bug/tao.php +++ b/module/bug/tao.php @@ -10,7 +10,7 @@ class bugTao extends bugModel * @access protected * @return object|false */ - protected function fetchBugInfo(int $bugID): object|false + protected function fetchBugInfo(string $bugID): object|false { return $this->dao->select('t1.*, t2.name AS executionName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName, t5.title AS planName') ->from(TABLE_BUG)->alias('t1') @@ -136,7 +136,7 @@ class bugTao extends bugModel * @access protected * @return array */ - protected function getCasesFromBug(int $bugID): array + protected function getCasesFromBug(string $bugID): array { return $this->dao->select('id, title')->from(TABLE_CASE)->where('`fromBug`')->eq($bugID)->fetchPairs(); } @@ -169,6 +169,97 @@ class bugTao extends bugModel return $this->dao->findById($objectID)->from($table)->fields($field)->fetch($field); } + /** + * 更新完bug后的相关处理。 + * Relevant processing after updating bug. + * + * @param object $bug + * @param object $oldBug + * @access protected + * @return void + */ + protected function afterUpdate(object $bug, object $oldBug) + { + /* 解除旧的版本关联关系,关联新的版本。*/ + /* Link bug to build and release. */ + if($bug->resolution == 'fixed' && !empty($bug->resolvedBuild) && $bug->resolvedBuild != $oldBug->resolvedBuild) + { + if(!empty($oldBug->resolvedBuild)) $this->loadModel('build')->unlinkBug($oldBug->resolvedBuild, $bug->id); + $this->linkBugToBuild($bug->id, $bug->resolvedBuild); + } + + /* 解除旧的计划关联关系,关联新的计划。*/ + /* Link new plan, unlink old plan. */ + if($bug->plan != $oldBug->plan) + { + $this->loadModel('action'); + if(!empty($oldBug->plan)) $this->action->create('productplan', $oldBug->plan, 'unlinkbug', '', $bug->id); + if(!empty($bug->plan)) $this->action->create('productplan', $bug->plan, 'linkbug', '', $bug->id); + } + + $this->updateLinkBug($bug->id, $bug->linkBug, $oldBug->linkBug); + + /* 给bug解决者积分奖励。*/ + /* Add score to resolvedby. */ + if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bug->id); + + /* 更新bug所属看板的泳道。*/ + /* Update the lane of the bug kanban. */ + if($bug->execution and $bug->status != $oldBug->status) $this->loadModel('kanban')->updateLane($bug->execution, 'bug'); + + /* 更新反馈的状态。*/ + /* Update the status of feedback. */ + if(($this->config->edition != 'open') && $oldBug->feedback) $this->loadModel('feedback')->updateStatus('bug', $oldBug->feedback, $bug->status, $oldBug->status); + + /* 更新bug的附件。*/ + /* Update the files of bug. */ + $this->loadModel('file')->processFile4Object('bug', $oldBug, $bug); + + return !dao::isError(); + } + + /** + * 更新相关bug。 + * Update the linked bug. + * + * @param int $bugID + * @param string $linkBug + * @param string $oldLinkBug + * @access private + * @return bool + */ + private function updateLinkBug(int $bugID, string $linkBug, string $oldLinkBug): bool + { + + return false; + + $linkBugs = explode(',', $linkBug); + $oldLinkBugs = explode(',', $oldLinkBug); + $addedLinkBugs = array_diff($linkBugs, $oldLinkBugs); + $removedLinkBugs = array_diff($oldLinkBugs, $linkBugs); + $changedLinkBugs = array_merge($addedLinkBugs, $removedLinkBugs); + $changedLinkBugs = $this->dao->select('id, linkbug')->from(TABLE_BUG)->where('id')->in(array_filter($changedLinkBugs))->fetchPairs(); + + foreach($changedLinkBugs as $changedBugID => $linkBugs) + { + if(in_array($changeBugID, $addedLinkBugs)) + { + $currentLinkBug = $bugID; + if(!empty($linkBugs)) $currentLinkBug = trim($linkBugs, ',') . ',' . $bugID; + } + else + { + $linkBugs = explode(',', $linkBugs); + unset($linkBugs[array_search($bugID, $linkBugs)]); + $currentLinkBug = implode(',', $linkBugs); + } + + $this->dao->update(TABLE_BUG)->set('linkBug')->eq($linkBug)->where('id')->eq($changeBugID)->exec(); + } + + return !dao::isError(); + } + /** * Call checkDelayBug in foreach to check if the bug is delay. * 循环调用checkDelayBug,检查bug是否延期 diff --git a/module/bug/test/bug.class.php b/module/bug/test/bug.class.php index 0be72507e8..084419b479 100644 --- a/module/bug/test/bug.class.php +++ b/module/bug/test/bug.class.php @@ -795,10 +795,11 @@ class bugTest $_POST[$field] = $value; } } - $_POST['closedDate'] = ''; + $_POST['deleteFiles'] = array(); + $object->files = array(); - $change = $this->objectModel->update($bugID); + $change = $this->objectModel->update((object)$_POST, $object); if($change == array()) $change = '没有数据更新'; unset($_POST); diff --git a/module/bug/test/model/getbyid.php b/module/bug/test/model/getbyid.php index a075854e94..940f221d48 100755 --- a/module/bug/test/model/getbyid.php +++ b/module/bug/test/model/getbyid.php @@ -45,7 +45,7 @@ $tester->loadModel('bug'); initData(); -r($tester->bug->getByID(2)) && p('pri,type') && e('1,codeerror'); //获取ID等于2的bug -r($tester->bug->getByID(3)) && p('title,status') && e('bug3,active'); //获取ID等于3的bug -r($tester->bug->getByID(4)) && p('severity,openedBuild') && e('3,trunk'); //获取ID等于4的bug -r($tester->bug->getByID(1)) && p('title') && e('0'); //获取不存在的bug +r($tester->bug->getByID(2)) && p('pri,type') && e('1,codeerror'); //获取ID等于2的bug +r($tester->bug->getByID(3)) && p('title,status') && e('bug3,active'); //获取ID等于3的bug +r($tester->bug->getByID(4)) && p('severity,openedBuild') && e('3,trunk'); //获取ID等于4的bug +r($tester->bug->getByID(1)) && p('title') && e('0'); //获取不存在的bug diff --git a/module/bug/test/model/update.php b/module/bug/test/model/update.php index 7ea4360a69..a2601b1843 100755 --- a/module/bug/test/model/update.php +++ b/module/bug/test/model/update.php @@ -1,33 +1,62 @@ #!/usr/bin/env php id->range('1-5'); + $data->product->range('1-5'); + $data->branch->range('0-1'); + $data->project->range('0-5'); + $data->execution->range('0-5'); + $data->title->prefix("BUG")->range('1-5'); + $data->openedBuild->range('1-5'); + $data->type->range("[codeerror]"); + $data->status->range("[active]"); + $data->pri->range("[3]"); + $data->severity->range("[3]"); + + $data->gen(4); +} /** title=bugModel->update(); +timeout=0 cid=1 -pid=1 -测试更新bug名称 >> title,BUG1,john -测试更新bug类型 >> type,codeerror,config -测试更新bug名称和类型 >> title,john,jack;type,config,install -测试不更改bug名称 >> 没有数据更新 -测试不更改bug类型 >> 没有数据更新 +- 测试更新bug名称 + - 第0条的field属性 @title + - 第0条的old属性 @BUG1 + - 第0条的new属性 @john + +- 测试更新bug类型 + - 第0条的field属性 @type + - 第0条的old属性 @codeerror + - 第0条的new属性 @config + +- 测试不更改bug名称 @没有数据更新 + +- 测试不更改bug类型 @没有数据更新 + + */ -$projectIdList = array('1', '2'); +initData(); -$t_uptitle = array('title' => 'john'); -$t_uptype = array('type' => 'config'); -$t_typetitle = array('title' => 'jack', 'type' => 'install'); -$t_untitle = array('title' => 'jack'); -$t_untype = array('type' => 'install'); +$bugIdList = array('1', '2'); -$bug=new bugTest(); -r($bug->updateObject($projectIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称 -r($bug->updateObject($projectIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型 -r($bug->updateObject($projectIdList[0], $t_typetitle)) && p('0:field,old,new;1:field,old,new') && e('title,john,jack;type,config,install'); // 测试更新bug名称和类型 -r($bug->updateObject($projectIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称 -r($bug->updateObject($projectIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型 +$t_uptitle = array('title' => 'john'); +$t_uptype = array('type' => 'config'); +$t_untitle = array('title' => 'john'); +$t_untype = array('type' => 'config'); + +$bug = new bugTest(); +r($bug->updateObject($bugIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称 +r($bug->updateObject($bugIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型 +r($bug->updateObject($bugIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称 +r($bug->updateObject($bugIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型 \ No newline at end of file diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php index 3e4629681a..dcc5c70f39 100644 --- a/module/bug/view/edit.html.php +++ b/module/bug/view/edit.html.php @@ -37,7 +37,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project); ?>