diff --git a/framework/base/router.class.php b/framework/base/router.class.php index cceaba51cd..de909ac83a 100644 --- a/framework/base/router.class.php +++ b/framework/base/router.class.php @@ -734,10 +734,13 @@ class baseRouter $account = $sql->quote($account); $vision = $this->dbh->query("SELECT * FROM " . TABLE_CONFIG . " WHERE owner = $account AND `key` = 'vision' LIMIT 1")->fetch(); if($vision) $vision = $vision->value; - if(empty($vision)) + + $user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch(); + if(!empty($user->visions)) { - $user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch(); - if(!empty($user->visions)) list($vision) = explode(',', $user->visions); + $userVisions = explode(',', $user->visions); + if(!in_array($vision, $userVisions)) $vision = ''; + if(empty($vision)) list($vision) = $userVisions; } } diff --git a/lib/scm/gitrepo.class.php b/lib/scm/gitrepo.class.php index 335768ffb5..718dbd6983 100644 --- a/lib/scm/gitrepo.class.php +++ b/lib/scm/gitrepo.class.php @@ -28,7 +28,9 @@ class GitRepo if($branch) { $branches = $this->branch(); - if(isset($branches[$branch])) $branch = "origin/$branch"; + $cmd = escapeCmd("$this->client branch -r"); + execCmd($cmd . ' 2>&1', 'string', $result); + if(isset($branches[$branch]) and !empty($result)) $branch = "origin/$branch"; } $this->branch = $branch; $this->repo = $repo; diff --git a/lib/zfile/zfile.class.php b/lib/zfile/zfile.class.php index 4903d50df4..0d2db1c2e6 100644 --- a/lib/zfile/zfile.class.php +++ b/lib/zfile/zfile.class.php @@ -18,10 +18,12 @@ class zfile * @param string $to * @param bool $logLevel * @param string $logFile + * @param array $excludeFiles + * @param bool $toIsLink * @access public * @return array copied files, count, size or message. */ - public function copyDir($from, $to, $logLevel = false, $logFile = '') + public function copyDir($from, $to, $logLevel = false, $logFile = '', $excludeFiles = array(), $toIsLink = false) { static $copiedFiles = array(); static $errorFiles = array(); @@ -41,12 +43,21 @@ class zfile if(!empty($log['message'])) return $log; $from = realpath($from) . '/'; - $to = realpath($to) . '/'; + if(is_link($to) || $toIsLink) + { + $to = $to . '/'; + + $toIsLink = true; + } + else + { + $to = realpath($to) . '/'; + } $entries = scandir($from); foreach($entries as $entry) { - if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue; + if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue; $fullEntry = $from . $entry; if(is_file($fullEntry)) @@ -82,7 +93,7 @@ class zfile { $nextFrom = $fullEntry; $nextTo = $to . $entry; - $result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile); + $result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile, array(), $toIsLink); $count += $result['count']; $size += $result['size']; } @@ -101,10 +112,11 @@ class zfile * Get count. * * @param string $dir + * @param array $excludeFiles * @access public * @return int */ - public function getCount($dir) + public function getCount($dir, $excludeFiles = array()) { if(!file_exists($dir)) return 0; if(is_file($dir)) return 1; @@ -113,7 +125,7 @@ class zfile $entries = scandir($dir); foreach($entries as $entry) { - if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue; + if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue; $fullEntry = $dir . '/' . $entry; $count += $this->getCount($fullEntry); diff --git a/module/action/lang/de.php b/module/action/lang/de.php index ab78919afe..c596635e12 100644 --- a/module/action/lang/de.php +++ b/module/action/lang/de.php @@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by action->desc->ganttmove = '$date, sort by $actor .' . "\n"; $lang->action->desc->relieved = '$date, relieved by $actor .' . "\n"; $lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by '. $lang->admin->system .'.' . "\n"; -$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n"; +$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n"; /* Used to describe the history of operations related to parent-child tasks. */ $lang->action->desc->createchildren = '$date, $actor created a child task $extra。' . "\n"; diff --git a/module/action/lang/en.php b/module/action/lang/en.php index 02c301f883..dae713028d 100755 --- a/module/action/lang/en.php +++ b/module/action/lang/en.php @@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by action->desc->ganttmove = '$date, sort by $actor .' . "\n"; $lang->action->desc->relieved = '$date, relieved by $actor .' . "\n"; $lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by '. $lang->admin->system .'.' . "\n"; -$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n"; +$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n"; /* Used to describe the history of operations related to parent-child tasks. */ $lang->action->desc->createchildren = '$date, $actor created a child task $extra。' . "\n"; diff --git a/module/action/lang/fr.php b/module/action/lang/fr.php index a3d3b7dabb..f57a68bc0c 100644 --- a/module/action/lang/fr.php +++ b/module/action/lang/fr.php @@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by action->desc->ganttmove = '$date, sort by $actor .' . "\n"; $lang->action->desc->relieved = '$date, relieved by $actor .' . "\n"; $lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by '. $lang->admin->system .'.' . "\n"; -$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n"; +$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n"; /* Used to describe the history of operations related to parent-child tasks. */ $lang->action->desc->createchildren = '$date, $actor a créé un sous-tâche $extra。' . "\n"; diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index e2867a07e3..11dc8c0688 100755 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, 由 $actor $lang->action->desc->ganttmove = '$date, 由 $actor 排序。' . "\n"; $lang->action->desc->relieved = '$date, 由 $actor 解除孪生需求关系。' . "\n"; $lang->action->desc->switchtolight = '$date, 由于 '. $lang->admin->system .' 从全生命周期管理模式切换为轻量管理模式,项目访问控制由项目集内公开调整为私有。' . "\n"; -$lang->action->desc->unlinkproduct = '$date, 系统判断由于迭代所属项目与$extra取消关联,同步将迭代与$extra取消关联。' . "\n"; +$lang->action->desc->unlinkproduct = '$date, 系统判断由于' . $lang->executionCommon . '所属项目与$extra取消关联,同步将' . $lang->executionCommon . '与$extra取消关联。' . "\n"; /* 用来描述和父子任务相关的操作历史记录。*/ $lang->action->desc->createchildren = '$date, 由 $actor 创建子任务 $extra。' . "\n"; diff --git a/module/admin/lang/de.php b/module/admin/lang/de.php index fd3014cc10..47418888f7 100644 --- a/module/admin/lang/de.php +++ b/module/admin/lang/de.php @@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off'; $lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.'; $lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.'; $lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!'; +$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.'; diff --git a/module/admin/lang/en.php b/module/admin/lang/en.php index b7fcb08a16..914214cb1a 100644 --- a/module/admin/lang/en.php +++ b/module/admin/lang/en.php @@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off'; $lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.'; $lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.'; $lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!'; +$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.'; \ No newline at end of file diff --git a/module/admin/lang/fr.php b/module/admin/lang/fr.php index efe3d511e6..745c72f69b 100644 --- a/module/admin/lang/fr.php +++ b/module/admin/lang/fr.php @@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off'; $lang->admin->safe->noticeMode = "Le mot de passe sera vérifié lors de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe."; $lang->admin->safe->noticeWeakMode = "Le mot de passe sera vérifié lors de la connexion au système, de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe."; $lang->admin->safe->noticeStrong = "Le mot de passe est d'autant plus sécurisé qu'il est long, qu'il contient plus de lettres, de chiffres ou de caractères spéciaux, et que les lettres du mot de passe sont peu répétitives !"; +$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.'; diff --git a/module/admin/lang/vi.php b/module/admin/lang/vi.php index 47deb84d6b..4b6e64b021 100644 --- a/module/admin/lang/vi.php +++ b/module/admin/lang/vi.php @@ -84,3 +84,4 @@ $lang->admin->safe->loginCaptchaList[0] = 'No'; $lang->admin->safe->noticeMode = 'Mật khẩu sẽ được kiểm tra khi người dùng đăng nhập hoặc người dùng thêm hoặc sửa.'; $lang->admin->safe->noticeStrong = ''; +$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.'; \ No newline at end of file diff --git a/module/admin/lang/zh-cn.php b/module/admin/lang/zh-cn.php index c573762af5..33831b046d 100644 --- a/module/admin/lang/zh-cn.php +++ b/module/admin/lang/zh-cn.php @@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = '关闭'; $lang->admin->safe->noticeMode = '系统会在创建和修改用户、修改密码的时候检查用户口令。'; $lang->admin->safe->noticeWeakMode = '系统会在登录、创建和修改用户、修改密码的时候检查用户口令。'; $lang->admin->safe->noticeStrong = '密码长度越长,含有大写字母或数字或特殊符号越多,密码字母越不重复,安全度越强!'; +$lang->admin->safe->noticeGd = '系统检测到您的服务器未安装GD模块,无法使用验证码功能,请安装后使用。'; diff --git a/module/admin/lang/zh-tw.php b/module/admin/lang/zh-tw.php index 457818eefd..6f6c404364 100644 --- a/module/admin/lang/zh-tw.php +++ b/module/admin/lang/zh-tw.php @@ -82,5 +82,7 @@ $lang->admin->safe->modifyPasswordList[0] = '不強制'; $lang->admin->safe->loginCaptchaList[1] = '是'; $lang->admin->safe->loginCaptchaList[0] = '否'; -$lang->admin->safe->noticeMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。'; -$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!'; +$lang->admin->safe->noticeMode = '系統會在創建和修改用戶、修改密碼的時候檢查用戶口令。'; +$lang->admin->safe->noticeWeakMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。'; +$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!'; +$lang->admin->safe->noticeGd = '系統檢測到您的伺服器未安裝GD模組,無法使用驗證碼功能,請安裝後使用。'; diff --git a/module/admin/view/safe.html.php b/module/admin/view/safe.html.php index 1524656a60..716b9cbd35 100644 --- a/module/admin/view/safe.html.php +++ b/module/admin/view/safe.html.php @@ -16,6 +16,7 @@ .notice {color:#2667E3; margin-left: 12px;} admin);?> + diff --git a/module/backup/model.php b/module/backup/model.php index f6d3432609..e2346b008f 100644 --- a/module/backup/model.php +++ b/module/backup/model.php @@ -34,6 +34,7 @@ class backupModel extends model public function backFile($backupFile) { $zfile = $this->app->loadClass('zfile'); + $return = new stdclass(); $return->result = true; $return->error = ''; @@ -42,10 +43,10 @@ class backupModel extends model $tmpLogFile = $this->getTmpLogFile($backupFile); $dataDir = $this->app->getAppRoot() . 'www/data/'; - $count = $zfile->getCount($dataDir); + $count = $zfile->getCount($dataDir, array('course')); file_put_contents($tmpLogFile, json_encode(array('allCount' => $count))); - $result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile); + $result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile, array('course')); $this->processSummary($backupFile, $result['count'], $result['size'], $result['errorFiles'], $count); unlink($tmpLogFile); diff --git a/module/block/view/printassigntomeblock.html.php b/module/block/view/printassigntomeblock.html.php index 9293eb4686..fa81e17117 100644 --- a/module/block/view/printassigntomeblock.html.php +++ b/module/block/view/printassigntomeblock.html.php @@ -19,8 +19,9 @@ + $bool):?> - + > my->audit : $lang->block->availableBlocks->$type;?> @@ -36,7 +37,7 @@ > - block->availableBlocks->$type;?> + my->audit : $lang->block->availableBlocks->$type;?> '> diff --git a/module/bug/config.php b/module/bug/config.php index 7accc01d9d..1d4e336021 100644 --- a/module/bug/config.php +++ b/module/bug/config.php @@ -328,11 +328,13 @@ $config->bug->datatable->fieldList['os']['title'] = 'os'; $config->bug->datatable->fieldList['os']['fixed'] = 'no'; $config->bug->datatable->fieldList['os']['width'] = '80'; $config->bug->datatable->fieldList['os']['required'] = 'no'; +$config->bug->datatable->fieldList['os']['control'] = 'multiple'; $config->bug->datatable->fieldList['browser']['title'] = 'browser'; $config->bug->datatable->fieldList['browser']['fixed'] = 'no'; $config->bug->datatable->fieldList['browser']['width'] = '80'; $config->bug->datatable->fieldList['browser']['required'] = 'no'; +$config->bug->datatable->fieldList['browser']['control'] = 'multiple'; $config->bug->datatable->fieldList['mailto']['title'] = 'mailto'; $config->bug->datatable->fieldList['mailto']['fixed'] = 'no'; diff --git a/module/bug/control.php b/module/bug/control.php index 9fb4edfa17..438460af70 100755 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -227,7 +227,8 @@ class bug extends control $this->view->product = $product; $this->view->projectProducts = $this->product->getProducts($this->projectID); $this->view->productName = $productName; - $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'withreleased'); + $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch); + $this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch); $this->view->modules = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch); $this->view->moduleTree = $moduleTree; $this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all; @@ -558,13 +559,13 @@ class bug extends control /* If executionID is setted, get builds and stories of this execution. */ if($executionID) { - $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone', $executionID, 'execution'); + $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,noreleased', $executionID, 'execution'); $stories = $this->story->getExecutionStoryPairs($executionID); if(!$projectID) $projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project'); } else { - $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch'); + $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch,noreleased'); $stories = $this->story->getProductStoryPairs($productID, $branch, 0, 'all','id_desc', 0, 'full', 'story', false); } @@ -655,6 +656,7 @@ class bug extends control $this->view->projectExecutionPairs = $this->loadModel('project')->getProjectExecutionPairs(); $this->view->executions = defined('TUTORIAL') ? $this->loadModel('tutorial')->getExecutionPairs() : $executions; $this->view->builds = $builds; + $this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch); $this->view->moduleID = (int)$moduleID; $this->view->projectID = $projectID; $this->view->projectModel = $projectModel; @@ -765,7 +767,7 @@ class bug extends control /* If executionID is setted, get builds and stories of this execution. */ if($executionID) { - $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution'); + $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution'); $stories = $this->story->getExecutionStoryPairs($executionID); $execution = $this->loadModel('execution')->getById($executionID); if($execution->type == 'kanban') @@ -785,7 +787,7 @@ class bug extends control } else { - $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty'); + $builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased'); $stories = $this->story->getProductStoryPairs($productID, $branch); } @@ -933,7 +935,7 @@ class bug extends control $this->view->branchName = $product->type == 'normal' ? '' : zget($branches, $bug->branch, ''); $this->view->users = $this->user->getPairs('noletter'); $this->view->actions = $this->action->getList('bug', $bugID); - $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withreleased'); + $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all'); $this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('bug', $bugID); $this->view->product = $product; @@ -1079,18 +1081,18 @@ class bug extends control $this->view->position[] = $this->lang->bug->edit; /* Assign. */ - $allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,withreleased'); + $allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty'); if($executionID) { - $openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch', $executionID, 'execution'); + $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', $projectID, 'project'); + $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'); + $openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased'); } /* Set the openedBuilds list. */ @@ -1163,7 +1165,6 @@ class bug extends control if($product->shadow) $this->view->project = $this->loadModel('project')->getByShadowProduct($bug->product); $this->view->bug = $bug; - $this->view->productID = $productID; $this->view->product = $product; $this->view->execution = $execution; $this->view->productBugs = $productBugs; @@ -1828,15 +1829,15 @@ class bug extends control $this->bug->checkBugExecutionPriv($bug); $this->qa->setMenu($this->products, $productID, $bug->branch); - $this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve; - $this->view->bug = $bug; - $this->view->users = $users; - $this->view->assignedTo = $assignedTo; - $this->view->productBugs = $productBugs; - $this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter'); - $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch'); - $this->view->actions = $this->action->getList('bug', $bugID); - $this->view->execution = isset($execution) ? $execution : ''; + $this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve; + $this->view->bug = $bug; + $this->view->users = $users; + $this->view->assignedTo = $assignedTo; + $this->view->productBugs = $productBugs; + $this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter'); + $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch,noreleased'); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->view->execution = isset($execution) ? $execution : ''; $this->display(); } @@ -1933,7 +1934,7 @@ class bug extends control $this->view->bug = $bug; $this->view->users = $this->user->getPairs('noclosed', $bug->resolvedBy); - $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty', 0, 'execution', $bug->openedBuild); + $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty,noreleased', 0, 'execution', $bug->openedBuild); $this->view->actions = $this->action->getList('bug', $bugID); $this->display(); @@ -2150,7 +2151,7 @@ class bug extends control $this->view->bugs = $bugs; $this->view->users = $this->user->getPairs(); - $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty'); + $this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased'); $this->display(); } @@ -2412,7 +2413,7 @@ class bug extends control public function ajaxGetBugFieldOptions($productID, $executionID = 0) { $modules = $this->loadModel('tree')->getOptionMenu($productID, 'bug'); - $builds = $this->loadModel('build')->getBuildPairs($productID, 'all', '', $executionID, 'execution'); + $builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noreleased', $executionID, 'execution'); $type = $this->lang->bug->typeList; $pri = $this->lang->bug->priList; $severity = $this->lang->bug->severityList; @@ -2500,4 +2501,19 @@ class bug extends control if($project->model == 'kanban') return print($this->lang->bug->kanban); return print($this->lang->bug->execution); } + + /** + * Ajax get released builds. + * + * @param int $productID + * @param int|string $branch + * @access public + * @return string + */ + public function ajaxGetReleasedBuilds($productID, $branch = 'all') + { + $releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch); + + return print(helper::jsonEncode($releasedBuilds)); + } } diff --git a/module/bug/js/batchcreate.js b/module/bug/js/batchcreate.js index a69fa47d0d..76eb225198 100644 --- a/module/bug/js/batchcreate.js +++ b/module/bug/js/batchcreate.js @@ -38,13 +38,13 @@ function setOpenedBuilds(link, index) var selected = $('#buildBox' + index).find('select').val(); $('#buildBox' + index).html(builds); $('#buildBox' + index).find('select').val(selected); - $('#openedBuilds' + index + '_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild' + index).remove(); $('#openedBuilds' + index).next('.picker').remove(); $('#buildBox' + index + ' select').removeClass('select-3'); $('#buildBox' + index + ' select').addClass('select-1'); $('#buildBox' + index + ' select').attr('name','openedBuilds[' + index + '][]'); $('#buildBox' + index + ' select').attr('id','openedBuilds' + index); - $('#buildBox' + index + ' select').chosen(); + $('#buildBox' + index + ' select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); index++; if($('#executions' + index).val() != 'ditto') break; diff --git a/module/bug/js/common.js b/module/bug/js/common.js index e7baa1bba6..0c74f79a6f 100644 --- a/module/bug/js/common.js +++ b/module/bug/js/common.js @@ -19,6 +19,27 @@ $(function() } }); + +if($('#openedBuild').length || $('#resolvedBuild').length || $('[name^=openedBuilds]').length) +{ + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + + $('#openedBuild, #resolvedBuild, [name^=openedBuilds]').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); +} + +function markReleasedBuilds($option) +{ + var build = $option.attr('data-value'); + if($.inArray(build, releasedBuilds) != -1) + { + if(!$option.find('.label-released').length) + { + var optionText = $option.find('.picker-option-text').html(); + $option.find('.picker-option-text').replaceWith("

" + releasedBuild + " " + optionText + "

"); + } + } +} + /** * Load all fields. * @@ -178,6 +199,8 @@ function loadAllExecutionBuilds(executionID, productID, buildBox) { branch = $('#branch').val(); if(typeof(branch) == 'undefined') branch = 0; + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + if(page == 'create') { oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0; @@ -186,10 +209,10 @@ function loadAllExecutionBuilds(executionID, productID, buildBox) { if(!data) data = ''; $('#openedBuild').replaceWith(data); - $('#openedBuild_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild').remove(); $('#openedBuild').next('.picker').remove(); - $("#openedBuild").chosen(); notice(); + $("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); }) } if(page == 'edit') @@ -197,12 +220,12 @@ function loadAllExecutionBuilds(executionID, productID, buildBox) if(buildBox == 'openedBuildBox') { link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all'); - $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } if(buildBox == 'resolvedBuildBox') { link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all'); - $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } } } @@ -219,6 +242,9 @@ function loadAllProductBuilds(productID, buildBox) { branch = $('#branch').val(); if(typeof(branch) == 'undefined') branch = 0; + + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + if(page == 'create') { link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all'); @@ -226,10 +252,10 @@ function loadAllProductBuilds(productID, buildBox) { if(!data) data = ''; $('#openedBuild').replaceWith(data); - $('#openedBuild_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild').remove(); $('#openedBuild').next('.picker').remove(); - $("#openedBuild").chosen(); notice(); + $("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); }) } if(page == 'edit') @@ -237,12 +263,12 @@ function loadAllProductBuilds(productID, buildBox) if(buildBox == 'openedBuildBox') { link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all'); - $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } if(buildBox == 'resolvedBuildBox') { link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all'); - $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } } } @@ -294,7 +320,7 @@ function loadProductStories(productID) function loadProductProjects(productID) { required = $('#project_chosen').hasClass('required'); - branch = $('#branch').val(); + branch = $('#branch').val(); if(typeof(branch) == 'undefined') branch = 0; link = createLink('product', 'ajaxGetProjects', 'productID=' + productID + '&branch=' + branch + '&projectID=' + oldProjectID); $('#projectBox').load(link, function() @@ -437,23 +463,25 @@ function loadProductBuilds(productID) if(typeof(oldOpenedBuild) == 'undefined') oldOpenedBuild = 0; link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch); + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + if(page == 'create') { $.get(link, function(data) { if(!data) data = ''; $('#openedBuild').replaceWith(data); - $('#openedBuild_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild').remove(); $('#openedBuild').next('.picker').remove(); - $("#openedBuild").chosen(); notice(); + $("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); }) } else { - $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch); - $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()}); + $('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } } @@ -466,9 +494,12 @@ function loadProductBuilds(productID) */ function loadExecutionRelated(executionID) { - executionID = parseInt(executionID); + executionID = parseInt(executionID); + currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val(); + if(executionID) { + if(currentProjectID == 0) loadProjectByExecutionID(executionID); loadExecutionTasks(executionID); loadExecutionStories(executionID); loadExecutionBuilds(executionID); @@ -477,7 +508,6 @@ function loadExecutionRelated(executionID) } else { - var currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val(); var currentProductID = $('#product').val(); $('#taskIdBox').innerHTML = ''; // Reset the task. @@ -496,6 +526,43 @@ function loadExecutionRelated(executionID) } } +/** + * Load a project by execution id. + * + * @param executionID $executionID + * @access public + * @return void + */ +function loadProjectByExecutionID(executionID) +{ + link = createLink('project', 'ajaxGetPairsByExecution', 'executionID=' + executionID, 'json'); + required = $('#project_chosen').hasClass('required'); + productID = $('#product').val(); + + $.post(link, function(data) + { + var originProject = $('#project').html(); + + if($('#project').find('option[value="' + data.id + '"]').length > 0) + { + $('#project').find('option[value="' + data.id + '"]').attr('selected', 'selected'); + originProject = $('#project').html(); + $('#project').replaceWith(''); + } + else + { + var newProject = ''; + $('#project').replaceWith(''); + } + + $('#project_chosen').remove(); + $('#project').next('.picker').remove(); + $('#project').chosen(); + + if(required) $('#project_chosen').addClass('required'); + }, 'json') +} + /** * Load execution tasks. * @@ -552,28 +619,30 @@ function loadProjectBuilds(projectID) var productID = $('#product').val(); var oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0; + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + if(page == 'create') { var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=&branch=' + branch); $.get(link, function(data) { - if(!data) data = ''; + if(!data) data = ''; $('#openedBuild').replaceWith(data); $('#openedBuild').val(oldOpenedBuild); - $('#openedBuild_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild').remove(); $('#openedBuild').next('.picker').remove(); - $("#openedBuild").chosen(); notice(); + $("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); }) } else { var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch); - $('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()}); + $('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); var oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0; var link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch); - $('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()}); + $('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } } @@ -595,28 +664,30 @@ function loadExecutionBuilds(executionID, num) if(typeof(branch) == 'undefined') var branch = 0; if(typeof(productID) == 'undefined') var productID = 0; + $.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json'); + if(page == 'create') { link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&index=0&needCreate=true"); $.get(link, function(data) { - if(!data) data = ''; + if(!data) data = ''; $('#openedBuild').replaceWith(data); $('#openedBuild').val(oldOpenedBuild); - $('#openedBuild_chosen').remove(); + $('#pickerDropMenu-pk_openedBuild').remove(); $('#openedBuild').next('.picker').remove(); - $("#openedBuild").chosen(); notice(); + $("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'}); }) } else { link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=false&type=normal&number=' + num); - $('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()}); + $('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleaseBuilds, dropWidth: 'auto'})}); oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0; link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch); - $('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()}); + $('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})}); } } @@ -776,7 +847,9 @@ function notice() if(page == 'edit') return; $('#buildBoxActions').empty().hide(); - if($('#openedBuild').find('option').length <= 1) + var itemCount = $('#openedBuild').find('option').length; + if($('#openedBuild').attr('data-items') != undefined) var itemCount = $('#openedBuild').attr('data-items'); + if(itemCount <= 1) { var html = ''; if($('#execution').length == 0 || $('#execution').val() == 0) diff --git a/module/bug/js/create.js b/module/bug/js/create.js index dd9892d975..6590029f6e 100644 --- a/module/bug/js/create.js +++ b/module/bug/js/create.js @@ -124,6 +124,7 @@ $(function() }); }); -$(window).unload(function(){ +$(window).unload(function() +{ if(blockID) window.parent.refreshBlock($('#block' + blockID)); }); diff --git a/module/bug/model.php b/module/bug/model.php index e24d83085f..0bcbe446fd 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -81,8 +81,6 @@ class bugModel extends model ->remove('files,labels,uid,oldTaskID,contactListMenu,region,lane,ticket') ->get(); - if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project'); - /* Check repeat bug. */ $result = $this->loadModel('common')->removeDuplicate('bug', $bug, "product={$bug->product}"); if($result and $result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']); @@ -219,8 +217,6 @@ class bugModel extends model if(isset($data->lanes[$i])) $bug->laneID = $data->lanes[$i]; - if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project'); - /* Assign the bug to the person in charge of the module. */ if(!empty($moduleOwners[$bug->module])) { @@ -1623,7 +1619,7 @@ class bugModel extends model $this->config->bug->search['params']['module']['values'] = $modules; $this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($productID, 0, 'id_desc', $projectID); $this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList; //Fix bug #939. - $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch'); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch|releasetag'); $this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values']; if($this->session->currentProductType == 'normal') { diff --git a/module/bug/view/activate.html.php b/module/bug/view/activate.html.php index e2f5fce4da..37cc6027b6 100644 --- a/module/bug/view/activate.html.php +++ b/module/bug/view/activate.html.php @@ -37,7 +37,7 @@ printExtendFields($bug, 'table');?> bug->openedBuild;?> - openedBuild, 'size=4 multiple=multiple class="form-control chosen"');?> + openedBuild, 'size=4 multiple=multiple class="form-control picker-select"');?> comment;?> @@ -56,4 +56,8 @@
+product); +js::set('releasedBuild', $lang->build->releasedBuild); +?> diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php index c93fe27e54..eb34d2370a 100755 --- a/module/bug/view/batchcreate.html.php +++ b/module/bug/view/batchcreate.html.php @@ -13,6 +13,8 @@ bug->create->requiredFields); +js::set('productID', $productID); +js::set('releasedBuild', $lang->build->releasedBuild); ?> bug->create->requiredFields) as $field) projectBox' style='overflow:visible'> executionBox' style='overflow:visible'> - +
@@ -163,7 +165,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field) projectBox' style='overflow:visible'> executionBox' style='overflow:visible'> - +
@@ -224,7 +226,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field) projectBox' style='overflow:visible'> executionBox' style='overflow:visible'> - +
@@ -267,7 +269,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field) projectBox' style='overflow:visible'> executionBox' style='overflow:visible'> - +
diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php index 79c85912a5..0a665ed306 100644 --- a/module/bug/view/browse.html.php +++ b/module/bug/view/browse.html.php @@ -328,7 +328,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow { $actionLink = $this->createLink('bug', 'batchResolve', "resolution=fixed&resolvedBuild=$key"); echo "
  • "; - echo html::a('javascript:;', $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\""); + echo html::a('javascript:;', (in_array($key, $releasedBuilds) ? "{$lang->build->releasedBuild} " : '') . $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\""); echo "
  • "; } echo ""; diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php index 1ff2b23c25..3cb9f567a2 100644 --- a/module/bug/view/create.html.php +++ b/module/bug/view/create.html.php @@ -30,6 +30,8 @@ js::set('tab', $this->app->tab); js::set('requiredFields', $config->bug->create->requiredFields); js::set('showFields', $showFields); js::set('projectExecutionPairs', $projectExecutionPairs); +js::set('productID', $productID); +js::set('releasedBuild', $lang->build->releasedBuild); if($this->app->tab == 'execution') js::set('objectID', zget($execution, 'id', '')); if($this->app->tab == 'project') js::set('objectID', $projectID); ?> @@ -128,7 +130,7 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
    bug->openedBuild?> - +
    bug->allBuilds, "class='btn' id='all' data-toggle='tooltip' onclick='loadAllBuilds()'")?>
    diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php index f2411a486b..5abdec20a3 100644 --- a/module/bug/view/edit.html.php +++ b/module/bug/view/edit.html.php @@ -30,6 +30,8 @@ js::set('bugID' , $bug->id); js::set('bugBranch' , $bug->branch); js::set('isClosedBug' , $bug->status == 'closed'); js::set('projectExecutionPairs' , $projectExecutionPairs); +js::set('productID' , $product->id); +js::set('releasedBuild' , $lang->build->releasedBuild); if($this->app->tab == 'execution') js::set('objectID', $bug->execution); if($this->app->tab == 'project') js::set('objectID', $bug->project); ?> @@ -100,7 +102,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project); bug->product;?>
    - + id, "onchange='loadAll(this.value)' class='form-control chosen'");?> type != 'normal') echo html::select('branch', $branchTagOption, $bug->branch, "onchange='loadBranch();' class='form-control'");?>
    @@ -114,9 +116,9 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project); if(count($moduleOptionMenu) == 1) { echo ""; - echo html::a($this->createLink('tree', 'browse', "rootID=$productID&view=bug¤tModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'"); + echo html::a($this->createLink('tree', 'browse', "rootID={$product->id}&view=bug¤tModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'"); echo '  '; - echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($productID)'"); + echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($product->id)'"); echo ''; } ?> @@ -240,7 +242,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project); bug->openedBuild;?>
    - openedBuild, 'size=4 multiple=multiple class="chosen form-control"');?> + openedBuild, 'size=4 multiple=multiple class="picker-select form-control"');?> bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?>
    @@ -257,7 +259,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project); bug->resolvedBuild;?>
    - resolvedBuild, "class='form-control chosen'");?> + resolvedBuild, "class='form-control picker-select'");?> bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?>
    diff --git a/module/bug/view/resolve.html.php b/module/bug/view/resolve.html.php index aea25327aa..b284f83a5c 100644 --- a/module/bug/view/resolve.html.php +++ b/module/bug/view/resolve.html.php @@ -14,8 +14,9 @@ product); +js::set('page', 'resolve'); +js::set('productID', $bug->product); +js::set('releasedBuild', $lang->build->releasedBuild); ?>
    @@ -49,7 +50,7 @@ js::set('productID' , $bug->product);
    -
    +
    diff --git a/module/build/control.php b/module/build/control.php index a479bdba7e..f2772a442f 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -385,32 +385,38 @@ class build extends control * @param string|int $branch * @param int $index the index of batch create bug. * @param string $type get all builds or some builds belong to normal releases and executions are not done. + * @param string $extra * @access public * @return string */ - public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal') + public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal', $extra = '') { $isJsonView = $this->app->getViewType() == 'json'; if($varName == 'openedBuild' ) { - $params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch'; + $params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName . '[]', $builds, $build, 'size=4 class=form-control multiple')); } if($varName == 'openedBuilds' ) { - $builds = $this->build->getBuildPairs($productID, $branch, 'noempty', 0, 'project', $build); + $builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', 0, 'project', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName . "[$index][]", $builds, $build, 'size=4 class=form-control multiple')); } if($varName == 'resolvedBuild') { - $params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch'; + $params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName, $builds, $build, "class='form-control'")); } + + $builds = $this->build->getBuildPairs($productID, $branch, $type, 0, 'project', $build); + if(strpos($extra, 'multiple') !== false) $varName .= '[]'; + if($isJsonView) return print(json_encode($builds)); + return print(html::select($varName, $builds, $build, "class='form-control chosen' $extra")); } /** @@ -434,7 +440,7 @@ class build extends control { if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); - $params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch'; + $params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName . '[]', $builds , '', 'size=4 class=form-control multiple')); @@ -443,13 +449,13 @@ class build extends control { if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); - $params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch'; + $params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName, $builds, $build, "class='form-control'")); } - if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); + if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type, $extra); $builds = $this->build->getBuildPairs($productID, $branch, $type, $projectID, 'project', $build, false); if(strpos($extra, 'multiple') !== false) $varName .= '[]'; if($isJsonView) return print(json_encode($builds)); @@ -478,7 +484,7 @@ class build extends control { if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); - $params = ($type == 'all') ? 'noempty' : 'noempty,noterminate,nodone'; + $params = ($type == 'all') ? 'noempty,noreleased' : 'noempty,noterminate,nodone,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build); if($isJsonView) return print(json_encode($builds)); @@ -489,7 +495,7 @@ class build extends control { if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); - $builds = $this->build->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution', $build); + $builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName . "[$index][]", $builds , $build, 'size=4 class=form-control multiple')); } @@ -497,14 +503,14 @@ class build extends control { if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type); - $params = ($type == 'all') ? '' : 'noterminate,nodone'; + $params = ($type == 'all') ? ',noreleased' : 'noterminate,nodone,noreleased'; $builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build); if($isJsonView) return print(json_encode($builds)); return print(html::select($varName, $builds, $build, "class='form-control'")); } if($varName == 'testTaskBuild') { - $builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution'); + $builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution', '', false); if($isJsonView) return print(json_encode($builds)); if(empty($builds)) @@ -543,7 +549,7 @@ class build extends control { $lastBuild = $this->build->getLast($executionID, $projectID); if($lastBuild) - { + { echo "
      " . $this->lang->build->last . ": " . $lastBuild->name . "
    "; } else @@ -714,7 +720,7 @@ class build extends control $this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($build->product, $build->branch, 'skipParent'); $this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($build->product, 'bug', 0, $build->branch); $this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project); - $this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $branch = 'all', $params = ''); + $this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $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']); diff --git a/module/build/lang/de.php b/module/build/lang/de.php index 58e816e8fe..0164196034 100644 --- a/module/build/lang/de.php +++ b/module/build/lang/de.php @@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon; $lang->build->integrated = 'Integrated'; $lang->build->singled = 'Singled'; $lang->build->builds = 'Included Builds'; +$lang->build->releasedBuild = 'Released Build'; $lang->build->name = 'Name'; $lang->build->date = 'Datum'; $lang->build->builder = 'Builder'; @@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers $lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}"; $lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds"; $lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version"; +$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted"; $lang->build->finishStories = " %s {$lang->SRCommon} sind abgeschlossen."; $lang->build->resolvedBugs = ' %s Bugs sind gelöst.'; diff --git a/module/build/lang/en.php b/module/build/lang/en.php index 1de167d912..75343df3d0 100644 --- a/module/build/lang/en.php +++ b/module/build/lang/en.php @@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon; $lang->build->integrated = 'Integrated'; $lang->build->singled = 'Singled'; $lang->build->builds = 'Included Builds'; +$lang->build->releasedBuild = 'Released Build'; $lang->build->name = 'Name'; $lang->build->date = 'Date'; $lang->build->builder = 'Builder'; @@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers $lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}"; $lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds"; $lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version"; +$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted"; $lang->build->finishStories = " Finished {$lang->SRCommon} %s"; $lang->build->resolvedBugs = ' Resolved Bug %s'; diff --git a/module/build/lang/fr.php b/module/build/lang/fr.php index 68b572a9fe..e6500fd173 100644 --- a/module/build/lang/fr.php +++ b/module/build/lang/fr.php @@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon; $lang->build->integrated = 'Integrated'; $lang->build->singled = 'Singled'; $lang->build->builds = 'Included Builds'; +$lang->build->releasedBuild = 'Released Build'; $lang->build->name = 'Nom'; $lang->build->date = 'Date'; $lang->build->builder = 'Builder'; @@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers $lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}"; $lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds"; $lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version"; +$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted"; $lang->build->finishStories = " {$lang->SRCommon} Terminées %s"; $lang->build->resolvedBugs = ' Bugs Résolus %s'; diff --git a/module/build/lang/vi.php b/module/build/lang/vi.php index aaf8d2800b..0c493659f2 100644 --- a/module/build/lang/vi.php +++ b/module/build/lang/vi.php @@ -54,6 +54,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers $lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}"; $lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds"; $lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version"; +$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted"; $lang->build->finishStories = " {$lang->SRCommon} đã kết thúc %s"; $lang->build->resolvedBugs = ' Bug đã giải quyết %s'; diff --git a/module/build/lang/zh-cn.php b/module/build/lang/zh-cn.php index 2f8c8ae839..fe804daf9c 100644 --- a/module/build/lang/zh-cn.php +++ b/module/build/lang/zh-cn.php @@ -28,7 +28,7 @@ $lang->build->confirmUnlinkBug = "您确认移除该Bug吗?"; $lang->build->basicInfo = '基本信息'; $lang->build->id = 'ID'; -$lang->build->product = $lang->productCommon; +$lang->build->product = '所属' . $lang->productCommon; $lang->build->project = '所属项目'; $lang->build->branch = '平台/分支'; $lang->build->branchName = '所属%s'; @@ -36,6 +36,7 @@ $lang->build->execution = '所属' . $lang->executionCommon; $lang->build->integrated = '集成版本'; $lang->build->singled = '单一版本'; $lang->build->builds = '包含版本'; +$lang->build->releasedBuild = '发布版本'; $lang->build->name = '名称编号'; $lang->build->date = '打包日期'; $lang->build->builder = '构建者'; @@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "已经关联{$lang->SRCommon}、Bug或 $lang->build->notice->changeExecution = "提交测试单的版本,不能修改其所属{$lang->executionCommon}"; $lang->build->notice->changeBuilds = "提交测试单的版本,不能修改关联版本"; $lang->build->notice->autoRelation = "相关版本下完成的需求、解决的Bug、产生的Bug将会自动关联到项目版本中"; +$lang->build->notice->createTest = "该版本所属执行已删除,不能提交测试"; $lang->build->finishStories = " 本次共完成 %s 个{$lang->SRCommon}"; $lang->build->resolvedBugs = ' 本次共解决 %s 个Bug'; diff --git a/module/build/model.php b/module/build/model.php index f9dae4d54a..fd739b41a0 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -181,6 +181,38 @@ class buildModel extends model return $this->getExecutionBuilds($executionID, 'bysearch', $buildQuery); } + /** + * Filter linked stories or bugs builds. + * + * @param array $buildIdList + * @access public + * @return array + */ + public function filterLinked($buildIdList) + { + $linkeds = array(); + $buildList = $this->getByList($buildIdList); + foreach($buildList as $build) + { + if(!$build->execution && !empty($build->builds)) + { + $childBuilds = $this->getByList($build->builds); + foreach($childBuilds as $childBuild) + { + $childBuild->stories = trim($childBuild->stories, ','); + $childBuild->bugs = trim($childBuild->bugs, ','); + + if($childBuild->stories) $build->stories .= ',' . $childBuild->stories; + if($childBuild->bugs) $build->bugs .= ',' . $childBuild->bugs; + } + } + + if(!empty($build->stories) or !empty($build->bugs)) $linkeds[$build->id] = $build->id; + } + + return $linkeds; + } + /** * Get story builds. * @@ -202,7 +234,7 @@ class buildModel extends model * * @param int|array $products * @param string|int $branch - * @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|withreleased, can be a set of them + * @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|noreleased|releasedtag, can be a set of them * @param string|int $objectID * @param string $objectType * @param int|array $buildIdList @@ -227,7 +259,7 @@ class buildModel extends model } $branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch; - $allBuilds = $this->dao->select('t1.id, t1.name, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1') + $allBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1') ->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi() ->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi() ->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)") @@ -243,6 +275,8 @@ class buildModel extends model ->beginIF($branch !== 'all')->andWhere('t1.branch')->in("$branchs")->fi() ->orderBy('t1.date desc, t1.id desc')->fetchAll('id'); + $deletedExecutions = $this->dao->select('id, deleted')->from(TABLE_EXECUTION)->where('type')->eq('sprint')->andWhere('deleted')->eq('1')->fetchPairs(); + /* Set builds and filter done executions and terminate releases. */ $builds = array(); $buildIdList = array(); @@ -251,6 +285,7 @@ class buildModel extends model { if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->objectStatus === 'done')) continue; if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue; + if((strpos($params, 'withexecution') !== false) and $build->execution and isset($executions[$build->execution])) continue; if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')'; $branchName = $build->branchName ? $build->branchName : $this->lang->branch->main; @@ -292,12 +327,13 @@ class buildModel extends model $releaseName = $release->name; $branchName = $release->branchName ? $release->branchName : $this->lang->branch->main; if($release->productType != 'normal') $releaseName = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName; + if(strpos($params, 'releasetag') !== false) $releaseName = "[{$this->lang->build->releasedBuild}] " . $releaseName; $builds[$release->date][$release->shadow] = $releaseName; foreach(explode(',', trim($release->build, ',')) as $buildID) { if(!isset($allBuilds[$buildID])) continue; $build = $allBuilds[$buildID]; - if(strpos($params, 'withreleased') === false) unset($builds[$build->date][$buildID]); + if(strpos($params, 'noreleased') !== false) unset($builds[$build->date][$buildID]); } } } @@ -621,7 +657,7 @@ class buildModel extends model { $action = strtolower($action); - if($module == 'testtask' && $action == 'create') return !!$object->execution; + if($module == 'testtask' and $action == 'create') return !$object->executionDeleted; return true; } @@ -651,11 +687,14 @@ class buildModel extends model { $executionID = $tab == 'execution' ? $extraParams['executionID'] : $build->execution; $execution = $this->loadModel('execution')->getByID($executionID); + $build->executionDeleted = $execution ? $execution->deleted : 0; + $testtaskApp = (!empty($execution->type) and $execution->type == 'kanban') ? 'data-app="qa"' : "data-app='{$tab}'"; if(common::hasPriv($module, 'linkstory') and common::canBeChanged('build', $build)) $menu .= $this->buildMenu($module, 'view', "{$params}&type=story&link=true", $build, $type, 'link', '', '', '', "data-app={$tab}", $this->lang->build->linkStory); - $menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp); + $title = ($execution and $execution->deleted === '1') ? $this->lang->build->notice->createTest : ''; + $menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp, $title); if($tab == 'execution' and !empty($execution->type) and $execution->type != 'kanban') $menu .= $this->buildMenu('execution', 'bug', "execution={$extraParams['executionID']}&productID={$extraParams['productID']}&branchID=all&orderBy=status&build=$build->id", $build, $type, '', '', '', '', $this->lang->execution->viewBug); if($tab == 'project' or empty($execution->type) or $execution->type == 'kanban') $menu .= $this->buildMenu($module, 'view', "{$params}&type=generatedBug", $build, $type, 'bug', '', '', '', "data-app='$tab'", $this->lang->project->bug); diff --git a/module/build/view/view.html.php b/module/build/view/view.html.php index aa18d5ecae..fe31522f6a 100644 --- a/module/build/view/view.html.php +++ b/module/build/view/view.html.php @@ -26,7 +26,11 @@ tbody tr td:first-child input {display: none;}