session->repoID); */ if($this->app->getMethodName() != 'browse') $this->loadModel('ci')->setMenu(); } /** * Browse mr. * * @param int $repoID * @param string $mode * @param string $param * @param int $objectID * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function browse($repoID = 0, $mode = 'status', $param = 'opened', $objectID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) { $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); $repoCount = $this->dao->select('*')->from(TABLE_REPO)->where('deleted')->eq('0') ->andWhere('SCM')->in(array('Gitlab', 'Gitea', 'Gogs')) ->andWhere('synced')->eq(1) ->orderBy('id') ->count(); if($repoCount == 0) $this->locate($this->loadModel('repo')->createLink('create')); $repoID = $this->loadModel('repo')->saveState($repoID, $objectID); $repo = $this->repo->getRepoByID($repoID); if(!in_array(strtolower($repo->SCM), $this->config->mr->gitServiceList)) { $repoID = $this->dao->select('id')->from(TABLE_REPO)->where('deleted')->eq('0')->andWhere('SCM')->in(array('Gitlab', 'Gitea', 'Gogs'))->andWhere('synced')->eq(1)->orderBy('id')->fetch('id'); $repo = $this->repo->getRepoByID($repoID); } $this->loadModel('ci')->setMenu($repo->id); $filterProjects = empty($repo->serviceProject) ? array() : array($repo->serviceHost => array($repo->serviceProject => $repo->serviceProject)); $MRList = $this->mr->getList($mode, $param, $orderBy, $pager, $filterProjects, $repoID); if($repo->SCM == 'Gitlab') { $projectIds = array(); foreach($MRList as $MR) { $projectIds[$MR->sourceProject] = $MR->sourceProject; $projectIds[$MR->targetProject] = $MR->targetProject; } $projects = $this->mr->getGitlabProjects($repo->serviceHost, $projectIds); } else { $projects = $this->mr->getAllProjects($repoID, $repo->SCM); } /* Save current URI to session. */ $this->session->set('mrList', $this->app->getURI(true), 'repo'); /* Sync GitLab MR to ZenTao Database. */ $MRList = $this->mr->batchSyncMR($MRList, $repo->SCM); /* Check whether Mr is linked with the product. */ foreach($MRList as $MR) { $product = $this->mr->getMRProduct($MR); $MR->linkButton = empty($product) ? false : true; $MR->createdDate = date('m-d H:i', strtotime($MR->createdDate)); } /* Load lang from compile module */ $this->app->loadLang('compile'); $openIDList = array(); if(!$this->app->user->admin) { if($repo->SCM == 'Gitlab') { $openIDList = $this->loadModel('gitlab')->getGitLabListByAccount($this->app->user->account); } elseif($repo->SCM == 'Gitea') { $openIDList = $this->loadModel('gitea')->getGiteaListByAccount($this->app->user->account); } elseif($repo->SCM == 'Gogs') { $openIDList = $this->loadModel('gogs')->getGogsListByAccount($this->app->user->account); } } $this->view->title = $this->lang->mr->common . $this->lang->colon . $this->lang->mr->browse; $this->view->MRList = $MRList; $this->view->projects = $projects; $this->view->pager = $pager; $this->view->mode = $mode; $this->view->param = $param; $this->view->repoID = $repoID; $this->view->objectID = $objectID; $this->view->repo = $repo; $this->view->orderBy = $orderBy; $this->view->openIDList = $openIDList; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->display(); } /** * Create MR function. * * @access public * @return void */ public function create() { if($_POST) { $result = $this->mr->create(); return $this->send($result); } $repoID = $this->loadModel('repo')->saveState(0); $repo = $this->repo->getRepoByID($repoID); $this->loadModel('gitlab'); $this->loadModel('gitea'); $this->loadModel('gogs'); if($repo->SCM == 'Gitea') { $project = $this->gitea->apiGetSingleProject($repo->gitService, $repo->project); if(empty($project) or !$project->allow_merge_commits) $repo = array(); } $hosts = $this->loadModel('pipeline')->getList(array('gitea', 'gitlab', 'gogs')); if(!$this->app->user->admin) { $gitlabUsers = $this->gitlab->getGitLabListByAccount(); $giteaUsers = $this->gitea->getGiteaListByAccount(); $gogsUsers = $this->gogs->getGogsListByAccount(); foreach($hosts as $hostID => $host) { if($host->type == 'gitlab' and isset($gitlabUsers[$hostID])) continue; if($host->type == 'gitea' and isset($giteaUsers[$hostID])) continue; if($host->type == 'gogs' and isset($gogsUsers[$hostID])) continue; unset($hosts[$hostID]); } } $hostPairs = array(); foreach($hosts as $host) $hostPairs[$host->id] = '[' . ucfirst($host->type) . "] {$host->name}"; $this->app->loadLang('repo'); /* Import lang in repo module. */ $this->app->loadLang('compile'); $this->view->title = $this->lang->mr->create; $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); $this->view->jobList = $this->loadModel('job')->getList(); $this->view->hostPairs = $hostPairs; $this->view->hosts = $hosts; $this->view->repo = $repo; $this->display(); } /** * Edit MR function. * * @access public * @return void */ public function edit($MRID) { if($_POST) { $result = $this->mr->update($MRID); return $this->send($result); } $MR = $this->mr->getByID($MRID); if(isset($MR->hostID)) $rawMR = $this->mr->apiGetSingleMR($MR->hostID, $MR->targetProject, $MR->mriid); $this->view->title = $this->lang->mr->edit; $this->view->MR = $MR; $this->view->rawMR = isset($rawMR) ? $rawMR : false; if(!isset($rawMR->id) or (isset($rawMR->message) and $rawMR->message == '404 Not found') or empty($rawMR)) return $this->display(); $host = $this->loadModel('pipeline')->getByID($MR->hostID); $scm = $host->type; $branchList = $this->loadModel($scm)->getBranches($MR->hostID, $MR->targetProject); $MR->canDeleteBranch = true; $branchPrivs = $this->loadModel($scm)->apiGetBranchPrivs($MR->hostID, $MR->sourceProject); foreach($branchPrivs as $priv) { if($MR->canDeleteBranch and $priv->name == $MR->sourceBranch) $MR->canDeleteBranch = false; } $targetBranchList = array(); foreach($branchList as $branch) $targetBranchList[$branch] = $branch; /* Fetch user list both in Zentao and current GitLab project. */ $bindedUsers = $this->$scm->getUserIdRealnamePairs($MR->hostID); $gitUsers = $this->$scm->getUserAccountIdPairs($MR->hostID); /* Check permissions. */ if(!$this->app->user->admin and $scm == 'gitlab') { $groupIDList = array(0 => 0); $groups = $this->$scm->apiGetGroups($MR->hostID, 'name_asc', 'developer'); foreach($groups as $group) $groupIDList[] = $group->id; $sourceProject = $this->$scm->apiGetSingleProject($MR->hostID, $MR->sourceProject); $isDeveloper = $this->$scm->checkUserAccess($MR->hostID, 0, $sourceProject, $groupIDList, 'developer'); if(!isset($gitUsers[$this->app->user->account]) or !$isDeveloper) return print(js::alert($this->lang->mr->errorLang[3]) . js::locate($this->createLink('mr', 'browse'))); } /* Import lang for required modules. */ $this->loadModel('repo'); $this->loadModel('job'); $this->loadModel('compile'); $repoList = array(); $rawRepoList = $this->repo->getRepoListByClient($MR->hostID, $MR->sourceProject); foreach($rawRepoList as $rawRepo) $repoList[$rawRepo->id] = "[$rawRepo->id] $rawRepo->name"; $jobList = array(); if($MR->repoID) { $rawJobList = $this->job->getListByRepoID($MR->repoID); foreach($rawJobList as $rawJob) $jobList[$rawJob->id] = "[$rawJob->id] $rawJob->name"; } $this->view->repoList = $repoList; $this->view->jobList = !empty($MR->repoID) ? $jobList : array(); $this->view->title = $this->lang->mr->edit; $this->view->MR = $MR; $this->view->host = $host; $this->view->targetBranchList = $targetBranchList; $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); $this->view->assignee = $MR->assignee; $this->view->reviewer = zget($gitUsers, $MR->reviewer, ''); $this->display(); } /** * Delete a MR. * * @param int $MRID * @access public * @return void */ public function delete($MRID, $confirm = 'no') { if($confirm != 'yes') return print(js::confirm($this->lang->mr->confirmDelete, inlink('delete', "MRID=$MRID&confirm=yes"))); $MR = $this->mr->getByID($MRID); if($MR->synced) { $res = $this->mr->apiDeleteMR($MR->hostID, $MR->targetProject, $MR->mriid); if(isset($res->message)) return print(js::alert($this->mr->convertApiError($res->message))); } $this->dao->delete()->from(TABLE_MR)->where('id')->eq($MRID)->exec(); $this->loadModel('action')->create('mr', $MRID, 'deleted', '', $MR->title); $this->mr->createMRLinkedAction($MRID, 'removemr'); echo js::locate(inlink('browse'), 'parent'); } /** * View a MR. * * @param int $MRID * @access public * @return void */ public function view($MRID) { $MR = $this->mr->getByID($MRID); if(!$MR) return print(js::error($this->lang->notFound) . js::locate($this->createLink('mr', 'browse'))); if(isset($MR->hostID)) $rawMR = $this->mr->apiGetSingleMR($MR->hostID, $MR->targetProject, $MR->mriid); if($MR->synced and (!isset($rawMR->id) or (isset($rawMR->message) and $rawMR->message == '404 Not found') or empty($rawMR))) return $this->display(); $host = $this->loadModel('pipeline')->getByID($MR->hostID); $scm = $host->type; $this->loadModel($scm); $this->loadModel('job'); /* Sync MR from GitLab to ZentaoPMS. */ $MR = $this->mr->apiSyncMR($MR); $sourceProject = $this->$scm->apiGetSingleProject($MR->hostID, $MR->sourceProject); $targetProject = $this->$scm->apiGetSingleProject($MR->hostID, $MR->targetProject); $sourceBranch = $this->$scm->apiGetSingleBranch($MR->hostID, $MR->sourceProject, $MR->sourceBranch); $targetBranch = $this->$scm->apiGetSingleBranch($MR->hostID, $MR->targetProject, $MR->targetBranch); $projectOwner = true; if(isset($MR->hostID) and !$this->app->user->admin) { $openID = $this->$scm->getUserIDByZentaoAccount($MR->hostID, $this->app->user->account); if(!$projectOwner and isset($sourceProject->owner->id) and $sourceProject->owner->id == $openID) $projectOwner = true; } $this->view->sourceProjectName = $sourceProject->name_with_namespace; $this->view->targetProjectName = $targetProject->name_with_namespace; $this->view->sourceProjectURL = isset($sourceBranch->web_url) ? $sourceBranch->web_url : ''; $this->view->targetProjectURL = isset($targetBranch->web_url) ? $targetBranch->web_url : ''; /* Those variables are used to render $lang->mr->commandDocument. */ $this->view->httpRepoURL = $sourceProject->http_url_to_repo; $this->view->branchPath = $sourceProject->path_with_namespace . '-' . $MR->sourceBranch; /* Get mr linked list. */ $this->app->loadLang('productplan'); $product = $this->mr->getMRProduct($MR); $this->view->compile = $this->loadModel('compile')->getById($MR->compileID); $this->view->compileJob = $MR->jobID ? $this->job->getById($MR->jobID) : false; $this->view->projectOwner = $projectOwner; $this->view->title = $this->lang->mr->view; $this->view->MR = $MR; $this->view->rawMR = isset($rawMR) ? $rawMR : false; $this->view->product = $product; $this->view->stories = $this->mr->getLinkList($MR->id, $product->id, 'story'); $this->view->bugs = $this->mr->getLinkList($MR->id, $product->id, 'bug'); $this->view->tasks = $this->mr->getLinkList($MR->id, $product->id, 'task'); $this->view->actions = $this->loadModel('action')->getList('mr', $MRID); $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); $this->display(); } /** * Crontab sync MR from GitLab API to Zentao database, default time 5 minutes to execute once. * * @access public * @return void */ public function syncMR() { $MRList = $this->mr->getList(); $this->mr->batchSyncMR($MRList); if(dao::isError()) { echo json_encode(dao::getError()); return true; } echo 'success'; } /** * Accept a MR. * * @param int $MRID * @access public * @return void */ public function accept($MRID) { $MR = $this->mr->getByID($MRID); /* Judge that if this MR can be accepted. */ if(isset($MR->needCI) and $MR->needCI == '1') { $compileStatus = empty($MR->compileID) ? 'fail' : $this->loadModel('compile')->getByID($MR->compileID)->status; if(isset($compileStatus) and $compileStatus != 'success') { return $this->send(array('result' => 'fail', 'message' => $this->lang->mr->needCI, 'locate' => helper::createLink('mr', 'view', "mr={$MRID}"))); } } if(isset($MR->needApproved) and $MR->needApproved == '1') { if($MR->approvalStatus != 'approved') { return $this->send(array('result' => 'fail', 'message' => $this->lang->mr->needApproved, 'locate' => helper::createLink('mr', 'view', "mr={$MRID}"))); } } if(isset($MR->hostID)) $rawMR = $this->mr->apiAcceptMR($MR); if(isset($rawMR->state) and $rawMR->state == 'merged') { $this->mr->logMergedAction($MR); return $this->send(array('result' => 'success', 'message' => $this->lang->mr->mergeSuccess, 'locate' => helper::createLink('mr', 'browse'))); } /* The type of variable `$rawMR->message` is string. This is different with apiCreateMR. */ if(isset($rawMR->message)) { $errorMessage = $this->mr->convertApiError($rawMR->message); return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->mr->apiError->sudo, $errorMessage), 'locate' => helper::createLink('mr', 'view', "mr={$MRID}"))); } return $this->send(array('result' => 'fail', 'message' => $this->lang->mr->mergeFailed, 'locate' => helper::createLink('mr', 'view', "mr={$MRID}"))); } /** * View diff between MR source and target branches. * * @param int $MRID * @access public * @return void */ public function diff($MRID, $encoding = '') { $this->app->loadLang('productplan'); $this->app->loadLang('bug'); $this->app->loadLang('task'); $encoding = empty($encoding) ? 'utf-8' : $encoding; $encoding = strtolower(str_replace('_', '-', $encoding)); /* Revert $config->requestFix in $encoding. */ $MR = $this->mr->getByID($MRID); $this->view->title = $this->lang->mr->viewDiff; $this->view->MR = $MR; $rawMR = null; if($MR->synced) { $rawMR = $this->mr->apiGetSingleMR($MR->hostID, $MR->targetProject, $MR->mriid); if(!isset($rawMR->id) or (isset($rawMR->message) and $rawMR->message == '404 Not found') or empty($rawMR)) return $this->display(); } $this->view->rawMR = $rawMR; $diffs = $this->mr->getDiffs($MR, $encoding); $arrange = $this->cookie->arrange ? $this->cookie->arrange : 'inline'; if($this->server->request_method == 'POST') { if($this->post->arrange) { $arrange = $this->post->arrange; setcookie('arrange', $arrange); } if($this->post->encoding) $encoding = $this->post->encoding; } if($arrange == 'appose') { foreach($diffs as $diffFile) { if(empty($diffFile->contents)) continue; foreach($diffFile->contents as $content) { $old = array(); $new = array(); foreach($content->lines as $line) { if($line->type != 'new') $old[$line->oldlc] = $line->line; if($line->type != 'old') $new[$line->newlc] = $line->line; } $content->old = $old; $content->new = $new; } } } $this->view->repo = $this->loadModel('repo')->getRepoByID($MR->repoID); $this->view->repoID = $MR->repoID; $this->view->diffs = $diffs; $this->view->encoding = $encoding; $this->view->arrange = $arrange; $this->view->sourceBranch = $MR->sourceBranch; $this->view->targetBranch = $MR->targetBranch; $this->view->oldRevision = $MR->targetBranch; $this->view->newRevision = $MR->sourceBranch; $this->display(); } /** * Approval for this MR. * * @param int $MRID * @param string $action * @return void */ public function approval($MRID, $action = 'approve') { $MR = $this->mr->getByID($MRID); if($_POST) { $comment = $this->post->comment; $result = $this->mr->approve($MR, $action, $comment); return $this->send($result); } $showCompileResult = false; if(!empty($MR->compileStatus)) { $showCompileResult = true; $this->app->loadLang('compile'); /* Import lang. */ $this->view->compileUrl = $this->createLink('job', 'view', "jobID={$MR->jobID}&compileID={$MR->compileID}"); } $this->view->showCompileResult = $showCompileResult; $this->view->MR = $MR; $this->view->action = $action; $this->view->actions = $this->loadModel('action')->getList('mr', $MRID); $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); $this->display(); } /** * Close this MR. * * @param int $MRID * @return void */ public function close($MRID) { $MR = $this->mr->getByID($MRID); $result = $this->mr->close($MR); return $this->send($result); } /** * Reopen this MR. * * @param int $MRID * @return void */ public function reopen($MRID) { $MR = $this->mr->getByID($MRID); return $this->send($this->mr->reopen($MR)); } /** * link MR list. * * @param int $MRID * @param string $type * @param string $orderBy * @param string $link * @param string $param * @param int $recTotal * @param int $recPerPage * @param int $pageID * @return void */ public function link($MRID, $type = 'story', $orderBy = 'id_desc', $link = 'false', $param = '', $recTotal = 0, $recPerPage = 100, $pageID = 1) { $this->app->loadLang('productplan'); $this->app->loadLang('bug'); $this->app->loadLang('task'); $MR = $this->mr->getByID($MRID); $product = $this->mr->getMRProduct($MR); /* Load pager. */ $this->app->loadClass('pager', $static = true); $storyPager = new pager(0, $recPerPage, $type == 'story' ? $pageID : 1); $bugPager = new pager(0, $recPerPage, $type == 'bug' ? $pageID : 1); $taskPager = new pager(0, $recPerPage, $type == 'task' ? $pageID : 1); $stories = $this->mr->getLinkList($MRID, $product->id, 'story', $type == 'story' ? $orderBy : '', $storyPager); $bugs = $this->mr->getLinkList($MRID, $product->id, 'bug', $type == 'bug' ? $orderBy : '', $bugPager); $tasks = $this->mr->getLinkList($MRID, $product->id, 'task', $type == 'task' ? $orderBy : '', $taskPager); $this->view->title = $this->lang->mr->common . $this->lang->colon . $this->lang->mr->link; $this->view->MR = $MR; $this->view->canBeChanged = true; $this->view->modulePairs = $this->loadModel('tree')->getOptionMenu($product->id, 'story'); $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->stories = $stories; $this->view->bugs = $bugs; $this->view->tasks = $tasks; $this->view->product = $product; $this->view->storyPager = $storyPager; $this->view->bugPager = $bugPager; $this->view->taskPager = $taskPager; $this->view->type = $type; $this->view->orderBy = $orderBy; $this->view->link = $link; $this->view->param = $param; $this->display(); } /** * Link story to mr. * * @param int $MRID * @param int $productID * @param string $browseType * @param int $param * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function linkStory($MRID, $productID = 0, $browseType = '', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1) { if(!empty($_POST['stories'])) { $this->mr->link($MRID, $productID, 'story'); if(dao::isError()) return print(js::error(dao::getError())); return print(js::locate(inlink('link', "MRID=$MRID&type=story&orderBy=$orderBy"), 'parent')); } $this->loadModel('story'); $this->app->loadLang('productplan'); $product = $this->loadModel('product')->getById($productID); $modules = $this->loadModel('tree')->getOptionMenu($productID, 'story'); /* Load pager. */ $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); /* Build search form. */ $storyStatusList = $this->lang->story->statusList; unset($storyStatusList['closed']); $queryID = ($browseType == 'bySearch') ? (int) $param : 0; unset($this->config->product->search['fields']['product']); $this->config->product->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=story&orderBy=$orderBy&link=true¶m=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID')); $this->config->product->search['queryID'] = $queryID; $this->config->product->search['style'] = 'simple'; $this->config->product->search['params']['product']['values'] = array($product) + array('all' => $this->lang->product->allProductsOfProject); $this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($productID => $productID)); $this->config->product->search['params']['module']['values'] = $modules; $this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $storyStatusList); if($product->type == 'normal') { unset($this->config->product->search['fields']['branch']); unset($this->config->product->search['params']['branch']); } else { $this->product->setMenu($productID, 0); $this->config->product->search['fields']['branch'] = $this->lang->product->branch; $branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty'); $this->config->product->search['params']['branch']['values'] = $branches; } $this->loadModel('search')->setSearchParams($this->config->product->search); $MR = $this->mr->getByID($MRID); $relatedStories = $this->mr->getCommitedLink($MR, 'story'); $linkedStories = $this->mr->getLinkList($MRID, $product->id, 'story'); if($browseType == 'bySearch') { $allStories = $this->story->getBySearch($productID, 0, $queryID, 'id', '', 'story', array_keys($linkedStories), $pager); } else { $allStories = $this->story->getProductStories($productID, 0, '0', 'draft,reviewing,active,changing', 'story', 'id_desc', false, array_keys($linkedStories), $pager); } $this->view->modules = $modules; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->allStories = $allStories; $this->view->relatedStories = $relatedStories; $this->view->product = $product; $this->view->MRID = $MRID; $this->view->browseType = $browseType; $this->view->param = $param; $this->view->orderBy = $orderBy; $this->view->pager = $pager; $this->display(); } /** * Link bug to mr. * * @param int $MRID * @param int $productID * @param string $browseType * @param int $param * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function linkBug($MRID, $productID = 0, $browseType = '', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1) { if(!empty($_POST['bugs'])) { $this->mr->link($MRID, $productID, 'bug'); if(dao::isError()) return print(js::error(dao::getError())); return print(js::locate(inlink('link', "MRID=$MRID&type=bug&orderBy=$orderBy"), 'parent')); } $this->loadModel('bug'); $this->app->loadLang('productplan'); $queryID = ($browseType == 'bysearch') ? (int)$param : 0; $product = $this->loadModel('product')->getById($productID); $modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'bug'); /* Load pager. */ $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); /* Build search form. */ $this->config->bug->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=bug&orderBy=$orderBy&link=true¶m=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID')); $this->config->bug->search['queryID'] = $queryID; $this->config->bug->search['style'] = 'simple'; $this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($productID => $productID)); $this->config->bug->search['params']['module']['values'] = $modules; $this->config->bug->search['params']['execution']['values'] = $this->product->getExecutionPairsByProduct($productID); $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = 'releasetag'); $this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values']; unset($this->config->bug->search['fields']['product']); if($product->type == 'normal') { unset($this->config->bug->search['fields']['branch']); unset($this->config->bug->search['params']['branch']); } else { $this->product->setMenu($productID, 0); $this->config->bug->search['fields']['branch'] = $this->lang->product->branch; $this->config->bug->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty'); } $this->loadModel('search')->setSearchParams($this->config->bug->search); $MR = $this->mr->getByID($MRID); $relatedBugs = $this->mr->getCommitedLink($MR, 'bug'); $linkedBugs = $this->mr->getLinkList($MRID, $product->id, 'bug'); if($browseType == 'bySearch') { $allBugs = $this->bug->getBySearch($productID, 0, $queryID, 'id_desc', array_keys($linkedBugs), $pager); } else { $allBugs = $this->bug->getActiveBugs($productID, 0, '0', array_keys($linkedBugs), $pager); } $this->view->modules = $modules; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->allBugs = $allBugs; $this->view->relatedBugs = $relatedBugs; $this->view->product = $product; $this->view->MRID = $MRID; $this->view->browseType = $browseType; $this->view->param = $param; $this->view->orderBy = $orderBy; $this->view->pager = $pager; $this->display(); } /** * Link task to mr. * * @param int $MRID * @param int $productID * @param string $browseType * @param int $param * @param string $orderBy * @param int $recTotal * @param int $recPerPage * @param int $pageID * @access public * @return void */ public function linkTask($MRID, $productID = 0, $browseType = 'unclosed', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1) { if(!empty($_POST['tasks'])) { $this->mr->link($MRID, $productID, 'task'); if(dao::isError()) return print(js::error(dao::getError())); return print(js::locate(inlink('link', "MRID=$MRID&type=task&orderBy=$orderBy"), 'parent')); } $this->loadModel('execution'); $this->loadModel('product'); $this->app->loadLang('task'); /* Set browse type. */ $browseType = strtolower($browseType); $queryID = ($browseType == 'bysearch') ? (int)$param : 0; $product = $this->loadModel('product')->getById($productID); $modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'task'); /* Load pager. */ $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); /* Build search form. */ $this->config->execution->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=task&orderBy=$orderBy&link=true¶m=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID')); $this->config->execution->search['queryID'] = $queryID; $this->config->execution->search['params']['module']['values'] = $modules; $this->config->execution->search['params']['execution']['values'] = $this->product->getExecutionPairsByProduct($productID); $this->loadModel('search')->setSearchParams($this->config->execution->search); $MR = $this->mr->getByID($MRID); $relatedTasks = $this->mr->getCommitedLink($MR, 'task'); $linkedTasks = $this->mr->getLinkList($MRID, $product->id, 'task'); /* Get executions by product. */ $productExecutions = $this->product->getExecutionPairsByProduct($productID); $productExecutionIDs = array_filter(array_keys($productExecutions)); $this->config->execution->search['params']['execution']['values'] = array_filter($productExecutions); /* Get tasks by executions. */ $allTasks = array(); foreach($productExecutionIDs as $productExecutionID) { $tasks = $this->execution->getTasks(0, $productExecutionID, array(), $browseType, $queryID, 0, $orderBy, null); $allTasks = array_merge($tasks, $allTasks); } /* Filter linked tasks. */ $linkedTaskIDs = array_keys($linkedTasks); foreach($allTasks as $key => $task) { if(in_array($task->id, $linkedTaskIDs)) unset($allTasks[$key]); } /* Page the records. */ $pager->setRecTotal(count($allTasks)); $pager->setPageTotal(); if($pager->pageID > $pager->pageTotal) $pager->setPageID($pager->pageTotal); $count = 1; $limitMin = ($pager->pageID - 1) * $pager->recPerPage; $limitMax = $pager->pageID * $pager->recPerPage; foreach($allTasks as $key => $task) { if($count <= $limitMin or $count > $limitMax) unset($allTasks[$key]); $count ++; } $this->view->modules = $modules; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->allTasks = $allTasks; $this->view->relatedTasks = $relatedTasks; $this->view->product = $product; $this->view->MRID = $MRID; $this->view->browseType = $browseType; $this->view->param = $param; $this->view->orderBy = $orderBy; $this->view->pager = $pager; $this->display(); } /** * UnLink an mr link. * * @param int $MRID * @param int $productID * @param string $type * @param int $linkID * @param string $confirm * @access public * @return mix */ public function unlink($MRID, $productID, $type, $linkID, $confirm = 'no') { $this->app->loadLang('productplan'); if($confirm == 'no') { return print(js::confirm($this->lang->productplan->confirmUnlinkStory, $this->createLink('mr', 'unlink', "MRID=$MRID&productID=$productID&linkID=$linkID&type=$type&confirm=yes"))); } else { $this->mr->unlink($MRID, $productID, $type, $linkID); /* if ajax request, send result. */ if($this->server->ajax) { if(dao::isError()) { $response['result'] = 'fail'; $response['message'] = dao::getError(); } else { $response['result'] = 'success'; $response['message'] = ''; } return $this->send($response); } return print(js::reload('parent')); } } /** * Add a review for this review. * * @param int $repoID * @param int $mr * @param int $v1 * @param int $v2 * @access public * @return void */ public function addReview($repoID, $mr, $v1, $v2) { /* Handle the exception that when $repoID is empty. */ if($repoID == "0") $this->send(array()); $this->loadModel('repo'); if(!empty($_POST)) { $v1 = helper::safe64Decode($v1); $v2 = helper::safe64Decode($v2); if($this->post->reviewType == 'bug') $result = $this->mr->saveBug($repoID, $mr, $v1, $v2); if($this->post->reviewType == 'task') $result = $this->mr->saveTask($repoID, $mr, $v1, $v2); if($result['result'] == 'fail') return print(json_encode($result)); $objectID = $result['id']; $repo = $this->repo->getRepoById($repoID); /* Handle the exception that when $repo is empty. */ if(empty($repo) or empty($result)) $this->send(json_encode(array())); $location = sprintf($this->lang->repo->reviewLocation, $this->post->entry ? base64_decode($this->post->entry) : '', $repo->SCM != 'Subversion' ? substr($v2, 0, 10) : $v2, $this->post->begin, $this->post->end); $link = $this->createLink('mr', 'diff', "mr=$mr") . '#L' . $this->post->begin; $actionID = $this->loadModel('action')->create($this->post->reviewType, $objectID, 'repoCreated', '', html::a($link, $location)); $this->loadModel('mail')->sendmail($objectID, $actionID); echo json_encode($result); } } /** * AJAX: Get MR target projects. * * @param int $hostID * @param int $projectID * @param string $scm * @access public * @return void */ public function ajaxGetMRTargetProjects($hostID, $projectID, $scm = 'gitlab') { $this->loadModel($scm); if($scm != 'gitlab') $projectID = urldecode(base64_decode($projectID)); /* First step: get forks. Only get first level forks(not recursively). */ $projects = $scm == 'gitlab' ? $this->$scm->apiGetForks($hostID, $projectID) : array(); /* Second step: get project itself. */ $projects[] = $this->$scm->apiGetSingleProject($hostID, $projectID); /* Last step: find its upstream recursively. */ $project = $this->$scm->apiGetUpstream($hostID, $projectID); if(!empty($project)) $projects[] = $project; if(!empty($project) and isset($project->id)) { $project = $this->$scm->apiGetUpstream($hostID, $project->id); if(!empty($project)) $projects[] = $project; } if($scm == 'gitlab') { $groupIDList = array(0 => 0); $groups = $this->$scm->apiGetGroups($hostID, 'name_asc', 'developer'); foreach($groups as $group) $groupIDList[] = $group->id; foreach($projects as $key => $project) { if($this->$scm->checkUserAccess($hostID, 0, $project, $groupIDList, 'developer') == false) unset($projects[$key]); } if(!$projects) return $this->send(array('message' => array())); } $options = ""; foreach($projects as $project) { if($scm == 'gitlab') { $options .= ""; } else { $options .= ""; } } $this->send($options); } /** * AJAX: Get repo list. * * @param int $hostID * @param int $projectID * @return void */ public function ajaxGetRepoList($hostID, $projectID) { $host = $this->loadModel('pipeline')->getByID($hostID); if($host->type != 'gitlab') $projectID = urldecode(base64_decode($projectID)); $repoList = $this->loadModel('repo')->getRepoListByClient($hostID, $projectID); if(!$repoList) return $this->send(array('message' => array())); $options = ""; foreach($repoList as $repo) $options .= ""; $this->send($options); } /** * AJAX: Get job list. * * @param int $repoID * @return void */ public function ajaxGetJobList($repoID) { $this->loadModel('job'); $jobList = $this->job->getListByRepoID($repoID); if(!$jobList) return $this->send(array('message' => array())); $options = ""; foreach($jobList as $job) $options .= ""; $this->send($options); } /** * AJAX: Get compile list. * * @param int $jobID * @return void */ public function ajaxGetCompileList($jobID) { $this->loadModel('compile'); $compileList = $this->compile->getListByJobID($jobID); if(!$compileList) return $this->send(array('message' => array())); $options = ""; foreach($compileList as $compile) $options .= ""; $this->send($options); } /** * Ajax check same opened mr for source branch. * * @param int $hostID * @access public * @return void */ public function ajaxCheckSameOpened($hostID) { $sourceProject = $this->post->sourceProject; $sourceBranch = $this->post->sourceBranch; $targetProject = $this->post->targetProject; $targetBranch = $this->post->targetBranch; $result = $this->mr->checkSameOpened($hostID, $sourceProject, $sourceBranch, $targetProject, $targetBranch); return print(json_encode($result)); } /** * Ajax get branch pivs. * * @param int $hostID * @param int|string $project * @access public * @return void */ public function ajaxGetBranchPivs($hostID, $project) { $host = $this->loadModel('pipeline')->getByID($hostID); $scm = $host->type; if(in_array($scm, array('gitea', 'gogs'))) $project = urldecode(base64_decode($project)); $branchPrivs = array(); $branches = $this->loadModel($scm)->apiGetBranchPrivs($hostID, $project); foreach($branches as $branch) $branchPrivs[$branch->name] = $branch->name; return print(json_encode($branchPrivs)); } }