* @package bug * @version $Id: control.php 5107 2013-07-12 01:46:12Z chencongzhi520@gmail.com $ * @link https://www.zentao.net */ class bug extends control { /** * 所有产品。 * All products. * * @var array * @access public */ public $products = array(); /** * 当前项目编号。 * Project id. * * @var int * @access public */ public $projectID = 0; /** * 构造函数 * * 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(string $moduleName = '', string $methodName = '') { parent::__construct($moduleName, $methodName); $this->loadModel('product'); $this->loadModel('tree'); $this->loadModel('user'); $this->loadModel('action'); $this->loadModel('story'); $this->loadModel('task'); $this->loadModel('qa'); /* Get product data. */ $products = array(); if(!isInModal()) { $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') { if(common::isTutorialMode()) { $products = $this->loadModel('tutorial')->getProductPairs(); } else { $products = $this->product->getProducts($objectID, $mode, '', false); } } else { $products = $this->product->getPairs($mode, 0, '', 'all'); } if(empty($products) && (helper::isAjaxRequest('zin') || helper::isAjaxRequest('fetch'))) $this->locate($this->createLink('product', 'showErrorNone', "moduleName=$tab&activeMenu=bug&objectID=$objectID")); } else { $mode = empty($this->config->CRProduct) ? 'noclosed' : ''; $products = $this->product->getPairs($mode, 0, '', 'all'); } $this->view->products = $this->products = $products; } /** * Bug 列表。 * Browse bugs. * * @param int $productID * @param string $branch * @param string $browseType * @param int $param * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function browse(int $productID = 0, string $branch = '', string $browseType = '', int $param = 0, string $orderBy = '', int $recTotal = 0, int $recPerPage = 20, int $pageID = 1, string $from = 'bug', int $blockID = 0) { if($from == 'doc' || $from === 'ai') { $this->app->loadLang('doc'); $realProducts = $this->product->getPairs('nodeleted', 0, '', 'all'); if(empty($realProducts)) return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->tips->noProduct)); } /* 把访问的产品ID等状态信息保存到session和cookie中。*/ /* Save the product id user last visited to session and cookie. */ $productID = $this->product->checkAccess($productID, $this->products); $product = $this->product->getByID($productID); $branch = $this->bugZen->getBrowseBranch($branch, (string)$product->type); $browseType = $browseType ? strtolower($browseType) : 'unclosed'; /* 设置1.5级导航相关信息。*/ /* Set the 1.5 nav. */ $this->qa->setMenu($productID, $branch); /* 设置排序字段。*/ /* Set the order field. */ if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc'; $this->bugZen->setBrowseCookie((object)$product, $branch, $browseType, $param, $orderBy); $this->bugZen->setBrowseSession($browseType); /* 处理列表页面的参数。*/ /* Processing browse params. */ $modules = $this->tree->getOptionMenu((int)$product->id, 'bug', 0, $branch); list($moduleID, $queryID, $realOrderBy, $pager) = $this->bugZen->prepareBrowseParams($browseType, $param, $orderBy, $recTotal, $recPerPage, $pageID); if(!isset($modules[$moduleID])) $moduleID = 0; $actionURL = $this->createLink('bug', 'browse', "productID=$productID&branch=$branch&browseType=bySearch&queryID=myQueryID&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID&from=$from&blockID=$blockID"); $this->bugZen->buildBrowseSearchForm($productID, $branch, $queryID, $actionURL); $executions = $this->loadModel('execution')->fetchPairs($this->projectID, 'all', false); $bugs = $this->bugZen->getBrowseBugs((int)$product->id, $branch, $browseType, array_keys($executions), $moduleID, $queryID, $realOrderBy, $pager); $this->bugZen->buildBrowseView($bugs, (object)$product, $branch, $browseType, $moduleID, $executions, $param, $orderBy, $pager); $this->view->from = $from; $this->view->blockID = $blockID; $this->view->idList = ''; if($from === 'doc') { $docBlock = $this->loadModel('doc')->getDocBlock($blockID); $this->view->docBlock = $docBlock; if($docBlock) { $content = json_decode($docBlock->content, true); if(isset($content['idList'])) $this->view->idList = $content['idList']; } } $this->view->modules = $modules; $this->display(); } /** * 查看一个 bug。 * View a bug. * * @param int $bugID * @access public * @return void */ public function view(int $bugID) { $bug = $this->bug->getByID($bugID, true); /* 判断 bug 是否存在。*/ /* Judge bug exits or not. */ if(!$bug) return $this->send(array('result' => 'success', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->createLink('qa', 'index')))); /* 检查用户是否拥有所属执行的权限。*/ /* Check bug execution priv. */ $this->bugZen->checkBugExecutionPriv($bug); /* Update action. */ if($bug->assignedTo == $this->app->user->account) $this->loadModel('action')->read('bug', $bugID); if(!isInModal()) $this->bugZen->setViewMenu($bug); $product = $this->product->getByID($bug->product); $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product); $projects = $this->product->getProjectPairsByProduct($bug->product, (string)$bug->branch); $projectID = isset($projects[$bug->project]) ? $bug->project : key($projects); if(in_array($this->app->tab, array('project', 'execution'))) { $objectType = $this->app->tab == 'project' ? 'projectID' : 'executionID'; $this->view->{$objectType} = $this->session->{$this->app->tab}; } if($this->app->tab == 'devops') $this->bugZen->processRepoIssueActions((int)$bug->repo); $builds = $this->loadModel('build')->getBuildPairs(array($bug->product), 'all', 'hasdeleted'); if($bug->resolvedBuild && !isset($builds[$bug->resolvedBuild])) { $build = $this->build->fetchByID((int)$bug->resolvedBuild); $builds[$build->id] = $build->name; } $this->session->set('project', $projectID, 'project'); $this->session->set('storyList', '', 'product'); $this->session->set('projectList', $this->app->getURI(true) . "#app={$this->app->tab}", 'project'); $this->view->title = "BUG #$bug->id $bug->title - " . $product->name; $this->view->branchID = $bug->branch; $this->view->product = $product; $this->view->project = $this->loadModel('project')->getByID($bug->project); $this->view->projects = $projects; $this->view->executions = $this->product->getExecutionPairsByProduct($bug->product, (string)$bug->branch, (int)$projectID, 'noclosed'); $this->view->bug = $bug; $this->view->bugModule = empty($bug->module) ? '' : $this->tree->getByID($bug->module); $this->view->modulePath = $this->loadModel('tree')->getParents($bug->module); $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->branches = $branches; $this->view->branchName = $product->type == 'normal' ? '' : zget($branches, $bug->branch, ''); $this->view->builds = $builds; $this->view->linkCommits = $this->loadModel('repo')->getCommitsByObject($bug->id, 'bug'); $this->view->actions = $this->loadModel('action')->getList('bug', $bug->id); $this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('bug', $bugID); $this->display(); } /** * 创建一个 bug。 * Create a bug. * * @param int $productID * @param string $branch * @param string $extras Other params, for example, executionID=10,moduleID=10. * @access public * @return void */ public function create(int $productID, string $branch = '', string $extras = '') { if(isset($_POST['stepIdList'])) { $extras .= "&stepIdList={$this->post->stepIdList}"; unset($_POST['stepIdList']); } $extras = str_replace(array(',', ' ', '*'), array('&', '', '-'), $extras); parse_str($extras, $params); $from = isset($params['from']) ? $params['from'] : ''; if(!empty($_POST)) { if(!empty($params['productID'])) $product = $this->bug->fetchByID((int)$params['productID'], 'product'); $formData = form::data($this->config->bug->form->create, 0, !empty($product->workflowGroup) ? $product->workflowGroup : 0); $bug = $this->bugZen->prepareCreateExtras($formData); $bugID = $this->bug->create($bug, $from); if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError())); $bug->id = $bugID; $this->bugZen->afterCreate($bug, $params, $from); $message = $this->executeHooks($bugID); return $this->responseAfterCreate($bug, $params, $message); } $productID = $this->product->checkAccess($productID, $this->products); $product = $this->product->getByID($productID); if($branch === '') $branch = (string)$this->cookie->preBranch; $this->bugZen->setCreateMenu($productID, $branch, $params); /* 初始化一个bug对象,尽可能把属性都绑定到bug对象上,extract() 出来的变量除外。 */ /* Init bug, give bug as many variables as possible, except for extract variables. */ $fields = array('id' => 0, 'productID' => $productID, 'branch' => $branch, 'title' => ($from == 'sonarqube' ? $_COOKIE['sonarqubeIssue'] : ''), 'assignedTo' => (isset($product->QD) ? $product->QD : '')); $fields = array_merge($fields, $params); $fields['product'] = $fields['productID']; $bug = $this->bugZen->initBug($fields); /* 处理复制 bug,从用例、测试单、日志转 bug。 */ /* Handle copy bug, bug from case, testtask, todo. */ $bug = $this->bugZen->extractObjectFromExtras($bug, $params); /* 获取分支、版本、需求、项目、执行、产品、项目的模式、用例,构造$this->view。*/ /* Get branches, builds, stories, project, projects, executions, products, project model, cases and build create form. */ $this->bugZen->buildCreateForm($bug, $params, $from); extract($params); $extrasValue = 'productID={product},moduleID={module},projectID={project},executionID={execution},regionID={region},allBuilds={allBuilds},allUsers={allUsers}' . (empty($from) ? '' : "&from=$from"); if(!empty($fromType)) $extrasValue .= ",fromType={$fromType}"; if(!empty($fromID)) $extrasValue .= ",fromID={$fromID}"; $this->view->loadUrl = $this->createLink('bug', 'create', "productID={$productID}&branch={branch}&extras={$extrasValue}"); $this->display(); } /** * 更新 bug 信息。 * Edit a bug. * * @param int $bugID * @param bool $comment true|false * @access public * @return void */ public function edit(int $bugID, bool $comment = false) { $oldBug = $this->bug->getByID($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); if(!empty($_POST)) { $formData = form::data($this->config->bug->form->edit, $bugID); $bug = $this->bugZen->prepareEditExtras($formData, $oldBug); $this->bugZen->checkRquiredForEdit($bug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $changes = array(); if(!$comment) { $changes = $this->bug->update($bug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->bugZen->afterUpdate($bug, $oldBug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); } /* Get response after editing bug. */ $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterOperate($bugID, $changes, $message); } $this->bugZen->checkBugExecutionPriv($oldBug); $this->bugZen->setEditMenu($oldBug); $this->bugZen->buildEditForm($oldBug); $this->display(); } /** * 指派 bug。 * Assign bug. * * @param int $bugID * @access public * @return void */ public function assignTo(int $bugID) { /* 获取更新前的 bug,并且检查所属执行的权限。*/ /* Get old bug and check privilege of the execution. */ $oldBug = $this->bug->getByID($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); $this->bugZen->checkBugExecutionPriv($oldBug); if(!empty($_POST)) { /* 初始化 bug 数据。*/ /* Init bug data. */ $bug = form::data($this->config->bug->form->assignTo, $bugID)->add('id', $bugID)->get(); if($this->app->rawMethod == 'batchassignto') unset($bug->mailto); if($oldBug->status != 'closed') $this->bug->assign($bug, $oldBug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = $this->executeHooks($bugID); if(!$message) $message = $this->lang->saveSuccess; return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true, 'load' => true)); } $this->qa->setMenu($oldBug->product, $oldBug->branch); /* 获取指派给的用户列表。*/ /* Get users that can be assigned to. */ if($this->app->tab == 'project' || $this->app->tab == 'execution') { $users = $this->bugZen->getAssignedToPairs($oldBug); } else { $users = $this->loadModel('user')->getPairs('devfirst|noclosed'); } $this->view->title = $this->lang->bug->assignTo; $this->view->bug = $oldBug; $this->view->users = $users; $this->display(); } /** * 确认 bug。 * confirm a bug. * * @param int $bugID * @param string $kanbanParams fromColID=,toColID=,fromLaneID=,toLaneID=,regionID= * @param string $from taskkanban * @access public * @return void */ public function confirm(int $bugID, string $kanbanParams = '', string $from = '') { $oldBug = $this->bug->getByID($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); /* 检查 bug 所属执行的权限。*/ /* Check privilege for execution of the bug. */ $this->bugZen->checkBugExecutionPriv($oldBug); if(!empty($_POST)) { /* 处理看板相关的参数。*/ /* Process the params related to kanban. */ $kanbanParams = str_replace(array(',', ' '), array('&', ''), $kanbanParams); parse_str($kanbanParams, $kanbanData); /* 构造 bug 的表单数据。*/ /* Structure the bug form data. */ $bug = form::data($this->config->bug->form->confirm, $bugID)->add('id', $bugID)->setDefault('confirmed', 1)->get(); $this->bug->confirm($bug, $kanbanData); /* 返回确认 bug 后的响应。 */ /* Return response after confirming bug. */ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterOperate($bugID, array(), $message, (!empty($kanbanParams) || $from)); } $this->qa->setMenu($oldBug->product, $oldBug->branch); /* 展示相关变量。 */ /* Show the variables associated. */ $this->view->title = $this->lang->bug->confirm; $this->view->bug = $oldBug; $this->view->users = $this->loadModel('user')->getPairs('noclosed', $oldBug->assignedTo); $this->view->actions = $this->loadModel('action')->getList('bug', $bugID); $this->display(); } /** * 解决bug。 * Resolve a bug. * * @param int $bugID * @param string $extra * @access public * @return void */ public function resolve(int $bugID, string $extra = '') { /* 获取 bug 信息,并检查 bug 所属执行的权限。*/ /* Get bug info, and check privilege of bug 所属执行的权限。*/ $oldBug = $this->bug->getById($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); $this->bugZen->checkBugExecutionPriv($oldBug); if(!empty($_POST)) { /* 解析信息,并获取变量。 */ /* Parse extra, and get variables. */ $extra = str_replace(array(',', ' '), array('&', ''), $extra); parse_str($extra, $output); /* 初始化 bug 数据。 */ /* Init bug data. */ $bug = $this->bugZen->buildBugForResolve($oldBug); /* 检查解决 bug 的必填项。 */ /* Check required fields. */ $this->bugZen->checkRequiredForResolve($bug, $oldBug->execution); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); /* 如果需要创建版本,创建版本。 */ /* If you need to create a build, create one. */ if($bug->createBuild == 'on') { $this->bug->createBuild($bug, $oldBug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); } /* 只有非关闭状态的 bug 可以解决。 */ /* Only unclosed bug can be resolved. */ if($oldBug->status != 'closed') $this->bug->resolve($bug, $output); /* 返回解决 bug 后的响应。 */ /* Return response after resolving bug. */ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterOperate($bugID, common::createChanges($oldBug, $bug), $message); } /* 移除解决方案“转需求”。 */ /* Remove 'Convert to story' from the solution list. */ unset($this->lang->bug->resolutionList['tostory']); /* 设置菜单。 */ /* Set menu. */ $this->qa->setMenu($oldBug->product, $oldBug->branch); $users = $this->loadModel('user')->getPairs('noclosed'); $builds = $this->loadModel('build')->getBuildPairs(array($oldBug->product), $oldBug->branch, 'withbranch,noreleased,nofail'); /* 展示相关变量。 */ /* Show the variables associated. */ $this->view->title = $this->lang->bug->resolve; $this->view->bug = $oldBug; $this->view->execution = $oldBug->execution ? $this->loadModel('execution')->getByID($oldBug->execution) : ''; $this->view->users = $users; $this->view->assignedTo = isset($users[$oldBug->openedBy]) ? $oldBug->openedBy : $this->bug->getModuleOwner($oldBug->module, $oldBug->product); $this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($oldBug->product, $oldBug->branch ? "0,{$oldBug->branch}" : '0', (int)$oldBug->project, 'stagefilter'); $this->view->builds = $this->build->addReleaseLabelForBuilds($oldBug->product, $builds); $this->view->actions = $this->loadModel('action')->getList('bug', $bugID); $this->display(); } /** * 激活一个bug。 * Activate a bug. * * @param int $bugID * @param string $kanbanInfo a string of kanban info, for example, 'fromColID=1,toColID=2,fromLaneID=1,toLaneID=2,regionID=1'. * @access public * @return void */ public function activate(int $bugID, string $kanbanInfo = '') { /* 获取 bug 信息,并检查 bug 所属执行的权限。*/ /* Get bug info, and check privilege of bug 所属执行的权限。*/ $oldBug = $this->bug->getByID($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); $this->bugZen->checkBugExecutionPriv($oldBug); if(!empty($_POST)) { /* 只有状态为解决或者关闭的bug才可以激活。 */ /* Only bugs whose status is resolved or closed can be activated. */ if($oldBug->status != 'resolved' && $oldBug->status != 'closed') { dao::$errors[] = $this->lang->bug->error->cannotActivate; return $this->send(array('result' => 'fail', 'message' => dao::getError())); } /* 获取bug信息。 */ /* Build bug data. */ $bug = form::data($this->config->bug->form->activate, $bugID)->setDefault('assignedTo', $oldBug->resolvedBy)->add('activatedCount', $oldBug->activatedCount + 1)->add('id', $bugID)->add('resolvedDate', null)->add('closedDate', null)->get(); /* 解析看板信息。 */ /* Parse kanban information. */ $kanbanInfo = str_replace(array(',', ' '), array('&', ''), $kanbanInfo); parse_str($kanbanInfo, $kanbanParams); $this->bug->activate($bug, $kanbanParams); /* 返回激活 bug 后的响应。 */ /* Return response after activating bug. */ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterOperate($bugID, array(), $message); } $productID = $oldBug->product; $this->qa->setMenu($productID, $oldBug->branch); /* 展示相关变量。 */ /* Show the variables associated. */ $this->view->title = $this->lang->bug->activate; $this->view->bug = $oldBug; $this->view->users = $this->loadModel('user')->getPairs('noclosed', $oldBug->resolvedBy); $this->view->builds = $this->loadModel('build')->getBuildPairs(array($productID), $oldBug->branch, 'noempty,noreleased,nofail', 0, 'execution', $oldBug->openedBuild); $this->view->actions = $this->loadModel('action')->getList('bug', $bugID); $this->display(); } /** * 根据Bug的ID来关闭Bug。 * Close a bug. * * @param int $bugID * @param string $extra * @access public * @return void */ public function close(int $bugID, string $extra = '') { /* 获取 bug 信息,并检查 bug 所属执行的权限。*/ /* Get bug info, and check privilege of bug 所属执行的权限。*/ $oldBug = $this->bug->getByID($bugID); if(!$oldBug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); $this->bugZen->checkBugExecutionPriv($oldBug); if(!empty($_POST)) { /* 设置bug信息。 */ /* Set bug information. */ $bug = form::data($this->config->bug->form->close, $bugID)->add('id', $bugID)->get(); /* 设置额外变量。 */ /* Set extra variables. */ $extra = str_replace(array(',', ' '), array('&', ''), $extra); parse_str($extra, $output); $this->bug->close($bug, $output); /* 返回关闭 bug 后的响应。 */ /* Return response after closing bug. */ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterOperate($bugID, array(), $message); } $this->view->title = $this->lang->bug->close; $this->view->bug = $oldBug; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->actions = $this->loadModel('action')->getList('bug', $oldBug->id); $this->display(); } /** * 删除 bug。 * Delete a bug. * * @param int $bugID * @param string $from taskkanban * @access public * @return void */ public function delete(int $bugID, string $from = '') { /* 删除 bug。 */ /* Delete bug. */ $bug = $this->bug->getByID($bugID); if(!$bug) return $this->send(array('result' => 'fail', 'message' => $this->lang->bug->error->notExist)); $this->bug->delete(TABLE_BUG, $bugID); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); /* 返回删除 bug 后的响应。 */ /* Return response after deleting bug. */ $message = $this->executeHooks($bugID); return $this->bugZen->responseAfterDelete($bug, $from, $message); } /** * 导出bug数据。 * Get data to export * * @param int $productID * @param string $browseType * @param int $executionID * @access public * @return void */ public function export(int $productID, string $browseType = '', int $executionID = 0) { if($_POST) { /* 设置bug导出的参数。 */ /* Set bug export params. */ if($executionID) { $productIdList = $this->loadModel('product')->getProductPairsByProject($executionID); $productIdList = array_keys($productIdList); } else { $productIdList = array($productID); } $this->session->set('bugTransferParams', array('productID' => $productID, 'executionID' => $executionID, 'branch' => 'all', 'productIdList' => $productIdList)); /* 设置导出数据源。 */ /* Set export data source. */ if(!$productID || $browseType == 'bysearch') { /* 设置模块数据源。 */ /* Set module data source. */ $this->config->bug->dtable->fieldList['module']['dataSource'] = array('module' => 'tree', 'method' => 'getAllModulePairs', 'params' => 'bug'); /* 如果导出执行的bug,设置数据源。 */ /* In execution, set data source. */ if($executionID) { $object = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch(); $projectID = $object->type == 'project' ? $object->id : $object->parent; $this->config->bug->dtable->fieldList['project']['dataSource'] = array('module' => 'project', 'method' => 'getPairsByIdList', 'params' => array('projectIdList' => array($projectID))); $this->config->bug->dtable->fieldList['execution']['dataSource'] = array('module' => 'execution', 'method' => 'getPairs', 'params' => $projectID); } } $this->config->bug->dtable->fieldList['assignedTo']['dataSource'] = array('module' => 'user', 'method' => 'getPairs', 'params' => array()); $this->loadModel('transfer')->export('bug'); $this->fetch('file', 'export2' . $this->post->fileType, $_POST); } /* 获取产品信息。 */ /* Get product information. */ $product = $this->loadModel('product')->getByID($productID); /* 展示相关变量。 */ /* Show the variables associated. */ $this->view->fileName = $this->bugZen->getExportFileName($executionID, $browseType, $product); $this->view->allExportFields = $this->bugZen->getExportFields($executionID, $product); $this->view->customExport = true; $this->display('file', 'export'); } /** * Bug 的统计报表。 * The report page. * * @param int $productID * @param string $browseType * @param int $branchID * @param int $moduleID * @param string $chartType * @access public * @return void */ public function report(int $productID, string $browseType, int $branchID, int $moduleID, string $chartType = 'pie') { $this->loadModel('report'); $charts = $datas = array(); if(!empty($_POST)) { foreach($this->post->charts as $chart) { $chartFunc = 'getDataOf' . $chart; $chartData = $this->bug->$chartFunc(); $charts[$chart] = $this->bugZen->mergeChartOption($chart, $chartType); $datas[$chart] = $this->report->computePercent($chartData); } } /* 如果是影子产品并且对应的项目不是多迭代项目,删掉迭代 Bug 数量报表。*/ /* Unset execution bugs report if the product is shadow and corresponding project is not multiple. */ $project = $this->loadModel('project')->getByShadowProduct($productID); if(!empty($project) && !$project->multiple) unset($this->lang->bug->report->charts['bugsPerExecution']); $this->qa->setMenu($productID, $branchID); $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->bug->common . $this->lang->hyphen . $this->lang->bug->reportChart; $this->view->productID = $productID; $this->view->browseType = $browseType; $this->view->branchID = $branchID; $this->view->moduleID = $moduleID; $this->view->chartType = $chartType; $this->view->checkedCharts = $this->post->charts ? implode(',', $this->post->charts) : ''; $this->view->charts = $charts; $this->view->datas = $datas; $this->display(); } /** * 关联相关 bug。 * Link related bugs. * * @param int $bugID * @param string $bySearch * @param string $excludeBugs * @param int $queryID * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function linkBugs(int $bugID, string $bySearch = 'false', string $excludeBugs = '', int $queryID = 0, int $recTotal = 0, int $recPerPage = 20, int $pageID = 1) { $bug = $this->bug->getByID($bugID); $bySearch = $bySearch === 'true'; /* 检查 bug 所属执行的权限。*/ /* Check privilege of bug 所属执行的权限。*/ $this->bugZen->checkBugExecutionPriv($bug); $this->qa->setMenu($bug->product, $bug->branch); $this->bugZen->buildSearchFormForLinkBugs($bug, $excludeBugs, $queryID); /* Load pager. */ $this->app->loadClass('pager', true); $pager = new pager($recTotal, $recPerPage, $pageID); /* Assign. */ $this->view->title = $this->lang->bug->linkBugs . "BUG #$bug->id $bug->title {$this->lang->dash} " . $this->products[$bug->product]; $this->view->bug = $bug; $this->view->bugs2Link = $this->bug->getBugs2Link($bugID, $bySearch, $excludeBugs, $queryID, $pager); $this->view->users = $this->user->getPairs('noletter'); $this->view->pager = $pager; $this->display(); } /** * 批量创建 bug。 * Batch create bug. * * @param int $productID * @param string $branch * @param int $executionID * @param int $moduleID * @param string $extra * @access public * @return void */ public function batchCreate(int $productID, string $branch = '', int $executionID = 0, int $moduleID = 0, string $extra = '') { $extra = str_replace(array(',', ' '), array('&', ''), $extra); parse_str($extra, $output); $bugImagesFile = $this->session->bugImagesFile ? $this->session->bugImagesFile : array(); if(!empty($_POST)) { $this->config->bug->create->requiredFields = $this->config->bug->batchcreate->requiredFields; $bugs = $this->bugZen->buildBugsForBatchCreate($productID, $branch, $bugImagesFile); $bugs = $this->bugZen->checkBugsForBatchCreate($bugs); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = ''; $bugIdList = array(); foreach($bugs as $bug) { if(!empty($bug->assignedTo)) $bug->assignedDate = helper::now(); $bug->id = $this->bug->create($bug); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); /* 批量创建后的一些其他操作。*/ /* Processing other operations after batch creation. */ $this->bugZen->afterBatchCreate($bug, $output); $message = $this->executeHooks($bug->id); $bugIdList[] = $bug->id; } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchCreate'); return $this->bugZen->responseAfterBatchCreate($productID, $branch, $executionID, $bugIdList, $message); } /* 把访问的产品ID等状态信息保存到session和cookie中。*/ /* Save the product id user last visited to session and cookie. */ $productID = $this->product->checkAccess($productID, $this->products); $product = $this->product->getByID($productID); /* 设置当前分支,并且设置导航。*/ /* Get branch and set menu. */ if($branch === '') $branch = $this->cookie->preBranch; $this->qa->setMenu($productID, $branch); /* 展示批量创建bug的相关变量。*/ /* Show the variables associated with the batch creation bugs. */ $this->bugZen->assignBatchCreateVars($executionID, $product, $branch, $output, $bugImagesFile); $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->bug->batchCreate; $this->view->moduleID = $moduleID; $this->view->product = $product; $this->view->users = $this->loadModel('user')->getPairs('noclosed'); $this->display(); } /** * 批量编辑 bugs。 * Batch edit bugs. * * @param int $productID * @param string $branch * @access public * @return void */ public function batchEdit(int $productID = 0, string $branch = '0') { /* 如果没有选择的 bug,跳转到前一个页面。*/ /* If there is no bug ID, locate to the previous step. */ if(!$this->post->bugIdList && !$this->post->id) { $url = !empty($this->session->bugList) ? $this->session->bugList : $this->createLink('qa', 'index'); $this->locate($url); } if($this->post->id) { /* 为批量编辑 bug 构造数据。*/ /* Build bugs. */ $oldBugs = $this->bug->getByIdList($this->post->id); $bugs = $this->bugZen->buildBugsForBatchEdit($oldBugs); /* 检查数据。*/ /* Check bugs. */ $this->bugZen->checkBugsForBatchUpdate($bugs); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $message = ''; foreach($bugs as $bugID => $bug) { $this->bug->update($bug); $oldBug = $oldBugs[$bugID]; $bug->status = $oldBug->status; /* 批量编辑 bug 后的一些操作。*/ /* Operate after batch edit bugs. */ $this->bugZen->operateAfterBatchEdit($bug, $oldBug); /* 获取待处理的任务和计划列表。*/ /* Get toTaskIdList, unlinkPlans and link2Plans to be processed. */ list($toTaskIdList, $unlinkPlans, $link2Plans) = $this->bugZen->getToBeProcessedData($bug, $oldBug); $message = $this->executeHooks($bug->id); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchEdit'); $this->loadModel('action'); foreach($unlinkPlans as $planID => $bugs) $this->action->create('productplan', $planID, 'unlinkbug', '', $bugs); foreach($link2Plans as $planID => $bugs) $this->action->create('productplan', $planID, 'linkbug', '', $bugs); /* 批量编辑的返回。*/ /* Response of batch edit. */ return $this->bugZen->responseAfterBatchEdit($toTaskIdList, $message); } $this->bugZen->assignBatchEditVars($productID, $branch); $this->display(); } /** * 批量修改 bug 的分支。 * Batch change branch of the bug. * * @param int $branchID * @access public * @return void */ public function batchChangeBranch(int $branchID) { if($this->post->bugIdList) { /* 准备 bug 修改分支需要的数据。 */ /* Prepare data to change branch. */ $bugIdList = array_unique($this->post->bugIdList); $oldBugs = $this->bug->getByIdList($bugIdList); /* 更新 bug 的分支,获取跳过的 bug id 列表。 */ /* Update the branch of the bug, and get the list of bug id to skip. */ $skipBugIdList = ''; foreach($bugIdList as $bugID) { $oldBug = $oldBugs[$bugID]; if($branchID != $oldBug->branch) { if(empty($oldBug->module)) { $bug = new stdclass(); $bug->id = (int)$bugID; $bug->branch = $branchID; $this->bug->update($bug); } else { $skipBugIdList .= '[' . $bugID . ']'; } } } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } /* 返回批量修改分支 bugs 后的响应。 */ /* Return response after batch changing branch of the bugs. */ $load = $this->session->bugList; if(!empty($skipBugIdList)) $load = array('confirm' => sprintf($this->lang->bug->notice->noSwitchBranch, $skipBugIdList), 'confirmed' => true, 'canceled' => true); return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $load)); } /** * 批量修改 bug 的所属模块。 * Batch change the module of the bug. * * @param int $moduleID * @access public * @return void */ public function batchChangeModule(int $moduleID) { if($this->post->bugIdList) { /* 获取要修改计划的 bug id 列表。 */ /* Get bug id list to change plan. */ $bugIdList = array_unique($this->post->bugIdList); foreach($bugIdList as $bugID) { /* 更新 bug 的模块。 */ /* Update the module of the bug. */ $bug = new stdclass(); $bug->id = (int)$bugID; $bug->module = $moduleID; $this->bug->update($bug); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $this->session->bugList)); } /** * 批量修改 bug 的计划。 * Batch change the plan of bug. * * @param int $planID * @access public * @return void */ public function batchChangePlan(int $planID) { if($this->post->bugIdList) { /* 准备 bug 修改计划需要的数据。 */ /* Prepare data to change plan. */ $bugIdList = array_unique($this->post->bugIdList); $oldBugs = $this->bug->getByIdList($bugIdList); /* 修改 bugs 的计划。 */ /* Change the plan of bugs. */ $unlinkPlans = array(); $link2Plans = array(); foreach($bugIdList as $bugID) { $oldBug = $oldBugs[$bugID]; /* 如果新老计划一致,跳过。 */ /* If the new plan is the same as the old one, skip it. */ if($planID == $oldBug->plan) continue; /* 关联 bug 到新计划,并取消与旧计划关联。 */ /* Link the bug to the new plan and unlink the bug from the old plan. */ $unlinkPlans[$oldBug->plan] = empty($unlinkPlans[$oldBug->plan]) ? $bugID : "{$unlinkPlans[$oldBug->plan]},$bugID"; $link2Plans[$planID] = empty($link2Plans[$planID]) ? $bugID : "{$link2Plans[$planID]},$bugID"; /* 更新 bug 的计划。 */ /* Update the plan of the bug. */ $bug = new stdclass(); $bug->id = (int)$bugID; $bug->plan = $planID; $this->bug->update($bug); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); /* 记录 bug 的计划变更动态。 */ /* Record plan action. */ $this->loadModel('action'); foreach($unlinkPlans as $planID => $bugs) $this->action->create('productplan', $planID, 'unlinkbug', '', $bugs); foreach($link2Plans as $planID => $bugs) $this->action->create('productplan', $planID, 'linkbug', '', $bugs); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $this->session->bugList)); } /** * 批量变更 bugs 的指派人。 * Batch update assign of bugs. * * @param string $assignedTo * @param int $objectID projectID|executionID * @param string $type execution|project|product|my * @access public * @return void */ public function batchAssignTo(string $assignedTo, int $objectID, string $type = 'execution') { $assignedTo = base64_decode($assignedTo); if($this->post->bugIdList) { /* 获取指派给的 bug id 列表。 */ /* Get bug id list to assign. */ $bugIdList = array_unique($this->post->bugIdList); $oldBugList = $this->bug->getByIdList($bugIdList); /* 初始化 bug 数据。 */ /* Init bug data. */ $bug = form::data($this->config->bug->form->assignTo)->remove('mailto')->get(); foreach($bugIdList as $bugID) { $oldBug = $oldBugList[$bugID]; if($oldBug->status == 'closed') continue; /* 构建 bug。 */ /* Build bug. */ $bug->id = (int)$bugID; $bug->assignedTo = $assignedTo; $this->bug->assign($bug, $oldBug); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } /* 返回批量指派 bugs 后的响应。 */ /* Return response after batch assigning bugs. */ if($type == 'execution') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('execution', 'bug', "executionID=$objectID"))); if($type == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'bug', "projectID=$objectID"))); return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true)); } /** * 批量确认 bugs。 * Batch confirm bugs. * * @access public * @return void */ public function batchConfirm() { if($this->post->bugIdList) { /* 准备 bug 确认需要的数据。 */ /* Prepare resolve data. */ $bugIdList = array_unique($this->post->bugIdList); $bugs = $this->bug->getByIdList($bugIdList); /* 初始化 bug 数据。 */ /* Init bug data. */ $bug = form::data($this->config->bug->form->confirm)->setDefault('confirmed', 1)->remove('pri,type,status,mailto')->get(); foreach($bugIdList as $bugID) { $bugID = (int)$bugID; /* 如果 bug 已经确认过,跳过。 */ /* If bug has been confirmed, skip it. */ if(!empty($bugs[$bugID]->confirmed)) continue; /* 构建 bug。 */ /* Build bug. */ $bug->id = $bugID; $bug->confirmed = 1; $bug->assignedTo = $this->app->user->account; unset($bug->deadline); $this->bug->confirm($bug); $message = $this->executeHooks($bugID); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } /* 返回批量确认 bugs 后的响应。 */ /* Return response after batch confirming bugs. */ if(empty($message)) $message = $this->lang->saveSuccess; return $this->send(array('result' => 'success', 'message' => $message, 'load' => true)); } /** * 批量解决 bugs。 * Batch resolve bugs. * * @param string $resolution * @param string $resolvedBuild * @access public * @return void */ public function batchResolve(string $resolution, string $resolvedBuild = '') { if($this->post->bugIdList) { /* 准备 bug 解决 需要的数据。 */ /* Prepare resolve data. */ $bugIdList = array_unique($this->post->bugIdList); $bugs = $this->bug->getByIdList($bugIdList); list($modules, $productQD) = $this->bugZen->getBatchResolveVars($bugs); $users = $this->loadModel('user')->getPairs(); $now = helper::now(); $skipBugList = array(); foreach($bugIdList as $bugID) { /* 只有激活的bug或者解决方案不为已解决的bug可以解决。 */ /* Only active bugs or bugs whose resolution is not fixed can be resolve. */ $oldBug = $bugs[$bugID]; if($oldBug->resolution == 'fixed' || $oldBug->status != 'active') { $skipBugList[] = '#' . $bugID; continue; } /* 获取 bug 的指派给人员。 */ /* Get bug assignedTo. */ $assignedTo = $oldBug->openedBy; if(!isset($users[$assignedTo])) { $assignedTo = ''; $module = isset($modules[$oldBug->module]) ? $modules[$oldBug->module] : ''; while($module) { if($module->owner and isset($users[$module->owner])) { $assignedTo = $module->owner; break; } $module = isset($modules[$module->parent]) ? $modules[$module->parent] : ''; } if(empty($assignedTo)) $assignedTo = $productQD; } /* 构建 bug。 */ /* Build bug. */ $bug = new stdClass(); $bug->id = (int)$bugID; $bug->resolution = $resolution; $bug->resolvedBuild = $resolution == 'fixed' ? $resolvedBuild : ''; $bug->resolvedBy = $this->app->user->account; $bug->resolvedDate = $now; $bug->status = 'resolved'; $bug->confirmed = 1; $bug->assignedTo = $assignedTo; $bug->assignedDate = $now; $this->bug->resolve($bug); $message = $this->executeHooks($bug->id); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); } /* 返回批量解决 bugs 后的响应。 */ /* Return response after batch resolving bugs. */ if(!empty($skipBugList)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->bug->notice->skipNotActive, implode(', ', $skipBugList)), 'load' => true)); if(empty($message)) $message = $this->lang->saveSuccess; return $this->send(array('result' => 'success', 'message' => $message, 'load' => true)); } /** * 批量关闭BUG。 * Batch close bugs. * * @param int $releaseID * @param string $viewType * @access public * @return void */ public function batchClose(int $releaseID = 0, string $viewType = '') { /* 关闭解决的 bugs。 */ /* Close resolved bugs. */ $bugIdList = $releaseID ? $this->post->unlinkBugs : $this->post->bugIdList; $skipBugs = array(); if($bugIdList) { $bugIdList = array_unique($bugIdList); $bugs = $this->bug->getByIdList($bugIdList); $bug = form::data($this->config->bug->form->close)->get(); foreach($bugIdList as $bugID) { $oldBug = $bugs[$bugID]; if($oldBug->status == 'resolved') { $bug->id = (int)$bugID; $this->bug->close($bug); } elseif($oldBug->status != 'closed') { $skipBugs[$bugID] = $bugID; } } $this->loadModel('score')->create('ajax', 'batchOther'); } /* 返回批量关闭 bugs 后的响应。 */ /* Return response after batch closing bugs. */ $load = true; if($skipBugs) $load = array('confirm' => sprintf($this->lang->bug->notice->skipClose, implode(',', $skipBugs)), 'confirmed' => true, 'canceled' => true); if($viewType) $load = $this->createLink($viewType, 'view', "releaseID=$releaseID&type=bug"); return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $load, 'closeModal' => true)); } /** * 批量激活bug。 * Batch activate bugs. * * @param int $productID * @param string $branch * @access public * @return void */ public function batchActivate(int $productID, string $branch = '0') { if($this->post->id) { /* 获取原有 bug 信息。 */ /* Get old bugs. */ $oldBugs = $this->bug->getByIdList($this->post->id); /* 激活状态是解决或关闭的 bugs。 */ /* Activate bugs whose status is resolved or closed. */ $activateBugs = form::batchData($this->config->bug->form->batchActivate)->get(); foreach($activateBugs as $bugID => $bug) { if($bug->status != 'resolved' && $bug->status != 'closed') continue; $oldBug = $oldBugs[$bugID]; $bug->status = 'active'; $bug->activatedCount = $oldBug->activatedCount + 1; $this->bug->activate($bug); $message = $this->executeHooks($bug->id); } if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('score')->create('ajax', 'batchOther'); /* 返回批量激活 bugs 后的响应。 */ /* Return response after batch activating bugs. */ if(empty($message)) $message = $this->lang->saveSuccess; return $this->send(array('result' => 'success', 'message' => $message, 'load' => $this->session->bugList)); } /* 如果没有要激活的bugs,跳转到上一个界面。 */ /* If there are no bugs to activate, locate to the previous interface. */ if(!$this->post->bugIdList) { $url = !empty($this->session->bugList) ? $this->session->bugList : $this->createLink('qa', 'index'); $this->locate($url); } $this->qa->setMenu($productID, $branch); /* 展示关联的变量。 */ /* Show the variables associated. */ $bugIdList = array_unique($this->post->bugIdList); $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->bug->batchActivate; $this->view->bugs = $this->bug->getByIdList($bugIdList); $this->view->users = $this->user->getPairs('noclosed'); $this->view->builds = $this->loadModel('build')->getBuildPairs(array($productID), $branch, 'noempty,noreleased,nofail'); $this->view->productID = $productID; $this->display(); } /** * 确认 bug 关联的需求变更。 * Confirm story change. * * @param int $bugID * @access public * @return void */ public function confirmStoryChange(int $bugID) { /* 获取更新前的 bug,并且检查所属执行的权限。*/ /* Get old bug and check privilege of the execution. */ $oldBug = $this->bug->getById($bugID); $this->bugZen->checkBugExecutionPriv($oldBug); /* 更新 bug 的需求版本。 */ /* Update the version of the story. */ $bug = new stdclass(); $bug->id = $bugID; $bug->storyVersion = $oldBug->latestStoryVersion; $this->bug->update($bug); $this->loadModel('action')->create('bug', $bugID, 'confirmed', '', $oldBug->latestStoryVersion); $message = $this->executeHooks($bugID); /* 返回确认 bug 需求变更后的响应。 */ /* Return response after confirming the version change of the story in the bug. */ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); if(empty($message)) $message = $this->lang->saveSuccess; return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('view', "bugID={$bugID}"))); } /** * AJAX: 获取指派给指定用户的BUG。 * AJAX: get bugs of a user in html select. * * @param int $userID * @param string $id the id of the select control. * @param int $appendID * @access public * @return string */ public function ajaxGetUserBugs(int $userID = 0, string $id = '' , int $appendID = 0) { /* 如果user id是0,把它设置为当前用户的id。 */ /* If user id is zero, set it to current user id. */ if($userID == 0) $userID = $this->app->user->id; /* 获取指派给user id的bug。 */ /* Get bugs of user id. */ $user = $this->loadModel('user')->getById($userID, 'id'); $account = $user->account; $bugs = $this->bug->getUserBugPairs($account, true, 0, array(), array(), $appendID); $items = array(); foreach($bugs as $bugID => $bugTitle) { if(empty($bugID)) continue; $items[] = array('text' => $bugTitle, 'value' => $bugID); } $fieldName = $id ? "bugs[$id]" : 'bug'; return print(json_encode(array('name' => $fieldName, 'items' => $items))); } /** * AJAX:获取 bug 模块的负责人。 * AJAX: Get bug owner of a module. * * @param int $moduleID * @param int $productID * @access public * @return int */ public function ajaxGetModuleOwner(int $moduleID, int $productID = 0) { /* 获取bug模块负责人。 */ /* Get module owner. */ list($account, $realname) = $this->bug->getModuleOwner($moduleID, $productID); return print(json_encode(array('account' => $account, 'realname' => $realname))); } /** * Ajax 方式加载指派给表单。 * AJAX: get team members of the executions as assignedTo list. * * @param int $executionID * @access public * @return string */ public function ajaxLoadAssignedTo(int $executionID) { /* 获取执行团队成员,并将它转为picker组件需要的数据。 */ /* Get execution team members, and convert it to picker items. */ $members = $this->user->getTeamMemberPairs($executionID, 'execution'); $items = array(); foreach($members as $account => $member) { if($account) $items[] = array('text' => $member, 'value' => $account); } return print(json_encode($items)); } /** * Ajax 方式加载所有的用户。 * AJAX: get all users as assignedTo list. * * @param string $params noletter|noempty|nodeleted|noclosed|withguest|pofirst|devfirst|qafirst|pmfirst|realname|outside|inside|all, can be sets of theme * @access public * @return array */ public function ajaxLoadAllUsers(string $params = 'devfirst|noclosed') { /* 获取所有用户,并将它转为picker组件需要的数据。 */ /* Get all users, and convert it to picker items. */ $allUsers = $this->loadModel('user')->getPairs($params); $userList = array(); foreach($allUsers as $account => $user) $userList[] = array('text' => $user, 'value' => $account, 'key' => $user . $account); return print(json_encode($userList)); } /** * Ajax 方式获取产品下拉菜单。 * Drop menu page. * * @param int $productID * @param string $module * @param string $method * @param string $extra * @access public * @return void */ public function ajaxGetDropMenu(int $productID, string $module, string $method, string $extra = '') { /* 如果extra不为空,通过extra获取产品。 */ /* IF extra is not empty, get products by extra. */ $products = array(); if(!empty($extra)) $products = $this->product->getProducts($extra, 'all', 'program desc, line desc, '); /* 如果当前系统模式是全生命周期管理模式,设置项目集和产品线信息。 */ /* If system mode is ALM, show programs and product lines. */ if($this->config->systemMode == 'ALM') { $this->view->programs = $this->loadModel('program')->getPairs(true); $this->view->lines = $this->product->getLinePairs(); } /* 设置要展示的相关变量。 */ /* Show the variables associated. */ $this->view->productID = $productID; $this->view->module = $module; $this->view->method = $method; $this->view->extra = $extra; $this->view->products = $products; $this->view->projectID = $this->session->project; $this->view->link = $this->product->getProductLink($module, $method, $extra); $this->display(); } /** * AJAX: 获取产品的团队成员。 * Ajax get product members. * * @param int $productID * @param string $selectedUser * @param int $branchID * @access public * @return string */ public function ajaxGetProductMembers(int $productID, string $selectedUser = '', string $branchID = '0') { /* 获取产品的成员。如果产品团队成员为空,返回未关闭的用户。 */ /* Get product members. If product members is empty, get noclosed users. */ $productMembers = $this->bug->getProductMemberPairs($productID, $branchID); $productMembers = array_filter($productMembers); if(empty($productMembers)) $productMembers = $this->loadModel('user')->getPairs('devfirst|noclosed'); $items = array(); foreach($productMembers as $account => $member) { if($account) $items[] = array('text' => $member, 'value' => $account); } return print(json_encode($items)); } /** * AJAX: 获产品的 bugs。 * AJAX: Get product bugs. * * @param int $productID * @param int $bugID * @param string $type * @access public * @return int */ public function ajaxGetProductBugs(int $productID, int $bugID, string $search = '', string $type = 'html') { /* 获取除了这个 bugID 的产品 bugs。 */ /* Get product bugs exclude this bugID. */ $limit = $this->get->limit ? $this->get->limit : $this->config->maxCount; $productBugs = $this->bug->getProductBugPairs($productID, '', $search, $limit, $productID ? 'single' : 'all'); unset($productBugs[$bugID]); if($type == 'json') return print(helper::jsonEncode($productBugs)); $bugList = array(); foreach($productBugs as $bugID => $bugName) $bugList[] = array('value' => $bugID, 'text' => $bugName); return $this->send($bugList); } /** * ajax方式获取项目团队成员。 * Ajax get project team members. * * @param int $projectID * @access public * @return string */ public function ajaxGetProjectTeamMembers(int $projectID) { /* 获取项目团队成员。 */ /* Get project team members. */ $teamMembers = empty($projectID) ? array() : $this->loadModel('project')->getTeamMemberPairs($projectID); $items = array(); foreach($teamMembers as $account => $member) { if($account) { $userName = ucfirst(mb_substr($account, 0, 1)) . ':' . ($member ? $member : $account); $items[] = array('text' => $userName, 'value' => $account); } } return print(json_encode($items)); } /** * ajax方式获取执行类别。 * Ajax get execution lang. * * @param int $projectID * @access public * @return string */ public function ajaxGetExecutionLang(int $projectID) { /* 获取项目信息,返回执行的语言项。 */ /* Get project information and then return language item of the execution. */ $project = $this->loadModel('project')->getByID($projectID); return $project->model == 'kanban' ? print($this->lang->bug->kanban) : print($this->lang->bug->execution); } /** * Ajax 方式获取已发布的版本。 * Ajax get released builds. * * @param int $productID * @param int|string $branch * @access public * @return string */ public function ajaxGetReleasedBuilds(int $productID, int|string $branch = 'all') { /* 获取已发布的版本。 */ /* Get released builds. */ $releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch); return print(helper::jsonEncode($releasedBuilds)); } /** * Ajax 方式获取 bug 所在产品的用例。 * Ajax get relation cases. * * @param int $productID * @param int $branchID * @access public * @return string */ public function ajaxGetProductCases(int $productID, int $branchID = 0) { $items = array(); $cases = $this->loadModel('testcase')->getPairsByProduct($productID, array(0, $branchID)); foreach($cases as $caseID => $caseTitle) { if(empty($caseID)) continue; $items[] = array('text' => $caseTitle, 'value' => $caseID); } return print(helper::jsonEncode($items)); } /** * 创建代码分支。 * Create repo branch. * * @param int $bugID * @param int $repoID * @access public * @return void */ public function createBranch(int $bugID, int $repoID = 0) { return print($this->fetch('repo', 'createBranch', array('objectID' => $bugID, 'repoID' => $repoID))); } /** * 取消代码分支的关联。 * Unlink code branch. * * @access public * @return void */ public function unlinkBranch() { return print($this->fetch('repo', 'unlinkBranch')); } /** * 获取项目信息。 * * @param int $projectID * @access public * @return void */ public function ajaxGetProjectInfo(int $projectID) { $project = $this->loadModel('project')->fetchByID($projectID); return print(json_encode($project)); } /** * 获取项目型项目关联产品的ID。 * Get product id by project. * * @param int $projectID * @access public * @return void */ public function ajaxGetProductIDByProject(int $projectID) { $productID = $this->loadModel('product')->getProductIDByProject($projectID); return print($productID); } /** * 获取关联产品的项目下拉数据。 * AJAX: get projects of a product in html select. * * @param int $productID * @param string $branch ''|'all'|int * @param int $projectID * @param string $pageType old * @access public * @return void */ public function ajaxGetProjects(int $productID, string $branch = '', int $projectID = 0, string $pageType = '') { $product = $this->loadModel('product')->fetchByID($productID); $projectPairs = $product->shadow ? $this->loadModel('project')->getPairs(false, 'noproduct,noclosed,haspriv') : array(); $projects = $this->product->getProjectPairsByProduct($productID, $branch, array_keys($projectPairs)); if($this->app->getViewType() == 'json') return print(json_encode($projects)); if($pageType == 'old') return print(html::select('project', array(0 => '') + $projects, $projectID, "class='form-control' onchange='loadProductExecutions({$productID}, this.value)'")); $items = array(); foreach($projects as $projectID => $projectName) $items[] = array('text' => $projectName, 'value' => $projectID, 'keys' => $projectName); return print(json_encode($items)); } /** * AJAX: 获重复Bug。 * AJAX: Get duplicate bugs. * * @param int $bugID * @param int $duplicateBug * @access public * @return void */ public function ajaxGetDuplicateBugs(int $bugID, int $duplicateBug = 0) { /* 获取除了这个 bugID 的重复Bug。 */ /* Get duplicate bugs exclude this bugID. */ $limit = $this->get->limit ? $this->get->limit : $this->config->maxCount; $productBugs = $this->bug->getProductBugPairs(0, '', '', $limit, 'all'); unset($productBugs[$bugID]); /* 如果选中的重复Bug不在列表中,加入列表。*/ if($duplicateBug && empty($productBugs[$duplicateBug])) { $duplicateBugInfo = $this->bug->fetchByID($duplicateBug); $productBugs[$duplicateBug] = $this->lang->productCommon . '#' . $duplicateBugInfo->product . '@'. $duplicateBugInfo->id . ':' . $duplicateBugInfo->title; } $bugItems = array(); foreach($productBugs as $bugID => $bugName) $bugItems[] = array('value' => $bugID, 'text' => $bugName); return print(json_encode($bugItems)); } }