diff --git a/api/v1/entries/productplans.php b/api/v1/entries/productplans.php index f8313c1683..6fc0b0757e 100644 --- a/api/v1/entries/productplans.php +++ b/api/v1/entries/productplans.php @@ -24,7 +24,7 @@ class productplansEntry extends entry if(!$productID) return $this->sendError(400, 'No product id.'); $control = $this->loadController('productplan', 'browse'); - $control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('order', 'begin_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); + $control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('query', 0), $this->param('order', 'begin_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); /* Response */ $data = $this->getData(); diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index beadc3089a..5c89698e49 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -535,7 +535,7 @@ class baseEntry /* Format array. */ $value = array(); - if(is_array($object->$key)) + if(is_array($object->$key) or is_object($object->$key)) { foreach($object->$key as $v) $value[] = $this->cast($v, $type); } diff --git a/lib/scm/gitea.class.php b/lib/scm/gitea.class.php index b01638fa87..1585de2822 100644 --- a/lib/scm/gitea.class.php +++ b/lib/scm/gitea.class.php @@ -320,9 +320,8 @@ class gitea foreach($list as $node) if($node->path == $entry) $file = $node; - $commits = $this->getCommitsByPath($entry); - - if(!empty($commits)) $file->revision = zget($commits[0], 'id', ''); + $commits = $this->getCommitsByPath($entry, $revision, $revision); + if(!empty($commits)) $file->revision = zget($commits[0], 'sha', ''); $info->kind = (isset($file->type) and $file->type == 'tree') ? 'dir' : 'file'; } diff --git a/module/action/control.php b/module/action/control.php index 4be60a2303..6edd4aed0d 100755 --- a/module/action/control.php +++ b/module/action/control.php @@ -157,7 +157,7 @@ class action extends control $repeatObject = $this->dao->select('*')->from(TABLE_PRODUCT) ->where('id')->ne($oldAction->objectID) ->andWhere("(name = '{$product->name}' and program = {$programID})", true) - ->orWhere("code = '{$product->code}'") + ->beginIF($product->code)->orWhere("code = '{$product->code}'")->fi() ->markRight(1) ->andWhere('deleted')->eq('0') ->fetch(); @@ -182,13 +182,26 @@ class action extends control if($repeatObject) { - $result = preg_match('/_(\d+)$/', $repeatObject->name, $nameMatches); - $replaceName = $result ? preg_replace('/_(\d+)$/', '_' . ($nameMatches[1] + 1), $repeatObject->name) : $repeatObject->name . '_1'; - $result = preg_match('/_(\d+)$/', $repeatObject->code, $codeMatches); - $replaceCode = $result ? preg_replace('/_(\d+)$/', '_' . ($codeMatches[1] + 1), $repeatObject->code) : $repeatObject->code . '_1'; - $table = $oldAction->objectType == 'product' ? TABLE_PRODUCT : TABLE_PROJECT; $object = $oldAction->objectType == 'product' ? $product : $project; + + $existNames = $this->dao->select('name')->from($table)->where('name')->like($repeatObject->name . '_%')->fetchPairs(); + for($i = 1; $i < 10000; $i ++) + { + $replaceName = $repeatObject->name . '_' . $i; + if(!in_array($replaceName, $existNames)) break; + } + $replaceCode = ''; + if($object->code) + { + $existCodes = $this->dao->select('code')->from($table)->where('code')->like($repeatObject->code . '_%')->fetchPairs(); + for($i = 1; $i < 10000; $i ++) + { + $replaceCode = $repeatObject->code . '_' . $i; + if(!in_array($replaceCode, $existCodes)) break; + } + } + if($repeatObject->name == $object->name and $repeatObject->code and $repeatObject->code == $object->code) { if($confirmChange == 'no') return print(js::confirm(sprintf($this->lang->action->repeatChange, $this->lang->{$oldAction->objectType}->common, $replaceName, $replaceCode), $this->createLink('action', 'undelete', "action={$actionID}&browseType={$browseType}&confirmChange=yes"))); diff --git a/module/action/model.php b/module/action/model.php index 8aec1a5db1..5e203ed3de 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -1000,13 +1000,15 @@ class actionModel extends model elseif($productID == 'all' and is_numeric($projectID)) { $products = $this->loadModel('product')->getProductPairsByProject($projectID); - $executions = $this->loadModel('execution')->getPairs($projectID) + array(0 => 0); + $executions = $this->loadModel('execution')->getPairs($projectID); + + $authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions); $productCondition = ''; foreach(array_keys($products) as $product) $productCondition = empty($productCondition) ? "product LIKE '%,$product,%'" : "$productCondition OR product LIKE '%,$product,%'"; $projectCondition = "project = $projectID"; - $executionCondition = "execution " . helper::dbIN(array_keys($executions)); + $executionCondition = "execution " . helper::dbIN($authedExecutions); } elseif(is_numeric($productID) and $projectID == 'all') { @@ -1014,15 +1016,18 @@ class actionModel extends model $projects = $this->product->getProjectPairsByProduct($productID); $executions = $this->product->getExecutionPairsByProduct($productID); - $productCondition = "product = $productID"; - $projectCondition = "project " . helper::dbIN(array_keys($projects)); - $executionCondition = "execution " . helper::dbIN(array_keys($executions)); + $authedProjects = array_intersect(array_keys($projects), explode(',', $authedProjects)); + $authedExecutions = isset($authedExecutions) ? array_intersect(array_keys($executions), explode(',', $authedExecutions)) : array_keys($executions); + + $productCondition = "product like '%,$productID,%'"; + $projectCondition = 'project ' . helper::dbIN($authedProjects); + $executionCondition = 'execution ' . helper::dbIN($authedExecutions); } - $condition = "((product =',0,' or product = '0') AND project = '0' AND execution = '0')"; - if(!empty($productCondition)) $condition .= ' OR ' . $productCondition; - if(!empty($projectCondition)) $condition .= ' OR ' . $projectCondition; - if(!empty($executionCondition)) $condition .= ' OR ' . $executionCondition; + $condition = "((product =',0,' or product = '0' or product=',,') AND project = '0' AND execution = '0')"; + if(!empty($productCondition)) $condition .= " OR $productCondition"; + if(!empty($projectCondition)) $condition .= " OR $projectCondition"; + if(!empty($executionCondition)) $condition .= " OR $executionCondition"; } $actionCondition = $this->getActionCondition(); @@ -1092,7 +1097,8 @@ class actionModel extends model foreach($this->app->user->rights['acls']['actions'] as $moduleName => $actions) { if(isset($this->lang->mainNav->$moduleName) and !empty($this->app->user->rights['acls']['views']) and !isset($this->app->user->rights['acls']['views'][$moduleName])) continue; - $actionCondition .= "(`objectType` = '$moduleName' and `action` " . helper::dbIN($actions) . ") or "; + $canViewPrograms = $moduleName == 'program' ? "`objectID` in ({$this->app->user->view->programs}) and " : ''; + $actionCondition .= "($canViewPrograms `objectType` = '$moduleName' and `action` " . helper::dbIN($actions) . ") or "; } $actionCondition = trim($actionCondition, 'or '); } @@ -1214,8 +1220,17 @@ class actionModel extends model $relatedProjects = $relatedData['relatedProjects']; $requirements = $relatedData['requirements']; + $aclViews = isset($this->app->user->rights['acls']['views']) ? $this->app->user->rights['acls']['views'] : array(); + $authedProjects = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['project']))) ? ",{$this->app->user->view->projects}," : array(); + $authedExecutions = (empty($aclViews) or (!empty($aclViews) and !empty($aclViews['execution']))) ? ",{$this->app->user->view->sprints},": array(); + foreach($actions as $i => $action) { + if(($action->execution != '0' and strpos($authedExecutions, ",$action->execution,") === false) or ($action->execution == '0' and $action->project != '0' and strpos($authedProjects, ",$action->project,") === false)) + { + unset($actions[$i]); + continue; + } /* Add name field to the actions. */ $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : ''; diff --git a/module/api/control.php b/module/api/control.php index 2601e6e871..a854a71abc 100755 --- a/module/api/control.php +++ b/module/api/control.php @@ -353,7 +353,7 @@ class api extends control $this->view->type = $type; $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->users = $this->user->getPairs('nocode'); + $this->view->users = $this->user->getPairs('nocode|noclosed'); $this->display(); } @@ -388,7 +388,7 @@ class api extends control $this->view->doc = $doc; $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->users = $this->user->getPairs('nocode'); + $this->view->users = $this->user->getPairs('nocode|noclosed'); $this->display(); } @@ -636,7 +636,7 @@ class api extends control if(intval($libID) > 0 and common::hasPriv('api', 'create')) { $menu .= "
  • "; - $menu .= html::a(helper::createLink('api', 'create', "libID=$libID&moduleID=$moduleID"), " " . $this->lang->api->apiDoc, '', "data-app='{$this->app->tab}'"); + $menu .= html::a(helper::createLink('api', 'create', "libID=$libID&moduleID=$moduleID"), " " . $this->lang->api->createApi, '', "data-app='{$this->app->tab}'"); $menu .= "
  • "; } diff --git a/module/build/model.php b/module/build/model.php index 241e46c134..8bbc38576d 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -217,6 +217,7 @@ class buildModel extends model { $selectedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD) ->where('id')->in($buildIdList) + ->beginIF($products)->andWhere('product')->in($products)->fi() ->beginIF($objectType === 'execution')->andWhere('execution')->eq($objectID)->fi() ->beginIF($objectType === 'project')->andWhere('project')->eq($objectID)->fi() ->fetchPairs(); diff --git a/module/execution/view/batchedit.html.php b/module/execution/view/batchedit.html.php index e9a76ecae3..a37f4b3145 100755 --- a/module/execution/view/batchedit.html.php +++ b/module/execution/view/batchedit.html.php @@ -52,7 +52,7 @@ execution->projectName;?> execution->$name;?> - setCode) and $config->setCode == 1):?> + setCode) or $config->setCode == 1):?> execution->$code;?> '>execution->$PM;?> @@ -86,7 +86,7 @@ project, "class='form-control picker-select' data-lastselected='{$executions[$executionID]->project}' onchange='changeProject(this, $executionID, {$executions[$executionID]->project})'");?> name, "id='names{$executionID}' class='form-control'");?> - setCode) and $config->setCode == 1):?> + setCode) or $config->setCode == 1):?> code, "class='form-control'");?> ' style='overflow:visible'>PM, "class='form-control picker-select'");?> diff --git a/module/file/model.php b/module/file/model.php index 2e68a57ab0..307368e266 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -1017,7 +1017,7 @@ class fileModel extends model { if($this->config->file->storageType == 'fs') { - return getimagesize($file->realPath); + return file_exists($file->realPath) ? getimagesize($file->realPath) : 0; } else if($this->config->file->storageType == 's3') { diff --git a/module/gitea/lang/de.php b/module/gitea/lang/de.php index 064ceb7d3e..ad89c301d3 100644 --- a/module/gitea/lang/de.php +++ b/module/gitea/lang/de.php @@ -8,7 +8,9 @@ $lang->gitea->edit = 'Edit Gitea'; $lang->gitea->view = 'View Gitea'; $lang->gitea->delete = 'Delete Gitea'; $lang->gitea->confirmDelete = 'Do you want to delete this Gitea server?'; +$lang->gitea->giteaAvatar = 'Avatar'; $lang->gitea->bindUser = 'Bind User'; +$lang->gitea->giteaEmail = 'Email'; $lang->gitea->giteaAccount = 'Gitea Account'; $lang->gitea->zentaoAccount = 'Zentao Account'; $lang->gitea->bindingStatus = 'Binding Status'; diff --git a/module/gitea/lang/en.php b/module/gitea/lang/en.php index 064ceb7d3e..ad89c301d3 100644 --- a/module/gitea/lang/en.php +++ b/module/gitea/lang/en.php @@ -8,7 +8,9 @@ $lang->gitea->edit = 'Edit Gitea'; $lang->gitea->view = 'View Gitea'; $lang->gitea->delete = 'Delete Gitea'; $lang->gitea->confirmDelete = 'Do you want to delete this Gitea server?'; +$lang->gitea->giteaAvatar = 'Avatar'; $lang->gitea->bindUser = 'Bind User'; +$lang->gitea->giteaEmail = 'Email'; $lang->gitea->giteaAccount = 'Gitea Account'; $lang->gitea->zentaoAccount = 'Zentao Account'; $lang->gitea->bindingStatus = 'Binding Status'; diff --git a/module/gitea/lang/fr.php b/module/gitea/lang/fr.php index 064ceb7d3e..ad89c301d3 100644 --- a/module/gitea/lang/fr.php +++ b/module/gitea/lang/fr.php @@ -8,7 +8,9 @@ $lang->gitea->edit = 'Edit Gitea'; $lang->gitea->view = 'View Gitea'; $lang->gitea->delete = 'Delete Gitea'; $lang->gitea->confirmDelete = 'Do you want to delete this Gitea server?'; +$lang->gitea->giteaAvatar = 'Avatar'; $lang->gitea->bindUser = 'Bind User'; +$lang->gitea->giteaEmail = 'Email'; $lang->gitea->giteaAccount = 'Gitea Account'; $lang->gitea->zentaoAccount = 'Zentao Account'; $lang->gitea->bindingStatus = 'Binding Status'; diff --git a/module/gitea/lang/vi.php b/module/gitea/lang/vi.php index 064ceb7d3e..ad89c301d3 100644 --- a/module/gitea/lang/vi.php +++ b/module/gitea/lang/vi.php @@ -8,7 +8,9 @@ $lang->gitea->edit = 'Edit Gitea'; $lang->gitea->view = 'View Gitea'; $lang->gitea->delete = 'Delete Gitea'; $lang->gitea->confirmDelete = 'Do you want to delete this Gitea server?'; +$lang->gitea->giteaAvatar = 'Avatar'; $lang->gitea->bindUser = 'Bind User'; +$lang->gitea->giteaEmail = 'Email'; $lang->gitea->giteaAccount = 'Gitea Account'; $lang->gitea->zentaoAccount = 'Zentao Account'; $lang->gitea->bindingStatus = 'Binding Status'; diff --git a/module/gitea/lang/zh-cn.php b/module/gitea/lang/zh-cn.php index 35d94b0dd5..13e4c187a5 100644 --- a/module/gitea/lang/zh-cn.php +++ b/module/gitea/lang/zh-cn.php @@ -9,7 +9,9 @@ $lang->gitea->view = '查看Gitea'; $lang->gitea->delete = '删除Gitea'; $lang->gitea->confirmDelete = '确认删除该Gitea吗?'; $lang->gitea->bindUser = '绑定用户'; +$lang->gitea->giteaAvatar = '头像'; $lang->gitea->giteaAccount = 'Gitea用户'; +$lang->gitea->giteaEmail = '邮箱'; $lang->gitea->zentaoAccount = '禅道用户'; $lang->gitea->bindingStatus = '绑定状态'; $lang->gitea->notBind = '未绑定'; diff --git a/module/gitea/model.php b/module/gitea/model.php index 0930573c47..1b52f42608 100644 --- a/module/gitea/model.php +++ b/module/gitea/model.php @@ -556,15 +556,22 @@ class giteaModel extends model * Get single branch by API. * * @param int $giteaID - * @param int $projectID - * @param string $branch + * @param string $project + * @param string $branchName * @access public * @return object */ - public function apiGetSingleBranch($giteaID, $projectID, $branch) + public function apiGetSingleBranch($giteaID, $project, $branchName) { - $url = sprintf($this->getApiRoot($giteaID), "/repos/$projectID/branches/$branch"); - return json_decode(commonModel::http($url)); + $url = sprintf($this->getApiRoot($giteaID), "/repos/$project/branches/$branchName"); + $branch = json_decode(commonModel::http($url)); + if($branch) + { + $gitea = $this->getByID($giteaID); + $branch->web_url = "{$gitea->url}/$project/src/branch/$branchName"; + } + + return $branch; } /** diff --git a/module/gitea/view/binduser.html.php b/module/gitea/view/binduser.html.php index 83c2982d7c..554c875fd8 100644 --- a/module/gitea/view/binduser.html.php +++ b/module/gitea/view/binduser.html.php @@ -17,12 +17,14 @@
    - +
    - + + + - + @@ -30,13 +32,13 @@ zentaoAccount)) continue;?> account]", $giteaUser->realname);?> - + + @@ -45,13 +47,13 @@ zentaoAccount)) continue;?> account]", $giteaUser->realname);?> - + +
    gitea->giteaAccount;?>gitea->giteaAvatar;?>gitea->giteaAccount;?>gitea->giteaEmail;?> gitea->zentaoAccount;?>gitea->bindingStatus;?>gitea->bindingStatus;?>
    avatar, "height=40");?>avatar, "height=40");?> realname;?>
    account;?> - email) echo " <" . $giteaUser->email . ">";?>
    email;?> account]", $userPairs, '', "class='form-control select chosen'" );?> gitea->notBind;?>
    avatar, "height=40");?>avatar, "height=40");?> realname;?>
    account;?> - email) echo " <" . $giteaUser->email . ">";?>
    email;?> account]", $userPairs, $giteaUser->zentaoAccount, "class='form-control select chosen'" );?> zentaoAccount])):?> diff --git a/module/gitlab/lang/de.php b/module/gitlab/lang/de.php index 41d82d8582..ef5d63cc87 100644 --- a/module/gitlab/lang/de.php +++ b/module/gitlab/lang/de.php @@ -12,7 +12,9 @@ $lang->gitlab->bindProduct = 'Import Product'; $lang->gitlab->importIssue = 'Import Issue'; $lang->gitlab->delete = 'Delete GitLab'; $lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?'; +$lang->gitlab->gitlabAvatar = 'Avatar'; $lang->gitlab->gitlabAccount = 'GitLab Account'; +$lang->gitlab->gitlabEmail = 'Email'; $lang->gitlab->zentaoAccount = 'Zentao Account'; $lang->gitlab->bindingStatus = 'Binding Status'; $lang->gitlab->notBind = 'Not bind'; diff --git a/module/gitlab/lang/en.php b/module/gitlab/lang/en.php index 41d82d8582..ef5d63cc87 100644 --- a/module/gitlab/lang/en.php +++ b/module/gitlab/lang/en.php @@ -12,7 +12,9 @@ $lang->gitlab->bindProduct = 'Import Product'; $lang->gitlab->importIssue = 'Import Issue'; $lang->gitlab->delete = 'Delete GitLab'; $lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?'; +$lang->gitlab->gitlabAvatar = 'Avatar'; $lang->gitlab->gitlabAccount = 'GitLab Account'; +$lang->gitlab->gitlabEmail = 'Email'; $lang->gitlab->zentaoAccount = 'Zentao Account'; $lang->gitlab->bindingStatus = 'Binding Status'; $lang->gitlab->notBind = 'Not bind'; diff --git a/module/gitlab/lang/fr.php b/module/gitlab/lang/fr.php index 41d82d8582..ef5d63cc87 100644 --- a/module/gitlab/lang/fr.php +++ b/module/gitlab/lang/fr.php @@ -12,7 +12,9 @@ $lang->gitlab->bindProduct = 'Import Product'; $lang->gitlab->importIssue = 'Import Issue'; $lang->gitlab->delete = 'Delete GitLab'; $lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?'; +$lang->gitlab->gitlabAvatar = 'Avatar'; $lang->gitlab->gitlabAccount = 'GitLab Account'; +$lang->gitlab->gitlabEmail = 'Email'; $lang->gitlab->zentaoAccount = 'Zentao Account'; $lang->gitlab->bindingStatus = 'Binding Status'; $lang->gitlab->notBind = 'Not bind'; diff --git a/module/gitlab/lang/vi.php b/module/gitlab/lang/vi.php index 41d82d8582..ef5d63cc87 100644 --- a/module/gitlab/lang/vi.php +++ b/module/gitlab/lang/vi.php @@ -12,7 +12,9 @@ $lang->gitlab->bindProduct = 'Import Product'; $lang->gitlab->importIssue = 'Import Issue'; $lang->gitlab->delete = 'Delete GitLab'; $lang->gitlab->confirmDelete = 'Do you want to delete this GitLab server?'; +$lang->gitlab->gitlabAvatar = 'Avatar'; $lang->gitlab->gitlabAccount = 'GitLab Account'; +$lang->gitlab->gitlabEmail = 'Email'; $lang->gitlab->zentaoAccount = 'Zentao Account'; $lang->gitlab->bindingStatus = 'Binding Status'; $lang->gitlab->notBind = 'Not bind'; diff --git a/module/gitlab/lang/zh-cn.php b/module/gitlab/lang/zh-cn.php index 7273c0c8ef..ef8637489c 100644 --- a/module/gitlab/lang/zh-cn.php +++ b/module/gitlab/lang/zh-cn.php @@ -12,7 +12,9 @@ $lang->gitlab->bindProduct = '关联产品'; $lang->gitlab->importIssue = '关联issue'; $lang->gitlab->delete = '删除GitLab'; $lang->gitlab->confirmDelete = '确认删除该GitLab吗?'; +$lang->gitlab->gitlabAvatar = '头像'; $lang->gitlab->gitlabAccount = 'GitLab用户'; +$lang->gitlab->gitlabEmail = '邮箱'; $lang->gitlab->zentaoAccount = '禅道用户'; $lang->gitlab->bindingStatus = '绑定状态'; $lang->gitlab->notBind = '未绑定'; diff --git a/module/gitlab/view/binduser.html.php b/module/gitlab/view/binduser.html.php index 8827890737..836fe3856e 100644 --- a/module/gitlab/view/binduser.html.php +++ b/module/gitlab/view/binduser.html.php @@ -17,12 +17,14 @@
    - +
    - + + + - + @@ -30,13 +32,13 @@ zentaoAccount)) continue;?> id]", $gitlabUser->realname);?> - + + @@ -45,13 +47,13 @@ zentaoAccount)) continue;?> id]", $gitlabUser->realname);?> - + + @@ -126,7 +130,7 @@ foreach(explode(',', $config->story->create->requiredFields) as $field) diff --git a/module/story/view/view.html.php b/module/story/view/view.html.php index fc1fd66e31..90392069fb 100644 --- a/module/story/view/view.html.php +++ b/module/story/view/view.html.php @@ -164,7 +164,7 @@
    gitlab->gitlabAccount;?>gitlab->gitlabAvatar;?>gitlab->gitlabAccount;?>gitlab->gitlabEmail;?> gitlab->zentaoAccount;?>gitlab->bindingStatus;?>gitlab->bindingStatus;?>
    avatar, "height=40");?>avatar, "height=40");?> realname;?>
    account;?> - email) echo " <" . $gitlabUser->email . ">";?>
    email;?> id]", $userPairs, '', "class='form-control select chosen'" );?> gitlab->notBind;?>
    avatar, "height=40");?>avatar, "height=40");?> realname;?>
    account;?> - email) echo " <" . $gitlabUser->email . ">";?>
    email;?> id]", $userPairs, $gitlabUser->zentaoAccount, "class='form-control select chosen'" );?> zentaoAccount])):?> diff --git a/module/kanban/model.php b/module/kanban/model.php index 88c2a6bcaa..7dff2257ac 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -1527,7 +1527,7 @@ class kanbanModel extends model $cardList = array(); if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory'); if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID); - if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id"); + if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID); if($browseType == 'task' and $groupBy == 'assignedTo') { diff --git a/module/mr/control.php b/module/mr/control.php index 5333cc6682..0b0bc2ef60 100644 --- a/module/mr/control.php +++ b/module/mr/control.php @@ -106,11 +106,19 @@ class mr extends control $repoID = $this->loadModel('repo')->saveState(0); $repo = $this->repo->getRepoByID($repoID); + + $this->loadModel('gitea'); + 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')); if(!$this->app->user->admin) { $gitlabUsers = $this->loadModel('gitlab')->getGitLabListByAccount(); - $giteaUsers = $this->loadModel('gitea')->getGiteaListByAccount(); + $giteaUsers = $this->gitea->getGiteaListByAccount(); foreach($hosts as $hostID => $host) { if($host->type == 'gitLab' and isset($gitlabUsers[$hostID])) continue; @@ -465,7 +473,7 @@ class mr extends control $this->view->MR = $MR; $this->view->action = $action; - $this->view->actions = $this->loadModel('action')->getList('mrapproval', $MRID); + $this->view->actions = $this->loadModel('action')->getList('mr', $MRID); $this->view->users = $this->loadModel('user')->getPairs('noletter|noclosed'); $this->display(); } @@ -524,9 +532,9 @@ class mr extends control $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', $orderBy, $storyPager); - $bugs = $this->mr->getLinkList($MRID, $product->id, 'bug', $orderBy, $bugPager); - $tasks = $this->mr->getLinkList($MRID, $product->id, 'task', $orderBy, $taskPager); + $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; @@ -575,7 +583,7 @@ class mr extends control $this->app->loadLang('productplan'); $product = $this->loadModel('product')->getById($productID); - $modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'story'); + $modules = $this->loadModel('tree')->getOptionMenu($productID, 'story'); /* Load pager. */ $this->app->loadClass('pager', $static = true); @@ -619,7 +627,7 @@ class mr extends control } else { - $allStories = $this->story->getProductStories($productID, 0, $moduleID = '0', $status = 'draft,active,changed', 'story', 'id_desc', $hasParent = false, array_keys($linkedStories), $pager); + $allStories = $this->story->getProductStories($productID, 0, '0', 'draft,active,changed', 'story', 'id_desc', false, array_keys($linkedStories), $pager); } $this->view->modules = $modules; diff --git a/module/mr/css/diff.css b/module/mr/css/diff.css index 01c74502ad..e06c5ca054 100644 --- a/module/mr/css/diff.css +++ b/module/mr/css/diff.css @@ -11,7 +11,6 @@ table.diff {margin-bottom: 0px;} .diff .line-all, .diff .line-all {background: #FFF;} .diff .w-num {width: 25px; border-right: 1px solid #E4E4E4; color: #999; border-left: 1px solid #E4E4E4; color: #999; font-weight: normal;} -.repoCode .diff tr .comment-btn .icon-wrapper {left: -23px;} .repoCode .diff tr.over td.line-all, .repoCode .diff tr.over td.line-all {background: #f8eec7;} .repoCode .diff tr.over td.line-new, .repoCode .diff tr.over td.line-new {background: #8eff8e;} .repoCode .diff tr.over td.line-old, .repoCode .diff tr.over td.line-old {background: #f6b2b2;} diff --git a/module/mr/js/create.js b/module/mr/js/create.js index ab97fc59ee..c9f9cdef18 100644 --- a/module/mr/js/create.js +++ b/module/mr/js/create.js @@ -68,6 +68,7 @@ $(function() $.get(repoUrl, function(response) { $('#repoID').html('').append(response); + $('#repoID').val(repo.id); $('#repoID').chosen().trigger("chosen:updated");; }); diff --git a/module/mr/lang/de.php b/module/mr/lang/de.php index f0046ebdd7..dde731f59d 100644 --- a/module/mr/lang/de.php +++ b/module/mr/lang/de.php @@ -119,6 +119,7 @@ $lang->mr->apiErrorMap[3] = "401 Unauthorized"; $lang->mr->apiErrorMap[4] = "403 Forbidden"; $lang->mr->apiErrorMap[5] = "/(pull request already exists for these targets).*/"; $lang->mr->apiErrorMap[6] = "Invalid PullRequest: There are no changes between the head and the base"; +$lang->mr->apiErrorMap[7] = "/(user doesn't have access to repo).*/"; $lang->mr->errorLang[1] = 'The source project branch cannot be the same as the target project branch'; $lang->mr->errorLang[2] = 'Another open merge request already exists for this source branch: ID%u'; @@ -126,6 +127,7 @@ $lang->mr->errorLang[3] = "Unauthorized"; $lang->mr->errorLang[4] = 'Permission denied'; $lang->mr->errorLang[5] = 'Another open merge request already exists for this source branch'; $lang->mr->errorLang[6] = 'The source project branch cannot be the same as the target project branch'; +$lang->mr->errorLang[7] = "user doesn't have access to repo"; $lang->mr->from = "from"; $lang->mr->to = "to"; diff --git a/module/mr/lang/en.php b/module/mr/lang/en.php index f0046ebdd7..dde731f59d 100644 --- a/module/mr/lang/en.php +++ b/module/mr/lang/en.php @@ -119,6 +119,7 @@ $lang->mr->apiErrorMap[3] = "401 Unauthorized"; $lang->mr->apiErrorMap[4] = "403 Forbidden"; $lang->mr->apiErrorMap[5] = "/(pull request already exists for these targets).*/"; $lang->mr->apiErrorMap[6] = "Invalid PullRequest: There are no changes between the head and the base"; +$lang->mr->apiErrorMap[7] = "/(user doesn't have access to repo).*/"; $lang->mr->errorLang[1] = 'The source project branch cannot be the same as the target project branch'; $lang->mr->errorLang[2] = 'Another open merge request already exists for this source branch: ID%u'; @@ -126,6 +127,7 @@ $lang->mr->errorLang[3] = "Unauthorized"; $lang->mr->errorLang[4] = 'Permission denied'; $lang->mr->errorLang[5] = 'Another open merge request already exists for this source branch'; $lang->mr->errorLang[6] = 'The source project branch cannot be the same as the target project branch'; +$lang->mr->errorLang[7] = "user doesn't have access to repo"; $lang->mr->from = "from"; $lang->mr->to = "to"; diff --git a/module/mr/lang/fr.php b/module/mr/lang/fr.php index f0046ebdd7..dde731f59d 100644 --- a/module/mr/lang/fr.php +++ b/module/mr/lang/fr.php @@ -119,6 +119,7 @@ $lang->mr->apiErrorMap[3] = "401 Unauthorized"; $lang->mr->apiErrorMap[4] = "403 Forbidden"; $lang->mr->apiErrorMap[5] = "/(pull request already exists for these targets).*/"; $lang->mr->apiErrorMap[6] = "Invalid PullRequest: There are no changes between the head and the base"; +$lang->mr->apiErrorMap[7] = "/(user doesn't have access to repo).*/"; $lang->mr->errorLang[1] = 'The source project branch cannot be the same as the target project branch'; $lang->mr->errorLang[2] = 'Another open merge request already exists for this source branch: ID%u'; @@ -126,6 +127,7 @@ $lang->mr->errorLang[3] = "Unauthorized"; $lang->mr->errorLang[4] = 'Permission denied'; $lang->mr->errorLang[5] = 'Another open merge request already exists for this source branch'; $lang->mr->errorLang[6] = 'The source project branch cannot be the same as the target project branch'; +$lang->mr->errorLang[7] = "user doesn't have access to repo"; $lang->mr->from = "from"; $lang->mr->to = "to"; diff --git a/module/mr/lang/vi.php b/module/mr/lang/vi.php index f0046ebdd7..dde731f59d 100644 --- a/module/mr/lang/vi.php +++ b/module/mr/lang/vi.php @@ -119,6 +119,7 @@ $lang->mr->apiErrorMap[3] = "401 Unauthorized"; $lang->mr->apiErrorMap[4] = "403 Forbidden"; $lang->mr->apiErrorMap[5] = "/(pull request already exists for these targets).*/"; $lang->mr->apiErrorMap[6] = "Invalid PullRequest: There are no changes between the head and the base"; +$lang->mr->apiErrorMap[7] = "/(user doesn't have access to repo).*/"; $lang->mr->errorLang[1] = 'The source project branch cannot be the same as the target project branch'; $lang->mr->errorLang[2] = 'Another open merge request already exists for this source branch: ID%u'; @@ -126,6 +127,7 @@ $lang->mr->errorLang[3] = "Unauthorized"; $lang->mr->errorLang[4] = 'Permission denied'; $lang->mr->errorLang[5] = 'Another open merge request already exists for this source branch'; $lang->mr->errorLang[6] = 'The source project branch cannot be the same as the target project branch'; +$lang->mr->errorLang[7] = "user doesn't have access to repo"; $lang->mr->from = "from"; $lang->mr->to = "to"; diff --git a/module/mr/lang/zh-cn.php b/module/mr/lang/zh-cn.php index cb129a2da4..4dbcbb1fca 100644 --- a/module/mr/lang/zh-cn.php +++ b/module/mr/lang/zh-cn.php @@ -119,6 +119,7 @@ $lang->mr->apiErrorMap[3] = "401 Unauthorized"; $lang->mr->apiErrorMap[4] = "403 Forbidden"; $lang->mr->apiErrorMap[5] = "/(pull request already exists for these targets).*/"; $lang->mr->apiErrorMap[6] = "Invalid PullRequest: There are no changes between the head and the base"; +$lang->mr->apiErrorMap[7] = "/(user doesn't have access to repo).*/"; $lang->mr->errorLang[1] = '源项目分支与目标项目分支不能相同'; $lang->mr->errorLang[2] = '存在另外一个同样的合并请求在源项目分支中: ID%u'; @@ -126,6 +127,7 @@ $lang->mr->errorLang[3] = '权限不足'; $lang->mr->errorLang[4] = '权限不足'; $lang->mr->errorLang[5] = '存在另外一个同样的合并请求在源项目分支中'; $lang->mr->errorLang[6] = '源项目分支与目标项目分支不能相同'; +$lang->mr->errorLang[7] = '您无权合并改版本库'; $lang->mr->from = "从"; $lang->mr->to = "合并到"; diff --git a/module/mr/model.php b/module/mr/model.php index a85568faaa..e0105fe73e 100644 --- a/module/mr/model.php +++ b/module/mr/model.php @@ -991,8 +991,8 @@ class mrModel extends model $apiRoot = $this->loadModel('gitea')->getApiRoot($hostID); $url = sprintf($apiRoot, "/repos/$projectID/pulls/$MRID/merge"); - $merege = ($MR and $MR->squash == '1') ? 'squash' : 'merge'; - $data = array('Do' => $merge); + $merge = ($MR and $MR->squash == '1') ? 'squash' : 'merge'; + $data = array('Do' => $merge); if($MR and $MR->removeSourceBranch == '1') $data['delete_branch_after_merge'] = true; $rowMR = json_decode(commonModel::http($url, $data, array(), array(), 'json', 'POST')); @@ -1213,7 +1213,7 @@ class mrModel extends model public function approve($MR, $action = 'approve', $comment = '') { $this->loadModel('action'); - $actionID = $this->action->create('mrapproval', $MR->id, $action); + $actionID = $this->action->create('mr', $MR->id, $action); $oldMR = $MR; if(isset($MR->status) and $MR->status == 'opened') diff --git a/module/mr/view/create.html.php b/module/mr/view/create.html.php index ee38b35821..d963aedb09 100644 --- a/module/mr/view/create.html.php +++ b/module/mr/view/create.html.php @@ -24,7 +24,7 @@ - + diff --git a/module/mr/view/linkstory.html.php b/module/mr/view/linkstory.html.php index 9e6834fa73..9b464d0574 100644 --- a/module/mr/view/linkstory.html.php +++ b/module/mr/view/linkstory.html.php @@ -47,7 +47,7 @@ - + - setCode) and $config->setCode == 1):?> + setCode) or $config->setCode == 1):?> @@ -53,7 +53,7 @@ - setCode) and $config->setCode == 1):?> + setCode) or $config->setCode == 1):?> diff --git a/module/repo/control.php b/module/repo/control.php index 84bd9ba78a..46b6837bd1 100644 --- a/module/repo/control.php +++ b/module/repo/control.php @@ -80,6 +80,7 @@ class repo extends control { $repoID = $this->repo->saveState(0, $objectID); if($this->viewType !== 'json') $this->commonAction($repoID, $objectID); + if(common::hasPriv('repo', 'create')) $this->lang->TRActions = html::a(helper::createLink('repo', 'create'), " " . $this->lang->repo->create, '', "class='btn btn-primary'"); $repoList = $this->repo->getList(0, '', $orderBy); $sonarRepoList = $this->loadModel('job')->getSonarqubeByRepo(array_keys($repoList)); diff --git a/module/repo/css/revision.css b/module/repo/css/revision.css index d6154798fc..8307c26fe6 100644 --- a/module/repo/css/revision.css +++ b/module/repo/css/revision.css @@ -1,3 +1,4 @@ .change ul {margin: 8px; margin-left: 1.5em;} .change li {list-style: none;} .panel-heading {border-bottom: 1px solid #ddd;} +.back-btn {margin-right: 5px !important;} diff --git a/module/repo/css/view.css b/module/repo/css/view.css index c82dcbb9b2..c33bb1fecf 100644 --- a/module/repo/css/view.css +++ b/module/repo/css/view.css @@ -2,7 +2,7 @@ .code .content {border: 1px solid #CCC; padding: 0;} .repoCode pre {margin: 0; padding: 0; background: white; border: none;} tr,th,td {border-bottom: none;} -.repoCode pre > table > tbody > tr > th {border: none; background-color: #ECECEC; width: 40px; text-align: right; vertical-align: top;} +.repoCode pre > table > tbody > tr > th {border-right: 1px solid #E4E4E4; width: 40px; text-align: right; vertical-align: top;} .repoCode pre > table > tbody > tr > th, .repoCode pre > table > tbody > tr > td {padding: 1px 3px;} .repoCode pre .commentContent {line-height: 1.4;} .repoCode pre > table {border: 0px; width: 100%;} diff --git a/module/repo/model.php b/module/repo/model.php index 878135438a..c5ff290a53 100644 --- a/module/repo/model.php +++ b/module/repo/model.php @@ -213,7 +213,7 @@ class repoModel extends model ->andWhere('client')->eq($data->client) ->andWhere('path')->eq($data->path) ->fetch(); - if(!empty($repo)) dao::$errors['serviceProject'] = sprintf($this->lang->error->unique, $this->lang->repo->serviceProject, $repo->id); + if(!empty($repo)) dao::$errors['serviceProject'] = sprintf($this->lang->error->unique, $this->lang->repo->serviceProject, $repo->name); if(dao::isError()) return false; } @@ -312,7 +312,7 @@ class repoModel extends model ->andWhere('path')->eq($data->path) ->andWhere('id')->ne($id) ->fetch(); - if(!empty($repo)) dao::$errors['serviceProject'] = sprintf($this->lang->error->unique, $this->lang->repo->serviceProject, $repo->id); + if(!empty($repo)) dao::$errors['serviceProject'] = sprintf($this->lang->error->unique, $this->lang->repo->serviceProject, $repo->name); if(dao::isError()) return false; } diff --git a/module/repo/view/browse.html.php b/module/repo/view/browse.html.php index 7fbff43146..29f7762e87 100644 --- a/module/repo/view/browse.html.php +++ b/module/repo/view/browse.html.php @@ -98,7 +98,7 @@ - + @@ -112,13 +112,13 @@ - + comment, ENT_QUOTES);?> diff --git a/module/repo/view/maintain.html.php b/module/repo/view/maintain.html.php index c3fb93bb70..a6ca530c45 100644 --- a/module/repo/view/maintain.html.php +++ b/module/repo/view/maintain.html.php @@ -11,11 +11,6 @@ */ ?> -
    mr->server;?>gitService, "class='form-control chosen'");?>
    mr->sourceProject;?> pri;?>' title='story->priList, $story->pri, $story->pri)?>'>story->priList, $story->pri, $story->pri)?> planTitle;?>module];?>' class='text-left'>module, '/');?> parent > 0) echo "story->children}>{$lang->story->childrenAB}"; diff --git a/module/my/model.php b/module/my/model.php index 487c1c7ecb..efd54ce73d 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -332,6 +332,7 @@ class myModel extends model ->andWhere('objectType')->eq($module) ->andWhere('action')->eq('assigned') ->fetchAll('objectID'); + if(empty($objectIDList)) return array(); $objectList = $this->dao->select('*')->from($this->config->objectTables[$module]) ->where('deleted')->eq(0) diff --git a/module/program/control.php b/module/program/control.php index 6c7f8403e6..b5eab0a13d 100644 --- a/module/program/control.php +++ b/module/program/control.php @@ -234,7 +234,7 @@ class program extends control $this->action->logHistory($actionID, $changes); } - return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse'))); + return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->session->programList ? $this->session->programList : inLink('browse'))); } $program = $this->program->getByID($programID); diff --git a/module/program/view/browse.html.php b/module/program/view/browse.html.php index 26d7fe1e81..65c7834846 100644 --- a/module/program/view/browse.html.php +++ b/module/program/view/browse.html.php @@ -43,7 +43,7 @@

    program->noProgram;?> - " . $lang->program->create, '', "class='btn btn-info'");?> + " . $lang->program->create, '', "class='btn btn-info'");?>

    diff --git a/module/programplan/model.php b/module/programplan/model.php index 7d8772b0d8..1718b6022a 100755 --- a/module/programplan/model.php +++ b/module/programplan/model.php @@ -217,8 +217,9 @@ class programplanModel extends model if(empty($selectCustom)) $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); - $tasks = array(); - $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->fetchAll('id'); + $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->fetchAll('id'); + $taskTeams = $this->dao->select('root,account')->from(TABLE_TEAM)->where('type')->eq('task')->andWhere('root')->in(array_keys($tasks))->fetchGroup('root', 'account'); + $users = $this->loadModel('user')->getPairs('noletter'); if($baselineID) { @@ -272,6 +273,15 @@ class programplanModel extends model $data->endDate = $end; $data->duration = 0; + /* If multi task then show the teams. */ + if($task->mode == 'multi' and !empty($taskTeams[$task->id])) + { + $teams = array_keys($taskTeams[$task->id]); + $assigneds = array(); + foreach($teams as $assignedTo) $assigneds[] = zget($users, $assignedTo); + $data->owner_id = join(',', $assigneds); + } + if($data->endDate > $data->start_date) $data->duration = helper::diffDate($data->endDate, $data->start_date) + 1; if($data->start_date) $data->start_date = date('d-m-Y', strtotime($data->start_date)); if($data->start_date == '' or $data->endDate == '') $data->duration = 0; diff --git a/module/programplan/view/gantt.html.php b/module/programplan/view/gantt.html.php index 98c18d897b..86c3cfe0db 100644 --- a/module/programplan/view/gantt.html.php +++ b/module/programplan/view/gantt.html.php @@ -53,6 +53,17 @@ form {display: block; margin-top: 0em; margin-block-end: 1em;} .gantt_critical_task{background:#e63030 !important; border-color:#9d3a3a !important;} .gantt_marker .gantt_marker_content {left: -15px; background-color: #f51e1e;} .gantt_row.task-item{cursor: pointer;} + +#ganttDownload, #ganttHeader {display: none;} +#ganttContainer {margin-top: 10px;} +#mainContent:before {background: #fff;} +#mainContent.loading {overflow: hidden} +#mainContent.loading #ganttView {overflow: hidden} +#mainContent.loading #ganttHeader {display: block; padding-bottom: 20px; margin: 0; height: 46px;} +#mainContent.loading #ganttDownload {display: inline} +#mainContent.loading #ganttContainer {padding: 40px;} +#mainContent.loading .scrollVer_cell, +#mainContent.loading .scrollVer_cell {display: none;} createLink('programplan', 'ajaxCustom'));?> @@ -89,7 +100,7 @@ var loadingPrefixText = 'programplan->exporting;?>'; * Get remote script for export. * * @param string $url - * @param function $sucessCallback + * @param function $successCallback * @param function $errorCallback * @access public * @return void @@ -125,7 +136,7 @@ function updateProgress(progress) * Draw gantt to canvas. * * @param string $exportType - * @param function $sucessCallback + * @param function $successCallback * @param function $errorCallback * @access public * @return void @@ -169,7 +180,17 @@ function drawGanttToCanvas(exportType, successCallback, errorCallback) height: '' }); $ganttView.css('height', oldHeight); - if(canvas) canvas.remove(); + if(canvas) + { + try + { + canvas.removeNode(true) + } + catch(err) + { + canvas.remove() + }; + } }; var delayTime = Math.max(1000, Math.floor(10 * (ganttHeight * ganttWidth) / 100000)); var progressTimer; @@ -225,7 +246,14 @@ function drawGanttToCanvas(exportType, successCallback, errorCallback) { updateProgress(0.95); var imageUrl = URL.createObjectURL(blob); - $('#ganttDownload').attr({href: imageUrl})[0].click(); + if(navigator.msSaveBlob) + { + navigator.msSaveOrOpenBlob(blob, 'gantt-export-.png'); + } + else + { + $('#ganttDownload').attr({href: imageUrl})[0].click(); + } if(successCallback) successCallback(imageUrl); afterFinish(canvas); }); @@ -249,7 +277,7 @@ function drawGanttToCanvas(exportType, successCallback, errorCallback) function exportGantt(exportType) { var $mainContent = $('#mainContent'); - $mainContent.addClass('loading').css('height', Math.max(200, Math.floor($(window).height() - $('#footer').outerHeight() - $('#header').outerHeight() - 38))); + $mainContent.addClass('loading').css('height', Math.max(200, Math.floor($(window).height() - $('#footer').outerHeight() - $('#header').outerHeight() - $('#mainMenu').outerHeight() - 38))); $('#ganttExportDate').text(new Date().format('yyyy-MM-dd hh:mm:ss')); var afterFinish = function(url) { diff --git a/module/project/model.php b/module/project/model.php index c51c9732fe..8b79a3f066 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -310,48 +310,27 @@ class projectModel extends model ->groupBy('t2.project') ->fetchAll('project'); - $leftTasks = $this->dao->select('t2.parent as project, count(*) as tasks')->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') - ->where('t2.project')->in($projectIdList) - ->andWhere('t2.deleted')->eq(0) - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t1.status')->in('wait,doing,pause') - ->groupBy('t2.project') - ->fetchPairs(); - - $allStories = $this->getTotalStoriesByProject($projectIdList, 'story'); - $doneStories = $this->getTotalStoriesByProject($projectIdList, 'story', 'closed'); - $leftStories = $this->getTotalStoriesByProject($projectIdList, 'story', 'active'); - - $leftBugs = $this->getTotalBugByProject($projectIdList, 'active'); - $allBugs = $this->getTotalBugByProject($projectIdList, 'all'); - $doneBugs = $this->getTotalBugByProject($projectIdList, 'resolved'); - - $leftTasks = $this->getTotalTaskByProject($projectIdList, 'undone'); - $allTasks = $this->getTotalTaskByProject($projectIdList, 'all'); - $waitTasks = $this->getTotalTaskByProject($projectIdList, 'wait'); - $doingTasks = $this->getTotalTaskByProject($projectIdList, 'doing'); - $rndDoneTasks = $this->getTotalTaskByProject($projectIdList, 'done'); - $liteDoneTasks = $this->getTotalTaskByProject($projectIdList, 'donelite'); + $storySummary = $this->getTotalStoriesByProject($projectIdList); + $taskSummary = $this->getTotalTaskByProject($projectIdList); + $bugSummary = $this->getTotalBugByProject($projectIdList); foreach($projects as $projectID => $project) { $project->consumed = isset($hours[$projectID]) ? (float)$hours[$projectID]->consumed : 0; $project->estimate = isset($hours[$projectID]) ? (float)$hours[$projectID]->estimate : 0; $project->teamCount = isset($teams[$projectID]) ? $teams[$projectID] : 0; - $project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0; - $project->leftBugs = isset($leftBugs[$projectID]) ? $leftBugs[$projectID] : 0; - $project->allBugs = isset($allBugs[$projectID]) ? $allBugs[$projectID] : 0; - $project->doneBugs = isset($doneBugs[$projectID]) ? $doneBugs[$projectID] : 0; - $project->allStories = isset($allStories[$projectID]) ? $allStories[$projectID] : 0; - $project->doneStories = isset($doneStories[$projectID]) ? $doneStories[$projectID] : 0; - $project->leftStories = isset($leftStories[$projectID]) ? $leftStories[$projectID] : 0; - $project->leftTasks = isset($leftTasks[$projectID]) ? $leftTasks[$projectID] : 0; - $project->allTasks = isset($allTasks[$projectID]) ? $allTasks[$projectID] : 0; - $project->waitTasks = isset($waitTasks[$projectID]) ? $waitTasks[$projectID] : 0; - $project->doingTasks = isset($doingTasks[$projectID]) ? $doingTasks[$projectID] : 0; - $project->rndDoneTasks = isset($rndDoneTasks[$projectID]) ? $rndDoneTasks[$projectID] : 0; - $project->liteDoneTasks = isset($liteDoneTasks[$projectID]) ? $liteDoneTasks[$projectID] : 0; + $project->leftBugs = isset($bugSummary[$projectID]) ? $bugSummary[$projectID]->leftBugs : 0; + $project->allBugs = isset($bugSummary[$projectID]) ? $bugSummary[$projectID]->allBugs : 0; + $project->doneBugs = isset($bugSummary[$projectID]) ? $bugSummary[$projectID]->doneBugs : 0; + $project->allStories = isset($storySummary[$projectID]) ? $storySummary[$projectID]->allStories: 0; + $project->doneStories = isset($storySummary[$projectID]) ? $storySummary[$projectID]->doneStories: 0; + $project->leftStories = isset($storySummary[$projectID]) ? $storySummary[$projectID]->leftStories: 0; + $project->leftTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->leftTasks : 0; + $project->allTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->allTasks : 0; + $project->waitTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->waitTasks : 0; + $project->doingTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->doingTasks : 0; + $project->rndDoneTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->doneTasks : 0; + $project->liteDoneTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->litedoneTasks : 0; if(is_float($project->consumed)) $project->consumed = round($project->consumed, 1); if(is_float($project->estimate)) $project->estimate = round($project->estimate, 1); @@ -364,23 +343,52 @@ class projectModel extends model * Get the number of stories associated with the project. * * @param array $projectIdList - * @param string $type story|requirement - * @param string $status all|closed|active * @access public * @return int */ - public function getTotalStoriesByProject($projectIdList = 0, $type = 'story', $status = 'all') + public function getTotalStoriesByProject($projectIdList = 0) { - return $this->dao->select('t1.project, count(t2.id) as stories')->from(TABLE_PROJECTSTORY)->alias('t1') + return $this->dao->select("t1.project, count(t2.id) as allStories, count(if(t2.status = 'active' or t2.status = 'changed', 1, null)) as leftStories, count(if(t2.status = 'closed' and t2.closedReason = 'done', 1, null)) as doneStories")->from(TABLE_PROJECTSTORY)->alias('t1') ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id') ->where('t1.project')->in($projectIdList) - ->andWhere('t2.type')->eq($type) - ->beginIF($status == 'active')->andWhere('t2.status')->in('active,changed')->fi() - ->beginIF($status == 'closed')->andWhere('t2.status')->eq('closed')->fi() - ->beginIF($status == 'closed')->andWhere('t2.closedReason')->eq('done')->fi() + ->andWhere('t2.type')->eq('story') ->andWhere('deleted')->eq('0') ->groupBy('project') - ->fetchPairs(); + ->fetchAll('project'); + } + + /** + * Get associated bugs by project. + * + * @param array $projectIdList + * @access public + * @return array + */ + public function getTotalBugByProject($projectIdList) + { + return $this->dao->select("project, count(id) as allBugs, count(if(status = 'active', 1, null)) as leftBugs, count(if(status = 'resolved', 1, null)) as doneBugs")->from(TABLE_BUG) + ->where('project')->in($projectIdList) + ->andWhere('deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + } + + /** + * Get associated tasks by project. + * + * @param array $projectIdList + * @access public + * @return array + */ + public function getTotalTaskByProject($projectIdList) + { + return $this->dao->select("t1.project, count(t1.id) as allTasks, count(if(t1.status = 'wait', 1, null)) as waitTasks, count(if(t1.status = 'doing', 1, null)) as doingTasks, count(if(t1.status = 'done', 1, null)) as doneTasks, count(if(t1.status = 'wait' or t1.status = 'pause' or t1.status = 'cancel', 1, null)) as leftTasks, count(if(t1.status = 'done' or t1.status = 'closed', 1, null)) as litedoneTasks")->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id') + ->where('t1.project')->in($projectIdList) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); } /** @@ -772,46 +780,6 @@ class projectModel extends model ->fetchPairs('id', 'name'); } - /** - * Get associated bugs by project. - * - * @param array $projectIdList - * @param string $status active|resolved|all - * @access public - * @return array - */ - public function getTotalBugByProject($projectIdList, $status) - { - return $this->dao->select('project, count(*) as bugs')->from(TABLE_BUG) - ->where('project')->in($projectIdList) - ->andWhere('deleted')->eq(0) - ->beginIF($status != 'all')->andWhere('status')->eq($status)->fi() - ->groupBy('project') - ->fetchPairs('project'); - } - - /** - * Get associated tasks by project. - * - * @param array $projectIdList - * @param string $status all|done|undone - * @access public - * @return array - */ - public function getTotalTaskByProject($projectIdList, $status) - { - return $this->dao->select('t1.project, count(t1.id) as tasks')->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id') - ->where('t1.project')->in($projectIdList) - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t2.deleted')->eq(0) - ->beginIF($status == 'donelite')->andWhere('t1.status')->in('done,closed')->fi() - ->beginIF($status == 'undone')->andWhere('t1.status')->in('wait,pause,cancel')->fi() - ->beginIF(strpos(',wait,doing,done,', ",$status,") !== false)->andWhere('t1.status')->eq($status)->fi() - ->groupBy('t1.project') - ->fetchPairs('project'); - } - /** * Get branches by project id. * diff --git a/module/project/view/batchedit.html.php b/module/project/view/batchedit.html.php index 2a3674c3d3..da24f8b8ed 100644 --- a/module/project/view/batchedit.html.php +++ b/module/project/view/batchedit.html.php @@ -26,7 +26,7 @@
    idAB;?> project->parent;?> project->name;?>project->code;?> project->PM;?>parent, "class='form-control chosen' data-id='$projectID' data-name='{$project->name}' data-parent='{$project->parent}'");?> name, "class='form-control'");?>code, "class='form-control'");?> PM, "class='form-control chosen'");?>
    repo->name?>repo->revisions?>repo->revisions?> repo->time?> repo->committer?> repo->comment?> - name, '/'); - $link = $info->kind == 'dir' ? $this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID&path=" . $this->repo->encodePath($infoPath)) : $this->repo->createLink('view', "repoID=$repoID&objectID=$objectID&entry=" . $this->repo->encodePath($infoPath)); - echo html::a($link, $info->name, '', "title='{$info->name}' data-app={$app->tab}"); - ?> + name, '/'); + $link = $info->kind == 'dir' ? $this->repo->createLink('browse', "repoID=$repoID&branchID=$base64BranchID&objectID=$objectID&path=" . $this->repo->encodePath($infoPath)) : $this->repo->createLink('view', "repoID=$repoID&objectID=$objectID&entry=" . $this->repo->encodePath($infoPath)); + echo html::a($link, $info->name, '', "title='{$info->name}' data-app={$app->tab}"); + ?> SCM == 'Subversion' ? $info->revision : substr($info->revision, 0, 10);?>SCM == 'Subversion' ? $info->revision : substr($info->revision, 0, 10);?> date, 0, 10)?> account?>
    @@ -27,13 +22,13 @@ - + - + session->revisionList != false ? $app->session->revisionList : $this->repo->createLink('browse', "repoID={$repoID}&branchID=" . helper::safe64Encode(base64_encode($branchID)) . "&objectID=$objectID{$preDir}");?> - " . $lang->goback, '', "class='btn btn-link'");?> + " . $lang->goback, '', "class='btn btn-link back-btn'");?>
    @@ -42,8 +42,8 @@ $typeInfo = $type == 'file' ? '&type=file' : '';
    repo->name); ?> repo->product); ?> repo->path; ?>actions; ?>actions; ?>
    id; ?>id; ?> repo->scmList, $repo->SCM); ?> createLink('repo', 'browse', "repoID={$repo->id}&branchID=&objectID=$objectID"), $repo->name);?>
    $change):?> - - + +
    " . $change['action'] . ' ' . $path?>" . $change['action'] . ' ' . $path;?>
    @@ -54,30 +54,30 @@ $typeInfo = $type == 'file' ? '&type=file' : '';
    -
    repo->info?>
    +
    repo->info;?>
    - - + + - - + + SCM != 'Subversion'):?> - - + + - - + + - - + +
    repo->committer?>committer?>repo->committer;?>committer;?>
    repo->revisionA?>revision?>repo->revisionA;?>revision, 0, 10);?>
    repo->commit?>commit?>repo->commit;?>commit;?>
    repo->comment?>comment?>repo->comment;?>comment;?>
    repo->time?>time?>repo->time;?>time;?>
    @@ -87,8 +87,8 @@ $typeInfo = $type == 'file' ? '&type=file' : '';
    diff --git a/module/story/css/create.css b/module/story/css/create.css index 1a2fa994f9..1e646d9c98 100644 --- a/module/story/css/create.css +++ b/module/story/css/create.css @@ -10,3 +10,9 @@ #dataform .priBox, #dataform .estimateBox {width: 120px;} #dataform .categoryBox {width: 150px;} #dataform .needNotReviewBox {width: 130px;} +.input-group-addon.assignedTo {min-width: 77px;} +.input-group .source {display: flex; width: 50%;} +.input-group .sourceNote {display: flex; width: 50%;} +.source .input-group-addon, .sourceNote .input-group-addon {padding-top: 9px;} +#sourceNoteBox {width: 80px;} +#moduleIdBox .input-group-addon {min-width: 77px;} diff --git a/module/story/view/create.html.php b/module/story/view/create.html.php index cf519dbeda..9b485e3d92 100644 --- a/module/story/view/create.html.php +++ b/module/story/view/create.html.php @@ -90,12 +90,16 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
    -
    -
    story->source;?>
    - story->sourceList, $source, "class='form-control chosen'");?> - story->sourceNote;?> - - +
    +
    +
    story->source;?>
    + story->sourceList, $source, "class='form-control chosen'");?> +
    +
    +
    story->sourceNote;?>
    + + +
    ' id='assignedToBox' class='hidden'>
    -
    story->assignedTo;?>
    +
    story->assignedTo;?>
    id;?> pri . "'>"; + echo ""; echo $child->pri == '0' ? '' : zget($this->lang->story->priList, $child->pri, $child->pri); echo ""; ?> diff --git a/module/task/config.php b/module/task/config.php index 60c00fe4b9..3a374318a8 100644 --- a/module/task/config.php +++ b/module/task/config.php @@ -116,7 +116,7 @@ $config->task->datatable->fieldList['left']['required'] = 'no'; $config->task->datatable->fieldList['progress']['title'] = 'progressAB'; $config->task->datatable->fieldList['progress']['fixed'] = 'no'; -$config->task->datatable->fieldList['progress']['width'] = '50'; +$config->task->datatable->fieldList['progress']['width'] = '80'; $config->task->datatable->fieldList['progress']['required'] = 'no'; $config->task->datatable->fieldList['progress']['sort'] = 'no'; $config->task->datatable->fieldList['progress']['name'] = $lang->task->progress; diff --git a/module/task/js/edit.js b/module/task/js/edit.js index 97606c1f2e..d0571552fa 100644 --- a/module/task/js/edit.js +++ b/module/task/js/edit.js @@ -12,12 +12,7 @@ $(function() */ function loadAll(executionID) { - if(!changeExecutionConfirmed) - { - firstChoice = confirm(confirmChangeExecution); - changeExecutionConfirmed = true; // Only notice the user one time. - } - if(changeExecutionConfirmed && firstChoice) + if(confirm(confirmChangeExecution)) { loadModuleMenu(executionID); loadExecutionStories(executionID); diff --git a/module/task/lang/de.php b/module/task/lang/de.php index 6bd4ae30b7..8582573fd3 100644 --- a/module/task/lang/de.php +++ b/module/task/lang/de.php @@ -49,7 +49,7 @@ $lang->task->case = 'Fall'; $lang->task->confirmStoryChange = "Storyäanderung bestätigen"; $lang->task->storyChange = "Story Changed"; $lang->task->progress = 'Fortschritt'; -$lang->task->progressAB = '%'; +$lang->task->progressAB = 'Fortschritt'; $lang->task->progressTips = 'Genutzt/(Genutzt+Rest)'; $lang->task->copy = 'Aufgabe kopieren'; $lang->task->waitTask = 'Waiting Task'; diff --git a/module/task/lang/en.php b/module/task/lang/en.php index 3561bfae37..df6caac102 100755 --- a/module/task/lang/en.php +++ b/module/task/lang/en.php @@ -49,7 +49,7 @@ $lang->task->case = 'Linked Case'; $lang->task->confirmStoryChange = "Confirm Change"; $lang->task->storyChange = "Story Changed"; $lang->task->progress = 'Progress'; -$lang->task->progressAB = '%'; +$lang->task->progressAB = 'Progress'; $lang->task->progressTips = 'Cost/(Cost+Left)'; $lang->task->copy = 'Copy Task'; $lang->task->waitTask = 'Waiting Task'; diff --git a/module/task/lang/fr.php b/module/task/lang/fr.php index eb892c7518..630fe3fc71 100644 --- a/module/task/lang/fr.php +++ b/module/task/lang/fr.php @@ -49,7 +49,7 @@ $lang->task->case = 'Associée CasTest'; $lang->task->confirmStoryChange = "Confirmer Changement"; $lang->task->storyChange = "Story Changée"; $lang->task->progress = 'Progression'; -$lang->task->progressAB = '%'; +$lang->task->progressAB = 'Progression'; $lang->task->progressTips = 'Coût/(Coût+Reste)'; $lang->task->copy = 'Copier Tâche'; $lang->task->waitTask = 'Tâche en attente'; diff --git a/module/task/lang/vi.php b/module/task/lang/vi.php index e4f03617e6..488a1fccea 100644 --- a/module/task/lang/vi.php +++ b/module/task/lang/vi.php @@ -47,7 +47,7 @@ $lang->task->case = 'Tình huống liên kết'; $lang->task->confirmStoryChange = "Xác nhận thay đổi"; $lang->task->storyChange = "Câu chuyện đã thay đổi"; $lang->task->progress = 'Tiến độ'; -$lang->task->progressAB = '%'; +$lang->task->progressAB = 'Tiến độ'; $lang->task->progressTips = 'Đã làm/(Đã làm + Còn lại)'; $lang->task->copy = 'Copy nhiệm vụ'; $lang->task->waitTask = 'Đang đợi nhiệm vụ'; diff --git a/module/task/view/edit.html.php b/module/task/view/edit.html.php index b1219baecd..ca510701c1 100644 --- a/module/task/view/edit.html.php +++ b/module/task/view/edit.html.php @@ -23,7 +23,6 @@ team);?> task->confirmChangeExecution);?> - team) < 6 ? 6 - count($task->team) : 1);?> task->error->teamMember);?> lang->task->error->leftEmptyAB, $this->lang->task->statusList[$task->status]));?> diff --git a/module/user/model.php b/module/user/model.php index f1d309d6ad..034d190f21 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -2812,7 +2812,7 @@ class userModel extends model public function getPersonalData($account = '') { if(empty($account)) $account = $this->app->user->account; - $count = 'count(*) AS count'; + $count = 'count(id) AS count'; $personalData = array(); $personalData['createdTodos'] = $this->dao->select($count)->from(TABLE_TODO)->where('account')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); @@ -2823,13 +2823,13 @@ class userModel extends model $personalData['createdCases'] = $this->dao->select($count)->from(TABLE_CASE)->where('openedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); if($this->config->edition == 'max') { - $personalData['createdRisks'] = $this->dao->select($count)->from(TABLE_RISK)->where('createdBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); - $personalData['resolvedRisks'] = $this->dao->select($count)->from(TABLE_RISK)->where('resolvedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); - $personalData['createdIssues'] = $this->dao->select($count)->from(TABLE_ISSUE)->where('createdBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); - $personalData['resolvedIssues'] = $this->dao->select($count)->from(TABLE_ISSUE)->where('resolvedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); + $personalData['createdRisks'] = $this->dao->select($count)->from(TABLE_RISK)->where('createdBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); + $personalData['resolvedRisks'] = $this->dao->select($count)->from(TABLE_RISK)->where('resolvedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); + $personalData['createdIssues'] = $this->dao->select($count)->from(TABLE_ISSUE)->where('createdBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); + $personalData['resolvedIssues'] = $this->dao->select($count)->from(TABLE_ISSUE)->where('resolvedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); } - $personalData['createdDocs'] = $this->dao->select($count)->from(TABLE_DOC)->where('addedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); - $personalData['finishedTasks'] = $this->dao->select($count)->from(TABLE_TASK)->where('deleted')->eq('0') + $personalData['createdDocs'] = $this->dao->select($count)->from(TABLE_DOC)->where('addedBy')->eq($account)->andWhere('deleted')->eq('0')->fetch('count'); + $personalData['finishedTasks'] = $this->dao->select($count)->from(TABLE_TASK)->where('deleted')->eq('0') ->andWhere('finishedBy', true)->eq($account) ->orWhere('finishedList')->like("%,{$account},%") ->markRight(1)