From 82fbee89e344a18fedc2ea325611c46454b1592a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 19 Oct 2021 15:09:10 +0800 Subject: [PATCH 001/129] * add project api test. --- api/v1/entries/projects.php | 3 +- test/api/project/get.php | 23 ++++++++++++++ test/api/projects/get.php | 18 +++++++++++ test/api/projects/post.php | 61 +++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/api/project/get.php create mode 100644 test/api/projects/get.php create mode 100644 test/api/projects/post.php diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 77f9c45f28..7a09c12e44 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -57,6 +57,7 @@ class projectsEntry extends entry $fields = 'name,begin,end,products'; $this->batchSetPost($fields); + $this->setPost('code', $this->request('code', '')); $this->setPost('acl', $this->request('acl', 'private')); $this->setPost('parent', $this->request('program', 0)); $this->setPost('whitelist', $this->request('whitelist', array())); @@ -64,7 +65,7 @@ class projectsEntry extends entry $this->setPost('model', $this->request('model', 'scrum')); $control = $this->loadController('project', 'create'); - $this->requireFields('name,begin,end,products'); + $this->requireFields('name,code,begin,end,products'); $control->create($this->request('model', 'scrum')); diff --git a/test/api/project/get.php b/test/api/project/get.php new file mode 100644 index 0000000000..677e970957 --- /dev/null +++ b/test/api/project/get.php @@ -0,0 +1,23 @@ +#!/usr/bin/env php +> 0,project +获取不存在的项目 >> 404 Not found +获取错误ID的项目 >> 404 Not found + +*/ +$token = $rest->post('/tokens', array('account' => 'admin', 'password' => '123456')); +$project = $rest->get('/projects/712', array("Token" => $token->body->token)); +$zeroIdError = $rest->get('/projects/0', array("Token" => $token->body->token)); +$stringIdError = $rest->get('/projects/test', array("Token" => $token->body->token)); + +r($project) && c('200') && p('project,type', ',') && e('0,project'); // 获取条目的project和type字段 +r($zeroIdError) && c('404') && p('error') && e('404 Not found'); // 获取不存在的项目 +r($stringIdError) && c('404') && p('error') && e('404 Not found'); // 获取错误ID的项目 diff --git a/test/api/projects/get.php b/test/api/projects/get.php new file mode 100644 index 0000000000..70367f0912 --- /dev/null +++ b/test/api/projects/get.php @@ -0,0 +1,18 @@ +#!/usr/bin/env php +> 0,project + +*/ +global $token; +$projects = $rest->get('/projects', array("Token" => $token)); + +$project = array(reset($projects->body->projects)); +r($project) && p('project,type', ',') && e('0,project'); // 获取条目的project和type字段 diff --git a/test/api/projects/post.php b/test/api/projects/post.php new file mode 100644 index 0000000000..3c8222de44 --- /dev/null +++ b/test/api/projects/post.php @@ -0,0 +1,61 @@ +#!/usr/bin/env php +> `『项目名称』` +创建失败,没有code字段 >> `『项目代号』` +创建失败,没有end字段 >> `『计划完成』` +创建成功,获取创建的name和code字段 >> test111,test222 +创建失败,获取错误信息 >> `『test111』` + +*/ +global $token; + +$postData = array(); +$postData['parent'] = '0'; +$postData['name'] = 'test111'; +$postData['code'] = ''; +$postData['PM'] = ''; +$postData['budget'] = ''; +$postData['budgetUnit'] = 'CNY'; +$postData['begin'] = date('Y-m-d'); +$postData['end'] = date('Y-m-d', time() + 10 * 24 * 3600); +$postData['days'] = '10'; +$postData['acl'] = 'private'; +$postData['auth'] = 'extend'; +$postData['model'] = 'scrum'; +$postData['products'][] = 1; +$postData['plan'][] = ''; +$postData['whitelist'][] = ''; + +$postData['name'] = ''; +$postData['code'] = 'test222'; +$noNameError = $rest->post('/projects', $postData, array("Token" => $token)); +$noNameError = $noNameError->body->error->name[0]; + +$postData['name'] = 'test111'; +$postData['code'] = ''; +$noCodeError = $rest->post('/projects', $postData, array("Token" => $token)); +$noCodeError = $noCodeError->body->error->code[0]; + +$postData['code'] = 'test222'; +$postData['end'] = ''; +$noEndError = $rest->post('/projects', $postData, array("Token" => $token)); +$noEndError = $noEndError->body->error->end[0]; + +$postData['end'] = date('Y-m-d', time() + 10 * 24 * 3600); +$project = $rest->post('/projects', $postData, array("Token" => $token)); +$error = $rest->post('/projects', $postData, array("Token" => $token)); +$error = $error->body->error->name[0]; + +r($noNameError) && p('error') && e('`『项目名称』`'); // 创建失败,没有name字段 +r($noCodeError) && p('error') && e('`『项目代号』`'); // 创建失败,没有code字段 +r($noEndError) && p('error') && e('`『计划完成』`'); // 创建失败,没有end字段 +r($project) && c('201') && p('name,code', ',') && e('test111,test222'); // 创建成功,获取创建的name和code字段 +r($error) && p('error') && e('`『test111』`'); // 创建失败,获取错误信息 From 16bd74d1bc52d3059144159353c64de091622227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 20 Oct 2021 13:25:32 +0800 Subject: [PATCH 002/129] * code for task #43333. --- api/v1/entries/user.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 8642cff4ee..614091a903 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -165,6 +165,14 @@ class userEntry extends Entry case 'contribute': $info->contribute = $this->my->getContribute(); break; + case 'rights': + $info->rights = array(); + $inAdminGroup = $this->dao->select('t1.*')->from(TABLE_USERGROUP)->alias('t1') + ->leftJoin(TABLE_GROUP)->alias('t2')->on('t1.group=t2.id') + ->where('t1.account')->eq($info->profile->account) + ->andWhere('t2.role')->eq('admin') + ->fetch(); + $info->rights['admin'] = (!empty($inAdminGroup) or $this->app->user->admin); } } From fe1f206e3d080acc48b92d20761e5143cb842678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 20 Oct 2021 17:08:30 +0800 Subject: [PATCH 003/129] * adjust for task #43336. --- api/v1/entries/tabs.php | 45 +++++++++++ api/v1/entries/user.php | 70 ++++++++++++---- config/routes.php | 1 + module/my/model.php | 175 ++++++++++++++++++++++++++++------------ 4 files changed, 223 insertions(+), 68 deletions(-) create mode 100644 api/v1/entries/tabs.php diff --git a/api/v1/entries/tabs.php b/api/v1/entries/tabs.php new file mode 100644 index 0000000000..cdde9befac --- /dev/null +++ b/api/v1/entries/tabs.php @@ -0,0 +1,45 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class tabsEntry extends baseEntry +{ + /** + * Get tabs. + * + * @param string $moduleName work| + * @access public + * @return void + */ + public function get($moduleName) + { + $menus = array(); + if($moduleName == 'work') + { + $this->app->loadLang('my'); + $tabs = array('calendar', 'task', 'bug', 'story', 'issue', 'risk', 'myMeeting'); + + foreach($tabs as $menuKey) + { + if(!common::hasPriv('my', $menuKey)) continue; + $label = $this->lang->my->$menuKey; + if($menuKey == 'calendar') $label = $this->lang->my->calendarAction; + + $menu = new stdclass(); + $menu->code = $menuKey; + $menu->name = $label; + + $menus[] = $menu; + } + } + + $this->send(200, array('menus' => $menus)); + } +} diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 614091a903..f3fa1818ae 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -50,7 +50,8 @@ class userEntry extends Entry unset($profile->password); $info->profile = $this->format($profile, 'last:time,locked:time,birthday:date,join:date'); - $info->profile->role = array('code' => $info->profile->role, 'name' => $this->lang->user->roleList[$info->profile->role]); + $info->profile->role = array('code' => $info->profile->role, 'name' => $this->lang->user->roleList[$info->profile->role]); + $info->profile->admin = $this->lang->user->admin; if(!$fields) return $this->send(200, $info); @@ -87,6 +88,7 @@ class userEntry extends Entry break; case 'task': $info->task = array('total' => 0, 'tasks' => array()); + if(!common::hasPriv('my', 'task')) break; $control = $this->loadController('my', 'task'); $control->task($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1)); @@ -95,12 +97,13 @@ class userEntry extends Entry if($data->status == 'success') { $info->task['total'] = $data->data->pager->recTotal; - $info->task['tasks'] = $data->data->tasks; + $info->task['tasks'] = array_values((array)$data->data->tasks); } break; case 'bug': $info->bug = array('total' => 0, 'bugs' => array()); + if(!common::hasPriv('my', 'bug')) break; $control = $this->loadController('my', 'bug'); $control->bug($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1)); @@ -109,53 +112,88 @@ class userEntry extends Entry if($data->status == 'success') { $info->bug['total'] = $data->data->pager->recTotal; - $info->bug['bugs'] = $data->data->bugs; + $info->bug['bugs'] = array_values((array)$data->data->bugs); } break; case 'todo': $info->todo = array('total' => 0, 'todos' => array()); + if(!common::hasPriv('my', 'todo')) break; $control = $this->loadController('my', 'todo'); - $control->todo($this->param('date', 'all'), '', 'all', 'date_desc', 0, 0, $this->param('limit', 10), 1); + $control->todo($this->param('date', 'all'), '', 'all', 'date_desc', 0, 0, $this->param('limit', 5), 1); $data = $this->getData(); if($data->status == 'success') { $info->todo['total'] = $data->data->pager->recTotal; - $info->todo['todos'] = $data->data->todos; + $info->todo['todos'] = array_values((array)$data->data->todos); + } + + break; + case 'story': + $info->story = array('total' => 0, 'stories' => array()); + if(!common::hasPriv('my', 'story')) break; + + $control = $this->loadController('my', 'story'); + $control->story($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1)); + $data = $this->getData(); + + if($data->status == 'success') + { + $info->story['total'] = $data->data->pager->recTotal; + $info->story['stories'] = array_values((array)$data->data->stories); } break; case 'issue': + $info->issue = array('total' => 0, 'issues' => array()); + if(!common::hasPriv('my', 'issue')) break; + if(!empty($this->config->maxVersion)) { - $info->issue = array('total' => 0, 'issues' => array()); - $control = $this->loadController('my', 'issue'); - $control->issue('createdBy', 'id_desc', 0, $this->param('limit', 10), 1); + $control->issue('createdBy', 'id_desc', 0, $this->param('limit', 5), 1); $data = $this->getData(); if($data->status == 'success') { $info->issue['total'] = $data->data->pager->recTotal; - $info->issue['issues'] = $data->data->issues; + $info->issue['issues'] = array_values((array)$data->data->issues); } } break; case 'risk': + $info->risk = array('total' => 0, 'risks' => array()); + if(!common::hasPriv('my', 'risk')) break; + if(!empty($this->config->maxVersion)) { - $info->risk = array('total' => 0, 'risks' => array()); - $control = $this->loadController('my', 'risk'); - $control->risk('createdBy', 'id_desc', 0, $this->param('limit', 10), 1); + $control->risk('createdBy', 'id_desc', 0, $this->param('limit', 5), 1); $data = $this->getData(); if($data->status == 'success') { $info->risk['total'] = $data->data->pager->recTotal; - $info->risk['risks'] = $data->data->risks; + $info->risk['risks'] = array_values((array)$data->data->risks); + } + } + break; + case 'meeting': + $info->meeting = array('total' => 0, 'meetings' => array()); + if(!common::hasPriv('my', 'myMeeting')) break; + + if(!empty($this->config->maxVersion)) + { + $control = $this->loadController('my', 'myMeeting'); + $control->myMeeting('futureMeeting', 'id_desc', 0, $this->param('limit', 5), 1); + $data = $this->getData(); + + if($data->status == 'success') + { + $info->meeting['total'] = $data->data->pager->recTotal; + $info->meeting['meetings'] = array_values((array)$data->data->meetings); } } break; @@ -166,13 +204,15 @@ class userEntry extends Entry $info->contribute = $this->my->getContribute(); break; case 'rights': - $info->rights = array(); $inAdminGroup = $this->dao->select('t1.*')->from(TABLE_USERGROUP)->alias('t1') ->leftJoin(TABLE_GROUP)->alias('t2')->on('t1.group=t2.id') ->where('t1.account')->eq($info->profile->account) ->andWhere('t2.role')->eq('admin') ->fetch(); - $info->rights['admin'] = (!empty($inAdminGroup) or $this->app->user->admin); + + $info->rights = array(); + $info->rights['admin'] = (!empty($inAdminGroup) or $this->app->user->admin); + $info->rights['rights'] = $this->app->user->rights['rights']; } } diff --git a/config/routes.php b/config/routes.php index c55fa34bb2..5ee9b53bb0 100644 --- a/config/routes.php +++ b/config/routes.php @@ -5,6 +5,7 @@ $routes = array(); $routes['/tokens'] = 'tokens'; +$routes['/tabs/:module'] = 'tabs'; $routes['/configurations'] = 'configs'; $routes['/configurations/:name'] = 'config'; diff --git a/module/my/model.php b/module/my/model.php index ce75ba9b1e..c79c0c1551 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -66,39 +66,61 @@ class myModel extends model public function getProducts() { $products = $this->dao->select('t1.id as id,t1.*')->from(TABLE_PRODUCT)->alias('t1') - ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id') - ->where('t1.deleted')->eq(0) - ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi() - ->orderBy('t1.order_asc') - ->fetchAll('id'); + ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id') + ->where('t1.deleted')->eq(0) + ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi() + ->orderBy('t1.order_asc') + ->fetchAll('id'); $productKeys = array_keys($products); - $stories = $this->dao->select('product, sum(estimate) AS estimateCount') - ->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('product')->in($productKeys) - ->groupBy('product') - ->fetchPairs(); + $storyGroups = $this->dao->select('id,product,status,stage,estimate') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('product')->in($productKeys) + ->groupBy('product') + ->fetchGroup('product', 'id'); + $summaryStories = array(); + foreach($storyGroups as $productID => $stories) + { + $summaryStory = new stdclass(); + $summaryStory->total = count($stories); + + $finishedTotal = 0; + $leftTotal = 0; + $estimateCount = 0; + foreach($stories as $story) + { + $estimateCount += $story->estimate; + ($story->status == 'closed' or $story->stage == 'released' or $story->stage == 'closed') ? $finishedTotal ++ : $leftTotal ++; + } + + $summaryStory->finishedTotal = $finishedTotal; + $summaryStory->leftTotal = $leftTotal; + $summaryStory->estimateCount = $estimateCount; + $summaryStory->finishedRate = $summaryStory->total == 0 ? 0 : ($finishedTotal / $summaryStory->total) * 100; + $summaryStories[$productID] = $summaryStory; + } + $plans = $this->dao->select('product, count(*) AS count') - ->from(TABLE_PRODUCTPLAN) - ->where('deleted')->eq(0) - ->andWhere('product')->in($productKeys) - ->andWhere('end')->gt(helper::now()) - ->groupBy('product') - ->fetchPairs(); + ->from(TABLE_PRODUCTPLAN) + ->where('deleted')->eq(0) + ->andWhere('product')->in($productKeys) + ->andWhere('end')->gt(helper::now()) + ->groupBy('product') + ->fetchPairs(); $releases = $this->dao->select('product, count(*) AS count') - ->from(TABLE_RELEASE) - ->where('deleted')->eq(0) - ->andWhere('product')->in($productKeys) - ->groupBy('product') - ->fetchPairs(); + ->from(TABLE_RELEASE) + ->where('deleted')->eq(0) + ->andWhere('product')->in($productKeys) + ->groupBy('product') + ->fetchPairs(); $executions = $this->dao->select('t1.product,t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id') - ->where('t1.product')->in($productKeys) - ->andWhere('t2.type')->in('stage,sprint') - ->andWhere('t2.deleted')->eq(0) - ->orderBy('t1.project') - ->fetchAll('product'); + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id') + ->where('t1.product')->in($productKeys) + ->andWhere('t2.type')->in('stage,sprint') + ->andWhere('t2.deleted')->eq(0) + ->orderBy('t1.project') + ->fetchAll('product'); foreach($executions as $key => $execuData) { $execution = $this->loadModel('execution')->getById($execuData->id); @@ -112,7 +134,11 @@ class myModel extends model $product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0; $product->releases = isset($releases[$product->id]) ? $releases[$product->id] : 0; if(isset($executions[$product->id])) $product->executions = $executions[$product->id]; - $product->storyEstimateCount = isset($stories[$product->id]) ? $stories[$product->id] : 0; + $product->storyEstimateCount = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->estimateCount : 0; + $product->storyTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->total : 0; + $product->storyFinishedTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedTotal : 0; + $product->storyLeftTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->leftTotal : 0; + $product->storyFinishedRate = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedRate : 0; if($product->status != 'closed') $unclosedCount ++; if($product->status == 'closed') unset($products[$key]); } @@ -137,22 +163,37 @@ class myModel extends model public function getDoingProjects() { $data = new stdClass(); - $doingProjects = array(); - $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc'); + $doingProjects = $this->loadModel('project')->getOverviewList('byStatus', 'doing', 'id_desc'); $maxCount = 5; - foreach($projects as $key => $project) + $myProjects = array(); + foreach($doingProjects as $key => $project) { - if($project->status == 'doing') + if($project->PM == $this->app->user->account) { - $workhour = $this->project->getWorkhour($project->id); - $projects[$key]->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0; - $doingProjects[] = $projects[$key]; - if(count($doingProjects) >= $maxCount) break; + $myProjects[$key] = $project; + unset($doingProjects[$key]); + } + if(count($myProjects) >= $maxCount) break; + } + if(count($myProjects) < $maxCount and !empty($doingProjects)) + { + foreach($doingProjects as $key => $project) + { + $myProjects[$key] = $project; + if(count($myProjects) >= $maxCount) break; } } - $data->doingCount = count($doingProjects); - $data->projects = $doingProjects; + foreach($myProjects as $key => $project) + { + $workhour = $this->project->getWorkhour($project->id); + $project->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0; + $project->delay = (helper::diffDate(helper::today(), $project->end) > 0); + $project->link = common::hasPriv('project', 'view') ? helper::createLink('project', 'view', "projectID={$project->id}") : ''; + } + + $data->doingCount = count($myProjects); + $data->projects = array_values($myProjects); return $data; } @@ -164,20 +205,36 @@ class myModel extends model */ public function getOverview() { - $allConsumed = 0; - $thisYearConsumed = 0; + $inAdminGroup = $this->dao->select('t1.*')->from(TABLE_USERGROUP)->alias('t1') + ->leftJoin(TABLE_GROUP)->alias('t2')->on('t1.group=t2.id') + ->where('t1.account')->eq($this->app->user->account) + ->andWhere('t2.role')->eq('admin') + ->fetch(); - $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc'); - $projectsConsumed = $this->project->getProjectsConsumed(array_keys($projects), 'THIS_YEAR'); - foreach($projects as $project) + $overview = new stdclass(); + if(!empty($inAdminGroup) or $this->app->user->admin) { - $allConsumed += $project->consumed; - $thisYearConsumed += $projectsConsumed[$project->id]->totalConsumed; - } + $allConsumed = 0; + $thisYearConsumed = 0; - $overview->projectTotal = count($projects); - $overview->allConsumed = $allConsumed; - $overview->thisYearConsumed = $thisYearConsumed; + $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc'); + $projectsConsumed = $this->project->getProjectsConsumed(array_keys($projects), 'THIS_YEAR'); + foreach($projects as $project) + { + $allConsumed += $project->consumed; + $thisYearConsumed += $projectsConsumed[$project->id]->totalConsumed; + } + + $overview->projectTotal = count($projects); + $overview->allConsumed = $allConsumed; + $overview->thisYearConsumed = $thisYearConsumed; + } + else + { + $overview->myTaskTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_TASK)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count'); + $overview->myStoryTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_STORY)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->andWhere('type')->eq('story')->fetch('count'); + $overview->myBugTotal = (int)$this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count'); + } return $overview; } @@ -223,7 +280,10 @@ class myModel extends model */ public function getActions() { - $actions = $this->loadModel('action')->getDynamic('all', 'today', 'date_desc'); + $this->app->loadClass('pager', $static = true); + $pager = new pager(0, 50, 1); + + $actions = $this->loadModel('action')->getDynamic('all', 'all', 'date_desc', $pager); $users = $this->loadModel('user')->getList(); $simplifyUsers = array(); @@ -237,8 +297,14 @@ class myModel extends model $simplifyUsers[$user->account] = $simplifyUser; } + $i = 1; + $maxCount = 5; + $filterActions = array(); foreach($actions as $key => $action) { + if($i > $maxCount) break; + if($action->objectType == 'user') continue; + $simplifyUser = zget($simplifyUsers, $action->actor, ''); $actionActor = $simplifyUser; if(empty($simplifyUser)) @@ -249,9 +315,12 @@ class myModel extends model $actionActor->realname = $action->actor; $actionActor->avatar = ''; } - $actions[$key]->actor = $actionActor; + + $action->actor = $actionActor; + $filterActions[] = $action; + $i++; } - return $actions; + return $filterActions; } } From 784f729a813c510e4531670802c11e6c701f4b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 21 Oct 2021 15:10:40 +0800 Subject: [PATCH 004/129] * code for task #43338. --- api/v1/entries/tabs.php | 2 +- api/v1/entries/user.php | 16 +++++++++++++++- module/user/model.php | 9 +++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/api/v1/entries/tabs.php b/api/v1/entries/tabs.php index cdde9befac..0448b012e9 100644 --- a/api/v1/entries/tabs.php +++ b/api/v1/entries/tabs.php @@ -40,6 +40,6 @@ class tabsEntry extends baseEntry } } - $this->send(200, array('menus' => $menus)); + $this->send(200, array('tabs' => $menus)); } } diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index f3fa1818ae..37dc570bae 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -51,7 +51,7 @@ class userEntry extends Entry $info->profile = $this->format($profile, 'last:time,locked:time,birthday:date,join:date'); $info->profile->role = array('code' => $info->profile->role, 'name' => $this->lang->user->roleList[$info->profile->role]); - $info->profile->admin = $this->lang->user->admin; + $info->profile->admin = strpos($this->app->company->admins, ",{$profile->account},") !== false; if(!$fields) return $this->send(200, $info); @@ -83,6 +83,20 @@ class userEntry extends Entry $info->project['projects'] = $projects->projects; } break; + case 'execution': + $info->execution = array('total' => 0, 'executions' => array()); + if(!common::hasPriv('my', 'execution')) break; + + $control = $this->loadController('my', 'execution'); + $control->execution($this->param('type', 'undone'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 5), $this->param('page', 1)); + $data = $this->getData(); + + if($data->status == 'success') + { + $info->execution['total'] = $data->data->pager->recTotal; + $info->execution['executions'] = array_values((array)$data->data->executions); + } + break; case 'actions': $info->actions = $this->my->getActions(); break; diff --git a/module/user/model.php b/module/user/model.php index 3533390f11..9290a20473 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -1082,9 +1082,9 @@ class userModel extends model /* Get all tasks and compute totalConsumed, totalLeft, totalWait, progress according to them. */ $hours = array(); - $emptyHour = array('totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0, 'waitTasks' => 0, 'assignedToMeTasks' => 0); + $emptyHour = array('totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0, 'waitTasks' => 0, 'assignedToMeTasks' => 0, 'doneTasks' => 0, 'taskTotal' => 0); $searchField = $type == 'project' ? 'project' : 'execution'; - $tasks = $this->dao->select('id, project, execution, consumed, `left`, status, assignedTo') + $tasks = $this->dao->select('id, project, execution, consumed, `left`, status, assignedTo,finishedBy') ->from(TABLE_TASK) ->where('parent')->lt(1) ->andWhere($searchField)->in($objectIdList)->fi() @@ -1095,9 +1095,11 @@ class userModel extends model foreach($tasks as $objectID => $objectTasks) { $hour = (object)$emptyHour; + $hour->taskTotal = count($objectTasks); foreach($objectTasks as $task) { if($task->status == 'wait') $hour->waitTasks += 1; + if($task->finishedBy != '') $hour->doneTasks += 1; if($task->status != 'cancel') $hour->totalConsumed += $task->consumed; if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left; if($task->assignedTo == $account) $hour->assignedToMeTasks += 1; @@ -1128,6 +1130,9 @@ class userModel extends model /* Process the hours. */ $object->progress = isset($hours[$object->id]) ? $hours[$object->id]->progress : 0; $object->waitTasks = isset($hours[$object->id]) ? $hours[$object->id]->waitTasks : 0; + $object->doneTasks = isset($hours[$object->id]) ? $hours[$object->id]->doneTasks : 0; + $object->taskTotal = isset($hours[$object->id]) ? $hours[$object->id]->taskTotal : 0; + $object->totalConsumed = isset($hours[$object->id]) ? $hours[$object->id]->totalConsumed : 0; $object->assignedToMeTasks = isset($hours[$object->id]) ? $hours[$object->id]->assignedToMeTasks : 0; if($object->project) From 5920491ee067f82f304ee1b83c534bd59d679c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 21 Oct 2021 16:22:43 +0800 Subject: [PATCH 005/129] * code for task #43339. --- api/v1/entries/todofinish.php | 32 ++++++++++++++++++++++++++++++++ api/v1/entries/todos.php | 4 ++-- config/routes.php | 5 +++-- module/todo/control.php | 2 ++ 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 api/v1/entries/todofinish.php diff --git a/api/v1/entries/todofinish.php b/api/v1/entries/todofinish.php new file mode 100644 index 0000000000..6d6f97339d --- /dev/null +++ b/api/v1/entries/todofinish.php @@ -0,0 +1,32 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class todoFinishEntry extends Entry +{ + /** + * GET method. + * + * @param int $taskID + * @access public + * @return void + */ + public function get($todoID) + { + $control = $this->loadController('todo', 'finish'); + $control->finish($todoID); + + $data = $this->getData(); + if($data->status == 'fail') return $this->sendError(400, $data->message); + + $todo = $this->loadModel('todo')->getByID($todoID); + $this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time')); + } +} diff --git a/api/v1/entries/todos.php b/api/v1/entries/todos.php index e03e26d90d..81e612c152 100644 --- a/api/v1/entries/todos.php +++ b/api/v1/entries/todos.php @@ -20,7 +20,7 @@ class todosEntry extends entry public function get() { $control = $this->loadController('my', 'todo'); - $control->todo($this->param('date', 'all'), $this->param('user', ''), $this->param('status', 'all'), $this->param('order', 'date_desc'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); + $control->todo($this->param('type', 'all'), $this->param('userID', ''), $this->param('status', 'all'), $this->param('order', 'date_desc,status,begin'), $this->param('total', 0), $this->param('limit', 100), $this->param('page', 1)); $data = $this->getData(); if(!isset($data->status)) return $this->sendError(400, 'error'); @@ -63,7 +63,7 @@ class todosEntry extends entry if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message); $todo = $this->loadModel('todo')->getByID($data->id); - + $this->send(201, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time')); } } diff --git a/config/routes.php b/config/routes.php index 5ee9b53bb0..4adf44290a 100644 --- a/config/routes.php +++ b/config/routes.php @@ -63,8 +63,9 @@ $routes['/projects/:projectID/issues'] = 'issues'; $routes['/issues'] = 'issues'; $routes['/issues/:issueID'] = 'issue'; -$routes['/todos'] = 'todos'; -$routes['/todos/:id'] = 'todo'; +$routes['/todos'] = 'todos'; +$routes['/todos/:id'] = 'todo'; +$routes['/todos/:id/finish'] = 'todoFinish'; $routes['/projects/:projectID/builds'] = 'builds'; $routes['/builds'] = 'builds'; diff --git a/module/todo/control.php b/module/todo/control.php index 0746c82942..5b207f0671 100644 --- a/module/todo/control.php +++ b/module/todo/control.php @@ -476,8 +476,10 @@ class todo extends control if($todo->type == 'task') $app = 'execution'; if($todo->type == 'story') $app = 'product'; $cancelURL = $this->server->HTTP_REFERER; + if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->idvalue), 'locate' => $confirmURL)); die(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app)); } + if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success')); if(isonlybody())die(js::reload('parent.parent')); die(js::reload('parent')); } From 96bf22be3a826afdfb1bbb53223bbb21381fcd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 21 Oct 2021 16:43:37 +0800 Subject: [PATCH 006/129] * finish task #43339. --- api/v1/entries/todoactivate.php | 32 ++++++++++++++++++++++++++++++++ config/routes.php | 7 ++++--- module/todo/control.php | 1 + 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 api/v1/entries/todoactivate.php diff --git a/api/v1/entries/todoactivate.php b/api/v1/entries/todoactivate.php new file mode 100644 index 0000000000..fe26a2ef2a --- /dev/null +++ b/api/v1/entries/todoactivate.php @@ -0,0 +1,32 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class todoActivateEntry extends Entry +{ + /** + * GET method. + * + * @param int $taskID + * @access public + * @return void + */ + public function get($todoID) + { + $control = $this->loadController('todo', 'activate'); + $control->activate($todoID); + + $data = $this->getData(); + if($data->status == 'fail') return $this->sendError(400, $data->message); + + $todo = $this->loadModel('todo')->getByID($todoID); + $this->send(200, $this->format($todo, 'assignedDate:time,finishedDate:time,closedDate:time')); + } +} diff --git a/config/routes.php b/config/routes.php index 4adf44290a..53e4fec658 100644 --- a/config/routes.php +++ b/config/routes.php @@ -63,9 +63,10 @@ $routes['/projects/:projectID/issues'] = 'issues'; $routes['/issues'] = 'issues'; $routes['/issues/:issueID'] = 'issue'; -$routes['/todos'] = 'todos'; -$routes['/todos/:id'] = 'todo'; -$routes['/todos/:id/finish'] = 'todoFinish'; +$routes['/todos'] = 'todos'; +$routes['/todos/:id'] = 'todo'; +$routes['/todos/:id/finish'] = 'todoFinish'; +$routes['/todos/:id/activate'] = 'todoActivate'; $routes['/projects/:projectID/builds'] = 'builds'; $routes['/builds'] = 'builds'; diff --git a/module/todo/control.php b/module/todo/control.php index 5b207f0671..d8dcb8f1c3 100644 --- a/module/todo/control.php +++ b/module/todo/control.php @@ -312,6 +312,7 @@ class todo extends control { $todo = $this->todo->getById($todoID); if($todo->status == 'done' or $todo->status == 'closed') $this->todo->activate($todoID); + if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success')); if(isonlybody()) die(js::reload('parent.parent')); die(js::reload('parent')); } From 43ac49410668f893380db85fd835ea6d87aa5039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 25 Oct 2021 08:42:13 +0800 Subject: [PATCH 007/129] * fix bug for loophole. --- module/action/model.php | 2 +- module/product/model.php | 13 +++++++------ module/testcase/control.php | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/module/action/model.php b/module/action/model.php index 61cf3e0d9b..3584f68631 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -69,7 +69,7 @@ class actionModel extends model $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec(); - $actionID = $this->dbh->lastInsertID(); + $actionID = $this->dao->lastInsertID(); if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType); diff --git a/module/product/model.php b/module/product/model.php index d8be0d310d..e5ca8375eb 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -145,14 +145,15 @@ class productModel extends model */ public function saveState($productID, $products) { - if($productID > 0) $this->session->set('product', (int)$productID); - if($productID == 0 and $this->cookie->lastProduct) $this->session->set('product', (int)$this->cookie->lastProduct); - if($productID == 0 and $this->session->product == '') $this->session->set('product', key($products)); + if($productID == 0 and $this->cookie->lastProduct) $productID = $this->cookie->lastProduct; + if($productID == 0 and $this->session->product == '') $productID = key($products); + $this->session->set('product', (int)$productID, $this->app->tab); + if(!isset($products[$this->session->product])) { - $product = $this->getById($productID); - if(empty($product)) $this->session->set('product', key($products)); - if($productID && strpos(",{$this->app->user->view->products},", ",{$this->session->product},") === false) $this->accessDenied(); + $productID = key($products); + $this->session->set('product', (int)$productID, $this->app->tab); + if($productID && strpos(",{$this->app->user->view->products},", ",{$productID},") === false) $this->accessDenied(); } if($this->cookie->preProductID != $productID) { diff --git a/module/testcase/control.php b/module/testcase/control.php index aed4fff98d..b9ae238cda 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -1307,7 +1307,7 @@ class testcase extends control { $cases = array(); $orderBy = " ORDER BY " . str_replace(array('|', '^A', '_'), ' ', $orderBy); - $stmt = $this->dbh->query($this->session->testcaseQueryCondition . $orderBy . ($this->post->limit ? ' LIMIT ' . $this->post->limit : '')); + $stmt = $this->dao->query($this->session->testcaseQueryCondition . $orderBy . ($this->post->limit ? ' LIMIT ' . $this->post->limit : '')); while($row = $stmt->fetch()) { $caseID = isset($row->case) ? $row->case : $row->id; From 95fde8eaca079df47413545b4697e07cf62000a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 25 Oct 2021 09:49:14 +0800 Subject: [PATCH 008/129] * code task #43342. --- api/v1/entries/executions.php | 2 +- api/v1/entries/program.php | 2 +- api/v1/entries/user.php | 12 +++++++++++- module/my/model.php | 13 +++++++++---- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 41de1524eb..720df0e3a7 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -21,7 +21,7 @@ class executionsEntry extends entry public function get($projectID = 0) { $control = $this->loadController('execution', 'all'); - $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); + $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') diff --git a/api/v1/entries/program.php b/api/v1/entries/program.php index f423487ef4..17a023d90b 100644 --- a/api/v1/entries/program.php +++ b/api/v1/entries/program.php @@ -9,6 +9,6 @@ * @version 1 * @link http://www.zentao.net */ -class ProgramEntry extends Entry +class programEntry extends Entry { } diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 37dc570bae..030090ba3e 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -66,7 +66,17 @@ class userEntry extends Entry case 'product': $info->product = array('total' => 0, 'products' => array()); - $products = $this->my->getProducts(); + $products = $this->my->getProducts('ownbyme'); + if($products) + { + $info->product['total'] = $products->allCount; + $info->product['products'] = $products->products; + } + break; + case 'undoneproduct': + $info->product = array('total' => 0, 'products' => array()); + + $products = $this->my->getProducts('undone'); if($products) { $info->product['total'] = $products->allCount; diff --git a/module/my/model.php b/module/my/model.php index c79c0c1551..da415df6a8 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -60,14 +60,17 @@ class myModel extends model /** * Get my charged products. * + * @param string $type undone|ownbyme * @access public * @return object */ - public function getProducts() + public function getProducts($type = 'undone') { $products = $this->dao->select('t1.id as id,t1.*')->from(TABLE_PRODUCT)->alias('t1') ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id') ->where('t1.deleted')->eq(0) + ->beginIF($type == 'undone')->andWhere('t1.status')->eq('normal')->fi() + ->beginIF($type == 'ownbyme')->andWhere('t1.PO')->eq($this->app->user->account)->fi() ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi() ->orderBy('t1.order_asc') ->fetchAll('id'); @@ -121,10 +124,11 @@ class myModel extends model ->andWhere('t2.deleted')->eq(0) ->orderBy('t1.project') ->fetchAll('product'); - foreach($executions as $key => $execuData) + $this->loadModel('execution'); + foreach($executions as $productID => $execution) { - $execution = $this->loadModel('execution')->getById($execuData->id); - $executions[$key]->progress = ($execution->totalConsumed + $execution->totalLeft) ? floor($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 1000) / 1000 * 100 : 0; + $execution = $this->execution->getById($execution->id); + $executions[$productID]->progress = ($execution->totalConsumed + $execution->totalLeft) ? floor($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 1000) / 1000 * 100 : 0; } $allCount = count($products); @@ -139,6 +143,7 @@ class myModel extends model $product->storyFinishedTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedTotal : 0; $product->storyLeftTotal = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->leftTotal : 0; $product->storyFinishedRate = isset($summaryStories[$product->id]) ? $summaryStories[$product->id]->finishedRate : 0; + $product->latestExecution = isset($executions[$product->id]) ? $executions[$product->id] : ''; if($product->status != 'closed') $unclosedCount ++; if($product->status == 'closed') unset($products[$key]); } From f21be3ec126a2aecbbe91d9708d2470a3239632b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 25 Oct 2021 13:53:34 +0800 Subject: [PATCH 009/129] * code for task #43341. --- api/v1/entries/user.php | 26 +++++++++++++++++++++++++- module/bug/lang/zh-cn.php | 15 +++++++++------ module/my/model.php | 2 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 030090ba3e..c543aac41d 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -135,8 +135,32 @@ class userEntry extends Entry if($data->status == 'success') { + $bugs = array(); + foreach($data->data->bugs as $bug) + { + $status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]); + if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed); + if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed); + if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs); + $bug->status = $status; + + $bugs[$bug->id] = $bug; + } + + $storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id') + ->where('t1.id')->in(array_keys($bugs)) + ->andWhere('t1.story')->ne('0') + ->andWhere('t1.storyVersion != t2.version') + ->fetchAll(); + foreach($storyChangeds as $bugID) + { + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $bugs[$bugID]->status = $status; + } + $info->bug['total'] = $data->data->pager->recTotal; - $info->bug['bugs'] = array_values((array)$data->data->bugs); + $info->bug['bugs'] = array_values($bugs); } break; diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index 8c11dead7d..fe7157f155 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -150,12 +150,15 @@ $lang->bug->assignToMeAB = '指派给我'; $lang->bug->openedByMeAB = '由我创建'; $lang->bug->resolvedByMeAB = '由我解决'; -$lang->bug->ditto = '同上'; -$lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!'; -$lang->bug->noAssigned = '未指派'; -$lang->bug->noBug = '暂时没有Bug。'; -$lang->bug->noModule = '
您现在还没有模块信息
请维护测试模块
'; -$lang->bug->delayWarning = " 延期%s天 "; +$lang->bug->ditto = '同上'; +$lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!'; +$lang->bug->noAssigned = '未指派'; +$lang->bug->noBug = '暂时没有Bug。'; +$lang->bug->noModule = '
您现在还没有模块信息
请维护测试模块
'; +$lang->bug->delayWarning = " 延期%s天 "; +$lang->bug->labelConfirmed = '已确认'; +$lang->bug->labelPostponed = '被延期'; +$lang->bug->storyChanged = '需求变动'; /* 页面标签。*/ $lang->bug->lblAssignedTo = '当前指派'; diff --git a/module/my/model.php b/module/my/model.php index da415df6a8..0b2a63a211 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -66,7 +66,7 @@ class myModel extends model */ public function getProducts($type = 'undone') { - $products = $this->dao->select('t1.id as id,t1.*')->from(TABLE_PRODUCT)->alias('t1') + $products = $this->dao->select('t1.*, t2.name as programName')->from(TABLE_PRODUCT)->alias('t1') ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id') ->where('t1.deleted')->eq(0) ->beginIF($type == 'undone')->andWhere('t1.status')->eq('normal')->fi() From 7372f327d98afa76ddfe47ff2d9dde5671c1a8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 09:41:15 +0800 Subject: [PATCH 010/129] * code for task #43565. --- api/v1/entries/langs.php | 50 ++++++++++++++++++++++++++++++++++++++++ api/v1/entries/user.php | 9 +++++++- config/routes.php | 2 ++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 api/v1/entries/langs.php diff --git a/api/v1/entries/langs.php b/api/v1/entries/langs.php new file mode 100644 index 0000000000..09e1e66947 --- /dev/null +++ b/api/v1/entries/langs.php @@ -0,0 +1,50 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class langsEntry extends entry +{ + /** + * GET method. + * + * @access public + * @return void + */ + public function get() + { + $modules = $this->param('modules', ''); + $language = $this->param('lang', ''); + + if($language and !isset($this->config->langs[$language])) return $this->sendError(400, 'Error lang parameter'); + if(empty($modules)) return $this->sendError(400, 'Need modules'); + + if($language) $this->app->setClientLang($language); + + $modules = explode(',', $modules); + foreach($modules as $module) + { + if($module == 'all') + { + foreach(glob($this->app->getModuleRoot() . '*') as $modulePath) + { + if(!is_dir($modulePath)) continue; + + $moduleName = basename($modulePath); + $this->app->loadLang($moduleName); + } + break; + } + + $this->app->loadLang($module); + } + + return $this->send(200, array('lang' => $this->lang)); + } +} diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index c543aac41d..440e9d900f 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -189,8 +189,15 @@ class userEntry extends Entry if($data->status == 'success') { + $stories = array(); + foreach($data->data->stories as $story) + { + $story->status = array('code' => $story->status, 'name' => $this->lang->story->statusList[$story->status]); + $stories[$story->id] = $story; + } + $info->story['total'] = $data->data->pager->recTotal; - $info->story['stories'] = array_values((array)$data->data->stories); + $info->story['stories'] = array_values($stories); } break; diff --git a/config/routes.php b/config/routes.php index 53e4fec658..05abfdf681 100644 --- a/config/routes.php +++ b/config/routes.php @@ -5,6 +5,8 @@ $routes = array(); $routes['/tokens'] = 'tokens'; +$routes['/langs'] = 'langs'; + $routes['/tabs/:module'] = 'tabs'; $routes['/configurations'] = 'configs'; From 0172e0106e86a76c17797b77b093dba8078a0ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 09:47:26 +0800 Subject: [PATCH 011/129] * code for task #43565. --- api/v1/entries/langs.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/langs.php b/api/v1/entries/langs.php index 09e1e66947..c1ae36bbd5 100644 --- a/api/v1/entries/langs.php +++ b/api/v1/entries/langs.php @@ -25,7 +25,8 @@ class langsEntry extends entry if($language and !isset($this->config->langs[$language])) return $this->sendError(400, 'Error lang parameter'); if(empty($modules)) return $this->sendError(400, 'Need modules'); - if($language) $this->app->setClientLang($language); + if(empty($language)) $language = 'zh-cn'; + $this->app->setClientLang($language); $modules = explode(',', $modules); foreach($modules as $module) From 7fb8c5ca8b5498548d520e613c621d5679f0a279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 10:57:52 +0800 Subject: [PATCH 012/129] * adjust for task #43565. --- api/v1/entries/langs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/entries/langs.php b/api/v1/entries/langs.php index c1ae36bbd5..a29ee1b0f8 100644 --- a/api/v1/entries/langs.php +++ b/api/v1/entries/langs.php @@ -46,6 +46,6 @@ class langsEntry extends entry $this->app->loadLang($module); } - return $this->send(200, array('lang' => $this->lang)); + return $this->send(200, $this->lang); } } From 001ca0ef8f2b372ec89f59251b6a1c9ef87574f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 15:39:46 +0800 Subject: [PATCH 013/129] * code for task #43347. --- api/v1/entries/execution.php | 11 ++++++++++- api/v1/entries/executions.php | 3 +++ api/v1/entries/projects.php | 2 ++ framework/api/entry.class.php | 24 ++++++++++++++++++++++++ module/program/model.php | 3 ++- 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php index 534b70d98f..0868abf625 100644 --- a/api/v1/entries/execution.php +++ b/api/v1/entries/execution.php @@ -36,7 +36,7 @@ class executionEntry extends Entry if(!$fields) $this->send(200, $execution); /* Set other fields. */ - $fields = explode(',', $fields); + $fields = explode(',', strtolower($fields)); foreach($fields as $field) { switch($field) @@ -50,6 +50,15 @@ class executionEntry extends Entry $execution->modules = $data->data->tree; } break; + case 'moduleoptionmenu': + $execution->moduleOptionMenu = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, 0, 'allModule'); + break; + case 'members': + $execution->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');; + break; + case 'stories': + $execution->stories = $this->loadModel('story')->getExecutionStoryPairs($executionID, 0, 0, '', 'full', 'unclosed'); + break; } } diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 720df0e3a7..9d378362aa 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -20,6 +20,8 @@ class executionsEntry extends entry */ public function get($projectID = 0) { + $returnFields = explode(',', $this->param('return', '')); + $control = $this->loadController('execution', 'all'); $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); $data = $this->getData(); @@ -30,6 +32,7 @@ class executionsEntry extends entry $result = array(); foreach($data->data->executionStats as $execution) { + if($returnFields) $execution = $this->filterFields($execution, $returnFields); $result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executions' => $result)); diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 7a09c12e44..470731ef41 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -21,6 +21,7 @@ class projectsEntry extends entry public function get($programID = 0) { if(!$programID) $programID = $this->param('program', 0); + $returnFields = explode(',', $this->param('return', '')); $control = $this->loadController('project', 'browse'); $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); @@ -32,6 +33,7 @@ class projectsEntry extends entry $result = array(); foreach($data->data->projectStats as $project) { + if($returnFields) $project = $this->filterFields($project, $returnFields); $result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index 39f469e22a..41b6284a60 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -486,6 +486,8 @@ class baseEntry $type = $field[1]; $isArray = false; + if(!isset($object->$key)) continue; + $pos = strpos($type, ']'); if($pos !== FALSE) { @@ -519,6 +521,28 @@ class baseEntry } } + /** + * Filter fields. + * + * @param object $object + * @param array $filters + * @access public + * @return object + */ + public function filterFields($object, $allowable = '') + { + if(empty($allowable)) return $object; + + $filtered = new stdclass(); + foreach($allowable as $field) + { + if(!isset($object->$field)) continue; + $filtered->$field = $object->$field; + } + + return $filtered; + } + /** * 类型转换. * Typecasting. diff --git a/module/program/model.php b/module/program/model.php index 0ba7e0cfd4..5c1ec55921 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -443,7 +443,8 @@ class programModel extends model $projectList = $this->dao->select('*')->from(TABLE_PROJECT) ->where('deleted')->eq('0') ->beginIF($this->config->systemMode == 'new')->andWhere('type')->eq('project')->fi() - ->beginIF($browseType != 'all')->andWhere('status')->eq($browseType)->fi() + ->beginIF($browseType != 'all' and $browseType != 'undone')->andWhere('status')->eq($browseType)->fi() + ->beginIF($browseType != 'undone')->andWhere('status')->in('wait,doing')->fi() ->beginIF($path)->andWhere('path')->like($path . '%')->fi() ->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('id')->in($this->app->user->view->projects)->fi() ->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('id')->in($this->app->user->view->sprints)->fi() From 089a1204f104ae3548134aec308bf403fd13c8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 16:18:35 +0800 Subject: [PATCH 014/129] * fix for return fields. --- api/v1/entries/executions.php | 2 +- api/v1/entries/projects.php | 2 +- framework/api/entry.class.php | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 9d378362aa..08409c4bf0 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -20,7 +20,7 @@ class executionsEntry extends entry */ public function get($projectID = 0) { - $returnFields = explode(',', $this->param('return', '')); + $returnFields = $this->param('return', ''); $control = $this->loadController('execution', 'all'); $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 470731ef41..2ff535b664 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -21,7 +21,7 @@ class projectsEntry extends entry public function get($programID = 0) { if(!$programID) $programID = $this->param('program', 0); - $returnFields = explode(',', $this->param('return', '')); + $returnFields = $this->param('return', ''); $control = $this->loadController('project', 'browse'); $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index 41b6284a60..8eec15e274 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -532,10 +532,12 @@ class baseEntry public function filterFields($object, $allowable = '') { if(empty($allowable)) return $object; + if(is_string($allowable)) $allowable = explode(',', $allowable); $filtered = new stdclass(); foreach($allowable as $field) { + $field = trim($field); if(!isset($object->$field)) continue; $filtered->$field = $object->$field; } From 4b31274644e41789f3f04f9d62156c5290db7aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 26 Oct 2021 16:25:25 +0800 Subject: [PATCH 015/129] * adjust for get undone product. --- api/v1/entries/user.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 440e9d900f..0f4158614e 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -56,7 +56,7 @@ class userEntry extends Entry if(!$fields) return $this->send(200, $info); /* Set other fields. */ - $fields = explode(',', $fields); + $fields = explode(',', strtolower($fields)); $this->loadModel('my'); foreach($fields as $field) @@ -74,13 +74,13 @@ class userEntry extends Entry } break; case 'undoneproduct': - $info->product = array('total' => 0, 'products' => array()); + $info->undoneProduct = array('total' => 0, 'products' => array()); $products = $this->my->getProducts('undone'); if($products) { - $info->product['total'] = $products->allCount; - $info->product['products'] = $products->products; + $info->undoneProduct['total'] = $products->allCount; + $info->undoneProduct['products'] = $products->products; } break; case 'project': From 076f32891492262d59b594f1c6882154f81e7247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 27 Oct 2021 19:58:50 +0800 Subject: [PATCH 016/129] * add lang for zentaoapp and adjust api. --- api/v1/entries/execution.php | 5 ++++- api/v1/entries/executions.php | 4 ++-- api/v1/entries/projects.php | 4 ++-- framework/api/entry.class.php | 1 + module/block/lang/zh-cn.php | 17 +++++++++++++++++ module/common/lang/zh-cn.php | 11 +++++++---- module/my/lang/zh-cn.php | 1 + module/my/model.php | 2 +- module/program/model.php | 2 +- module/project/model.php | 22 +++++++++++----------- module/todo/lang/zh-cn.php | 1 + module/user/lang/zh-cn.php | 30 ++++++++++++++++++++---------- 12 files changed, 68 insertions(+), 32 deletions(-) diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php index 0868abf625..ad0881dfbb 100644 --- a/api/v1/entries/execution.php +++ b/api/v1/entries/execution.php @@ -57,7 +57,10 @@ class executionEntry extends Entry $execution->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');; break; case 'stories': - $execution->stories = $this->loadModel('story')->getExecutionStoryPairs($executionID, 0, 0, '', 'full', 'unclosed'); + $stories = $this->loadModel('story')->getExecutionStories($executionID); + foreach($stories as $storyID => $story) $stories[$storyID] = $this->filterFields($story, 'id,title,module,pri,status,stage,estimate'); + + $execution->stories = array_values($stories); break; } } diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 08409c4bf0..594f5722cd 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -20,7 +20,7 @@ class executionsEntry extends entry */ public function get($projectID = 0) { - $returnFields = $this->param('return', ''); + $appendFields = $this->param('fields', ''); $control = $this->loadController('execution', 'all'); $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); @@ -32,7 +32,7 @@ class executionsEntry extends entry $result = array(); foreach($data->data->executionStats as $execution) { - if($returnFields) $execution = $this->filterFields($execution, $returnFields); + $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); $result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executions' => $result)); diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 2ff535b664..4ff7ba360f 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -21,7 +21,7 @@ class projectsEntry extends entry public function get($programID = 0) { if(!$programID) $programID = $this->param('program', 0); - $returnFields = $this->param('return', ''); + $appendFields = $this->param('fields', ''); $control = $this->loadController('project', 'browse'); $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); @@ -33,7 +33,7 @@ class projectsEntry extends entry $result = array(); foreach($data->data->projectStats as $project) { - if($returnFields) $project = $this->filterFields($project, $returnFields); + $project = $this->filterFields($project, 'id,name,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); $result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index 8eec15e274..7a0f698d7d 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -538,6 +538,7 @@ class baseEntry foreach($allowable as $field) { $field = trim($field); + if(empty($field)) continue; if(!isset($object->$field)) continue; $filtered->$field = $object->$field; } diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php index dbd8e2ed9f..7ce129a602 100644 --- a/module/block/lang/zh-cn.php +++ b/module/block/lang/zh-cn.php @@ -585,3 +585,20 @@ $lang->block->flowchart['project'] = array('项目经理', '创建' . $lang->exe if($config->systemMode == 'new') $lang->block->flowchart['project'] = array('项目经理', '创建项目、' . $lang->executionCommon, '维护团队', "关联需求", '分解任务', '跟踪进度'); $lang->block->flowchart['dev'] = array('研发人员', '领取任务和Bug', '设计实现方案', '更新状态', '完成任务和Bug', '提交代码'); $lang->block->flowchart['tester'] = array('测试人员', '撰写用例', '执行用例', '提交Bug', '验证Bug', '关闭Bug'); + +$lang->block->zentaoapp = new stdclass(); +$lang->block->zentaoapp->thisYearInvestment = '今年投入'; +$lang->block->zentaoapp->sinceTotalInvestment = '从使用至今,总投入'; +$lang->block->zentaoapp->myStory = '我的需求'; +$lang->block->zentaoapp->allStorySum = '需求总数'; +$lang->block->zentaoapp->storyCompleteRate = '需求完成率'; +$lang->block->zentaoapp->latestExecution = '近期执行'; +$lang->block->zentaoapp->involvedExecution = '我参与的执行'; +$lang->block->zentaoapp->mangedProduct = '负责产品'; +$lang->block->zentaoapp->involvedProject = '参与项目'; +$lang->block->zentaoapp->customIndexCard = '定制首页卡片'; +$lang->block->zentaoapp->createStory = '提需求'; +$lang->block->zentaoapp->createEffort = '记日志'; +$lang->block->zentaoapp->createDoc = '建文档'; +$lang->block->zentaoapp->createTodo = '建待办'; +$lang->block->zentaoapp->workbench = '工作台'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 3888dd0a4d..44de2a8baf 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -34,6 +34,7 @@ $lang->logout = '退出'; $lang->login = '登录'; $lang->help = '帮助'; $lang->aboutZenTao = '关于禅道'; +$lang->ztWebsite = '禅道系统网址'; $lang->profile = '个人档案'; $lang->changePassword = '修改密码'; $lang->unfoldMenu = '展开导航'; @@ -104,9 +105,10 @@ $lang->customField = '自定义表单项'; $lang->lineNumber = '行号'; $lang->tutorialConfirm = '检测到你尚未退出新手教程模式,是否现在退出?'; -$lang->preShortcutKey = '[快捷键:←]'; -$lang->nextShortcutKey = '[快捷键:→]'; -$lang->backShortcutKey = '[快捷键:Alt+↑]'; +$lang->preShortcutKey = '[快捷键:←]'; +$lang->nextShortcutKey = '[快捷键:→]'; +$lang->backShortcutKey = '[快捷键:Alt+↑]'; +$lang->shortcutOperation = '快捷操作'; $lang->select = '选择'; $lang->selectAll = '全选'; @@ -304,7 +306,8 @@ $lang->createObjects['program'] = '项目集'; $lang->createObjects['doc'] = '文档'; /* 语言 */ -$lang->lang = 'Language'; +$lang->lang = 'Language'; +$lang->setLang = '语音设置'; /* 风格列表。*/ $lang->theme = '主题'; diff --git a/module/my/lang/zh-cn.php b/module/my/lang/zh-cn.php index 6eef0eb79e..6c5335819b 100644 --- a/module/my/lang/zh-cn.php +++ b/module/my/lang/zh-cn.php @@ -3,6 +3,7 @@ global $config; /* 方法列表。*/ $lang->my->index = '首页'; +$lang->my->data = '我的数据'; $lang->my->todo = '我的待办'; $lang->my->calendar = '日程'; $lang->my->work = '待处理'; diff --git a/module/my/model.php b/module/my/model.php index 0b2a63a211..c21f4f159f 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -222,7 +222,7 @@ class myModel extends model $allConsumed = 0; $thisYearConsumed = 0; - $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc'); + $projects = $this->loadModel('project')->getOverviewList('byStatus', 'all', 'id_desc', 0); $projectsConsumed = $this->project->getProjectsConsumed(array_keys($projects), 'THIS_YEAR'); foreach($projects as $project) { diff --git a/module/program/model.php b/module/program/model.php index 5c1ec55921..af32a189a8 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -444,7 +444,7 @@ class programModel extends model ->where('deleted')->eq('0') ->beginIF($this->config->systemMode == 'new')->andWhere('type')->eq('project')->fi() ->beginIF($browseType != 'all' and $browseType != 'undone')->andWhere('status')->eq($browseType)->fi() - ->beginIF($browseType != 'undone')->andWhere('status')->in('wait,doing')->fi() + ->beginIF($browseType == 'undone')->andWhere('status')->in('wait,doing')->fi() ->beginIF($path)->andWhere('path')->like($path . '%')->fi() ->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('id')->in($this->app->user->view->projects)->fi() ->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('id')->in($this->app->user->view->sprints)->fi() diff --git a/module/project/model.php b/module/project/model.php index 24dcbda385..44358df6ad 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -286,18 +286,18 @@ class projectModel extends model $hours = $this->dao->select('t2.parent as project, sum(t1.consumed) as consumed, sum(t1.estimate) as estimate')->from(TABLE_TASK)->alias('t1') ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') - ->where('t2.parent')->in($projectIdList) + ->where('t2.project')->in($projectIdList) ->andWhere('t1.deleted')->eq(0) ->andWhere('t1.parent')->lt(1) - ->groupBy('t2.parent') + ->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.parent')->in($projectIdList) + ->where('t2.project')->in($projectIdList) ->andWhere('t1.deleted')->eq(0) ->andWhere('t1.status')->in('wait,doing,pause') - ->groupBy('t2.parent') + ->groupBy('t2.project') ->fetchPairs(); $this->loadModel('product'); @@ -412,13 +412,13 @@ class projectModel extends model { $projects = array(); - $totalConsumeds = $this->dao->select('project,ROUND(SUM(consumed), 1) AS totalConsumed') - ->from(TABLE_TASK) - ->where('project')->in($projectIdList) - ->beginIF($time == 'THIS_YEAR')->andWhere('realStarted')->ge(date("Y-01-01 00:00:00"))->fi() - ->andWhere('deleted')->eq(0) - ->andWhere('parent')->lt(1) - ->groupBy('project') + $totalConsumeds = $this->dao->select('t2.project,ROUND(SUM(t1.consumed), 1) AS totalConsumed')->from(TABLE_TASKESTIMATE)->alias('t1') + ->leftJoin(TABLE_TASK)->alias('t2')->on('t1.task=t2.id') + ->where('t2.project')->in($projectIdList) + ->beginIF($time == 'THIS_YEAR')->andWhere('LEFT(t1.`date`, 4)')->eq(date('Y'))->fi() + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t2.parent')->lt(1) + ->groupBy('t2.project') ->fetchAll('project'); foreach($projectIdList as $projectID) diff --git a/module/todo/lang/zh-cn.php b/module/todo/lang/zh-cn.php index f709d457b2..400422870f 100644 --- a/module/todo/lang/zh-cn.php +++ b/module/todo/lang/zh-cn.php @@ -112,6 +112,7 @@ $lang->todo->lblClickCreate = "点击添加待办"; $lang->todo->noTodo = '该类型没有待办事务'; $lang->todo->noAssignedTo = '被指派人不能为空'; $lang->todo->unfinishedTodo = '待办ID %s 不是完成状态,不能关闭。'; +$lang->todo->today = '今日待办'; $lang->todo->periods['all'] = '所有'; $lang->todo->periods['before'] = '未完'; diff --git a/module/user/lang/zh-cn.php b/module/user/lang/zh-cn.php index 2c4e33c843..b221554de6 100644 --- a/module/user/lang/zh-cn.php +++ b/module/user/lang/zh-cn.php @@ -186,8 +186,9 @@ $lang->user->personalData['createdIssues'] = '创建的问题数'; $lang->user->personalData['resolvedIssues'] = '解决的问题数'; $lang->user->personalData['createdDocs'] = '创建的文档数'; -$lang->user->keepLogin['on'] = '保持登录'; -$lang->user->loginWithDemoUser = '使用demo帐号登录:'; +$lang->user->keepLogin['on'] = '保持登录'; +$lang->user->loginWithDemoUser = '使用demo帐号登录:'; +$lang->user->scanToLogin = '扫一扫登录'; $lang->user->tpl = new stdclass(); $lang->user->tpl->type = '类型'; @@ -199,12 +200,16 @@ $lang->usertpl = new stdclass(); $lang->usertpl->title = '模板名称'; $lang->user->placeholder = new stdclass(); -$lang->user->placeholder->account = '英文、数字和下划线的组合,三位以上'; -$lang->user->placeholder->password1 = '六位以上'; -$lang->user->placeholder->role = '职位影响内容和用户列表的顺序。'; -$lang->user->placeholder->group = '分组决定用户的权限列表。'; -$lang->user->placeholder->commiter = '版本控制系统(subversion)中的帐号'; -$lang->user->placeholder->verify = '请输入您的系统登录密码'; +$lang->user->placeholder->account = '英文、数字和下划线的组合,三位以上'; +$lang->user->placeholder->password1 = '六位以上'; +$lang->user->placeholder->role = '职位影响内容和用户列表的顺序。'; +$lang->user->placeholder->group = '分组决定用户的权限列表。'; +$lang->user->placeholder->commiter = '版本控制系统(subversion)中的帐号'; +$lang->user->placeholder->verify = '请输入您的系统登录密码'; + +$lang->user->placeholder->loginPassword = '请输入密码'; +$lang->user->placeholder->loginAccount = '请输入用户名'; +$lang->user->placeholder->loginUrl = '请输入禅道系统网址'; $lang->user->placeholder->passwordStrength[1] = '6位以上,包含大小写字母,数字。'; $lang->user->placeholder->passwordStrength[2] = '10位以上,包含大小写字母,数字,特殊字符。'; @@ -219,6 +224,8 @@ $lang->user->error->reserved = "【ID %s】的用户名已被系统预留" $lang->user->error->weakPassword = "【ID %s】的密码强度小于系统设定。"; $lang->user->error->dangerPassword = "【ID %s】的密码不能使用【%s】这些常用若口令。"; +$lang->user->error->url = "网址不正确,请联系管理员"; +$lang->user->error->verify = "用户名或密码错误"; $lang->user->error->verifyPassword = "验证失败,请检查您的系统登录密码是否正确"; $lang->user->error->originalPassword = "原密码不正确"; $lang->user->error->companyEmpty = "公司名称不能为空!"; @@ -267,16 +274,19 @@ $lang->user->process4DB = "检测到您可能在使用一键安装包环境, $lang->user->mkdirWin = <<
-
不能创建临时目录,请确认目录%s是否存在并有操作权限。
+
不能创建临时目录,请确认目录%s是否存在并有操作权限。
Can't create tmp directory, make sure the directory %s exists and has permission to operate.
EOT; $lang->user->mkdirLinux = <<
-
不能创建临时目录,请确认目录%s是否存在并有操作权限。
+
不能创建临时目录,请确认目录%s是否存在并有操作权限。
命令为:chmod o=rwx -R %s。
Can't create tmp directory, make sure the directory %s exists and has permission to operate.
Commond: chmod o=rwx -R %s.
EOT; + +$lang->user->zentaoapp = new stdclass(); +$lang->user->zentaoapp->logout = '退出登录'; From fb17df4424b74f0456a3aa249d6f1956716ed8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 28 Oct 2021 13:12:33 +0800 Subject: [PATCH 017/129] * add upload file api. --- api/v1/entries/execution.php | 1 + api/v1/entries/files.php | 37 ++++++++++++++++++++++++++++++++++++ api/v1/entries/tasks.php | 4 ++-- config/routes.php | 2 ++ module/file/control.php | 2 +- module/my/model.php | 4 ++-- module/task/control.php | 16 ++++++++-------- 7 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 api/v1/entries/files.php diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php index ad0881dfbb..4134a3c3d3 100644 --- a/api/v1/entries/execution.php +++ b/api/v1/entries/execution.php @@ -55,6 +55,7 @@ class executionEntry extends Entry break; case 'members': $execution->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');; + unset($execution->members['']); break; case 'stories': $stories = $this->loadModel('story')->getExecutionStories($executionID); diff --git a/api/v1/entries/files.php b/api/v1/entries/files.php new file mode 100644 index 0000000000..17faf9f28f --- /dev/null +++ b/api/v1/entries/files.php @@ -0,0 +1,37 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class filesEntry extends Entry +{ + /** + * POST method. + * + * @access public + * @return void + */ + public function post() + { + $uid = $this->param('uid', ''); + + $control = $this->loadController('file', 'ajaxUpload'); + $control->ajaxUpload($uid); + + $data = $this->getData(); + + if(!$data or !isset($data->status)) return $this->send400('error'); + if(isset($data->status) and $data->status == 'error') + { + return isset($data->code) and $data->code == 404 ? $this->send404() : $this->sendError(400, $data->message); + } + + $this->send(200, array('id' => $data->id)); + } +} diff --git a/api/v1/entries/tasks.php b/api/v1/entries/tasks.php index 0a6b31ac07..160c6fce35 100644 --- a/api/v1/entries/tasks.php +++ b/api/v1/entries/tasks.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class tasksEntry extends entry +class tasksEntry extends entry { /** * GET method. @@ -71,7 +71,7 @@ class tasksEntry extends entry $this->requireFields('name,assignedTo,type,estStarted,deadline'); $control->create($executionID, $this->request('storyID', 0), $this->request('moduleID', 0), $this->request('copyTaskID', 0), $this->request('copyTodoID', 0)); - + $data = $this->getData(); if(!isset($data->id)) return $this->sendError(400, $data->message); diff --git a/config/routes.php b/config/routes.php index 05abfdf681..3bab8cee8c 100644 --- a/config/routes.php +++ b/config/routes.php @@ -9,6 +9,8 @@ $routes['/langs'] = 'langs'; $routes['/tabs/:module'] = 'tabs'; +$routes['/files'] = 'files'; + $routes['/configurations'] = 'configs'; $routes['/configurations/:name'] = 'config'; diff --git a/module/file/control.php b/module/file/control.php index ba4318d1d4..3ae7ddde32 100644 --- a/module/file/control.php +++ b/module/file/control.php @@ -79,7 +79,7 @@ class file extends control if(defined('RUN_MODE') && RUN_MODE == 'api') { $_SERVER['SCRIPT_NAME'] = 'index.php'; - die(json_encode(array('status' => 'success', 'data' => commonModel::getSysURL() . $this->config->webRoot . $url))); + die(json_encode(array('status' => 'success', 'id' => $fileID, 'data' => commonModel::getSysURL() . $this->config->webRoot . $url))); } else { diff --git a/module/my/model.php b/module/my/model.php index c21f4f159f..2e858a1e26 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -231,8 +231,8 @@ class myModel extends model } $overview->projectTotal = count($projects); - $overview->allConsumed = $allConsumed; - $overview->thisYearConsumed = $thisYearConsumed; + $overview->allConsumed = round($allConsumed, 1); + $overview->thisYearConsumed = round($thisYearConsumed, 1); } else { diff --git a/module/task/control.php b/module/task/control.php index 0c39718954..4348f64c7b 100644 --- a/module/task/control.php +++ b/module/task/control.php @@ -138,7 +138,7 @@ class task extends control $this->executeHooks($taskID); /* Return task id when call the API. */ - if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $taskID)); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $taskID)); /* If link from no head then reload. */ if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent')); @@ -300,7 +300,7 @@ class task extends control foreach($mails as $mail) $taskIDList[] = $mail->taskID; /* Return task id list when call the API. */ - if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $taskIDList)); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $taskIDList)); /* Locate the browser. */ if(!empty($iframe)) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent')); @@ -408,7 +408,7 @@ class task extends control } } - if(defined('RUN_MODE') && RUN_MODE == 'api') + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) { return $this->send(array('status' => 'success', 'data' => $taskID)); } @@ -576,7 +576,7 @@ class task extends control if(dao::isError()) { - if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError())); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError())); die(js::error(dao::getError())); } @@ -585,7 +585,7 @@ class task extends control $this->executeHooks($taskID); - if($this->viewType == 'json') return $this->send(array('result' => 'success')); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success')); if(isonlybody()) die(js::closeModal('parent.parent', 'this')); die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); } @@ -780,7 +780,7 @@ class task extends control if(dao::isError()) { - if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError())); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError())); die(js::error(dao::getError())); } @@ -808,7 +808,7 @@ class task extends control } } - if($this->viewType == 'json') return $this->send(array('result' => 'success')); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success')); if(isonlybody()) die(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}")); die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); } @@ -940,7 +940,7 @@ class task extends control $changes = $this->task->finish($taskID); if(dao::isError()) { - if($this->viewType == 'json') return $this->send(array('result' => 'fail', 'message' => dao::getError())); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError())); die(js::error(dao::getError())); } $files = $this->loadModel('file')->saveUpload('task', $taskID); From 2c3d42360c5eaee0574d2a54bda0ad816f14212b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 28 Oct 2021 16:26:16 +0800 Subject: [PATCH 018/129] * adjust for delete file session. --- api/v1/entries/file.php | 28 ++++++++++++++++++++++++++++ api/v1/entries/tasks.php | 2 +- config/routes.php | 3 ++- module/file/control.php | 7 ++++--- module/file/model.php | 2 +- module/task/model.php | 1 - 6 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 api/v1/entries/file.php diff --git a/api/v1/entries/file.php b/api/v1/entries/file.php new file mode 100644 index 0000000000..b69ed0539d --- /dev/null +++ b/api/v1/entries/file.php @@ -0,0 +1,28 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class fileEntry extends Entry +{ + /** + * PUT method. + * + * @access public + * @return void + */ + public function put($fileID) + { + $uid = $this->param('uid', ''); + $action = $this->param('action', ''); + if($action == 'remove') unset($_SESSION['album']['used'][$uid][$fileID]); + + $this->send(200, array('id' => $fileID)); + } +} diff --git a/api/v1/entries/tasks.php b/api/v1/entries/tasks.php index 160c6fce35..3f04889092 100644 --- a/api/v1/entries/tasks.php +++ b/api/v1/entries/tasks.php @@ -61,7 +61,7 @@ class tasksEntry extends entry */ public function post($executionID) { - $fields = 'name,type,assignedTo,estimate,story,parent,execution,module,pri,desc,estStarted,deadline,mailto'; + $fields = 'name,type,assignedTo,estimate,story,execution,project,module,pri,desc,estStarted,deadline,mailto,team,teamEstimate,multiple,uid'; $this->batchSetPost($fields); $assignedTo = $this->request('assignedTo'); diff --git a/config/routes.php b/config/routes.php index 3bab8cee8c..0ab76b3989 100644 --- a/config/routes.php +++ b/config/routes.php @@ -9,7 +9,8 @@ $routes['/langs'] = 'langs'; $routes['/tabs/:module'] = 'tabs'; -$routes['/files'] = 'files'; +$routes['/files'] = 'files'; +$routes['/files/:id'] = 'file'; $routes['/configurations'] = 'configs'; $routes['/configurations/:name'] = 'config'; diff --git a/module/file/control.php b/module/file/control.php index 3ae7ddde32..b36252c3c3 100644 --- a/module/file/control.php +++ b/module/file/control.php @@ -78,8 +78,9 @@ class file extends control if($uid) $_SESSION['album'][$uid][] = $fileID; if(defined('RUN_MODE') && RUN_MODE == 'api') { + if($uid) $_SESSION['album']['used'][$uid][$fileID] = $fileID; $_SERVER['SCRIPT_NAME'] = 'index.php'; - die(json_encode(array('status' => 'success', 'id' => $fileID, 'data' => commonModel::getSysURL() . $this->config->webRoot . $url))); + return $this->send(array('status' => 'success', 'id' => $fileID, 'data' => commonModel::getSysURL() . $this->config->webRoot . $url)); } else { @@ -91,7 +92,7 @@ class file extends control $error = strip_tags(sprintf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath)); if(defined('RUN_MODE') && RUN_MODE == 'api') { - die(json_encode(array('status' => 'error', 'message' => $error))); + return $this->send(array('status' => 'error', 'message' => $error)); } else { @@ -99,7 +100,7 @@ class file extends control } } } - die(json_encode(array('status' => 'error', 'message' => $this->lang->file->uploadImagesExplain))); + return $this->send(array('status' => 'error', 'message' => $this->lang->file->uploadImagesExplain)); } /** diff --git a/module/file/model.php b/module/file/model.php index 5cc061e6f7..112a8b4d6d 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -834,7 +834,7 @@ class fileModel extends model $data = new stdclass(); $data->objectID = $objectID; $data->objectType = $objectType; - $data->extra = 'editor'; + if(!defined('RUN_MODE') OR RUN_MODE != 'api') $data->extra = 'editor'; if(isset($_SESSION['album']['used'][$uid]) and $_SESSION['album']['used'][$uid]) { $this->dao->update(TABLE_FILE)->data($data)->where('id')->in($_SESSION['album']['used'][$uid])->exec(); diff --git a/module/task/model.php b/module/task/model.php index 52acee0b86..0a0606e289 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -22,7 +22,6 @@ class taskModel extends model */ public function create($executionID) { - if($this->post->estimate < 0) { dao::$errors[] = $this->lang->task->error->recordMinus; From a89fb80abcaac72e2d641714c8d072489d59f95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 29 Oct 2021 11:11:09 +0800 Subject: [PATCH 019/129] * fix bug for export testcase. --- module/testcase/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index b9ae238cda..313833643a 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -1368,7 +1368,7 @@ class testcase extends control $result = isset($results[$case->id]) ? $results[$case->id] : array(); $case->real = ''; - if(!empty($result)) + if(!empty($result) and !isset($relatedSteps[$case->id])) { $firstStep = reset($result); $case->real = $firstStep['real']; From c295854d261a165cf0df54808d8a7f9ce1d60e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 29 Oct 2021 14:01:52 +0800 Subject: [PATCH 020/129] * adjust for users api. --- api/v1/entries/user.php | 2 +- api/v1/entries/users.php | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 0f4158614e..500721942d 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -242,7 +242,7 @@ class userEntry extends Entry if(!empty($this->config->maxVersion)) { $control = $this->loadController('my', 'myMeeting'); - $control->myMeeting('futureMeeting', 'id_desc', 0, $this->param('limit', 5), 1); + $control->myMeeting('all', 'id_desc', 0, $this->param('limit', 5), 1); $data = $this->getData(); if($data->status == 'success') diff --git a/api/v1/entries/users.php b/api/v1/entries/users.php index 3401fc4781..c3ae22f01a 100644 --- a/api/v1/entries/users.php +++ b/api/v1/entries/users.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class usersEntry extends entry +class usersEntry extends entry { /** * GET method. @@ -19,22 +19,32 @@ class usersEntry extends entry */ public function get() { - $control = $this->loadController('company', 'browse'); - $control->browse('inside', 0, $this->param('type', 'bydept'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); - $data = $this->getData(); + if(!common::hasPriv('company', 'browse')) return $this->sendError(400, 'error: no company-browse priv.'); - if(isset($data->status) and $data->status == 'success') + $appendFields = $this->param('fileds', ''); + $type = $this->param('type', 'bydept'); + $limit = (int)$this->param('limit', 20); + + $pager = null; + if($limit) { - $users = $data->data->users; - $pager = $data->data->pager; - $result = array(); - foreach($users as $user) $result[] = $this->format($user, 'locked:time'); - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'users' => $result)); + $this->app->loadClass('pager', $static = true); + $pager = pager::init(0, $limit, $this->param('page', 1)); } - if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + $users = $this->loadModel('company')->getUsers($this->param('browse', 'inside'), $type, 0, 0, $this->param('order', 'id_desc'), $pager); + $result = array(); + foreach($users as $user) + { + $user = $this->filterFields($user, 'id,dept,account,realname,role,pinyin,email,' . $appendFields); + $result[] = $this->format($user, 'locked:time'); + } - return $this->sendError(400, 'error'); + $pageID = $pager ? $pager->pageID : 1; + $total = $pager ? $pager->recTotal : count($result); + $limit = $pager ? $pager->recPerPage : $total; + + return $this->send(200, array('page' => $pageID, 'total' => $total, 'limit' => $limit, 'users' => $result)); } /** From a459f5fd4797fa00c63f6e0a88656bae317dfc96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 1 Nov 2021 15:15:28 +0800 Subject: [PATCH 021/129] * fix bug for set actions. --- module/group/model.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/module/group/model.php b/module/group/model.php index db27dc620c..303f0d09b4 100644 --- a/module/group/model.php +++ b/module/group/model.php @@ -372,7 +372,10 @@ class groupModel extends model $dynamic = array(); foreach($actions['actions'] as $moduleName => $moduleActions) { - if($moduleName != 'todo' and isset($actions['views']) and !in_array($this->lang->navGroup->$moduleName, $actions['views'])) continue; + $groupName = $moduleName; + if(isset($this->lang->navGroup->$moduleName)) $groupName = $this->lang->navGroup->$moduleName; + if($moduleName == 'case') $groupName = $this->lang->navGroup->testcase; + if($groupName != 'my' and isset($actions['views']) and !in_array($groupName, $actions['views'])) continue; $dynamic[$moduleName] = $moduleActions; } From 9fba68e3672f41a2e8c29e7028fddc7888828ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 2 Nov 2021 13:44:00 +0800 Subject: [PATCH 022/129] * code for task #43768. --- api/v1/entries/reports.php | 69 ++++++++++++++++++++++++++++++++++++++ config/routes.php | 2 ++ module/report/model.php | 27 ++++++++++++++- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 api/v1/entries/reports.php diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php new file mode 100644 index 0000000000..5fdb5921fc --- /dev/null +++ b/api/v1/entries/reports.php @@ -0,0 +1,69 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class reportsEntry extends entry +{ + /** + * GET method. + * + * @access public + * @return void + */ + public function get() + { + $this->loadModel('report'); + + $fields = $this->param('fields', ''); + $dept = $this->param('dept', 0); + $account = $this->param('account', ''); + $year = $this->param('year', date('Y')); + if(empty($fields)) return $this->send(400, 'Need fields param for report.'); + + $accounts = array(); + if($account) $accounts = array($account => $account); + if(empty($accounts) and $dept) $accounts = $this->loadModel('dept')->getDeptUserPairs($dept); + + $fields = explode(',', strtolower($fields)); + $report = array(); + foreach($fields as $field) + { + $field = trim($field); + if(empty($field)) continue; + + if($field == 'projectoverview') + { + $statusOverview = $this->report->getProjectStatusOverview(array_keys($accounts)); + + $this->app->loadLang('project'); + $total = 0; + $overview = array(); + foreach($statusOverview as $status => $count) + { + $total += $count; + $statusName = zget($this->lang->project->statusList, $status); + + $overview[$status] = array(); + $overview[$status]['code'] = $status; + $overview[$status]['name'] = $statusName; + $overview[$status]['total'] = $count; + } + + $projectOverview = array(); + $projectOverview['total'] = $total; + $projectOverview['overview'] = array_values($overview); + + $report['projectOverview'] = $projectOverview; + } + } + + return $this->send(200, $report); + } +} diff --git a/config/routes.php b/config/routes.php index 0ab76b3989..312ad92c22 100644 --- a/config/routes.php +++ b/config/routes.php @@ -92,6 +92,8 @@ $routes['/risks/:id'] = 'risk'; $routes['/departments'] = 'departments'; $routes['/departments/:id'] = 'department'; +$routes['/reports'] = 'reports'; + $routes['/z/folders'] = 'zfolders'; $routes['/z/folders/:id'] = 'zfolder'; $routes['/z/files/:id'] = 'zfile'; diff --git a/module/report/model.php b/module/report/model.php index 8b01517ab1..2c7929a928 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -988,7 +988,7 @@ class reportModel extends model } /** - * Get status vverview. + * Get status overview. * * @param string $objectType * @param array $statusStat @@ -1018,6 +1018,31 @@ class reportModel extends model return $overview; } + + /** + * Get project status overview. + * + * @param array $accounts + * @access public + * @return array + */ + public function getProjectStatusOverview($accounts = array()) + { + $projectStatus = $this->dao->select('t1.id,t1.status')->from(TABLE_PROJECT)->alias('t1') + ->leftJoin(TABLE_TEAM)->alias('t2')->on("t1.id=t2.root && t2.type='project'") + ->where('t1.type')->eq('project') + ->beginIF(!empty($accounts))->where('t2.account')->in($accounts)->fi() + ->fetchPairs('id', 'status'); + + $statusOverview = array(); + foreach($projectStatus as $projectID => $status) + { + if(!isset($statusOverview[$status])) $statusOverview[$status] = 0; + $statusOverview[$status] ++; + } + + return $statusOverview; + } } /** From 420c0ab6d410d4eb48516fb7f68290ae4b0c8ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 3 Nov 2021 13:07:04 +0800 Subject: [PATCH 023/129] * code for task #43781. --- api/v1/entries/reports.php | 26 +++++++++++++++++++ module/report/model.php | 52 ++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 5fdb5921fc..5cda4e6d74 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -62,6 +62,32 @@ class reportsEntry extends entry $report['projectOverview'] = $projectOverview; } + elseif($field == 'radar') + { + $allAccounts = $this->loadModel('user')->getPairs('noletter|noclosed'); + $radarData = array('product' => 0, 'execution' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0); + $contributions = $this->report->getUserYearContributions(empty($accounts) ? array_keys($allAccounts) : $accounts, $year); + $annualDataConfig = $this->config->report->annualData; + + foreach($contributions as $objectType => $objectContributions) + { + foreach($objectContributions as $actionName => $count) + { + $radarTypes = isset($annualDataConfig['radar'][$objectType][$actionName]) ? $annualDataConfig['radar'][$objectType][$actionName] : array('other'); + foreach($radarTypes as $radarType) $radarData[$radarType] += $count; + } + } + + $radar = array(); + foreach($radarData as $radarType => $total) + { + $radar[$radarType]['code'] = $radarType; + $radar[$radarType]['name'] = $this->lang->report->annualData->radarItems[$radarType]; + $radar[$radarType]['total'] = $total; + } + + $report['radar'] = array_values($radar); + } } return $this->send(200, $report); diff --git a/module/report/model.php b/module/report/model.php index 2c7929a928..fe4d60004b 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -567,18 +567,40 @@ class reportModel extends model */ public function getUserYearContributions($accounts, $year) { - $actionGroups = array(); - foreach($this->config->report->annualData['contributions'] as $objectType => $actions) + $stmt = $this->dao->select('*')->from(TABLE_ACTION) + ->where('LEFT(date, 4)')->eq($year) + ->andWhere('objectType')->in(array_keys($this->config->report->annualData['contributions'])) + ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi() + ->orderBy('objectType,objectID,id') + ->query(); + + $filterActions = array(); + $deletedObject = array(); + while($action = $stmt->fetch()) { - $table = $this->config->objectTables[$objectType]; - $actionGroups[$objectType] = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1') - ->leftJoin($table)->alias('t2')->on("t1.objectType='$objectType' && t1.objectID=t2.id") - ->where('LEFT(t1.date, 4)')->eq($year) - ->andWhere('t1.objectType')->eq($objectType) - ->andWhere('t1.action')->in(array_keys($actions)) - ->andWhere('t2.deleted')->eq(0) - ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi() - ->fetchAll('id'); + $objectType = $action->objectType; + $objectID = $action->objectID; + $lowerAction = strtolower($action->action); + if(!isset($this->config->report->annualData['contributions'][$objectType][$lowerAction])) continue; + + if($action->action == 'deleted') $deletedObject[$objectType][$objectID] = $objectID; + if($action->action == 'undeleted') unset($deletedObject[$objectType][$objectID]); + + $filterActions[$objectType][$objectID][$action->id] = $action; + } + + foreach($deletedObject as $objectType => $idList) + { + foreach($idList as $id) unset($filterActions[$objectType][$id]); + } + + $actionGroups = array(); + foreach($filterActions as $objectType => $objectActions) + { + foreach($objectActions as $objectID => $actions) + { + foreach($actions as $action) $actionGroups[$objectType][$action->id] = $action; + } } $contributions = array(); @@ -587,9 +609,7 @@ class reportModel extends model foreach($actions as $action) { $lowerAction = strtolower($action->action); - if(!isset($this->config->report->annualData['contributions'][$objectType][$lowerAction])) continue; - - $actionName = $this->config->report->annualData['contributions'][$objectType][$lowerAction]; + $actionName = $this->config->report->annualData['contributions'][$objectType][$lowerAction]; $type = ($actionName == 'svnCommit' or $actionName == 'gitCommit') ? 'repo' : $objectType; if(!isset($contributions[$type][$actionName])) $contributions[$type][$actionName] = 0; @@ -1030,8 +1050,8 @@ class reportModel extends model { $projectStatus = $this->dao->select('t1.id,t1.status')->from(TABLE_PROJECT)->alias('t1') ->leftJoin(TABLE_TEAM)->alias('t2')->on("t1.id=t2.root && t2.type='project'") - ->where('t1.type')->eq('project') - ->beginIF(!empty($accounts))->where('t2.account')->in($accounts)->fi() + ->where('t1.type')->in($this->config->systemMode == 'classic' ? 'sprint,stage' : 'project') + ->beginIF(!empty($accounts))->andWhere('t2.account')->in($accounts)->fi() ->fetchPairs('id', 'status'); $statusOverview = array(); From 9eadf03db64e7ff01b3976076588782c4f7bcdba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 3 Nov 2021 14:55:52 +0800 Subject: [PATCH 024/129] * code for task #43777. --- api/v1/entries/projects.php | 5 +- api/v1/entries/reports.php | 143 ++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 4ff7ba360f..82ab1e6dc9 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -39,10 +39,7 @@ class projectsEntry extends entry return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); } - if(isset($data->status) and $data->status == 'fail') - { - return $this->sendError(400, $data->message); - } + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); // TODO There is no handle for 401. return $this->sendError(400, 'error'); diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 5cda4e6d74..848996f922 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -19,8 +19,6 @@ class reportsEntry extends entry */ public function get() { - $this->loadModel('report'); - $fields = $this->param('fields', ''); $dept = $this->param('dept', 0); $account = $this->param('account', ''); @@ -40,56 +38,109 @@ class reportsEntry extends entry if($field == 'projectoverview') { - $statusOverview = $this->report->getProjectStatusOverview(array_keys($accounts)); - - $this->app->loadLang('project'); - $total = 0; - $overview = array(); - foreach($statusOverview as $status => $count) - { - $total += $count; - $statusName = zget($this->lang->project->statusList, $status); - - $overview[$status] = array(); - $overview[$status]['code'] = $status; - $overview[$status]['name'] = $statusName; - $overview[$status]['total'] = $count; - } - - $projectOverview = array(); - $projectOverview['total'] = $total; - $projectOverview['overview'] = array_values($overview); - - $report['projectOverview'] = $projectOverview; + $report['projectOverview'] = $this->projectOverview($accounts); } elseif($field == 'radar') { - $allAccounts = $this->loadModel('user')->getPairs('noletter|noclosed'); - $radarData = array('product' => 0, 'execution' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0); - $contributions = $this->report->getUserYearContributions(empty($accounts) ? array_keys($allAccounts) : $accounts, $year); - $annualDataConfig = $this->config->report->annualData; - - foreach($contributions as $objectType => $objectContributions) - { - foreach($objectContributions as $actionName => $count) - { - $radarTypes = isset($annualDataConfig['radar'][$objectType][$actionName]) ? $annualDataConfig['radar'][$objectType][$actionName] : array('other'); - foreach($radarTypes as $radarType) $radarData[$radarType] += $count; - } - } - - $radar = array(); - foreach($radarData as $radarType => $total) - { - $radar[$radarType]['code'] = $radarType; - $radar[$radarType]['name'] = $this->lang->report->annualData->radarItems[$radarType]; - $radar[$radarType]['total'] = $total; - } - - $report['radar'] = array_values($radar); + $report['radar'] = $this->radar($accounts, $year); + } + elseif($field == 'projectprogress') + { + $report['projectProgress'] = $this->projectProgress(); } } return $this->send(200, $report); } + + public function projectOverview($accounts) + { + $statusOverview = $this->loadModel('report')->getProjectStatusOverview(array_keys($accounts)); + + $this->app->loadLang('project'); + $total = 0; + $overview = array(); + foreach($statusOverview as $status => $count) + { + $total += $count; + $statusName = zget($this->lang->project->statusList, $status); + + $overview[$status] = array(); + $overview[$status]['code'] = $status; + $overview[$status]['name'] = $statusName; + $overview[$status]['total'] = $count; + } + + $projectOverview = array(); + $projectOverview['total'] = $total; + $projectOverview['overview'] = array_values($overview); + + return $projectOverview; + } + + public function radar($accounts, $year) + { + $allAccounts = $this->loadModel('user')->getPairs('noletter|noclosed'); + $contributions = $this->loadModel('report')->getUserYearContributions(empty($accounts) ? array_keys($allAccounts) : $accounts, $year); + $annualDataConfig = $this->config->report->annualData; + + $radarData = array('product' => 0, 'execution' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0); + foreach($contributions as $objectType => $objectContributions) + { + foreach($objectContributions as $actionName => $count) + { + $radarTypes = isset($annualDataConfig['radar'][$objectType][$actionName]) ? $annualDataConfig['radar'][$objectType][$actionName] : array('other'); + foreach($radarTypes as $radarType) $radarData[$radarType] += $count; + } + } + + $radar = array(); + foreach($radarData as $radarType => $total) + { + $radar[$radarType]['code'] = $radarType; + $radar[$radarType]['name'] = $this->lang->report->annualData->radarItems[$radarType]; + $radar[$radarType]['total'] = $total; + } + + return array_values($radar); + } + + public function projectProgress() + { + $projects = $this->loadModel('program')->getProjectStats(0, 'all'); + $this->app->loadLang('project'); + + $processedProjects = array(); + $statusList['all']['total'] = 0; + $statusList['doing']['total'] = 0; + $statusList['wait']['total'] = 0; + $statusList['closed']['total'] = 0; + foreach($projects as $project) + { + $newProject = new stdclass(); + $newProject->id = $project->id; + $newProject->name = $project->name; + $newProject->status = $project->status; + $newProject->progress = $project->hours->progress; + $newProject->totalConsumed = $project->hours->totalConsumed; + $newProject->totalLeft = $project->hours->totalLeft; + if(isset($project->delay)) $newProject->delay = $project->delay; + + $statusList['all']['total'] += 1; + if(isset($statusList[$project->status])) $statusList[$project->status]['total'] += 1; + + $processedProjects[$project->id] = $newProject; + } + + foreach(array_keys($statusList) as $status) + { + $statusName = zget($this->lang->project->statusList, $status); + if($status == 'all') $statusName = $this->lang->project->featureBar['all']; + + $statusList[$status]['code'] = $status; + $statusList[$status]['name'] = $statusName; + } + + return array('statusList' => $statusList, 'projects' => array_values($processedProjects)); + } } From c5e9e3713e0ebc4b05559a7e146ef6b2911d1c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 3 Nov 2021 15:17:13 +0800 Subject: [PATCH 025/129] * code for task #43778. --- api/v1/entries/reports.php | 49 +++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 848996f922..6b41d15f53 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -48,6 +48,10 @@ class reportsEntry extends entry { $report['projectProgress'] = $this->projectProgress(); } + elseif($field == 'executionprogress') + { + $report['executionProgress'] = $this->executionProgress(); + } } return $this->send(200, $report); @@ -121,9 +125,9 @@ class reportsEntry extends entry $newProject->id = $project->id; $newProject->name = $project->name; $newProject->status = $project->status; - $newProject->progress = $project->hours->progress; - $newProject->totalConsumed = $project->hours->totalConsumed; - $newProject->totalLeft = $project->hours->totalLeft; + $newProject->progress = round($project->hours->progress, 1); + $newProject->totalConsumed = round($project->hours->totalConsumed, 1); + $newProject->totalLeft = round($project->hours->totalLeft, 1); if(isset($project->delay)) $newProject->delay = $project->delay; $statusList['all']['total'] += 1; @@ -143,4 +147,43 @@ class reportsEntry extends entry return array('statusList' => $statusList, 'projects' => array_values($processedProjects)); } + + public function executionProgress() + { + $executions = $this->loadModel('project')->getStats(0, 'all', 0, 0, 30, 'id_desc'); + $this->app->loadLang('execution'); + + $processedExecutions = array(); + $statusList['all']['total'] = 0; + $statusList['doing']['total'] = 0; + $statusList['wait']['total'] = 0; + $statusList['closed']['total'] = 0; + foreach($executions as $execution) + { + $newExecution = new stdclass(); + $newExecution->id = $execution->id; + $newExecution->name = $execution->name; + $newExecution->status = $execution->status; + $newExecution->progress = round($execution->hours->progress, 1); + $newExecution->totalConsumed = round($execution->hours->totalConsumed, 1); + $newExecution->totalLeft = round($execution->hours->totalLeft, 1); + if(isset($execution->delay)) $newExecution->delay = $execution->delay; + + $statusList['all']['total'] += 1; + if(isset($statusList[$execution->status])) $statusList[$execution->status]['total'] += 1; + + $processedExecutions[$execution->id] = $newExecution; + } + + foreach(array_keys($statusList) as $status) + { + $statusName = zget($this->lang->execution->statusList, $status); + if($status == 'all') $statusName = $this->lang->execution->allTasks; + + $statusList[$status]['code'] = $status; + $statusList[$status]['name'] = $statusName; + } + + return array('statusList' => $statusList, 'executions' => array_values($processedExecutions)); + } } From 7cbfe70bd436f44daff9fcc7f5fc127664d8ae5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 4 Nov 2021 10:19:50 +0800 Subject: [PATCH 026/129] * code for task #43779. --- api/v1/entries/reports.php | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 6b41d15f53..ffc37288cc 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -52,6 +52,10 @@ class reportsEntry extends entry { $report['executionProgress'] = $this->executionProgress(); } + elseif($field == 'productprogress') + { + $report['productProgress'] = $this->productProgress(); + } } return $this->send(200, $report); @@ -186,4 +190,66 @@ class reportsEntry extends entry return array('statusList' => $statusList, 'executions' => array_values($processedExecutions)); } + + public function productProgress() + { + $this->app->loadLang('product'); + $this->app->loadLang('story'); + $storyStatusStat = $this->dao->select('t1.product,t2.name,t2.status,t1.status as storyStatus,count(*) as storyCount')->from(TABLE_STORY)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->products)->fi() + ->groupBy('t1.product,t1.status') + ->orderBy('t1.product_desc,t1.status') + ->fetchAll(); + + $productStatusList['all']['total'] = 0; + $productStatusList['normal']['total'] = 0; + $productStatusList['closed']['total'] = 0; + + $processedProducts = array(); + $productStoryStat = array(); + foreach($storyStatusStat as $product) + { + $productStoryStat[$product->product][$product->storyStatus] = $product->storyCount; + + if(isset($processedProducts[$product->product])) continue; + + $newProduct = new stdclass(); + $newProduct->id = $product->product; + $newProduct->name = $product->name; + $newProduct->status = $product->status; + + $processedProducts[$product->product] = $newProduct; + $productStatusList['all']['total'] += 1; + if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1; + } + + $storyStatusList = array('draft' => array(), 'active' => array(), 'closed' => array(), 'changed' => array()); + foreach($processedProducts as $productID => $product) + { + $product->storyStat = array(); + foreach(array_keys($storyStatusList) as $storyStatus) $product->storyStat[$storyStatus] = isset($productStoryStat[$productID][$storyStatus]) ? $productStoryStat[$productID][$storyStatus] : 0; + } + + foreach(array_keys($productStatusList) as $status) + { + $statusName = zget($this->lang->product->statusList, $status); + if($status == 'all') $statusName = $this->lang->product->allStory; + + $productStatusList[$status]['code'] = $status; + $productStatusList[$status]['name'] = $statusName; + } + + foreach(array_keys($storyStatusList) as $status) + { + $statusName = zget($this->lang->story->statusList, $status); + + $storyStatusList[$status]['code'] = $status; + $storyStatusList[$status]['name'] = $statusName; + } + + return array('productStatusList' => $productStatusList, 'products' => array_values($processedProducts), 'storyStatusList' => $storyStatusList); + } } From 2d8ea6385be804fdfb7f9606c28293ee42d1bf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 4 Nov 2021 10:46:26 +0800 Subject: [PATCH 027/129] * code for task #43780. --- api/v1/entries/reports.php | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index ffc37288cc..9864f6a09d 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -56,6 +56,10 @@ class reportsEntry extends entry { $report['productProgress'] = $this->productProgress(); } + elseif($field == 'bugprogress') + { + $report['bugProgress'] = $this->bugProgress(); + } } return $this->send(200, $report); @@ -237,6 +241,7 @@ class reportsEntry extends entry { $statusName = zget($this->lang->product->statusList, $status); if($status == 'all') $statusName = $this->lang->product->allStory; + if($status == 'normal') $statusName = $this->lang->product->unclosed; $productStatusList[$status]['code'] = $status; $productStatusList[$status]['name'] = $statusName; @@ -252,4 +257,67 @@ class reportsEntry extends entry return array('productStatusList' => $productStatusList, 'products' => array_values($processedProducts), 'storyStatusList' => $storyStatusList); } + + public function bugProgress() + { + $this->app->loadLang('product'); + $this->app->loadLang('bug'); + $bugStatusStat = $this->dao->select('t1.product,t2.name,t2.status,t1.status as bugStatus,count(*) as bugCount')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->products)->fi() + ->groupBy('t1.product,t1.status') + ->orderBy('t1.product_desc,t1.status') + ->fetchAll(); + + $productStatusList['all']['total'] = 0; + $productStatusList['normal']['total'] = 0; + $productStatusList['closed']['total'] = 0; + + $processedProducts = array(); + $productBugStat = array(); + foreach($bugStatusStat as $product) + { + $productBugStat[$product->product][$product->bugStatus] = $product->bugCount; + + if(isset($processedProducts[$product->product])) continue; + + $newProduct = new stdclass(); + $newProduct->id = $product->product; + $newProduct->name = $product->name; + $newProduct->status = $product->status; + + $processedProducts[$product->product] = $newProduct; + $productStatusList['all']['total'] += 1; + if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1; + } + + $bugStatusList = array('active' => array(), 'resolved' => array(), 'closed' => array()); + foreach($processedProducts as $productID => $product) + { + $product->bugStat = array(); + foreach(array_keys($bugStatusList) as $bugStatus) $product->bugStat[$bugStatus] = isset($productBugStat[$productID][$bugStatus]) ? $productBugStat[$productID][$bugStatus] : 0; + } + + foreach(array_keys($productStatusList) as $status) + { + $statusName = zget($this->lang->product->statusList, $status); + if($status == 'all') $statusName = $this->lang->product->allStory; + if($status == 'normal') $statusName = $this->lang->product->unclosed; + + $productStatusList[$status]['code'] = $status; + $productStatusList[$status]['name'] = $statusName; + } + + foreach(array_keys($bugStatusList) as $status) + { + $statusName = zget($this->lang->bug->statusList, $status); + + $bugStatusList[$status]['code'] = $status; + $bugStatusList[$status]['name'] = $statusName; + } + + return array('productStatusList' => $productStatusList, 'bugs' => array_values($processedProducts), 'bugStatusList' => $bugStatusList); + } } From b684d521228b35c4dde4309260937b56756ddb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 4 Nov 2021 11:29:55 +0800 Subject: [PATCH 028/129] * code for task #43770. --- api/v1/entries/reports.php | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 9864f6a09d..7d415b25a9 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -60,6 +60,16 @@ class reportsEntry extends entry { $report['bugProgress'] = $this->bugProgress(); } + elseif($field == 'bugprogress') + { + $report['bugProgress'] = $this->bugProgress(); + } + elseif($field == 'output') + { + $this->loadModel('report'); + $storyStat = $this->report->getYearObjectStat($accounts, $year, 'story'); + $report['output']['story'] = $this->processStatus($storyStat['statusStat'], 'story'); + } } return $this->send(200, $report); @@ -230,7 +240,7 @@ class reportsEntry extends entry if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1; } - $storyStatusList = array('draft' => array(), 'active' => array(), 'closed' => array(), 'changed' => array()); + $storyStatusList = array('draft' => array(), 'active' => array(), 'changed' => array(), 'closed' => array()); foreach($processedProducts as $productID => $product) { $product->storyStat = array(); @@ -320,4 +330,23 @@ class reportsEntry extends entry return array('productStatusList' => $productStatusList, 'bugs' => array_values($processedProducts), 'bugStatusList' => $bugStatusList); } + + public function processStatus($statusStat, $objectType) + { + $this->app->loadLang($objectType); + + $processedStatus = array(); + $total = 0; + foreach($this->lang->$objectType->statusList as $status => $statusName) + { + if(empty($statusStat[$status])) continue; + + $processedStatus[$status]['code'] = $status; + $processedStatus[$status]['name'] = $statusName; + $processedStatus[$status]['total'] = $statusStat[$status]; + $total += $statusStat[$status]; + } + + return array('total' => $total, 'statusList' => array_values($processedStatus)); + } } From 62041f2bf3f74352616259f39482f666afa8b993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 10:15:53 +0800 Subject: [PATCH 029/129] * code task #43770,43771,43772,43773,43774,43775,43776. --- api/v1/entries/reports.php | 68 ++++++++++++++++++++++++------------ module/report/config.php | 8 +++++ module/report/lang/zh-cn.php | 4 +++ module/report/model.php | 65 ++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 23 deletions(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 7d415b25a9..75ffa215a1 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -66,15 +66,20 @@ class reportsEntry extends entry } elseif($field == 'output') { - $this->loadModel('report'); - $storyStat = $this->report->getYearObjectStat($accounts, $year, 'story'); - $report['output']['story'] = $this->processStatus($storyStat['statusStat'], 'story'); + $report['output'] = $this->loadModel('report')->getOutput4API($accounts, $year); } } return $this->send(200, $report); } + /** + * Get project overview by status. + * + * @param array $accounts + * @access public + * @return array + */ public function projectOverview($accounts) { $statusOverview = $this->loadModel('report')->getProjectStatusOverview(array_keys($accounts)); @@ -100,6 +105,14 @@ class reportsEntry extends entry return $projectOverview; } + /** + * Get radar data. include product, execution, qa, devel and other. + * + * @param array $accounts + * @param string $year + * @access public + * @return array + */ public function radar($accounts, $year) { $allAccounts = $this->loadModel('user')->getPairs('noletter|noclosed'); @@ -127,6 +140,12 @@ class reportsEntry extends entry return array_values($radar); } + /** + * Get project progress. + * + * @access public + * @return array + */ public function projectProgress() { $projects = $this->loadModel('program')->getProjectStats(0, 'all'); @@ -166,6 +185,12 @@ class reportsEntry extends entry return array('statusList' => $statusList, 'projects' => array_values($processedProjects)); } + /** + * Get execution progress. + * + * @access public + * @return array + */ public function executionProgress() { $executions = $this->loadModel('project')->getStats(0, 'all', 0, 0, 30, 'id_desc'); @@ -205,10 +230,17 @@ class reportsEntry extends entry return array('statusList' => $statusList, 'executions' => array_values($processedExecutions)); } + /** + * Get product progress with story. + * + * @access public + * @return array + */ public function productProgress() { $this->app->loadLang('product'); $this->app->loadLang('story'); + $storyStatusStat = $this->dao->select('t1.product,t2.name,t2.status,t1.status as storyStatus,count(*) as storyCount')->from(TABLE_STORY)->alias('t1') ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id') ->where('t2.deleted')->eq(0) @@ -240,6 +272,7 @@ class reportsEntry extends entry if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1; } + /* Set story status statistics integrate into product. */ $storyStatusList = array('draft' => array(), 'active' => array(), 'changed' => array(), 'closed' => array()); foreach($processedProducts as $productID => $product) { @@ -268,10 +301,17 @@ class reportsEntry extends entry return array('productStatusList' => $productStatusList, 'products' => array_values($processedProducts), 'storyStatusList' => $storyStatusList); } + /** + * Get bug progress by product. + * + * @access public + * @return array + */ public function bugProgress() { $this->app->loadLang('product'); $this->app->loadLang('bug'); + $bugStatusStat = $this->dao->select('t1.product,t2.name,t2.status,t1.status as bugStatus,count(*) as bugCount')->from(TABLE_BUG)->alias('t1') ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id') ->where('t2.deleted')->eq(0) @@ -286,7 +326,7 @@ class reportsEntry extends entry $productStatusList['closed']['total'] = 0; $processedProducts = array(); - $productBugStat = array(); + $productBugStat = array(); foreach($bugStatusStat as $product) { $productBugStat[$product->product][$product->bugStatus] = $product->bugCount; @@ -303,6 +343,7 @@ class reportsEntry extends entry if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1; } + /* Set bug status statistics integrate into product. */ $bugStatusList = array('active' => array(), 'resolved' => array(), 'closed' => array()); foreach($processedProducts as $productID => $product) { @@ -330,23 +371,4 @@ class reportsEntry extends entry return array('productStatusList' => $productStatusList, 'bugs' => array_values($processedProducts), 'bugStatusList' => $bugStatusList); } - - public function processStatus($statusStat, $objectType) - { - $this->app->loadLang($objectType); - - $processedStatus = array(); - $total = 0; - foreach($this->lang->$objectType->statusList as $status => $statusName) - { - if(empty($statusStat[$status])) continue; - - $processedStatus[$status]['code'] = $status; - $processedStatus[$status]['name'] = $statusName; - $processedStatus[$status]['total'] = $statusStat[$status]; - $total += $statusStat[$status]; - } - - return array('total' => $total, 'statusList' => array_values($processedStatus)); - } } diff --git a/module/report/config.php b/module/report/config.php index 9bd447e755..ef44d7a72f 100644 --- a/module/report/config.php +++ b/module/report/config.php @@ -54,3 +54,11 @@ $config->report->annualData['month']['story'] = array('opened' => 'create', 'act $config->report->annualData['month']['task'] = array('opened' => 'create', 'started' => 'start', 'finished' => 'finish', 'paused' => 'pause', 'activated' => 'activate', 'canceled' => 'cancel', 'closed' => 'close'); $config->report->annualData['month']['bug'] = array('opened' => 'create', 'bugconfirmed' => 'confirm', 'activated' => 'activate', 'resolved' => 'resolve', 'closed' => 'close'); $config->report->annualData['month']['case'] = array('opened' => 'create', 'run' => 'run', 'createBug' => 'createBug'); + +$config->report->outputData['story'] = array('opened' => 'create', 'changed' => 'change', 'reviewed' => 'review', 'closed' => 'close'); +$config->report->outputData['productplan'] = array('opened' => 'create'); +$config->report->outputData['release'] = array('opened' => 'create', 'stoped' => 'stop', 'activated' => 'activate'); +$config->report->outputData['execution'] = array('opened' => 'create', 'started' => 'start', 'delayed' => 'putoff', 'suspended' => 'suspend', 'closed' => 'close'); +$config->report->outputData['task'] = array('opened' => 'create', 'assigned' => 'assign', 'finished' => 'finish', 'activated' => 'activate', 'closed' => 'close'); +$config->report->outputData['bug'] = array('opened' => 'create', 'resolved' => 'resolve', 'activated' => 'activate', 'closed' => 'close'); +$config->report->outputData['case'] = array('opened' => 'create', 'run' => 'run', 'createBug' => 'createBug'); diff --git a/module/report/lang/zh-cn.php b/module/report/lang/zh-cn.php index 428efdce3a..0d84257637 100644 --- a/module/report/lang/zh-cn.php +++ b/module/report/lang/zh-cn.php @@ -193,6 +193,10 @@ $lang->report->annualData->actionList['assign'] = '指派'; $lang->report->annualData->actionList['activate'] = '激活'; $lang->report->annualData->actionList['resolve'] = '解决'; $lang->report->annualData->actionList['run'] = '执行'; +$lang->report->annualData->actionList['stop'] = '停止维护'; + +$lang->report->annualData->actionList['putoff'] = '延期'; +$lang->report->annualData->actionList['suspend'] = '挂起'; $lang->report->annualData->actionList['change'] = '变更'; $lang->report->annualData->actionList['pause'] = '暂停'; $lang->report->annualData->actionList['cancel'] = '取消'; diff --git a/module/report/model.php b/module/report/model.php index fe4d60004b..a558bbe421 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -1063,6 +1063,71 @@ class reportModel extends model return $statusOverview; } + + /** + * Get output data for API. + * + * @param array $accounts + * @param string $year + * @access public + * @return array + */ + public function getOutput4API($accounts, $year) + { + $stmt = $this->dao->select('*')->from(TABLE_ACTION) + ->where('objectType')->in(array_keys($this->config->report->outputData)) + ->andWhere('LEFT(date, 4)')->eq($year) + ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi() + ->query(); + + $outputData = array(); + while($action = $stmt->fetch()) + { + if($action->objectType == 'release' and $action->action == 'changestatus') + { + if($action->extra == 'terminate') $action->action = 'stoped'; + if($action->extra == 'normal') $action->action = 'activated'; + } + + if(!isset($this->config->report->outputData[$action->objectType][$action->action])) continue; + if(!isset($outputData[$action->objectType][$action->action])) $outputData[$action->objectType][$action->action] = 0; + + $outputData[$action->objectType][$action->action] += 1; + } + + $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1') + ->leftJoin(TABLE_BUG)->alias('t2')->on('t1.objectID=t2.id') + ->where('t1.objectType')->eq('bug') + ->andWhere('t2.deleted')->eq(0) + ->andWhere('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t1.action')->eq('opened') + ->andWhere('t2.case')->ne('0') + ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi() + ->query(); + while($action = $stmt->fetch()) + { + if(!isset($outputData['case']['createBug'])) $outputData['case']['createBug'] = 0; + $outputData['case']['createBug'] += 1; + } + + $processedOutput = array(); + foreach($this->config->report->outputData as $objectType => $actions) + { + $objectActions = $outputData[$objectType]; + $processedOutput[$objectType]['total'] = array_sum($objectActions); + + foreach($actions as $action => $langCode) + { + if(empty($objectActions[$action])) continue; + + $processedOutput[$objectType]['actions'][$langCode]['code'] = $langCode; + $processedOutput[$objectType]['actions'][$langCode]['name'] = $this->lang->report->annualData->actionList[$langCode]; + $processedOutput[$objectType]['actions'][$langCode]['total'] = $objectActions[$action]; + } + } + + return $processedOutput; + } } /** From fce9a155c06b340502dd996e9a3e42176cf0ffd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 10:17:24 +0800 Subject: [PATCH 030/129] * adjust for js error. --- module/my/js/common.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/module/my/js/common.js b/module/my/js/common.js index 60242230cc..ad12c9cff0 100644 --- a/module/my/js/common.js +++ b/module/my/js/common.js @@ -5,7 +5,10 @@ $(function() $('#subNavbar li[data-id=' + mode + ']').addClass('active'); if(typeof rawMethod === 'string' && rawMethod == 'work') $('#subNavbar li[data-id=' + mode + '] a').append('' + total + ''); } - var scp = $('[data-id="changePassword"] a'); - var sign = config.requestType == 'GET' ? '&' : '?'; - scp.attr('href', scp.attr('href') + sign + 'onlybody=yes').modalTrigger({width:500, type:'iframe'}); + var $scp = $('[data-id="changePassword"] a'); + if($scp.length > 0) + { + var sign = config.requestType == 'GET' ? '&' : '?'; + $scp.attr('href', $scp.attr('href') + sign + 'onlybody=yes').modalTrigger({width:500, type:'iframe'}); + } }); From a802ccc98200c8e443322da13a5ab58aa2e0877e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 10:35:22 +0800 Subject: [PATCH 031/129] * fix error. --- module/report/model.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/report/model.php b/module/report/model.php index a558bbe421..6c25d1865a 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -1113,6 +1113,8 @@ class reportModel extends model $processedOutput = array(); foreach($this->config->report->outputData as $objectType => $actions) { + if(!isset($outputData[$objectType])) continue; + $objectActions = $outputData[$objectType]; $processedOutput[$objectType]['total'] = array_sum($objectActions); From d2c653ff48531d51f66f72b384c3e2ea9f7057f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 11:22:05 +0800 Subject: [PATCH 032/129] * fix bug #15189. --- lib/filter/filter.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/filter/filter.class.php b/lib/filter/filter.class.php index 3c92af1281..ebedf6292b 100644 --- a/lib/filter/filter.class.php +++ b/lib/filter/filter.class.php @@ -5,7 +5,7 @@ * * The author disclaims copyright to this source code. In place of * a legal notice, here is a blessing: - * + * * May you do good and not evil. * May you find forgiveness for yourself and forgive others. * May you share freely, never taking more than you give. @@ -15,7 +15,7 @@ helper::import(dirname(dirname(__FILE__)) . '/base/filter/filter.class.php'); /** * validater类,检查数据是否符合规则。 * The validater class, checking data by rules. - * + * * @package framework */ class validater extends baseValidater @@ -25,7 +25,7 @@ class validater extends baseValidater /** * fixer类,处理数据。 * fixer class, to fix data types. - * + * * @package framework */ class fixer extends baseFixer @@ -60,7 +60,7 @@ class fixer extends baseFixer } if($canImplode) $this->data->$field = implode(',', $value); } - if(isset($flowFields[$field]) and $flowFields[$field]->control == 'textarea') $this->skipSpecial($field); + if(isset($flowFields[$field]) and ($flowFields[$field]->control == 'textarea' or $flowFields[$field]->control == 'richtext')) $this->skipSpecial($field); $this->specialChars($field); } From 5f9b3ed65400e3df2b653cc75b8077b1f6a20028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 13:11:42 +0800 Subject: [PATCH 033/129] * adjust for lang for api. --- module/common/lang/zh-cn.php | 2 +- module/report/lang/zh-cn.php | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index db5ccc3076..a1b7929efb 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -310,7 +310,7 @@ $lang->createObjects['doc'] = '文档'; /* 语言 */ $lang->lang = 'Language'; -$lang->setLang = '语音设置'; +$lang->setLang = '语言设置'; /* 风格列表。*/ $lang->theme = '主题'; diff --git a/module/report/lang/zh-cn.php b/module/report/lang/zh-cn.php index 0d84257637..bb3f419f8f 100644 --- a/module/report/lang/zh-cn.php +++ b/module/report/lang/zh-cn.php @@ -194,7 +194,6 @@ $lang->report->annualData->actionList['activate'] = '激活'; $lang->report->annualData->actionList['resolve'] = '解决'; $lang->report->annualData->actionList['run'] = '执行'; $lang->report->annualData->actionList['stop'] = '停止维护'; - $lang->report->annualData->actionList['putoff'] = '延期'; $lang->report->annualData->actionList['suspend'] = '挂起'; $lang->report->annualData->actionList['change'] = '变更'; @@ -212,3 +211,20 @@ $lang->report->annualData->radarItems['execution'] = $lang->executionCommon; $lang->report->annualData->radarItems['devel'] = "研发"; $lang->report->annualData->radarItems['qa'] = "测试"; $lang->report->annualData->radarItems['other'] = "其他"; + +$lang->report->companyRadar = "公司能力雷达图"; +$lang->report->outputData = "产出数据"; +$lang->report->outputTotal = "产出总数"; +$lang->report->storyOutput = "需求产出"; +$lang->report->planOutput = "计划产出"; +$lang->report->releaseOutput = "发布产出"; +$lang->report->executionOutput = "执行产出"; +$lang->report->taskOutput = "任务产出"; +$lang->report->bugOutput = "Bug产出"; +$lang->report->caseOutput = "用例产出"; +$lang->report->bugProgress = "Bug进展"; +$lang->report->productProgress = "产品进展"; +$lang->report->executionProgress = "执行进展"; +$lang->report->projectProgress = "项目进展"; +$lang->report->yearProjectOverview = "年度项目总览"; +$lang->report->projectOverview = "截止目前项目总览"; From a9f849138851398dea76e8c0b472f636761929e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 5 Nov 2021 16:41:26 +0800 Subject: [PATCH 034/129] * adjust for flow. --- module/project/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/project/model.php b/module/project/model.php index 44358df6ad..a0f3c66ab0 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -131,7 +131,7 @@ class projectModel extends model $moduleName = $this->app->getModuleName(); $methodName = $this->app->getMethodName(); $this->loadModel('common')->resetProjectPriv($this->session->project); - if(!commonModel::hasPriv($moduleName, $methodName)) $this->common->deny($moduleName, $methodName, false); + if(!$this->common->isOpenMethod($moduleName, $methodName) and !commonModel::hasPriv($moduleName, $methodName)) $this->common->deny($moduleName, $methodName, false); return $this->session->project; } From 19c88ede74e7d7849b2a90802fc32b137f643f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 8 Nov 2021 11:05:12 +0800 Subject: [PATCH 035/129] * adjust for remove deleted data. --- module/report/model.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/module/report/model.php b/module/report/model.php index 6c25d1865a..88b98130c5 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -1074,13 +1074,15 @@ class reportModel extends model */ public function getOutput4API($accounts, $year) { - $stmt = $this->dao->select('*')->from(TABLE_ACTION) + $stmt = $this->dao->select('id,objectType,objectID,action,extra')->from(TABLE_ACTION) ->where('objectType')->in(array_keys($this->config->report->outputData)) ->andWhere('LEFT(date, 4)')->eq($year) ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi() ->query(); - $outputData = array(); + $outputData = array(); + $actionGroup = array(); + $objectIdList = array(); while($action = $stmt->fetch()) { if($action->objectType == 'release' and $action->action == 'changestatus') @@ -1088,11 +1090,24 @@ class reportModel extends model if($action->extra == 'terminate') $action->action = 'stoped'; if($action->extra == 'normal') $action->action = 'activated'; } + unset($action->extra); if(!isset($this->config->report->outputData[$action->objectType][$action->action])) continue; - if(!isset($outputData[$action->objectType][$action->action])) $outputData[$action->objectType][$action->action] = 0; - $outputData[$action->objectType][$action->action] += 1; + if(!isset($outputData[$action->objectType][$action->action])) $outputData[$action->objectType][$action->action] = 0; + $objectIdList[$action->objectType][$action->objectID] = $action->objectID; + $actionGroup[$action->objectType][$action->id] = $action; + } + + foreach($actionGroup as $objectType => $actions) + { + $deletedIdList = $this->dao->select('id')->from($this->config->objectTables[$objectType])->where('deleted')->eq(1)->andWhere('id')->in($objectIdList[$objectType])->fetchPairs('id', 'id'); + + foreach($actions as $action) + { + if(isset($deletedIdList[$action->objectID])) continue; + $outputData[$action->objectType][$action->action] += 1; + } } $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1') From e257dc4adf7db85985a755fa34148ff7f5fc58f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 8 Nov 2021 13:23:47 +0800 Subject: [PATCH 036/129] * fix bug for get report by dept. --- api/v1/entries/reports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 75ffa215a1..c0d102d340 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -27,7 +27,7 @@ class reportsEntry extends entry $accounts = array(); if($account) $accounts = array($account => $account); - if(empty($accounts) and $dept) $accounts = $this->loadModel('dept')->getDeptUserPairs($dept); + if(empty($accounts) and $dept) $accounts = array_keys($this->loadModel('dept')->getDeptUserPairs($dept)); $fields = explode(',', strtolower($fields)); $report = array(); From 2225f9acb866c7225a797b58fb870f988307f7e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 8 Nov 2021 14:52:40 +0800 Subject: [PATCH 037/129] * adjust for report data. --- api/v1/entries/reports.php | 1 + module/report/model.php | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index c0d102d340..55f434a3c5 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -28,6 +28,7 @@ class reportsEntry extends entry $accounts = array(); if($account) $accounts = array($account => $account); if(empty($accounts) and $dept) $accounts = array_keys($this->loadModel('dept')->getDeptUserPairs($dept)); + if(empty($accounts) and empty($dept)) $accounts = array_keys($this->loadModel('user')->getPairs('noclosed')); $fields = explode(',', strtolower($fields)); $report = array(); diff --git a/module/report/model.php b/module/report/model.php index 88b98130c5..ee5d1a2fe7 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -575,7 +575,7 @@ class reportModel extends model ->query(); $filterActions = array(); - $deletedObject = array(); + $objectIdList = array(); while($action = $stmt->fetch()) { $objectType = $action->objectType; @@ -583,15 +583,14 @@ class reportModel extends model $lowerAction = strtolower($action->action); if(!isset($this->config->report->annualData['contributions'][$objectType][$lowerAction])) continue; - if($action->action == 'deleted') $deletedObject[$objectType][$objectID] = $objectID; - if($action->action == 'undeleted') unset($deletedObject[$objectType][$objectID]); - + $objectIdList[$objectType][$objectID] = $objectID; $filterActions[$objectType][$objectID][$action->id] = $action; } - foreach($deletedObject as $objectType => $idList) + foreach($objectIdList as $objectType => $idList) { - foreach($idList as $id) unset($filterActions[$objectType][$id]); + $deletedIdList = $this->dao->select('id')->from($this->config->objectTables[$objectType])->where('deleted')->eq(1)->andWhere('id')->in($idList)->fetchPairs('id', 'id'); + foreach($deletedIdList as $id) unset($filterActions[$objectType][$id]); } $actionGroups = array(); From ad213ae93ad8d4c00beec9b4c40ff6138583f101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 8 Nov 2021 18:56:48 +0800 Subject: [PATCH 038/129] * adjust for report api. --- api/v1/entries/reports.php | 5 ++--- module/report/model.php | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 55f434a3c5..656579ab53 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -83,7 +83,7 @@ class reportsEntry extends entry */ public function projectOverview($accounts) { - $statusOverview = $this->loadModel('report')->getProjectStatusOverview(array_keys($accounts)); + $statusOverview = $this->loadModel('report')->getProjectStatusOverview($accounts); $this->app->loadLang('project'); $total = 0; @@ -116,8 +116,7 @@ class reportsEntry extends entry */ public function radar($accounts, $year) { - $allAccounts = $this->loadModel('user')->getPairs('noletter|noclosed'); - $contributions = $this->loadModel('report')->getUserYearContributions(empty($accounts) ? array_keys($allAccounts) : $accounts, $year); + $contributions = $this->loadModel('report')->getUserYearContributions($accounts, $year); $annualDataConfig = $this->config->report->annualData; $radarData = array('product' => 0, 'execution' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0); diff --git a/module/report/model.php b/module/report/model.php index ee5d1a2fe7..a6dc4f6e84 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -1124,6 +1124,13 @@ class reportModel extends model $outputData['case']['createBug'] += 1; } + $outputData['case']['run'] = $this->dao->select('count(*) as count')->from(TABLE_TESTRESULT)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') + ->where('LEFT(t1.date, 4)')->eq($year) + ->andWhere('t2.deleted')->eq(0) + ->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi() + ->fetch('count'); + $processedOutput = array(); foreach($this->config->report->outputData as $objectType => $actions) { From 6669badf55a0d56631766e41ed7e9967db8660a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 9 Nov 2021 09:57:48 +0800 Subject: [PATCH 039/129] * code for task #43763. --- api/v1/entries/products.php | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 11698865cf..fe814d11ad 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -20,6 +20,9 @@ class productsEntry extends entry */ public function get($programID = 0) { + $fields = strtolower($this->param('fields', '')); + if(strpos(",{$fields},", ',dropmenu,') !== false) return $this->getDropMenu(); + if(!$programID) $programID = $this->param('program', 0); if($programID) @@ -88,4 +91,47 @@ class productsEntry extends entry $this->send(200, $product); } + + /** + * Get dropmenu. + * + * @access public + * @return void + */ + public function getDropMenu() + { + $control = $this->loadController('product', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu($this->request('productID', 0), $this->request('module', 'product'), $this->request('method', 'browse'), $this->request('extra', ''), $this->request('from', '')); + + $data = $this->getData(); + if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); + + $dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array()); + foreach($data->data->products as $programID => $products) + { + foreach($products as $product) + { + $newProduct = new stdclass(); + $newProduct->id = $product->id; + $newProduct->program = $product->program; + $newProduct->name = $product->name; + $newProduct->code = $product->code; + $newProduct->status = $product->status; + + if($product->status == 'closed') + { + $dropMenu['closed'][] = $newProduct; + } + elseif($product->PO == $this->app->user->account) + { + $dropMenu['owner'][] = $newProduct; + } + else + { + $dropMenu['other'][] = $newProduct; + } + } + } + $this->send(200, $dropMenu); + } } From e3530d7e735b9079f2786a8e05375cd6135f4792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 9 Nov 2021 10:31:55 +0800 Subject: [PATCH 040/129] * code for task #43762. --- api/v1/entries/projects.php | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 82ab1e6dc9..5a098dd15a 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -22,6 +22,7 @@ class projectsEntry extends entry { if(!$programID) $programID = $this->param('program', 0); $appendFields = $this->param('fields', ''); + if(strpos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu(); $control = $this->loadController('project', 'browse'); $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); @@ -76,4 +77,47 @@ class projectsEntry extends entry $this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time')); } + + /** + * Get drop menu. + * + * @access public + * @return void + */ + public function getDropMenu() + { + $control = $this->loadController('project', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse')); + + $data = $this->getData(); + if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); + + $dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array()); + foreach($data->data->projects as $programID => $projects) + { + foreach($projects as $project) + { + $newProject = new stdclass(); + $newProject->id = $project->id; + $newProject->name = $project->name; + $newProject->code = $project->code; + $newProject->parent = $project->parent; + $newProject->status = $project->status; + + if($project->status == 'closed') + { + $dropMenu['closed'][] = $newProject; + } + elseif($project->PM == $this->app->user->account) + { + $dropMenu['owner'][] = $newProject; + } + else + { + $dropMenu['other'][] = $newProject; + } + } + } + $this->send(200, $dropMenu); + } } From fe82c61361102602c16fce3f0d5cf1fee8b20928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 9 Nov 2021 13:47:06 +0800 Subject: [PATCH 041/129] * code for task #43761. --- api/v1/entries/product.php | 28 ++++++++++++++++++++++++++++ framework/api/entry.class.php | 17 +++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/api/v1/entries/product.php b/api/v1/entries/product.php index ca5af67f04..aed5960169 100644 --- a/api/v1/entries/product.php +++ b/api/v1/entries/product.php @@ -33,6 +33,13 @@ class productEntry extends Entry } $product = $this->format($data->data->product, 'createdDate:time'); + + $users = $this->loadModel('user')->getPairs('noletter|nodeleted'); + $product->PO = $this->formatUser($product->PO, $users); + $product->QD = $this->formatUser($product->QD, $users); + $product->RD = $this->formatUser($product->RD, $users); + $product->createdBy = $this->formatUser($product->createdBy, $users); + if(isset($product->feedback)) $product->feedback = $this->formatUser($product->feedback, $users); if(!$fields) return $this->send(200, $product); /* Set other fields. */ @@ -50,6 +57,27 @@ class productEntry extends Entry $product->modules = $data->data->tree; } break; + case 'actions': + $actions = $this->loadModel('action')->getList('product', $productID); + $actions = $this->action->transformActions($actions); + + $product->actions = array(); + foreach($actions as $action) + { + $action = $this->filterFields($action, 'id,objectType,objectID,actor,action,date,comment,extra,objectName,originalDate,actionLabel,objectLabel,history'); + $action->actor = $this->formatUser($action->actor, $users); + if($action->history) + { + foreach($action->history as $i => $history) + { + $history = $this->filterFields($history, 'id,field,old,new,diff'); + $history->fieldName = zget($this->lang->product, $history->field); + $action->history[$i] = $history; + } + } + $product->actions[] = $action; + } + break; } } diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index 7a0f698d7d..bd1e9bb5f0 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -546,6 +546,23 @@ class baseEntry return $filtered; } + /** + * Format user. + * + * @param string $account + * @param array $users + * @access public + * @return array + */ + public function formatUser($account, $users) + { + $user = array(); + $user['account'] = $account; + $user['realname'] = zget($users, $account); + + return $user; + } + /** * 类型转换. * Typecasting. From 9d0023b96923c6f2a28029cbd8b22b4b86ca4538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 9 Nov 2021 16:31:28 +0800 Subject: [PATCH 042/129] * code for task #43761. --- api/v1/entries/product.php | 16 ++++++++++++---- config/routes.php | 5 +++-- module/action/control.php | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/api/v1/entries/product.php b/api/v1/entries/product.php index aed5960169..9df8b4962c 100644 --- a/api/v1/entries/product.php +++ b/api/v1/entries/product.php @@ -58,14 +58,22 @@ class productEntry extends Entry } break; case 'actions': - $actions = $this->loadModel('action')->getList('product', $productID); - $actions = $this->action->transformActions($actions); + $product->addComment = common::hasPriv('action', 'comment') ? true : false; + $actions = $this->loadModel('action')->getList('product', $productID); $product->actions = array(); foreach($actions as $action) { - $action = $this->filterFields($action, 'id,objectType,objectID,actor,action,date,comment,extra,objectName,originalDate,actionLabel,objectLabel,history'); - $action->actor = $this->formatUser($action->actor, $users); + $action->actor = zget($users, $action->actor); + if($action->action == 'assigned') $action->extra = zget($users, $action->extra); + if(strpos($action->actor, ':') !== false) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1); + + ob_start(); + $this->action->printAction($action); + $action->desc = ob_get_contents(); + ob_end_clean(); + + $action = $this->filterFields($action, 'id,objectType,objectID,actor,action,date,comment,extra,desc,history'); if($action->history) { foreach($action->history as $i => $history) diff --git a/config/routes.php b/config/routes.php index 312ad92c22..763319bbc8 100644 --- a/config/routes.php +++ b/config/routes.php @@ -4,8 +4,9 @@ */ $routes = array(); -$routes['/tokens'] = 'tokens'; -$routes['/langs'] = 'langs'; +$routes['/tokens'] = 'tokens'; +$routes['/langs'] = 'langs'; +$routes['/comments'] = 'comments'; $routes['/tabs/:module'] = 'tabs'; diff --git a/module/action/control.php b/module/action/control.php index 2525547440..61d51ee2d6 100755 --- a/module/action/control.php +++ b/module/action/control.php @@ -134,7 +134,7 @@ class action extends control $actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment); if(defined('RUN_MODE') && RUN_MODE == 'api') { - die(array('status' => 'success', 'data' => $actionID)); + return $this->send(array('status' => 'success', 'data' => $actionID)); } else { From 87d1d09997775a2676af1593f13d73ec7a34eb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 10 Nov 2021 11:34:16 +0800 Subject: [PATCH 043/129] * adjust for get dropmenu by api. --- api/v1/entries/products.php | 13 ++++--------- api/v1/entries/projects.php | 16 ++++++---------- module/action/model.php | 5 +++-- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index fe814d11ad..94053ce8e6 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -111,24 +111,19 @@ class productsEntry extends entry { foreach($products as $product) { - $newProduct = new stdclass(); - $newProduct->id = $product->id; - $newProduct->program = $product->program; - $newProduct->name = $product->name; - $newProduct->code = $product->code; - $newProduct->status = $product->status; + $product = $this->filterFields($product, 'id,program,name,code,status,PO'); if($product->status == 'closed') { - $dropMenu['closed'][] = $newProduct; + $dropMenu['closed'][] = $product; } elseif($product->PO == $this->app->user->account) { - $dropMenu['owner'][] = $newProduct; + $dropMenu['owner'][] = $product; } else { - $dropMenu['other'][] = $newProduct; + $dropMenu['other'][] = $product; } } } diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 5a098dd15a..06ae81214d 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -34,7 +34,7 @@ class projectsEntry extends entry $result = array(); foreach($data->data->projectStats as $project) { - $project = $this->filterFields($project, 'id,name,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); + $project = $this->filterFields($project, 'id,name,code,model,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); $result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); @@ -97,24 +97,20 @@ class projectsEntry extends entry { foreach($projects as $project) { - $newProject = new stdclass(); - $newProject->id = $project->id; - $newProject->name = $project->name; - $newProject->code = $project->code; - $newProject->parent = $project->parent; - $newProject->status = $project->status; + if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true; + $project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay'); if($project->status == 'closed') { - $dropMenu['closed'][] = $newProject; + $dropMenu['closed'][] = $project; } elseif($project->PM == $this->app->user->account) { - $dropMenu['owner'][] = $newProject; + $dropMenu['owner'][] = $project; } else { - $dropMenu['other'][] = $newProject; + $dropMenu['other'][] = $project; } } } diff --git a/module/action/model.php b/module/action/model.php index 9ce593c030..371da50593 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -972,7 +972,7 @@ class actionModel extends model $action->date = date(DT_MONTHTIME2, strtotime($action->date)); $action->actionLabel = isset($this->lang->$objectType->$actionType) ? $this->lang->$objectType->$actionType : $action->action; $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->actionLabel; - $action->objectLabel = $this->getObjectLabel($objectType, $action->objectID, $requirements); + $action->objectLabel = $this->getObjectLabel($objectType, $action->objectID, $actionType, $requirements); /* If action type is login or logout, needn't link. */ if($actionType == 'svncommited' or $actionType == 'gitcommited') $action->actor = zget($commiters, $action->actor); @@ -1093,11 +1093,12 @@ class actionModel extends model * * @param string $objectType * @param int $objectID + * @param string $actionType * @param array $requirements * @access public * @return string */ - public function getObjectLabel($objectType, $objectID, $requirements) + public function getObjectLabel($objectType, $objectID, $actionType, $requirements) { $actionObjectLabel = $objectType; if(isset($this->lang->action->label->$objectType)) From 938b382fce7670cb26d67e10362a0f10c8ffdeb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 10 Nov 2021 11:57:12 +0800 Subject: [PATCH 044/129] * code for task #43750. --- api/v1/entries/user.php | 72 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 970f749d2f..65c2932aae 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -71,7 +71,7 @@ class userEntry extends Entry $products = $this->my->getProducts('ownbyme'); if($products) { - $info->product['total'] = $products->allCount; + $info->product['total'] = $products->unclosedCount; $info->product['products'] = $products->products; } break; @@ -95,6 +95,41 @@ class userEntry extends Entry $info->project['projects'] = $projects->projects; } break; + case 'lastproject': + $info->lastProject = array('total' => 0, 'projects' => array()); + + $control = $this->loadController('project', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu(0, 'project', 'index'); + $data = $this->getData(); + + if($data->status == 'success') + { + $myProjects['owner'] = array(); + $myProjects['other'] = array(); + foreach($data->data->projects as $programID => $programProjects) + { + foreach($programProjects as $project) + { + if($project->status == 'closed') continue; + + $project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM'); + if($project->PM == $this->app->user->account) + { + $myProjects['owner'][] = $project; + } + else + { + $myProjects['other'][] = $project; + } + } + } + $lastProjects = array_merge($myProjects['owner'], $myProjects['other']); + $lastProjects = array_slice($lastProjects, 0, 3); + + $info->lastProject['total'] = count($lastProjects); + $info->lastProject['projects'] = $lastProjects; + } + break; case 'execution': $info->execution = array('total' => 0, 'executions' => array()); if(!common::hasPriv('my', 'execution')) break; @@ -109,6 +144,41 @@ class userEntry extends Entry $info->execution['executions'] = array_values((array)$data->data->executions); } break; + case 'lastexecution': + $info->lastExecution = array('total' => 0, 'executions' => array()); + + $control = $this->loadController('execution', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu(0, 'execution', 'browse', ''); + $data = $this->getData(); + + $account = $this->app->user->account; + if($data->status == 'success') + { + $myExecutions['owner'] = array(); + $myExecutions['other'] = array(); + foreach($data->data->executions as $projectID => $projectExecutions) + { + foreach($projectExecutions as $execution) + { + if($execution->status == 'done' or $execution->status == 'closed') continue; + + if($execution->PM == $account or isset($execution->teams->$account)) + { + $myExecutions['owner'][] = $this->filterFields($execution, 'id,model,type,name,code,parent,status,PM'); + } + else + { + $myExecutions['other'][] = $this->filterFields($execution, 'id,model,type,name,code,parent,status,PM'); + } + } + } + $lastExecutions = array_merge($myExecutions['owner'], $myExecutions['other']); + $lastExecutions = array_slice($lastExecutions, 0, 3); + + $info->lastExecution['total'] = count($lastExecutions); + $info->lastExecution['executions'] = $lastExecutions; + } + break; case 'actions': $info->actions = $this->my->getActions(); break; From 118133afdd6b92a8d10abb4d9498fcaa46609f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 11 Nov 2021 10:16:21 +0800 Subject: [PATCH 045/129] * code for task #44190. --- module/report/css/annualdata.css | 4 ++-- module/report/lang/zh-cn.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module/report/css/annualdata.css b/module/report/css/annualdata.css index 2001f5f069..aad549989b 100644 --- a/module/report/css/annualdata.css +++ b/module/report/css/annualdata.css @@ -58,8 +58,8 @@ section.active {border: 1px solid rgb(0, 166, 255);} #actionData .ratio {display: inline-block; width: 400px;} #actionData .ratio .item {display: inline-block; text-align: center;} -#radar {width: 350px; height: 330px;} -#radarCanvas {width: 310px; height: 310px; margin: 0 auto;} +#radar {width: 350px; height: 330px; padding-left:10px;} +#radarCanvas {width: 330px; height: 310px; margin: 0 auto;} #executionData, #productData {width: 633px; height: 350px; margin-top: 20px; position: relative;} #executionData div.has-table, #productData div.has-table {margin-top: 30px; height: 285px; overflow: auto;} diff --git a/module/report/lang/zh-cn.php b/module/report/lang/zh-cn.php index bb3f419f8f..b884bf3de9 100644 --- a/module/report/lang/zh-cn.php +++ b/module/report/lang/zh-cn.php @@ -206,8 +206,8 @@ $lang->report->annualData->todoStatus['all'] = '所有待办'; $lang->report->annualData->todoStatus['undone'] = '未完成'; $lang->report->annualData->todoStatus['done'] = '已完成'; -$lang->report->annualData->radarItems['product'] = '产品'; -$lang->report->annualData->radarItems['execution'] = $lang->executionCommon; +$lang->report->annualData->radarItems['product'] = '产品管理'; +$lang->report->annualData->radarItems['execution'] = '项目管理'; $lang->report->annualData->radarItems['devel'] = "研发"; $lang->report->annualData->radarItems['qa'] = "测试"; $lang->report->annualData->radarItems['other'] = "其他"; From 789f650473915796ccad2a0243766b71b3bb28fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 11 Nov 2021 14:28:43 +0800 Subject: [PATCH 046/129] * adjust for product progress report. --- api/v1/entries/reports.php | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1/entries/reports.php b/api/v1/entries/reports.php index 656579ab53..d55f98932b 100644 --- a/api/v1/entries/reports.php +++ b/api/v1/entries/reports.php @@ -278,6 +278,7 @@ class reportsEntry extends entry { $product->storyStat = array(); foreach(array_keys($storyStatusList) as $storyStatus) $product->storyStat[$storyStatus] = isset($productStoryStat[$productID][$storyStatus]) ? $productStoryStat[$productID][$storyStatus] : 0; + $product->progress = $product->storyStat['closed'] == 0 ? 0 : round($product->storyStat['closed'] / array_sum($product->storyStat) * 100, 1); } foreach(array_keys($productStatusList) as $status) From ca49d7d380a202d700d0c4e668bcbaf78e5c8d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 12 Nov 2021 09:28:10 +0800 Subject: [PATCH 047/129] * code for task #43751. --- api/v1/entries/programs.php | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 1b36ddafea..3df9668be2 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class ProgramsEntry extends Entry +class programsEntry extends Entry { /** * GET method. @@ -19,17 +19,47 @@ class ProgramsEntry extends Entry */ public function get() { + $_COOKIE['showClosed'] = $this->param('showClosed', 0); + $mergeChildren = $this->param('mergeChildren', 0); + $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') { - $programs = $data->data->programs; - $result = array(); + $programs = (array)$data->data->programs; + $progressList = $data->data->progressList; + $users = $data->data->users; + $result = array(); foreach($programs as $program) { - $result[] = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); + $program->progress = zget($progressList, $program->id, 0); + $program->openedBy = zget($users, $program->openedBy); + $program->closedBy = zget($users, $program->closedBy); + $program->canceledBy = zget($users, $program->canceledBy); + $program->PO = zget($users, $program->PO); + $program->PM = zget($users, $program->PM); + $program->QD = zget($users, $program->QD); + $program->RD = zget($users, $program->RD); + unset($program->desc); + + $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); + + if($mergeChildren) + { + if(empty($program->parent)) $result[$program->parent][$program->id] = $program; + if(isset($programs[$program->parent])) + { + $parentProgram = $programs[$program->parent]; + if(!isset($parentProgram->children)) $parentProgram->children = array(); + $parentProgram->children[] = $program; + } + } + else + { + $result[] = $program; + } } return $this->send(200, array('programs' => $result)); } From b68cbf646dc5e2fbe970145566deecdb747b6176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Fri, 12 Nov 2021 10:38:29 +0800 Subject: [PATCH 048/129] * code for task #43751. --- api/v1/entries/programs.php | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 3df9668be2..d327b9fd3e 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class programsEntry extends Entry +class ProgramsEntry extends Entry { /** * GET method. @@ -19,35 +19,34 @@ class programsEntry extends Entry */ public function get() { - $_COOKIE['showClosed'] = $this->param('showClosed', 0); - $mergeChildren = $this->param('mergeChildren', 0); - $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') { - $programs = (array)$data->data->programs; - $progressList = $data->data->progressList; - $users = $data->data->users; - $result = array(); + $programs = $data->data->programs; + $result = array(); foreach($programs as $program) { - $program->progress = zget($progressList, $program->id, 0); - $program->openedBy = zget($users, $program->openedBy); - $program->closedBy = zget($users, $program->closedBy); - $program->canceledBy = zget($users, $program->canceledBy); - $program->PO = zget($users, $program->PO); - $program->PM = zget($users, $program->PM); - $program->QD = zget($users, $program->QD); - $program->RD = zget($users, $program->RD); - unset($program->desc); - + $program->progress = zget($progressList, $program->id, 0); $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); if($mergeChildren) { + unset($program->desc); + $program->openedBy = zget($users, $program->openedBy); + $program->closedBy = zget($users, $program->closedBy); + $program->canceledBy = zget($users, $program->canceledBy); + $program->PO = zget($users, $program->PO); + $program->PM = zget($users, $program->PM); + $program->QD = zget($users, $program->QD); + $program->RD = zget($users, $program->RD); + $program->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end; + + $programBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$program->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$program->budget, 2); + $program->labelBudget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future; + if(empty($program->parent)) $result[$program->parent][$program->id] = $program; if(isset($programs[$program->parent])) { From 1feb6d2b2fe93bf612131ab395cf45bb038ecfb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 08:37:51 +0800 Subject: [PATCH 049/129] * code for task #43747. --- api/v1/entries/products.php | 65 +++++++++++++++++++++++++++++++++-- framework/api/entry.class.php | 2 +- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 94053ce8e6..1ddbd6f055 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -43,6 +43,8 @@ class productsEntry extends entry } else { + $mergeChildren = $this->param('mergeChildren', ''); + $control = $this->loadController('product', 'all'); $control->all($this->param('status', 'all'), $this->param('order', 'order_asc')); @@ -51,10 +53,67 @@ class productsEntry extends entry if(isset($data->status) and $data->status == 'success') { $result = array(); - $products = $data->data->productStats; - foreach($products as $product) $result[] = $this->format($product, 'createdDate:time'); + if($mergeChildren) + { + $programs = array(); + foreach($data->data->productStructure as $programID => $program) + { + $programs[$programID] = new stdclass(); + $programs[$programID]->id = $programID; + $programs[$programID]->name = $program->programName; + $programs[$programID]->type = 'program'; - return $this->send(200, array('products' => $result)); + foreach($program as $field => $value) + { + if(!isset($programs[$programID]->children)) $programs[$programID]->children = array(); + if(isset($value->products)) + { + $lineID = $field; + if(empty($lineID)) + { + foreach($value->products as $product) + { + unset($product->desc); + $product->stories = (array)$product->stories; + $product->requirements = (array)$product->requirements; + $closedTotal = ($product->stories['closed'] + $product->requirements['closed']); + $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); + $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); + $programs[$programID]->children[$product->id] = $product; + } + } + else + { + $line = new stdclass(); + $line->id = $lineID; + $line->name = $value->lineName; + $line->type = 'line'; + + $line->children = array(); + foreach($value->products as $product) + { + unset($product->desc); + $product->stories = (array)$product->stories; + $product->requirements = (array)$product->requirements; + $closedTotal = ($product->stories['closed'] + $product->requirements['closed']); + $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); + $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); + $line->children[$product->id] = $product; + } + + $programs[$programID]->children[$lineID] = $line; + } + } + } + } + return $this->send(200, $programs); + } + else + { + $products = $data->data->productStats; + foreach($products as $product) $result[] = $this->format($product, 'createdDate:time'); + return $this->send(200, array('products' => $result)); + } } } diff --git a/framework/api/entry.class.php b/framework/api/entry.class.php index bd1e9bb5f0..983177ad7c 100644 --- a/framework/api/entry.class.php +++ b/framework/api/entry.class.php @@ -633,7 +633,7 @@ class baseEntry { $module = $this->app->getModuleName(); $method = $this->app->getMethodName(); - if($module and $method and !commonModel::hasPriv($module, $method)) + if($module and $method and !$this->loadModel('common')->isOpenMethod($module, $method) and !commonModel::hasPriv($module, $method)) { $this->send(403, array('error' => 'Access not allowed')); } From 66d7d68f950f3204390ad644d9dd081fb3f5577a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 08:41:11 +0800 Subject: [PATCH 050/129] * adjust for task #43747. --- api/v1/entries/products.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 1ddbd6f055..a1748693eb 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -106,7 +106,7 @@ class productsEntry extends entry } } } - return $this->send(200, $programs); + return $this->send(200, array_values($programs)); } else { From 93794998a9010fdb2fcf4f30c7bff7071aee55d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 09:06:14 +0800 Subject: [PATCH 051/129] * code task #43747. --- api/v1/entries/products.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index a1748693eb..08b43482d3 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -63,6 +63,7 @@ class productsEntry extends entry $programs[$programID]->name = $program->programName; $programs[$programID]->type = 'program'; + $unclosedTotal = 0; foreach($program as $field => $value) { if(!isset($programs[$programID]->children)) $programs[$programID]->children = array(); @@ -80,6 +81,7 @@ class productsEntry extends entry $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); $programs[$programID]->children[$product->id] = $product; + if($product->status != 'closed') $unclosedTotal += 1; } } else @@ -99,10 +101,12 @@ class productsEntry extends entry $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); $line->children[$product->id] = $product; + if($product->status != 'closed') $unclosedTotal += 1; } $programs[$programID]->children[$lineID] = $line; } + $programs[$programID]->unclosedTotal = $unclosedTotal; } } } From d6cd8a284efae699d1e33182dccef0456d654513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 11:31:12 +0800 Subject: [PATCH 052/129] * adjust for api. --- api/v1/entries/products.php | 2 ++ api/v1/entries/programs.php | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 08b43482d3..378051fa63 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -103,9 +103,11 @@ class productsEntry extends entry $line->children[$product->id] = $product; if($product->status != 'closed') $unclosedTotal += 1; } + if(isset($line->children)) $line->children = array_values($line->children); $programs[$programID]->children[$lineID] = $line; } + if(isset($programs[$programID]->children)) $programs[$programID]->children = array_values($programs[$programID]->children); $programs[$programID]->unclosedTotal = $unclosedTotal; } } diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index d327b9fd3e..d16ec355af 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class ProgramsEntry extends Entry +class programsEntry extends Entry { /** * GET method. @@ -19,17 +19,20 @@ class ProgramsEntry extends Entry */ public function get() { + $mergeChildren = $this->param('mergeChildren', ''); + $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') { - $programs = $data->data->programs; + $programs = (array)$data->data->programs; + $users = $data->data->users; $result = array(); foreach($programs as $program) { - $program->progress = zget($progressList, $program->id, 0); + $program->progress = zget($data->data->progressList, $program->id, 0); $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); if($mergeChildren) From 0c2c05331f23b1f89c4df74e876b9f50c1895f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 14:56:27 +0800 Subject: [PATCH 053/129] * adjust for programs and products api. --- api/v1/entries/products.php | 23 +++++++++++++++++++---- api/v1/entries/programs.php | 12 +++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 378051fa63..f1f1671b33 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -59,9 +59,12 @@ class productsEntry extends entry foreach($data->data->productStructure as $programID => $program) { $programs[$programID] = new stdclass(); - $programs[$programID]->id = $programID; - $programs[$programID]->name = $program->programName; - $programs[$programID]->type = 'program'; + if(!empty($programID)) + { + $programs[$programID]->id = $programID; + $programs[$programID]->name = $program->programName; + $programs[$programID]->type = 'program'; + } $unclosedTotal = 0; foreach($program as $field => $value) @@ -111,8 +114,20 @@ class productsEntry extends entry $programs[$programID]->unclosedTotal = $unclosedTotal; } } + } - return $this->send(200, array_values($programs)); + + $topProducts = array(); + if(isset($programs[0])) + { + $topProducts = $programs[0]->children; + unset($programs[0]); + } + + $programs = array_values($programs); + foreach($topProducts as $product) $programs[] = $product; + + return $this->send(200, $programs); } else { diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index d16ec355af..42d3763dbd 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -19,7 +19,8 @@ class programsEntry extends Entry */ public function get() { - $mergeChildren = $this->param('mergeChildren', ''); + $_COOKIE['showClosed'] = $this->param('showClosed', 0); + $mergeChildren = $this->param('mergeChildren', 0); $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); @@ -27,12 +28,13 @@ class programsEntry extends Entry $data = $this->getData(); if(isset($data->status) and $data->status == 'success') { - $programs = (array)$data->data->programs; - $users = $data->data->users; - $result = array(); + $programs = (array)$data->data->programs; + $progressList = $data->data->progressList; + $users = $data->data->users; + $result = array(); foreach($programs as $program) { - $program->progress = zget($data->data->progressList, $program->id, 0); + $program->progress = zget($progressList, $program->id, 0); $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); if($mergeChildren) From 6c240f4b38da4038ea591336b336ba16a727bc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 16:02:08 +0800 Subject: [PATCH 054/129] * code for task #44335. --- api/v1/entries/programs.php | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 42d3763dbd..7f6bb6c5f7 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -22,6 +22,9 @@ class programsEntry extends Entry $_COOKIE['showClosed'] = $this->param('showClosed', 0); $mergeChildren = $this->param('mergeChildren', 0); + $fields = $this->param('fields', ''); + if(stripos(",{$fields},", ",dropmenu,") !== false) return $this->getDropMenu(); + $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); @@ -65,7 +68,7 @@ class programsEntry extends Entry $result[] = $program; } } - return $this->send(200, array('programs' => $result)); + return $this->send(200, array('programs' => array_values($result))); } if(isset($data->status) and $data->status == 'fail') { @@ -74,4 +77,38 @@ class programsEntry extends Entry return $this->sendError(400, 'error'); } + + /** + * Get drop menu. + * + * @access public + * @return void + */ + public function getDropMenu() + { + + $programs = $this->dao->select('id,name,parent,path,grade,`order`')->from(TABLE_PROJECT) + ->where('deleted')->eq('0') + ->andWhere('type')->eq('program') + ->andWhere('id')->in($this->app->user->view->programs) + ->beginIF(empty($_COOKIE['showClosed']))->andWhere('status')->ne('closed')->fi() + ->orderBy('grade desc, `order`') + ->fetchAll('id'); + + $dropMenu = array(); + foreach($programs as $programID => $program) + { + if(empty($program->parent)) + { + $dropMenu[] = $program; + } + elseif(isset($programs[$program->parent])) + { + if(!isset($programs[$program->parent]->children)) $programs[$program->parent]->children = array(); + $programs[$program->parent]->children[] = $program; + } + } + + $this->send(200, $dropMenu); + } } From 86622cc61882ddda8dcbccf4fe003be49758379d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 16:24:54 +0800 Subject: [PATCH 055/129] * code for task #44304. --- api/v1/entries/projects.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 06ae81214d..5e5fd1c08e 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -22,7 +22,9 @@ class projectsEntry extends entry { if(!$programID) $programID = $this->param('program', 0); $appendFields = $this->param('fields', ''); - if(strpos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu(); + if(stripos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu(); + + $_COOKIE['involved'] = $this->param('involved', 0); $control = $this->loadController('project', 'browse'); $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); @@ -34,7 +36,9 @@ class projectsEntry extends entry $result = array(); foreach($data->data->projectStats as $project) { - $project = $this->filterFields($project, 'id,name,code,model,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); + foreach($project->hours as $field => $value) $project->$field = $value; + + $project = $this->filterFields($project, 'id,name,code,model,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); $result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); From dff6726c6baa27e71df3a876ee2fd00fe15e8084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Mon, 15 Nov 2021 17:11:12 +0800 Subject: [PATCH 056/129] * code for task #44305. --- module/product/model.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/module/product/model.php b/module/product/model.php index 2c6c6a5642..be7cdac0a8 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -1486,6 +1486,16 @@ class productModel extends model ->groupBy('product') ->fetchPairs(); + $this->app->loadClass('date', true); + $weekDate = date::getThisWeek(); + $thisWeekBugs = $this->dao->select('product,count(*) AS count') + ->from(TABLE_BUG) + ->where('deleted')->eq(0) + ->andWhere('openedDate')->between($weekDate['begin'], $weekDate['end']) + ->andWhere('product')->in($productKeys) + ->groupBy('product') + ->fetchPairs(); + $assignToNull = $this->dao->select('product,count(*) AS count') ->from(TABLE_BUG) ->where('deleted')->eq(0) @@ -1517,6 +1527,7 @@ class productModel extends model $product->unResolved = isset($unResolved[$product->id]) ? $unResolved[$product->id] : 0; $product->closedBugs = isset($closedBugs[$product->id]) ? $closedBugs[$product->id] : 0; $product->fixedBugs = isset($fixedBugs[$product->id]) ? $fixedBugs[$product->id] : 0; + $product->thisWeekBugs = isset($thisWeekBugs[$product->id]) ? $thisWeekBugs[$product->id] : 0; $product->assignToNull = isset($assignToNull[$product->id]) ? $assignToNull[$product->id] : 0; $stats[] = $product; } From 77b0b5d61e0bb715ac55e8ccb42b1d721b680cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 09:31:10 +0800 Subject: [PATCH 057/129] * code for task #44305. --- api/v1/entries/products.php | 31 +++++++++++++++++++++++++++++-- module/user/model.php | 2 +- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index f1f1671b33..8eefb08255 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -132,8 +132,35 @@ class productsEntry extends entry else { $products = $data->data->productStats; - foreach($products as $product) $result[] = $this->format($product, 'createdDate:time'); - return $this->send(200, array('products' => $result)); + $accounts = array(); + foreach($products as $product) + { + $accounts[$product->PO] = $product->PO; + $accounts[$product->QD] = $product->QD; + $accounts[$product->RD] = $product->RD; + $accounts[$product->createdBy] = $product->createdBy; + if(isset($product->feedback)) $accounts[$product->feedback] = $product->feedback; + if(!empty($product->mailto)) + { + foreach(explode(',', $product->mailto) as $account) + { + $account = trim($account); + if(empty($account)) continue; + $accounts[$account] = $account; + } + } + + $result[] = $this->format($product, 'createdDate:time'); + } + + $data = array(); + $data['total'] = count($result); + $data['products'] = $result; + + $withUser = $this->param('withUser', ''); + if(!empty($withUser)) $data['users'] = $this->loadModel('user')->getListByAccounts($accounts, 'account'); + + return $this->send(200, $data); } } } diff --git a/module/user/model.php b/module/user/model.php index 9290a20473..c79cc18c01 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -58,7 +58,7 @@ class userModel extends model { if(empty($accounts)) return array(); - return $this->dao->select('id,account,realname,role')->from(TABLE_USER) + return $this->dao->select('id,account,realname,avatar,role')->from(TABLE_USER) ->where('account')->in($accounts) ->andWhere('deleted')->eq(0) ->andWhere('type')->eq('inside') From 41d2fb9a04eb3ad12aa343ad36b6fdc1a049e156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 14:38:52 +0800 Subject: [PATCH 058/129] * adjust for program list. --- api/v1/entries/programs.php | 74 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 7f6bb6c5f7..3e61e2ff43 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -29,53 +29,47 @@ class programsEntry extends Entry $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); $data = $this->getData(); - if(isset($data->status) and $data->status == 'success') + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + $programs = (array)$data->data->programs; + $progressList = $data->data->progressList; + $users = $data->data->users; + $result = array(); + foreach($programs as $program) { - $programs = (array)$data->data->programs; - $progressList = $data->data->progressList; - $users = $data->data->users; - $result = array(); - foreach($programs as $program) + $program->progress = zget($progressList, $program->id, 0); + $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); + + if($mergeChildren) { - $program->progress = zget($progressList, $program->id, 0); - $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); + unset($program->desc); + $program->openedBy = zget($users, $program->openedBy); + $program->closedBy = zget($users, $program->closedBy); + $program->canceledBy = zget($users, $program->canceledBy); + $program->PO = zget($users, $program->PO); + $program->PM = zget($users, $program->PM); + $program->QD = zget($users, $program->QD); + $program->RD = zget($users, $program->RD); + $program->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end; - if($mergeChildren) + $programBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$program->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$program->budget, 2); + $program->labelBudget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future; + + if(empty($program->parent)) $result[$program->id] = $program; + if(isset($programs[$program->parent])) { - unset($program->desc); - $program->openedBy = zget($users, $program->openedBy); - $program->closedBy = zget($users, $program->closedBy); - $program->canceledBy = zget($users, $program->canceledBy); - $program->PO = zget($users, $program->PO); - $program->PM = zget($users, $program->PM); - $program->QD = zget($users, $program->QD); - $program->RD = zget($users, $program->RD); - $program->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end; - - $programBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$program->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$program->budget, 2); - $program->labelBudget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future; - - if(empty($program->parent)) $result[$program->parent][$program->id] = $program; - if(isset($programs[$program->parent])) - { - $parentProgram = $programs[$program->parent]; - if(!isset($parentProgram->children)) $parentProgram->children = array(); - $parentProgram->children[] = $program; - } - } - else - { - $result[] = $program; + $parentProgram = $programs[$program->parent]; + if(!isset($parentProgram->children)) $parentProgram->children = array(); + $parentProgram->children[] = $program; } } - return $this->send(200, array('programs' => array_values($result))); + else + { + $result[] = $program; + } } - if(isset($data->status) and $data->status == 'fail') - { - return $this->sendError(400, $data->message); - } - - return $this->sendError(400, 'error'); + return $this->send(200, array('programs' => array_values($result))); } /** From d68ce78a66d73442f114957b22e060455f91aa92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 14:40:42 +0800 Subject: [PATCH 059/129] * code for task #44325. --- api/v1/entries/project.php | 52 ++++++++++++++++++++++++- module/action/model.php | 79 ++++++++++++++++++++++++++++++++++++++ module/my/model.php | 26 ++----------- module/project/model.php | 24 +++++++++--- 4 files changed, 151 insertions(+), 30 deletions(-) diff --git a/api/v1/entries/project.php b/api/v1/entries/project.php index b46e169f63..ec346cf026 100644 --- a/api/v1/entries/project.php +++ b/api/v1/entries/project.php @@ -20,20 +20,68 @@ class projectEntry extends entry */ public function get($projectID) { + $fields = strtolower($this->param('fields')); + $control = $this->loadController('project', 'view'); $control->view($projectID); $data = $this->getData(); if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); - if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->project, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool')); if(isset($data->status) and $data->status == 'fail') { if(isset($data->code) and $data->code == 404) $this->send404(); return $this->sendError(400, $data->message); } - $this->sendError(400, 'error'); + $project = $this->format($data->data->project, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); + if(empty($fields)) return $this->send(200, $project); + + /* Set other fields. */ + $fields = explode(',', $fields); + foreach($fields as $field) + { + switch($field) + { + case 'team': + $teams = array(); + $accounts = array(); + foreach($data->data->teamMembers as $account => $team) + { + $team = $this->filterFields($team, "account,role,join,realname"); + + $teams[$account] = $team; + $accounts[$account] = $account; + } + $users = $this->loadModel('user')->getListByAccounts($accounts, 'account'); + foreach($teams as $account => $team) + { + $user = zget($users, $account, ''); + $team->avatar = $user->avatar; + } + + $project->teams = $teams; + break; + case "stat": + $project->stat = $data->data->statData; + break; + case "workhour": + $workhour = $data->data->workhour; + $workhour->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0; + $project->workhour = $workhour; + break; + case "actions": + $actions = $data->data->actions; + $project->actions = $this->loadModel('action')->processActionForAPI($actions, (array)$data->data->users, $this->lang->project); + break; + case "dynamics": + $dynamics = $data->data->dynamics; + $project->dynamics = $this->loadModel('action')->processDynamicForAPI($dynamics); + break; + } + } + + return $this->send(200, $project); } /** diff --git a/module/action/model.php b/module/action/model.php index 371da50593..ceed082d13 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -1565,4 +1565,83 @@ class actionModel extends model echo $actionType; } } + + /** + * Process action for API. + * + * @param array $actions + * @param array $users + * @param array $objectLang + * @access public + * @return array + */ + public function processActionForAPI($actions, $users = array(), $objectLang = array()) + { + $actions = (array)$actions; + foreach($actions as $action) + { + $action->actor = zget($users, $action->actor); + if($action->action == 'assigned') $action->extra = zget($users, $action->extra); + if(strpos($action->actor, ':') !== false) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1); + + ob_start(); + $this->printAction($action); + $action->desc = ob_get_contents(); + ob_end_clean(); + + if($action->history) + { + foreach($action->history as $i => $history) + { + $history->fieldName = zget($objectLang, $history->field); + $action->history[$i] = $history; + } + } + } + return array_values($actions); + } + + /** + * Process dynamic for API. + * + * @param array $dynamics + * @access public + * @return array + */ + public function processDynamicForAPI($dynamics) + { + $users = $this->loadModel('user')->getList(); + $simplifyUsers = array(); + foreach($users as $user) + { + $simplifyUser = new stdclass(); + $simplifyUser->id = $user->id; + $simplifyUser->account = $user->account; + $simplifyUser->realname = $user->realname; + $simplifyUser->avatar = $user->avatar; + $simplifyUsers[$user->account] = $simplifyUser; + } + + $actions = array(); + foreach($dynamics as $key => $dynamic) + { + if($dynamic->objectType == 'user') continue; + + $simplifyUser = zget($simplifyUsers, $dynamic->actor, ''); + $actor = $simplifyUser; + if(empty($simplifyUser)) + { + $actor = new stdclass(); + $actor->id = 0; + $actor->account = $dynamic->actor; + $actor->realname = $dynamic->actor; + $actor->avatar = ''; + } + + $dynamic->actor = $actor; + $actions[] = $dynamic; + } + + return $actions; + } } diff --git a/module/my/model.php b/module/my/model.php index 2e858a1e26..57ea22b967 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -302,30 +302,10 @@ class myModel extends model $simplifyUsers[$user->account] = $simplifyUser; } - $i = 1; $maxCount = 5; - $filterActions = array(); - foreach($actions as $key => $action) - { - if($i > $maxCount) break; - if($action->objectType == 'user') continue; + $actions = $this->action->processDynamicForAPI($actions); + $actions = array_slice($actions, 0, $maxCount); - $simplifyUser = zget($simplifyUsers, $action->actor, ''); - $actionActor = $simplifyUser; - if(empty($simplifyUser)) - { - $actionActor = new stdclass(); - $actionActor->id = 0; - $actionActor->account = $action->actor; - $actionActor->realname = $action->actor; - $actionActor->avatar = ''; - } - - $action->actor = $actionActor; - $filterActions[] = $action; - $i++; - } - - return $filterActions; + return $actions; } } diff --git a/module/project/model.php b/module/project/model.php index a0f3c66ab0..d91c2f53f4 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -447,13 +447,27 @@ class projectModel extends model ->andWhere('t1.deleted')->eq(0) ->fetch('storyCount'); - $taskCount = $this->dao->select('count(id) as taskCount')->from(TABLE_TASK)->where('project')->in(array_keys($executions))->andWhere('deleted')->eq(0)->fetch('taskCount'); - $bugCount = $this->dao->select('count(id) as bugCount')->from(TABLE_BUG)->where('project')->in(array_keys($executions))->andWhere('deleted')->eq(0)->fetch('bugCount'); + $taskCount = $this->dao->select('count(id) as taskCount')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere('deleted')->eq(0)->fetch('taskCount'); + $bugCount = $this->dao->select('count(id) as bugCount')->from(TABLE_BUG)->where('project')->in($projectID)->andWhere('deleted')->eq(0)->fetch('bugCount'); + + $statusPairs = $this->dao->select('status,count(id) as count')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere('deleted')->eq(0)->groupBy('status')->fetchPairs('status', 'count'); + $finishedCount = $this->dao->select('count(id) as taskCount')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere('finishedBy')->ne('')->andWhere('deleted')->eq(0)->fetch('taskCount'); + $delayedCount = $this->dao->select('count(id) as count')->from(TABLE_TASK) + ->where('execution')->in(array_keys($executions)) + ->andWhere('deadline')->ne('0000-00-00') + ->andWhere('deadline')->lt(helper::today()) + ->andWhere('status')->in('wait,doing') + ->andWhere('deleted')->eq(0) + ->fetch('count'); $statData = new stdclass(); - $statData->storyCount = $storyCount; - $statData->taskCount = $taskCount; - $statData->bugCount = $bugCount; + $statData->storyCount = $storyCount; + $statData->taskCount = $taskCount; + $statData->bugCount = $bugCount; + $statData->waitCount = zget($statusPairs, 'wait', 0); + $statData->doingCount = zget($statusPairs, 'doing', 0); + $statData->finishedCount = $finishedCount; + $statData->delayedCount = $delayedCount; return $statData; } From e9caee64f7175e076881cc8747d4a0c6d8c15431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 14:41:36 +0800 Subject: [PATCH 060/129] * code for task #44306. --- api/v1/entries/executions.php | 19 +++++++++++++++---- api/v1/entries/product.php | 29 +++-------------------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 594f5722cd..4a55ac51dc 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -21,6 +21,7 @@ class executionsEntry extends entry public function get($projectID = 0) { $appendFields = $this->param('fields', ''); + $withProject = $this->param('withProject', ''); $control = $this->loadController('execution', 'all'); $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); @@ -28,14 +29,24 @@ class executionsEntry extends entry if(isset($data->status) and $data->status == 'success') { - $pager = $data->data->pager; - $result = array(); + $pager = $data->data->pager; + $projects = $data->data->projects; + $result = array(); foreach($data->data->executionStats as $execution) { - $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); + foreach($execution->hours as $field => $value) $execution->$field = $value; + + $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,delay,progress,' . $appendFields); $result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executions' => $result)); + + $data = array(); + $data['page'] = $pager->pageID; + $data['total'] = $pager->recTotal; + $data['limit'] = $pager->recPerPage; + $data['executions'] = $result; + if(!empty($withProject)) $data['projects'] = $projects; + return $this->send(200, $data); } if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); diff --git a/api/v1/entries/product.php b/api/v1/entries/product.php index 9df8b4962c..a2b2294318 100644 --- a/api/v1/entries/product.php +++ b/api/v1/entries/product.php @@ -34,7 +34,7 @@ class productEntry extends Entry $product = $this->format($data->data->product, 'createdDate:time'); - $users = $this->loadModel('user')->getPairs('noletter|nodeleted'); + $users = $data->data->users; $product->PO = $this->formatUser($product->PO, $users); $product->QD = $this->formatUser($product->QD, $users); $product->RD = $this->formatUser($product->RD, $users); @@ -60,31 +60,8 @@ class productEntry extends Entry case 'actions': $product->addComment = common::hasPriv('action', 'comment') ? true : false; - $actions = $this->loadModel('action')->getList('product', $productID); - $product->actions = array(); - foreach($actions as $action) - { - $action->actor = zget($users, $action->actor); - if($action->action == 'assigned') $action->extra = zget($users, $action->extra); - if(strpos($action->actor, ':') !== false) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1); - - ob_start(); - $this->action->printAction($action); - $action->desc = ob_get_contents(); - ob_end_clean(); - - $action = $this->filterFields($action, 'id,objectType,objectID,actor,action,date,comment,extra,desc,history'); - if($action->history) - { - foreach($action->history as $i => $history) - { - $history = $this->filterFields($history, 'id,field,old,new,diff'); - $history->fieldName = zget($this->lang->product, $history->field); - $action->history[$i] = $history; - } - } - $product->actions[] = $action; - } + $actions = $data->data->actions; + $product->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->product); break; } } From ec558fc04a9057354919a0e3a5cb8bee148c1b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 15:06:54 +0800 Subject: [PATCH 061/129] * code for task #44327. --- api/v1/entries/executions.php | 63 ++++++++++++++++++++++------------- api/v1/entries/project.php | 8 ++--- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 4a55ac51dc..0bd49f493d 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -23,34 +23,51 @@ class executionsEntry extends entry $appendFields = $this->param('fields', ''); $withProject = $this->param('withProject', ''); - $control = $this->loadController('execution', 'all'); - $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); - $data = $this->getData(); - - if(isset($data->status) and $data->status == 'success') + if($projectID) { - $pager = $data->data->pager; - $projects = $data->data->projects; - $result = array(); - foreach($data->data->executionStats as $execution) - { - foreach($execution->hours as $field => $value) $execution->$field = $value; + $control = $this->loadController('project', 'execution'); + $control->execution($this->param('status', 'undone'), $projectID, $this->param('order', 'id_desc'), $this->param('product', 0), 0, $this->param('limit', 20), $this->param('page', 1)); - $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,delay,progress,' . $appendFields); - $result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); - } + /* Response */ + $data = $this->getData(); + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); - $data = array(); - $data['page'] = $pager->pageID; - $data['total'] = $pager->recTotal; - $data['limit'] = $pager->recPerPage; - $data['executions'] = $result; - if(!empty($withProject)) $data['projects'] = $projects; - return $this->send(200, $data); + $executions = $data->data->executionStats; + $pager = $data->data->pager; + $projects = $data->data->projects; } - if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + else + { + $control = $this->loadController('execution', 'all'); + $control->all($this->param('status', 'all'), $this->param('project', $projectID), $this->param('order', 'id_desc'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); + $data = $this->getData(); - return $this->sendError(400, 'error'); + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + $executions = $data->data->executionStats; + $pager = $data->data->pager; + $projects = $data->data->projects; + } + + $result = array(); + foreach($data->data->executionStats as $execution) + { + foreach($execution->hours as $field => $value) $execution->$field = $value; + + $execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,delay,progress,' . $appendFields); + $result[] = $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); + } + + $data = array(); + $data['page'] = $pager->pageID; + $data['total'] = $pager->recTotal; + $data['limit'] = $pager->recPerPage; + $data['executions'] = $result; + if(!empty($withProject)) $data['projects'] = $projects; + + return $this->send(200, $data); } /** diff --git a/api/v1/entries/project.php b/api/v1/entries/project.php index ec346cf026..9776cb1615 100644 --- a/api/v1/entries/project.php +++ b/api/v1/entries/project.php @@ -26,13 +26,9 @@ class projectEntry extends entry $control->view($projectID); $data = $this->getData(); - if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); - if(isset($data->status) and $data->status == 'fail') - { - if(isset($data->code) and $data->code == 404) $this->send404(); - return $this->sendError(400, $data->message); - } + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); $project = $this->format($data->data->project, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); if(empty($fields)) return $this->send(200, $project); From d268587e8df03d72f177ca98e413e1a3008d92f1 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 16 Nov 2021 15:07:18 +0800 Subject: [PATCH 062/129] * Finish task #44496. --- module/story/control.php | 35 ++++++++++++++++++++----- module/story/view/batchedit.html.php | 9 +++---- module/testcase/control.php | 30 ++++++++++++++++----- module/testcase/view/batchedit.html.php | 6 ++--- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/module/story/control.php b/module/story/control.php index 9946bdcfa8..2c77f443e7 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -711,14 +711,35 @@ class story extends control $product = $this->product->getByID($productID); $branchProduct = $product->type == 'normal' ? false : true; - /* Set modules. */ - $modules = array('ditto' => $this->lang->story->ditto) + $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); + /* Set branches and modules. */ + $branches = array(); + $modules = array(); + if($product->type != 'normal') + { + $branches = $this->loadModel('branch')->getPairs($productID); + if($branch === 'all') + { + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); + foreach($branches as $branchID => $branchName) + { + $modules[$branchID] = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branchID); + } + } + else + { + $modules[$branch] = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); + } + } + else + { + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); + } - $this->view->modules = $modules; - $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id); - $this->view->plans = $this->productplan->getBranchPlanPairs($productID); - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name); - $this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit; + $this->view->modules = $modules; + $this->view->branches = $branches; + $this->view->plans = $this->productplan->getBranchPlanPairs($productID); + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name); + $this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit; } elseif($executionID) { diff --git a/module/story/view/batchedit.html.php b/module/story/view/batchedit.html.php index b789d3567e..5e3f65d5cb 100644 --- a/module/story/view/batchedit.html.php +++ b/module/story/view/batchedit.html.php @@ -76,15 +76,12 @@ foreach(explode(',', $showFields) as $field) if($product->type != 'normal') { foreach($branches as $branchID => $branchName) $branches[$branchID] = '/' . $product->name . '/' . $branchName; - $branches = array('ditto' => $this->lang->story->ditto) + $branches; } - $modules = $this->tree->getOptionMenu($story->product, $viewType = 'story', 0, $story->branch); - foreach($modules as $moduleID => $moduleName) $modules[$moduleID] = '/' . $product->name . $moduleName; - $modules = array('ditto' => $this->lang->story->ditto) + $modules; + if(!isset($modules[$story->branch])) $modules[$story->branch] = $this->tree->getOptionMenu($story->product, $viewType = 'story', 0, $story->branch); + foreach($modules[$story->branch] as $moduleID => $moduleName) $modules[$story->branch][$moduleID] = '/' . $product->name . $moduleName; $productPlans = $this->productplan->getPairs($story->product, $branch); - $productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans; } ?> @@ -97,7 +94,7 @@ foreach(explode(',', $showFields) as $field) '> - module, "class='form-control chosen'");?> + branch], $story->module, "class='form-control chosen'");?> '> tree->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0, $branch); - $modules = array('ditto' => $this->lang->testcase->ditto) + $modules; $this->view->modules = $modules; $this->view->title = $libraries[$libID] . $this->lang->colon . $this->lang->testcase->batchEdit; @@ -877,11 +876,31 @@ class testcase extends control if($product->type != 'normal') $branchProduct = true; - /* Set modules. */ - $modules = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch); - $modules = array('ditto' => $this->lang->testcase->ditto) + $modules; + /* Set branches and modules. */ + $branches = array(); + $modules = array(); + if($product->type != 'normal') + { + $branches = $this->loadModel('branch')->getPairs($productID); + if($branch === 'all') + { + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branch); + foreach($branches as $branchID => $branchName) + { + $modules[$branchID] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branchID); + } + } + else + { + $modules[$branch] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branch); + } + } + else + { + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branch); + } - $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id); + $this->view->branches = $branches; $this->view->modules = $modules; $this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); $this->view->title = $product->name . $this->lang->colon . $this->lang->testcase->batchEdit; @@ -906,7 +925,6 @@ class testcase extends control $this->view->position[] = html::a($this->server->http_referer, $this->lang->my->testCase); $this->view->title = $this->lang->testcase->batchEdit; - /* Set modules. */ $productIdList = array(); foreach($cases as $case) $productIdList[$case->product] = $case->product; diff --git a/module/testcase/view/batchedit.html.php b/module/testcase/view/batchedit.html.php index 4095b21ddf..88762552cf 100644 --- a/module/testcase/view/batchedit.html.php +++ b/module/testcase/view/batchedit.html.php @@ -67,6 +67,7 @@ branch; if((!$productID and !$cases[$caseID]->lib) or $app->tab != 'qa') { $product = $this->product->getByID($cases[$caseID]->product); @@ -74,10 +75,9 @@ if($product->type != 'normal') { foreach($branches as $branchID => $branchName) $branches[$branchID] = '/' . $product->name . '/' . $branchName; - $branches = array('ditto' => $this->lang->story->ditto) + $branches; } - $modules = $this->tree->getOptionMenu($cases[$caseID]->product, $viewType = 'case', 0, $cases[$caseID]->branch); + $modules[$caseBranch] = $this->tree->getOptionMenu($cases[$caseID]->product, $viewType = 'case', 0, $caseBranch); } ?> @@ -103,7 +103,7 @@ branch, "class='form-control chosen' onchange='loadBranches($branchProductID, this.value, $caseID)', $disabled");?> - ' style='overflow:visible'>module, "class='form-control chosen'");?> + ' style='overflow:visible'>module, "class='form-control chosen'");?> ' style='overflow:visible'>story, "class='form-control chosen'");?>
From fdfadb794013c287b6414261e4b032791eec9f96 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 16 Nov 2021 15:15:14 +0800 Subject: [PATCH 063/129] * Modify the wrong parameter. --- module/testcase/control.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index 998577a1eb..01fdfb5e10 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -884,7 +884,7 @@ class testcase extends control $branches = $this->loadModel('branch')->getPairs($productID); if($branch === 'all') { - $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branch); + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, 0); foreach($branches as $branchID => $branchName) { $modules[$branchID] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branchID); @@ -897,7 +897,7 @@ class testcase extends control } else { - $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, $branch); + $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, 0); } $this->view->branches = $branches; From 3b4070c2f01c93e58d8cc354450f1f863e07d6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 15:42:53 +0800 Subject: [PATCH 064/129] * code for task #44329. --- api/v1/entries/executions.php | 47 +++++++++++++++++++++++++++++++++++ api/v1/entries/products.php | 4 +-- api/v1/entries/programs.php | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/api/v1/entries/executions.php b/api/v1/entries/executions.php index 0bd49f493d..507076dabb 100644 --- a/api/v1/entries/executions.php +++ b/api/v1/entries/executions.php @@ -22,6 +22,7 @@ class executionsEntry extends entry { $appendFields = $this->param('fields', ''); $withProject = $this->param('withProject', ''); + if(strpos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu(); if($projectID) { @@ -101,4 +102,50 @@ class executionsEntry extends entry $this->send(201, $this->format($execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time')); } + + /** + * Get drop menu. + * + * @access public + * @return void + */ + public function getDropMenu() + { + $control = $this->loadController('execution', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu($this->request('executionID', 0), $this->request('module', 'execution'), $this->request('method', 'task'), $this->request('extra', '')); + + $data = $this->getData(); + if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); + + $account = $this->app->user->account; + $projects = $data->data->projects; + $dropMenu = array('involved' => array(), 'other' => array(), 'closed' => array()); + foreach($data->data->executions as $projectID => $projectExecutions) + { + foreach($projectExecutions as $execution) + { + if(helper::diffDate(date('Y-m-d'), $execution->end) > 0) $execution->delay = true; + $teams = $execution->teams; + $execution = $this->filterFields($execution, 'id,project,model,type,name,code,status,PM,delay'); + + $projectName = zget($projects, $execution->project, ''); + if($projectName) $execution->name = $projectName . '/' . $execution->name; + + if($execution->status == 'closed') + { + $dropMenu['closed'][] = $execution; + } + elseif($execution->status != 'done' and $execution->status != 'closed' and ($execution->PM == $account or isset($teams->$account))) + { + $dropMenu['involved'][] = $execution; + } + else + { + $dropMenu['other'][] = $execution; + } + } + } + + $this->send(200, $dropMenu); + } } diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 8eefb08255..6aa0ca75f7 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -20,8 +20,8 @@ class productsEntry extends entry */ public function get($programID = 0) { - $fields = strtolower($this->param('fields', '')); - if(strpos(",{$fields},", ',dropmenu,') !== false) return $this->getDropMenu(); + $fields = $this->param('fields', ''); + if(strpos(strtolower(",{$fields},"), ',dropmenu,') !== false) return $this->getDropMenu(); if(!$programID) $programID = $this->param('program', 0); diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 3e61e2ff43..96f2e53891 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -23,7 +23,7 @@ class programsEntry extends Entry $mergeChildren = $this->param('mergeChildren', 0); $fields = $this->param('fields', ''); - if(stripos(",{$fields},", ",dropmenu,") !== false) return $this->getDropMenu(); + if(stripos(strtolower(",{$fields},"), ",dropmenu,") !== false) return $this->getDropMenu(); $program = $this->loadController('program', 'browse'); $program->browse($this->param('status', 'all'), $this->param('order', 'order_asc')); From ba48e8e38f207cb7ab9b10bc8f135578a0e45dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Tue, 16 Nov 2021 17:09:15 +0800 Subject: [PATCH 065/129] * code for task #43761. --- api/v1/entries/product.php | 19 ++++++++++++++++++- module/product/model.php | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/product.php b/api/v1/entries/product.php index a2b2294318..e22c2d34ba 100644 --- a/api/v1/entries/product.php +++ b/api/v1/entries/product.php @@ -43,7 +43,7 @@ class productEntry extends Entry if(!$fields) return $this->send(200, $product); /* Set other fields. */ - $fields = explode(',', $fields); + $fields = explode(',', strtolower($fields)); foreach($fields as $field) { switch($field) @@ -63,6 +63,23 @@ class productEntry extends Entry $actions = $data->data->actions; $product->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->product); break; + case 'lastexecution': + $execution = $this->dao->select('t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.product')->eq($productID) + ->andWhere('t2.type')->in('sprint,stage') + ->orderBy('t2.id desc') + ->limit(1) + ->fetch(); + if($execution) + { + $workhour = $this->loadModel('project')->computerProgress(array($execution->id => $execution)); + if(isset($workhour[$execution->id])) $execution->progress = $workhour[$execution->id]->progress; + } + + $product->lastExecution = $execution; + break; } } diff --git a/module/product/model.php b/module/product/model.php index be7cdac0a8..59ab28e38f 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -1349,6 +1349,10 @@ class productModel extends model $product->bugs = $bugs ? $bugs->count : 0; $product->docs = $docs ? $docs->count : 0; + $closedTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('status')->eq('closed')->andWhere('product')->eq($productID)->fetch('count'); + $allTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch('count'); + $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); + return $product; } From fdade49b5d1d55a1d5a9e1c6c65edc5a647d5455 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Wed, 17 Nov 2021 09:21:05 +0800 Subject: [PATCH 066/129] * Fix the creation and editing of stories and bugs. --- module/bug/css/create.css | 1 + module/bug/js/batchcreate.js | 11 +++++++++++ module/bug/view/edit.html.php | 2 +- module/product/control.php | 4 ++-- module/productplan/control.php | 2 +- module/story/js/batchcreate.js | 11 +++++++++++ 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/module/bug/css/create.css b/module/bug/css/create.css index 433e87435a..de274bd781 100644 --- a/module/bug/css/create.css +++ b/module/bug/css/create.css @@ -45,3 +45,4 @@ html[lang='en'] #deadlineTd .input-group-addon {padding: 5px 18px;} #osBox .required:after {right: 1px;} #osBox {width: 190px;} #projectBox .required:after {right: 1px;} +#branch_chosen {min-width: 90px;} diff --git a/module/bug/js/batchcreate.js b/module/bug/js/batchcreate.js index 41834f78d2..a7ae9e9e8a 100644 --- a/module/bug/js/batchcreate.js +++ b/module/bug/js/batchcreate.js @@ -39,6 +39,17 @@ function setBranchRelated(branchID, productID, num) buildLink = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + "&varName=openedBuilds&build=&branch=" + branchID + "&index=" + num); + /* If the branch of the current row is inconsistent with the one below, clear the module and execution of the nex row. */ + var nextBranchID = $('#branch' + (num + 1)).val(); + if(nextBranchID != branchID) + { + $('#modules' + (num + 1)).find("option[value='ditto']").remove(); + $('#modules' + (num + 1)).trigger("chosen:updated"); + + $('#executions' + (num + 1)).find("option[value='ditto']").remove(); + $('#executions' + (num + 1)).trigger("chosen:updated"); + } + setOpenedBuilds(buildLink, num); } diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php index 552d3e2002..ae065ded78 100644 --- a/module/bug/view/edit.html.php +++ b/module/bug/view/edit.html.php @@ -19,7 +19,7 @@ js::set('changeProductConfirmed' , false); js::set('changeExecutionConfirmed' , false); js::set('confirmChangeProduct' , $lang->bug->confirmChangeProduct); js::set('planID' , $bug->plan); -js::set('oldExecutionID' , $bug->execution); +js::set('oldProjectID' , $bug->project); js::set('oldStoryID' , $bug->story); js::set('oldTaskID' , $bug->task); js::set('oldOpenedBuild' , $bug->openedBuild); diff --git a/module/product/control.php b/module/product/control.php index f1628fdda8..38a40b0eeb 100644 --- a/module/product/control.php +++ b/module/product/control.php @@ -929,7 +929,7 @@ class product extends control public function ajaxGetProjects($productID, $branch = 0, $projectID = 0) { $projects = array('' => ''); - $projects += $this->product->getProjectPairsByProduct($productID, $branch ? "0,$branch" : $branch); + $projects += $this->product->getProjectPairsByProduct($productID, $branch); if($this->app->getViewType() == 'json') die(json_encode($projects)); die(html::select('project', $projects, $projectID, "class='form-control' onchange='loadProductExecutions({$productID}, this.value)'")); @@ -948,7 +948,7 @@ class product extends control */ public function ajaxGetExecutions($productID, $projectID = 0, $branch = 0, $number = '', $executionID = 0) { - $executions = $this->product->getExecutionPairsByProduct($productID, $branch ? "0,$branch" : $branch, 'id_desc', $projectID); + $executions = $this->product->getExecutionPairsByProduct($productID, $branch, 'id_desc', $projectID); if($this->app->getViewType() == 'json') die(json_encode($executions)); if($number === '') diff --git a/module/productplan/control.php b/module/productplan/control.php index 4b4f947742..b5f8500776 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -346,7 +346,7 @@ class productplan extends control } else { - $plans = $this->productplan->getPairs($productID, $branch, $expired); + $plans = $this->productplan->getPairs($productID, $branch); } $planName = $number === '' ? 'plan' : "plan[$number]"; diff --git a/module/story/js/batchcreate.js b/module/story/js/batchcreate.js index 412811809f..98da6e91d8 100644 --- a/module/story/js/batchcreate.js +++ b/module/story/js/batchcreate.js @@ -67,6 +67,17 @@ function setModuleAndPlan(branchID, productID, num) $("#plan" + num).next('.picker').remove(); $("#plan" + num).chosen(); }); + + /* If the branch of the current row is inconsistent with the one below, clear the module and plan of the nex row. */ + var nextBranchID = $('#branch' + (num + 1)).val(); + if(nextBranchID != branchID) + { + $('#module' + (num + 1)).find("option[value='ditto']").remove(); + $('#module' + (num + 1)).trigger("chosen:updated"); + + $('#plan' + (num + 1)).find("option[value='ditto']").remove(); + $('#plan' + (num + 1)).trigger("chosen:updated"); + } } /* Copy story title as story spec. */ From bc81d745d8692af5abff5039d5130601f14fe4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 09:22:05 +0800 Subject: [PATCH 067/129] * fix for statistical data. --- module/project/model.php | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/module/project/model.php b/module/project/model.php index d91c2f53f4..2591805d25 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -284,9 +284,10 @@ class projectModel extends model ->andWhere('type')->eq('project') ->groupBy('root')->fetchPairs(); - $hours = $this->dao->select('t2.parent as project, sum(t1.consumed) as consumed, sum(t1.estimate) as estimate')->from(TABLE_TASK)->alias('t1') + $hours = $this->dao->select('t2.parent as project, ROUND(SUM(t1.consumed), 1) AS consumed, ROUND(SUM(t1.estimate), 1) AS estimate')->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.parent')->lt(1) ->groupBy('t2.project') @@ -295,6 +296,7 @@ class projectModel extends model $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') @@ -367,32 +369,38 @@ class projectModel extends model */ public function getWorkhour($projectID) { - $executions = $this->loadModel('execution')->getPairs($projectID); - - $total = $this->dao->select(' - ROUND(SUM(estimate), 1) AS totalEstimate, - ROUND(SUM(`left`), 2) AS totalLeft') - ->from(TABLE_TASK) - ->where('execution')->in(array_keys($executions)) - ->andWhere('deleted')->eq(0) - ->andWhere('parent')->lt(1) + $total = $this->dao->select('ROUND(SUM(estimate), 1) AS totalEstimate, ROUND(SUM(`left`), 2) AS totalLeft')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') + ->where('t2.project')->in($projectID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.parent')->lt(1) ->fetch(); - $totalConsumed = $this->dao->select('ROUND(SUM(consumed), 1) AS totalConsumed')->from(TABLE_TASK) - ->where('execution')->in(array_keys($executions)) - ->andWhere('deleted')->eq(0) - ->andWhere('parent')->lt(1) + $totalConsumed = $this->dao->select('ROUND(SUM(consumed), 1) AS totalConsumed')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') + ->where('t2.project')->in($projectID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.parent')->lt(1) ->fetch('totalConsumed'); - $closedTotalLeft = $this->dao->select('ROUND(SUM(`left`), 2) AS totalLeft')->from(TABLE_TASK) - ->where('execution')->in(array_keys($executions)) - ->andWhere('deleted')->eq(0) - ->andWhere('parent')->lt(1) - ->andWhere('status')->in('closed,cancel') + $closedTotalLeft = $this->dao->select('ROUND(SUM(`left`), 2) AS totalLeft')->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') + ->where('t2.project')->in($projectID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.parent')->lt(1) + ->andWhere('t1.status')->in('closed,cancel') ->fetch('totalLeft'); $workhour = new stdclass(); - $workhour->totalHours = $this->dao->select('sum(days * hours) AS totalHours')->from(TABLE_TEAM)->where('root')->in(array_keys($executions))->andWhere('type')->eq('project')->fetch('totalHours'); + $workhour->totalHours = $this->dao->select('sum(t1.days * t1.hours) AS totalHours')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.root=t2.id') + ->where('t2.project')->in($projectID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t1.type')->eq('project') + ->fetch('totalHours'); $workhour->totalEstimate = $total->totalEstimate; $workhour->totalConsumed = $totalConsumed; $workhour->totalLeft = round($total->totalLeft - $closedTotalLeft, 1); From 217c887499f0cc551978ad2b48d5f6e2c68914e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 09:23:43 +0800 Subject: [PATCH 068/129] * code for task #44307. --- api/v1/entries/projects.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 5e5fd1c08e..07a773bc66 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -33,15 +33,26 @@ class projectsEntry extends entry if(isset($data->status) and $data->status == 'success') { $pager = $data->data->pager; + $users = $data->data->users; $result = array(); foreach($data->data->projectStats as $project) { foreach($project->hours as $field => $value) $project->$field = $value; - $project = $this->filterFields($project, 'id,name,code,model,type,parent,begin,end,status,openedBy,openedDate,' . $appendFields); + $project = $this->filterFields($project, 'id,name,code,model,type,budget,budgetUnit,parent,begin,end,status,openedBy,openedDate,PM,delay,progress,' . $appendFields); $result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'); } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => (int)$pager->recPerPage, 'projects' => $result)); + + $data = array(); + $data['page'] = $pager->pageID; + $data['total'] = $pager->recTotal; + $data['limit'] = (int)$pager->recPerPage; + $data['projects'] = $result; + + $withUser = $this->param('withUser', ''); + if(!empty($withUser)) $data['users'] = $users; + + return $this->send(200, $data); } if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); From 7cc9e9f875033594f45c30aa91f2698b7841d9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 09:59:39 +0800 Subject: [PATCH 069/129] * code for task #44308. --- api/v1/entries/projects.php | 15 +++- api/v1/entries/stakeholders.php | 134 ++++++++++++++++++++++++++++++++ config/routes.php | 2 + module/program/model.php | 2 +- 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 api/v1/entries/stakeholders.php diff --git a/api/v1/entries/projects.php b/api/v1/entries/projects.php index 07a773bc66..ae68b4319d 100644 --- a/api/v1/entries/projects.php +++ b/api/v1/entries/projects.php @@ -26,9 +26,18 @@ class projectsEntry extends entry $_COOKIE['involved'] = $this->param('involved', 0); - $control = $this->loadController('project', 'browse'); - $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); - $data = $this->getData(); + if($programID) + { + $control = $this->loadController('program', 'project'); + $control->project($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); + $data = $this->getData(); + } + else + { + $control = $this->loadController('project', 'browse'); + $control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1)); + $data = $this->getData(); + } if(isset($data->status) and $data->status == 'success') { diff --git a/api/v1/entries/stakeholders.php b/api/v1/entries/stakeholders.php new file mode 100644 index 0000000000..e67a3a2d30 --- /dev/null +++ b/api/v1/entries/stakeholders.php @@ -0,0 +1,134 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class stakeholdersEntry extends entry +{ + /** + * GET method. + * + * @param int $programID + * @access public + * @return void + */ + public function get($programID = 0) + { + if(!$programID) $programID = $this->param('program', 0); + + if($programID) + { + $control = $this->loadController('program', 'stakeholder'); + $control->stakeholder($programID, $this->param('order', 't1.id_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); + $data = $this->getData(); + } + + if(isset($data->status) and $data->status == 'success') + { + $this->app->loadLang('stakeholder'); + $pager = $data->data->pager; + $users = $data->data->users; + $result = array(); + foreach($data->data->stakeholders as $stakeholder) + { + $stakeholder->roleName = zget($this->lang->user->roleList, $stakeholder->role, ''); + $stakeholder->typeName = zget($this->lang->stakeholder->fromList, $stakeholder->from, ''); + + $result[] = $stakeholder; + } + + $data = array(); + $data['page'] = $pager->pageID; + $data['total'] = $pager->recTotal; + $data['limit'] = (int)$pager->recPerPage; + $data['stakeholders'] = $result; + + $withUser = $this->param('withUser', ''); + if(!empty($withUser)) $data['users'] = $users; + + return $this->send(200, $data); + } + + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + // TODO There is no handle for 401. + return $this->sendError(400, 'error'); + } + + /** + * POST method. + * + * @access public + * @return void + */ + public function post() + { + $fields = 'name,begin,end,products'; + $this->batchSetPost($fields); + + $this->setPost('code', $this->request('code', '')); + $this->setPost('acl', $this->request('acl', 'private')); + $this->setPost('parent', $this->request('program', 0)); + $this->setPost('whitelist', $this->request('whitelist', array())); + $this->setPost('PM', $this->request('PM', '')); + $this->setPost('model', $this->request('model', 'scrum')); + + $control = $this->loadController('project', 'create'); + $this->requireFields('name,code,begin,end,products'); + + $control->create($this->request('model', 'scrum')); + + $data = $this->getData(); + if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); + if(!isset($data->result)) return $this->sendError(400, 'error'); + + $project = $this->loadModel('project')->getByID($data->id); + + $this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time')); + } + + /** + * Get drop menu. + * + * @access public + * @return void + */ + public function getDropMenu() + { + $control = $this->loadController('project', 'ajaxGetDropMenu'); + $control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse')); + + $data = $this->getData(); + if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); + + $dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array()); + foreach($data->data->projects as $programID => $projects) + { + foreach($projects as $project) + { + if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true; + $project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay'); + + if($project->status == 'closed') + { + $dropMenu['closed'][] = $project; + } + elseif($project->PM == $this->app->user->account) + { + $dropMenu['owner'][] = $project; + } + else + { + $dropMenu['other'][] = $project; + } + } + } + $this->send(200, $dropMenu); + } +} diff --git a/config/routes.php b/config/routes.php index 763319bbc8..e94995e20c 100644 --- a/config/routes.php +++ b/config/routes.php @@ -64,6 +64,8 @@ $routes['/user'] = 'user'; $routes['/programs'] = 'programs'; $routes['/programs/:id'] = 'program'; +$routes['/programs/:id/stakeholders'] = 'stakeholders'; + $routes['/products/:productID/issues'] = 'productIssues'; $routes['/projects/:projectID/issues'] = 'issues'; $routes['/issues'] = 'issues'; diff --git a/module/program/model.php b/module/program/model.php index 01e4bf238c..d053f2370d 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -488,7 +488,7 @@ class programModel extends model */ public function getStakeholders($programID = 0, $orderBy, $pager = null) { - return $this->dao->select('t2.account,t2.realname,t2.role,t2.qq,t2.mobile,t2.phone,t2.weixin,t2.email,t1.id,t1.type,t1.key')->from(TABLE_STAKEHOLDER)->alias('t1') + return $this->dao->select('t2.account,t2.realname,t2.role,t2.qq,t2.mobile,t2.phone,t2.weixin,t2.email,t1.id,t1.type,t1.from,t1.key')->from(TABLE_STAKEHOLDER)->alias('t1') ->leftJoin(TABLE_USER)->alias('t2')->on('t1.user=t2.account') ->where('t1.objectID')->eq($programID) ->andWhere('t1.objectType')->eq('program') From 35cbf3830dbaf8c5ea3afbe6ab769b448c4371f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 10:36:56 +0800 Subject: [PATCH 070/129] * code for task #44309. --- api/v1/entries/products.php | 244 ++++++++++++++++++------------------ module/product/model.php | 7 +- 2 files changed, 126 insertions(+), 125 deletions(-) diff --git a/api/v1/entries/products.php b/api/v1/entries/products.php index 6aa0ca75f7..aad54b2939 100644 --- a/api/v1/entries/products.php +++ b/api/v1/entries/products.php @@ -24,150 +24,73 @@ class productsEntry extends entry if(strpos(strtolower(",{$fields},"), ',dropmenu,') !== false) return $this->getDropMenu(); if(!$programID) $programID = $this->param('program', 0); + $mergeChildren = $this->param('mergeChildren', ''); if($programID) { $control = $this->loadController('program', 'product'); - $control->product($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, 10000); + $control->product($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', '20'), $this->param('page', '1')); /* Response */ $data = $this->getData(); - if(isset($data->status) and $data->status == 'success') - { - $result = array(); - $products = $data->data->products; - foreach($products as $product) $result[] = $this->format($product, 'createdDate:time'); + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + $products = $data->data->products; - return $this->send(200, array('products' => $result)); - } } else { - $mergeChildren = $this->param('mergeChildren', ''); - $control = $this->loadController('product', 'all'); $control->all($this->param('status', 'all'), $this->param('order', 'order_asc')); /* Response */ $data = $this->getData(); - if(isset($data->status) and $data->status == 'success') - { - $result = array(); - if($mergeChildren) - { - $programs = array(); - foreach($data->data->productStructure as $programID => $program) - { - $programs[$programID] = new stdclass(); - if(!empty($programID)) - { - $programs[$programID]->id = $programID; - $programs[$programID]->name = $program->programName; - $programs[$programID]->type = 'program'; - } + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); - $unclosedTotal = 0; - foreach($program as $field => $value) - { - if(!isset($programs[$programID]->children)) $programs[$programID]->children = array(); - if(isset($value->products)) - { - $lineID = $field; - if(empty($lineID)) - { - foreach($value->products as $product) - { - unset($product->desc); - $product->stories = (array)$product->stories; - $product->requirements = (array)$product->requirements; - $closedTotal = ($product->stories['closed'] + $product->requirements['closed']); - $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); - $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); - $programs[$programID]->children[$product->id] = $product; - if($product->status != 'closed') $unclosedTotal += 1; - } - } - else - { - $line = new stdclass(); - $line->id = $lineID; - $line->name = $value->lineName; - $line->type = 'line'; - - $line->children = array(); - foreach($value->products as $product) - { - unset($product->desc); - $product->stories = (array)$product->stories; - $product->requirements = (array)$product->requirements; - $closedTotal = ($product->stories['closed'] + $product->requirements['closed']); - $allTotal = (array_sum($product->stories) + array_sum($product->requirements)); - $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); - $line->children[$product->id] = $product; - if($product->status != 'closed') $unclosedTotal += 1; - } - if(isset($line->children)) $line->children = array_values($line->children); - - $programs[$programID]->children[$lineID] = $line; - } - if(isset($programs[$programID]->children)) $programs[$programID]->children = array_values($programs[$programID]->children); - $programs[$programID]->unclosedTotal = $unclosedTotal; - } - } - - } - - $topProducts = array(); - if(isset($programs[0])) - { - $topProducts = $programs[0]->children; - unset($programs[0]); - } - - $programs = array_values($programs); - foreach($topProducts as $product) $programs[] = $product; - - return $this->send(200, $programs); - } - else - { - $products = $data->data->productStats; - $accounts = array(); - foreach($products as $product) - { - $accounts[$product->PO] = $product->PO; - $accounts[$product->QD] = $product->QD; - $accounts[$product->RD] = $product->RD; - $accounts[$product->createdBy] = $product->createdBy; - if(isset($product->feedback)) $accounts[$product->feedback] = $product->feedback; - if(!empty($product->mailto)) - { - foreach(explode(',', $product->mailto) as $account) - { - $account = trim($account); - if(empty($account)) continue; - $accounts[$account] = $account; - } - } - - $result[] = $this->format($product, 'createdDate:time'); - } - - $data = array(); - $data['total'] = count($result); - $data['products'] = $result; - - $withUser = $this->param('withUser', ''); - if(!empty($withUser)) $data['users'] = $this->loadModel('user')->getListByAccounts($accounts, 'account'); - - return $this->send(200, $data); - } - } + $products = $data->data->productStats; + if($mergeChildren) $products = $data->data->productStructure; } - if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + $result = array(); + if($mergeChildren) + { + $programs = $this->mergeChildren($products); + return $this->send(200, $programs); + } + else + { + $accounts = array(); + foreach($products as $product) + { + $accounts[$product->PO] = $product->PO; + $accounts[$product->QD] = $product->QD; + $accounts[$product->RD] = $product->RD; + $accounts[$product->createdBy] = $product->createdBy; + if(isset($product->feedback)) $accounts[$product->feedback] = $product->feedback; + if(!empty($product->mailto)) + { + foreach(explode(',', $product->mailto) as $account) + { + $account = trim($account); + if(empty($account)) continue; + $accounts[$account] = $account; + } + } - return $this->sendError(400, 'error'); + $result[] = $this->format($product, 'createdDate:time'); + } + + $data = array(); + $data['total'] = count($result); + $data['products'] = $result; + + $withUser = $this->param('withUser', ''); + if(!empty($withUser)) $data['users'] = $this->loadModel('user')->getListByAccounts($accounts, 'account'); + + return $this->send(200, $data); + } } /** @@ -236,4 +159,77 @@ class productsEntry extends entry } $this->send(200, $dropMenu); } + + /** + * Merge children products. + * + * @param array $products + * @access public + * @return void + */ + public function mergeChildren($products) + { + $programs = array(); + foreach($products as $programID => $program) + { + $programs[$programID] = new stdclass(); + if(!empty($programID)) + { + $programs[$programID]->id = $programID; + $programs[$programID]->name = $program->programName; + $programs[$programID]->type = 'program'; + } + + $unclosedTotal = 0; + foreach($program as $field => $value) + { + if(!isset($programs[$programID]->children)) $programs[$programID]->children = array(); + if(isset($value->products)) + { + $lineID = $field; + if(empty($lineID)) + { + foreach($value->products as $product) + { + unset($product->desc); + $programs[$programID]->children[$product->id] = $product; + if($product->status != 'closed') $unclosedTotal += 1; + } + } + else + { + $line = new stdclass(); + $line->id = $lineID; + $line->name = $value->lineName; + $line->type = 'line'; + + $line->children = array(); + foreach($value->products as $product) + { + unset($product->desc); + $line->children[$product->id] = $product; + if($product->status != 'closed') $unclosedTotal += 1; + } + if(isset($line->children)) $line->children = array_values($line->children); + + $programs[$programID]->children[$lineID] = $line; + } + if(isset($programs[$programID]->children)) $programs[$programID]->children = array_values($programs[$programID]->children); + $programs[$programID]->unclosedTotal = $unclosedTotal; + } + } + } + + $topProducts = array(); + if(isset($programs[0])) + { + $topProducts = $programs[0]->children; + unset($programs[0]); + } + + $programs = array_values($programs); + foreach($topProducts as $product) $programs[] = $product; + + return $programs; + } } diff --git a/module/product/model.php b/module/product/model.php index 59ab28e38f..23fd17ea4c 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -1510,7 +1510,7 @@ class productModel extends model if(empty($programID)) { - $programKeys = array(0=>0); + $programKeys = array(0 => 0); foreach($products as $product) $programKeys[] = $product->program; $programs = $this->dao->select('id,name')->from(TABLE_PROGRAM) ->where('id')->in(array_unique($programKeys)) @@ -1533,6 +1533,11 @@ class productModel extends model $product->fixedBugs = isset($fixedBugs[$product->id]) ? $fixedBugs[$product->id] : 0; $product->thisWeekBugs = isset($thisWeekBugs[$product->id]) ? $thisWeekBugs[$product->id] : 0; $product->assignToNull = isset($assignToNull[$product->id]) ? $assignToNull[$product->id] : 0; + + $closedTotal = $product->stories['closed'] + $product->requirements['closed']; + $allTotal = array_sum($product->stories) + array_sum($product->requirements); + $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); + $stats[] = $product; } From 03236423ae49a08090e1fbab38ccbe47ab89654c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 11:17:47 +0800 Subject: [PATCH 071/129] * code for task #44459. --- api/v1/entries/tabs.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/api/v1/entries/tabs.php b/api/v1/entries/tabs.php index 0448b012e9..03c155b54b 100644 --- a/api/v1/entries/tabs.php +++ b/api/v1/entries/tabs.php @@ -39,6 +39,30 @@ class tabsEntry extends baseEntry $menus[] = $menu; } } + elseif($moduleName == 'product') + { + $this->app->loadLang('product'); + $tabs = array('story', 'plan', 'project', 'release', 'requirement', 'doc', 'view'); + + foreach($tabs as $menuKey) + { + if(!common::hasPriv('product', $menuKey)) continue; + if($menuKey == 'requirement' and empty($this->config->URAndSR)) continue; + + $label = zget($this->lang->product, $menuKey, ''); + if($menuKey == 'view') $label = $this->lang->overview; + if($menuKey == 'doc') $label = $this->lang->doc->common; + if($menuKey == 'project') $label = $this->lang->project->common; + if($menuKey == 'story') $label = $this->lang->createObjects['story']; + if($menuKey == 'requirement') $label = $this->lang->URCommon; + + $menu = new stdclass(); + $menu->code = $menuKey; + $menu->name = $label; + + $menus[] = $menu; + } + } $this->send(200, array('tabs' => $menus)); } From 3956d6bfd0330d8a20b9545999e0e19e7d626afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 13:00:29 +0800 Subject: [PATCH 072/129] * code for task #44310. --- api/v1/entries/stories.php | 48 ++++++++++++-------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/api/v1/entries/stories.php b/api/v1/entries/stories.php index 0f14613b7d..095dcc37b3 100644 --- a/api/v1/entries/stories.php +++ b/api/v1/entries/stories.php @@ -9,53 +9,35 @@ * @version 1 * @link http://www.zentao.net */ -class storiesEntry extends entry +class storiesEntry extends entry { /** * GET method. * * @param int $productID - * @param int $projectID * @access public * @return void */ - public function get($productID = 0, $projectID = 0) + public function get($productID = 0) { if(!$productID) $productID = $this->param('product'); - if(!$projectID) $projectID = $this->param('project'); - if(!$productID and !$projectID) return $this->sendError(400, 'Need product or project id.'); + if(!$productID) return $this->sendError(400, 'Need product id.'); - if($projectID) - { - $control = $this->loadController('projectstory', 'story'); - $control->story($projectID, $productID, $this->param('branch', 0), $this->param('type', ''), 0, 'story', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); - $data = $this->getData(); - } - else - { - $control = $this->loadController('product', 'browse'); - $control->browse($productID, $this->param('branch', 0), $this->param('type', ''), 0, 'story', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); - $data = $this->getData(); - } + $control = $this->loadController('product', 'browse'); + $control->browse($productID, $this->param('branch', ''), $this->param('status', 'unclosed'), 0, $this->param('type', 'story'), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); - if(isset($data->status) and $data->status == 'success') - { - $stories = $data->data->stories; - $pager = $data->data->pager; - $result = array(); - foreach($stories as $story) - { - $result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'); - } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); - } + $data = $this->getData(); + if(!$data or !isset($data->status)) return $this->sendError(400, 'error'); + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); - if(isset($data->status) and $data->status == 'fail') + $stories = $data->data->stories; + $pager = $data->data->pager; + $result = array(); + foreach($stories as $story) { - return $this->sendError(400, $data->message); + $result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'); } - - return $this->sendError(400, 'error'); + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); } /** @@ -83,7 +65,7 @@ class storiesEntry extends entry $this->requireFields('title,spec,pri,category'); $control->create($productID); - + $data = $this->getData(); if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message); if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message); From c14392a3ac8255256a675adc2b0696de1ab3f6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 13:31:56 +0800 Subject: [PATCH 073/129] * round for project progress. --- module/project/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/project/model.php b/module/project/model.php index 2591805d25..0939a9c436 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -1941,7 +1941,7 @@ class projectModel extends model $hour->totalConsumed = round($hour->totalConsumed, 1); $hour->totalLeft = round($hour->totalLeft, 1); $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; - $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0; + $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal * 100, 2) : 0; } return $hours; From f7a063e9ec3e827ef1682393a2d6d9d41df8597a Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Wed, 17 Nov 2021 05:56:48 +0000 Subject: [PATCH 074/129] * Add branch name before product plan name in product list page. --- module/productplan/model.php | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/module/productplan/model.php b/module/productplan/model.php index 893a17f060..9b7274c73b 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -181,25 +181,27 @@ class productplanModel extends model public function getPairs($product = 0, $branch = '', $expired = '', $skipParent = false) { $date = date('Y-m-d'); - $plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN) - ->where('product')->in($product) - ->andWhere('deleted')->eq(0) - ->beginIF($branch !== '')->andWhere('branch')->eq($branch)->fi() - ->beginIF($expired == 'unexpired')->andWhere('end')->ge($date)->fi() - ->beginIF($skipParent)->andWhere('parent')->ne(-1)->fi() - ->orderBy('begin desc') + $plans = $this->dao->select('t1.id,t1.title,t1.parent,t1.begin,t1.end,t2.name as branchName')->from(TABLE_PRODUCTPLAN)->alias('t1') + ->leftJoin(TABLE_BRANCH)->alias('t2')->on('t2.id=t1.branch') + ->where('t1.product')->in($product) + ->andWhere('t1.deleted')->eq(0) + ->beginIF($branch !== '')->andWhere('t1.branch')->eq($branch)->fi() + ->beginIF($expired == 'unexpired')->andWhere('t1.end')->ge($date)->fi() + ->beginIF($skipParent)->andWhere('t1.parent')->ne(-1)->fi() + ->orderBy('t1.begin desc') ->fetchAll('id'); if($expired == 'unexpired') { - $plans += $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN) - ->where('product')->in($product) - ->andWhere('deleted')->eq(0) - ->andWhere('end')->lt($date) - ->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi() - ->beginIF($plans)->andWhere("id")->notIN(array_keys($plans))->fi() - ->beginIF($skipParent)->andWhere('parent')->ne(-1)->fi() - ->orderBy('begin desc') + $plans += $this->dao->select('t1.id,t1.title,t1.parent,t1.begin,t1.end,t2.name as branchName')->from(TABLE_PRODUCTPLAN)->alias('t1') + ->leftJoin(TABLE_BRANCH)->alias('t2')->on('t2.id=t1.branch') + ->where('t1.product')->in($product) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t1.end')->lt($date) + ->beginIF($branch)->andWhere("t1.branch")->in("0,$branch")->fi() + ->beginIF($plans)->andWhere("t1.id")->notIN(array_keys($plans))->fi() + ->beginIF($skipParent)->andWhere('t1.parent')->ne(-1)->fi() + ->orderBy('t1.begin desc') ->limit(5) ->fetchAll('id'); } @@ -211,7 +213,7 @@ class productplanModel extends model { if($plan->parent == '-1') $parentTitle[$plan->id] = $plan->title; if($plan->parent > 0 and isset($parentTitle[$plan->parent])) $plan->title = $parentTitle[$plan->parent] . ' /' . $plan->title; - $planPairs[$plan->id] = $plan->title . " [{$plan->begin} ~ {$plan->end}]"; + $planPairs[$plan->id] = '[' . ($plan->branchName ? $plan->branchName : $this->lang->branch->main) . '] ' . $plan->title . " [{$plan->begin} ~ {$plan->end}]"; if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planPairs[$plan->id] = $plan->title . ' ' . $this->lang->productplan->future; } return array('' => '') + $planPairs; From 859327d7a35d7aad8b4e2b6f89648e5bafaad79d Mon Sep 17 00:00:00 2001 From: tianshujie Date: Wed, 17 Nov 2021 14:50:42 +0800 Subject: [PATCH 075/129] * Modify the logic of loading stories when creating use cases in batches. --- module/story/control.php | 11 +++- module/story/model.php | 5 +- module/testcase/control.php | 5 +- module/testcase/js/batchcreate.js | 75 +++++------------------ module/testcase/js/common.js | 23 +++++++ module/testcase/view/batchcreate.html.php | 4 +- 6 files changed, 52 insertions(+), 71 deletions(-) diff --git a/module/story/control.php b/module/story/control.php index 2c77f443e7..d65168cc40 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -1828,15 +1828,20 @@ class story extends control * AJAX: get stories of a product in html select. * * @param int $productID + * @param int $branch * @param int $moduleID * @param int $storyID * @param string $onlyOption * @param string $status * @param int $limit + * @param string $type + * @param bool $hasParent + * @param int $executionID + * @param int $number * @access public * @return void */ - public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1, $executionID = 0) + public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1, $executionID = 0, $number = '') { if($moduleID) { @@ -1858,11 +1863,11 @@ class story extends control } else { - $stories = $this->story->getProductStoryPairs($productID, $branch ? "0,$branch" : $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent); + $stories = $this->story->getProductStoryPairs($productID, $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent); } $storyID = isset($stories[$storyID]) ? $storyID : 0; - $select = html::select('story', empty($stories) ? array('' => '') : $stories, $storyID, "class='form-control'"); + $select = html::select('story' . $number, empty($stories) ? array('' => '') : $stories, $storyID, "class='form-control'"); /* If only need options, remove select wrap. */ if($onlyOption == 'true') die(substr($select, strpos($select, '>') + 1, -10)); diff --git a/module/story/model.php b/module/story/model.php index 5d51043f70..22ddb25fcf 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -2228,13 +2228,12 @@ class storyModel extends model */ public function getProductStoryPairs($productID = 0, $branch = 0, $moduleIdList = 0, $status = 'all', $order = 'id_desc', $limit = 0, $type = 'full', $storyType = 'story', $hasParent = true) { - if($branch) $branch = "0,$branch";//Fix bug 1059. $stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product') ->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') ->where('1=1') ->beginIF($productID)->andWhere('t1.product')->in($productID)->fi() ->beginIF($moduleIdList)->andWhere('t1.module')->in($moduleIdList)->fi() - ->beginIF($branch)->andWhere('t1.branch')->in($branch)->fi() + ->beginIF($branch !== 'all')->andWhere('t1.branch')->in($branch)->fi() ->beginIF(!$hasParent)->andWhere('t1.parent')->ge(0)->fi() ->beginIF($status and $status != 'all')->andWhere('t1.status')->in($status)->fi() ->andWhere('t1.deleted')->eq(0) @@ -2673,7 +2672,7 @@ class storyModel extends model ->where('t1.project')->eq((int)$executionID) ->andWhere('t2.deleted')->eq(0) ->beginIF($productID)->andWhere('t2.product')->eq((int)$productID)->fi() - ->beginIF($branch)->andWhere('t2.branch')->in("0,$branch")->fi() + ->beginIF($branch != 'all')->andWhere('t2.branch')->eq($branch)->fi() ->beginIF($moduleIdList)->andWhere('t2.module')->in($moduleIdList)->fi() ->beginIF($status == 'unclosed')->andWhere('t2.status')->ne('closed')->fi() ->orderBy('t1.`order` desc') diff --git a/module/testcase/control.php b/module/testcase/control.php index 01fdfb5e10..73501f4046 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -522,8 +522,9 @@ class testcase extends control $this->app->tab == 'project' ? $this->loadModel('project')->setMenu($this->session->project) : $this->testcase->setMenu($this->products, $productID, $branch); /* Set story list. */ - $story = $storyID ? $this->story->getByID($storyID) : ''; - $storyList = $storyID ? array($storyID => $story->id . ':' . $story->title) : array(''); + $story = $storyID ? $this->story->getByID($storyID) : ''; + $storyList = $this->loadModel('story')->getProductStoryPairs($productID, $branch); + $storyList += $storyID ? array($storyID => $story->id . ':' . $story->title) : array(''); /* Set module option menu. */ $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch === 'all' ? 0 : $branch); diff --git a/module/testcase/js/batchcreate.js b/module/testcase/js/batchcreate.js index adfc541b4f..421ffc79f9 100644 --- a/module/testcase/js/batchcreate.js +++ b/module/testcase/js/batchcreate.js @@ -3,66 +3,6 @@ $(document).ready(function() removeDitto();//Remove 'ditto' in first row. if($('#batchCreateForm table thead tr th.c-title').width() < 150) $('#batchCreateForm table thead tr th.c-title').width('150'); - $(document).on('mouseup', '.chosen-with-drop', function() - { - var select = $(this).prev('select'); - var id = $(select).attr('id'); - if(id.indexOf('story') != -1) - { - var index = id.substring(5); - var moduleID = $('#module' + index).val(); - var branch = $('#branch' + index).length > 0 ? $('#branch' + index).val() : 0; - if(moduleID == 'ditto') - { - for(var i = index - 1; i >=0; i--) - { - if($('#module' + i).val() != 'ditto') - { - moduleID = $('#module' + i).val(); - break; - } - } - } - var link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID='+ ($(select).val() || '0') + '&onlyOption=true&status=noclosed&limit=0&type=null&hasParent=0'); - var $story = $('#story' + index); - if($story.data('loadLink') !== link) - { - $story.load(link, function(){$story.data('loadLink', link).trigger("chosen:updated");}); - } - } - if($(select).val() == 'ditto') - { - var index = $(select).closest('td').index(); - var row = $(select).closest('tr').index(); - var table = $(select).closest('tr').parent(); - var value = ''; - for(i = row - 1; i >= 0; i--) - { - value = $(table).find('tr').eq(i).find('td').eq(index).find('select').val(); - if(value != 'ditto') break; - } - $(select).val(value); - $(select).trigger("chosen:updated"); - } - }); - - $(document).on('mousedown', 'select', function() - { - if($(this).val() == 'ditto') - { - var index = $(this).closest('td').index(); - var row = $(this).closest('tr').index(); - var table = $(this).closest('tr').parent(); - var value = ''; - for(i = row - 1; i >= 0; i--) - { - value = $(table).find('tr').eq(i).find('td').eq(index).find('select').val(); - if(value != 'ditto') break; - } - $(this).val(value); - } - }); - $(document).keydown(function(event) { if(event.ctrlKey && event.keyCode == 38) @@ -106,6 +46,19 @@ function setModules(branchID, productID, num) $('#module' + num).replaceWith(modules); $("#module" + num + "_chosen").remove(); $("#module" + num).next('.picker').remove(); - $("#module" + num).chosen(); + $("#module" + num).attr('onchange', "loadStories("+ productID + ", this.value, " + num + ")").chosen(); }); + + loadStories(productID, 0, num); + + /* If the branch of the current row is inconsistent with the one below, clear the module and story of the nex row. */ + var nextBranchID = $('#branch' + (num + 1)).val(); + if(nextBranchID != branchID) + { + $('#module' + (num + 1)).find("option[value='ditto']").remove(); + $('#module' + (num + 1)).trigger("chosen:updated"); + + $('#plan' + (num + 1)).find("option[value='ditto']").remove(); + $('#plan' + (num + 1)).trigger("chosen:updated"); + } } diff --git a/module/testcase/js/common.js b/module/testcase/js/common.js index 5da8863fb8..38e2ae74ce 100644 --- a/module/testcase/js/common.js +++ b/module/testcase/js/common.js @@ -343,3 +343,26 @@ function updateStepID() var i = 1; $('.stepID').each(function(){$(this).html(i ++)}); } + +/** + * Set stories. + * + * @param int productID + * @param int moduleID + * @param int num + * @access public + * @return void + */ +function loadStories(productID, moduleID, num) +{ + var branchID = $('#branch' + num).val(); + var storyLink = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branchID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=0&number=' + num); + $.get(storyLink, function(stories) + { + if(!stories) modules = ''; + $('#story' + num).replaceWith(stories); + $("#story" + num + "_chosen").remove(); + $("#story" + num).next('.picker').remove(); + $("#story" + num).chosen(); + }); +} diff --git a/module/testcase/view/batchcreate.html.php b/module/testcase/view/batchcreate.html.php index 3b76d24e83..a5c29bf3d0 100644 --- a/module/testcase/view/batchcreate.html.php +++ b/module/testcase/view/batchcreate.html.php @@ -83,7 +83,7 @@ '> - ' style='overflow:visible'> + ' style='overflow:visible'> ' style='overflow:visible'> id : '', 'class="form-control chosen"');?>
@@ -124,7 +124,7 @@ %s '> - ' style='overflow:visible'> + ' style='overflow:visible'> ' style='overflow:visible'>
From cad1e69298b22754df09a6b22e48bc0157f7a261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 14:53:33 +0800 Subject: [PATCH 076/129] * finish task #44459. --- api/v1/entries/tabs.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/tabs.php b/api/v1/entries/tabs.php index 03c155b54b..caf7fa7ae5 100644 --- a/api/v1/entries/tabs.php +++ b/api/v1/entries/tabs.php @@ -46,8 +46,16 @@ class tabsEntry extends baseEntry foreach($tabs as $menuKey) { - if(!common::hasPriv('product', $menuKey)) continue; if($menuKey == 'requirement' and empty($this->config->URAndSR)) continue; + if(isset($this->lang->product->menu->$menuKey)) + { + list($label, $module, $method) = explode('|', $this->lang->product->menu->$menuKey['link']); + if(!common::hasPriv($module, $method)) continue; + } + else + { + if(!common::hasPriv('product', $menuKey)) continue; + } $label = zget($this->lang->product, $menuKey, ''); if($menuKey == 'view') $label = $this->lang->overview; From f9473570e007f4de1e6bdfeaa46f24478d0b51e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 15:15:18 +0800 Subject: [PATCH 077/129] * code for task #44317. --- api/v1/entries/projectstories.php | 49 +++++++++++++++++++++++++++++++ config/routes.php | 1 + 2 files changed, 50 insertions(+) create mode 100644 api/v1/entries/projectstories.php diff --git a/api/v1/entries/projectstories.php b/api/v1/entries/projectstories.php new file mode 100644 index 0000000000..867d58a9a1 --- /dev/null +++ b/api/v1/entries/projectstories.php @@ -0,0 +1,49 @@ + + * @package project + * @version 1 + * @link http://www.zentao.net + */ +class projectStoriesEntry extends entry +{ + /** + * GET method. + * + * @param int $projectID + * @access public + * @return void + */ + public function get($projectID) + { + if(!$projectID) $projectID = $this->param('project'); + if(!$projectID) return $this->sendError(400, 'Need product id.'); + + $control = $this->loadController('projectstory', 'story'); + $control->story($projectID, $this->param('product', 0), $this->param('branch', ''), $this->param('status', 'unclosed'), 0, 'story', $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); + $data = $this->getData(); + + if(isset($data->status) and $data->status == 'success') + { + $stories = $data->data->stories; + $pager = $data->data->pager; + $result = array(); + foreach($stories as $story) + { + $result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time'); + } + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); + } + + if(isset($data->status) and $data->status == 'fail') + { + return $this->sendError(400, $data->message); + } + + return $this->sendError(400, 'error'); + } +} diff --git a/config/routes.php b/config/routes.php index e94995e20c..a4709ae1bf 100644 --- a/config/routes.php +++ b/config/routes.php @@ -34,6 +34,7 @@ $routes['/releases/:id'] = 'release'; $routes['/stories'] = 'stories'; $routes['/products/:id/stories'] = 'stories'; +$routes['/projects/:id/stories'] = 'projectStories'; $routes['/executions/:id/stories'] = 'executionStories'; $routes['/stories/:id'] = 'story'; $routes['/stories/:id/change'] = 'storyChange'; From f0ee430addb29b54a49962feeff21b46f4e30003 Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Wed, 17 Nov 2021 07:18:27 +0000 Subject: [PATCH 078/129] * Insert branch name into drop list of bug search form. --- module/bug/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/bug/model.php b/module/bug/model.php index 8e8b91b1a1..6a556db39e 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1313,7 +1313,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')->getProductBuildPairs($productID, 0, $params = ''); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID, 0, $params = 'withbranch'); $this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values']; if($this->session->currentProductType == 'normal') { From 6f813292f2c80239a323036fb9db3e85ae166caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 16:19:16 +0800 Subject: [PATCH 079/129] * code for task #44318. --- api/v1/entries/tasks.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/tasks.php b/api/v1/entries/tasks.php index 3f04889092..7d657f275a 100644 --- a/api/v1/entries/tasks.php +++ b/api/v1/entries/tasks.php @@ -31,7 +31,7 @@ class tasksEntry extends entry { /* Get tasks by execution. */ $control = $this->loadController('execution', 'task'); - $control->task($executionID, $this->param('status', 'all'), 0, $this->param('order', ''), $this->param('total', 0), $this->param('limit', 100), $this->param('page', 1)); + $control->task($executionID, $this->param('status', 'all'), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 100), $this->param('page', 1)); $data = $this->getData(); } @@ -42,6 +42,7 @@ class tasksEntry extends entry $result = array(); foreach($tasks as $task) { + if(isset($task->children)) $task->children = array_values((array)$task->children); $result[] = $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time,deleted:bool'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'tasks' => $result)); From 27d509df08752bed87c46d11583b88f8a74e188c Mon Sep 17 00:00:00 2001 From: tianshujie Date: Wed, 17 Nov 2021 16:28:30 +0800 Subject: [PATCH 080/129] * Finish task #44496. --- module/testcase/js/batchedit.js | 28 ++++++++++++++++++++++++- module/testcase/js/common.js | 12 ++++++----- module/testcase/model.php | 8 +++---- module/testcase/view/batchedit.html.php | 5 +++-- module/testcase/view/edit.html.php | 1 + 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/module/testcase/js/batchedit.js b/module/testcase/js/batchedit.js index 618c579d39..a9cc368d19 100644 --- a/module/testcase/js/batchedit.js +++ b/module/testcase/js/batchedit.js @@ -31,13 +31,39 @@ function loadBranches(product, branch, caseID) if(!branch) branch = 0; moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + product + '&viewtype=case&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=' + caseID + '&needManage=true'); - $('#modules' + caseID).parent('td').load(moduleLink, function(){$('#modules' + caseID).chosen();}) + $('#modules' + caseID).parent('td').load(moduleLink, function() + { + $("#modules" + caseID).attr('onchange', "loadStories("+ product + ", this.value, " + caseID + ")").chosen(); + }); + + loadStories(product, 0, caseID); } $(function() { removeDitto(); //Remove 'ditto' in first row. $('#subNavbar li[data-id="testcase"]').addClass('active'); + if($("[name^='story']").length > 0) + { + $("[name^='story']").each(function() + { + var id = $(this).attr('id'); + var num = id.substring(5); + var moduleID = $('#modules' + num).val(); + var branchID = $('#branches' + num).val(); + var storyID = $("#story" + num).val(); + var storyLink = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branchID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=0&number=' + num); + $.get(storyLink, function(stories) + { + if(!stories) modules = ''; + $('#story' + num).replaceWith(stories); + $('#story' + num + "_chosen").remove(); + $('#story' + num).next('.picker').remove(); + $('#story' + num).attr('name', 'story[' + num + ']').chosen(); + $('#story' + num).val(storyID).trigger('chosen:updated'); + }); + }); + } }); $(document).on('click', '.chosen-with-drop', function(){oldValue = $(this).prev('select').val();})//Save old value. diff --git a/module/testcase/js/common.js b/module/testcase/js/common.js index 38e2ae74ce..8ec70ffa3f 100644 --- a/module/testcase/js/common.js +++ b/module/testcase/js/common.js @@ -355,14 +355,16 @@ function updateStepID() */ function loadStories(productID, moduleID, num) { - var branchID = $('#branch' + num).val(); - var storyLink = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branchID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=0&number=' + num); + var branchIDName = config.currentMethod == 'batchcreate' ? '#branch' : '#branches'; + var branchID = $(branchIDName + num).val(); + var storyLink = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branchID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=0&number=' + num); $.get(storyLink, function(stories) { if(!stories) modules = ''; $('#story' + num).replaceWith(stories); - $("#story" + num + "_chosen").remove(); - $("#story" + num).next('.picker').remove(); - $("#story" + num).chosen(); + $('#story' + num + "_chosen").remove(); + $('#story' + num).next('.picker').remove(); + $('#story' + num).attr('name', 'story[' + num + ']'); + $('#story' + num).chosen(); }); } diff --git a/module/testcase/model.php b/module/testcase/model.php index ad374b9e53..c53bcbd59c 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -863,13 +863,13 @@ class testcaseModel extends model if($data->pris[$caseID] == 'ditto') $data->pris[$caseID] = isset($prev['pri']) ? $prev['pri'] : 3; if($data->branches[$caseID] == 'ditto') $data->branches[$caseID] = isset($prev['branch']) ? $prev['branch'] : 0; if($data->modules[$caseID] == 'ditto') $data->modules[$caseID] = isset($prev['module']) ? $prev['module'] : 0; - if($data->stories[$caseID] == 'ditto') $data->stories[$caseID] = isset($prev['story']) ? $prev['story'] : 0; + if($data->story[$caseID] == 'ditto') $data->story[$caseID] = isset($prev['story']) ? $prev['story'] : 0; if($data->types[$caseID] == 'ditto') $data->types[$caseID] = isset($prev['type']) ? $prev['type'] : ''; - if($data->stories[$caseID] == '') $data->stories[$caseID] = 0; + if($data->story[$caseID] == '') $data->story[$caseID] = 0; $prev['pri'] = $data->pris[$caseID]; $prev['type'] = $data->types[$caseID]; - $prev['story'] = $data->stories[$caseID]; + $prev['story'] = $data->story[$caseID]; $prev['branch'] = $data->branches[$caseID]; $prev['module'] = $data->modules[$caseID]; } @@ -885,7 +885,7 @@ class testcaseModel extends model $case->branch = $data->branches[$caseID]; $case->module = $data->modules[$caseID]; $case->status = $data->statuses[$caseID]; - $case->story = $data->stories[$caseID]; + $case->story = $data->story[$caseID]; $case->color = $data->color[$caseID]; $case->title = $data->title[$caseID]; $case->precondition = $data->precondition[$caseID]; diff --git a/module/testcase/view/batchedit.html.php b/module/testcase/view/batchedit.html.php index 88762552cf..bc98616b26 100644 --- a/module/testcase/view/batchedit.html.php +++ b/module/testcase/view/batchedit.html.php @@ -12,6 +12,7 @@ ?> lang->testcase->dittoNotice);?> +

testcase->common . $lang->colon . $lang->testcase->batchEdit;?>

@@ -103,8 +104,8 @@ branch, "class='form-control chosen' onchange='loadBranches($branchProductID, this.value, $caseID)', $disabled");?> - ' style='overflow:visible'>module, "class='form-control chosen'");?> - ' style='overflow:visible'>story, "class='form-control chosen'");?> + ' style='overflow:visible'>module, "class='form-control chosen' onchange='loadStories($productID, this.value, $caseID)'");?> + ' style='overflow:visible'>story, "class='form-control chosen'");?>
diff --git a/module/testcase/view/edit.html.php b/module/testcase/view/edit.html.php index 46cebce8aa..9764da5f59 100644 --- a/module/testcase/view/edit.html.php +++ b/module/testcase/view/edit.html.php @@ -16,6 +16,7 @@ testcase->insertBefore);?> testcase->insertAfter);?> id);?> +execution);?>

From 0eee3bf282e23a4cea26b825f248d094aae73ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 16:29:16 +0800 Subject: [PATCH 081/129] * code for task #44326. --- api/v1/entries/stories.php | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1/entries/stories.php b/api/v1/entries/stories.php index 095dcc37b3..09e8182702 100644 --- a/api/v1/entries/stories.php +++ b/api/v1/entries/stories.php @@ -35,6 +35,7 @@ class storiesEntry extends entry $result = array(); foreach($stories as $story) { + if(isset($story->children)) $story->children = array_values((array)$story->children); $result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'); } return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); From d4ccff00e360594733db9d9378f40b5abfee0276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Wed, 17 Nov 2021 17:13:00 +0800 Subject: [PATCH 082/129] * fix bug. --- module/task/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/task/model.php b/module/task/model.php index 0a0606e289..673e5735c3 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -2494,7 +2494,7 @@ class taskModel extends model /* Delayed or not?. */ if($task->status !== 'done' and $task->status !== 'cancel' and $task->status != 'closed') { - if(!empty($taks->deadline) and !helper::isZeroDate($task->deadline)) + if(!empty($task->deadline) and !helper::isZeroDate($task->deadline)) { $delay = helper::diffDate($today, $task->deadline); if($delay > 0) $task->delay = $delay; From 79fa0758545ab313b2a65c1fe7133049fd8a75c4 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Wed, 17 Nov 2021 17:25:59 +0800 Subject: [PATCH 083/129] * Scope of repair stories. --- module/testcase/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index 73501f4046..bd5634bc20 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -523,7 +523,7 @@ class testcase extends control /* Set story list. */ $story = $storyID ? $this->story->getByID($storyID) : ''; - $storyList = $this->loadModel('story')->getProductStoryPairs($productID, $branch); + $storyList = $this->loadModel('story')->getProductStoryPairs($productID, $branch === 'all' ? 0 : $branch); $storyList += $storyID ? array($storyID => $story->id . ':' . $story->title) : array(''); /* Set module option menu. */ From 4fd69c66616e08ed632b5fd02d644b4fd50b2dbc Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Wed, 17 Nov 2021 09:59:16 +0000 Subject: [PATCH 084/129] * Finish task 44503. --- module/build/model.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/module/build/model.php b/module/build/model.php index 8a556bf792..81efc3e0d9 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -288,7 +288,8 @@ class buildModel extends model { if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->executionStatus === 'done')) continue; if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue; - $builds[$key] = ((strpos($params, 'withbranch') !== false and $build->branchName) ? $build->branchName . '/' : '') . $build->name; + $branchName = $build->branchName ? $build->branchName : $this->lang->branch->main; + $builds[$key] = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $build->name; } if(!$builds) return $sysBuilds; @@ -302,7 +303,11 @@ class buildModel extends model ->beginIF($branch)->andWhere('branch')->in("0,$branch")->fi() ->andWhere('deleted')->eq(0) ->fetchPairs(); - foreach($releases as $buildID => $releaseName) $builds[$buildID] = ((strpos($params, 'withbranch') !== false and $productBuilds[$buildID]->branchName) ? $productBuilds[$buildID]->branchName . '/' : '') . $releaseName; + foreach($releases as $buildID => $releaseName) + { + $branchName = $productBuilds[$buildID]->branchName ? $productBuilds[$buildID]->branchName : $this->lang->branch->main; + $builds[$buildID] = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName; + } } return $sysBuilds + $builds; From a1e07d2b4b15b7a92c283e42746fd3e9957df3cb Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Wed, 17 Nov 2021 13:55:59 +0000 Subject: [PATCH 085/129] * Finish task 44491. --- module/productplan/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/productplan/model.php b/module/productplan/model.php index 9b7274c73b..a0ea6eef3c 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -213,7 +213,7 @@ class productplanModel extends model { if($plan->parent == '-1') $parentTitle[$plan->id] = $plan->title; if($plan->parent > 0 and isset($parentTitle[$plan->parent])) $plan->title = $parentTitle[$plan->parent] . ' /' . $plan->title; - $planPairs[$plan->id] = '[' . ($plan->branchName ? $plan->branchName : $this->lang->branch->main) . '] ' . $plan->title . " [{$plan->begin} ~ {$plan->end}]"; + $planPairs[$plan->id] = '' . ($plan->branchName ? $plan->branchName : $this->lang->branch->main) . ' ' . $plan->title . " [{$plan->begin} ~ {$plan->end}]"; if($plan->begin == '2030-01-01' and $plan->end == '2030-01-01') $planPairs[$plan->id] = $plan->title . ' ' . $this->lang->productplan->future; } return array('' => '') + $planPairs; From fc50ece3e24102166ffd262f27f0715f960426c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 08:56:53 +0800 Subject: [PATCH 086/129] * code for task #44319. --- api/v1/entries/projectbugs.php | 54 ++++++++++++++++++++++++++++++++++ config/routes.php | 1 + module/bug/model.php | 2 ++ 3 files changed, 57 insertions(+) create mode 100644 api/v1/entries/projectbugs.php diff --git a/api/v1/entries/projectbugs.php b/api/v1/entries/projectbugs.php new file mode 100644 index 0000000000..711e239970 --- /dev/null +++ b/api/v1/entries/projectbugs.php @@ -0,0 +1,54 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class projectbugsEntry extends entry +{ + /** + * GET method. + * + * @param int $projectID + * @access public + * @return void + */ + public function get($projectID = 0) + { + if(!$projectID) $projectID = $this->param('project', 0); + if(empty($projectID)) return $this->sendError(400, 'Need project id.'); + + $control = $this->loadController('project', 'bug'); + $control->bug($projectID, $this->param('product', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); + + $data = $this->getData(); + + if(isset($data->status) and $data->status == 'success') + { + $bugs = $data->data->bugs; + $pager = $data->data->pager; + $result = array(); + foreach($bugs as $bug) + { + $status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]); + if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed); + if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed); + if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs); + $bug->status = $status; + + $result[] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); + } + + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => $result)); + } + + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + return $this->sendError(400, 'error'); + } +} diff --git a/config/routes.php b/config/routes.php index a4709ae1bf..52acdeedc5 100644 --- a/config/routes.php +++ b/config/routes.php @@ -40,6 +40,7 @@ $routes['/stories/:id'] = 'story'; $routes['/stories/:id/change'] = 'storyChange'; $routes['/products/:id/bugs'] = 'bugs'; +$routes['/projects/:id/bugs'] = 'projectBugs'; $routes['/bugs'] = 'bugs'; $routes['/bugs/:id'] = 'bug'; diff --git a/module/bug/model.php b/module/bug/model.php index cfe3c1200e..87c7e7950d 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1511,6 +1511,8 @@ class bugModel extends model ->beginIF(!empty($productID))->andWhere('product')->eq($productID)->fi() ->beginIF($type == 'unresolved')->andWhere('status')->eq('active')->fi() ->beginIF($type == 'noclosed')->andWhere('status')->ne('closed')->fi() + ->beginIF($type == 'assigntome')->andWhere('assignedTo')->eq($this->app->user->account)->fi() + ->beginIF($type == 'openedbyme')->andWhere('openedBy')->eq($this->app->user->account)->fi() ->beginIF($build)->andWhere("CONCAT(',', openedBuild, ',') like '%,$build,%'")->fi() ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi() ->orderBy($orderBy)->page($pager)->fetchAll(); From dcb971c040020747ef9b688ed94274dbeabb7dae Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Thu, 18 Nov 2021 02:39:03 +0000 Subject: [PATCH 087/129] * Finish task 44491. --- module/product/view/browse.html.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/product/view/browse.html.php b/module/product/view/browse.html.php index e69b1d120b..6e7aaeec95 100644 --- a/module/product/view/browse.html.php +++ b/module/product/view/browse.html.php @@ -485,9 +485,10 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : ''; $plan) { - $searchKey = $withSearch ? ('data-key="' . zget($plansPinYin, $plan, '') . '"') : ''; + $planTitle = strip_tags($plan); + $searchKey = $withSearch ? ('data-key="' . zget($plansPinYin, $plan, '') . '"') : ''; $actionLink = $this->createLink('story', 'batchChangePlan', "planID=$planID"); - echo html::a('#', $plan, '', "$searchKey title='{$plan}' onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\""); + echo html::a('#', $plan, '', "$searchKey title='{$planTitle}' onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\""); } ?>

From 3510f6ef63c42d59b6302d8d6b075d64a74d134f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 11:20:39 +0800 Subject: [PATCH 088/129] * code for task #44321. --- api/v1/entries/doclibs.php | 42 ++++++++++++++++++++++++++ api/v1/entries/docs.php | 38 +++++++++++++++++++++++ config/routes.php | 5 +++ module/bug/model.php | 2 +- module/common/view/kindeditor.html.php | 4 +-- module/doc/model.php | 10 +++--- module/file/control.php | 2 +- 7 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 api/v1/entries/doclibs.php create mode 100644 api/v1/entries/docs.php diff --git a/api/v1/entries/doclibs.php b/api/v1/entries/doclibs.php new file mode 100644 index 0000000000..6438a5abb2 --- /dev/null +++ b/api/v1/entries/doclibs.php @@ -0,0 +1,42 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class doclibsEntry extends Entry +{ + /** + * GET method. + * + * @access public + * @return void + */ + public function get() + { + $type = $this->param('type', 0); + $objectID = $this->param('objectID', 0); + + $libs = $this->loadModel('doc')->getLibs($type, $this->param('extra', ''), $this->param('appendLibs', ''), $objectID); + $result = array(); + foreach($libs as $libID => $libName) + { + $lib = new stdclass(); + $lib->id = $libID; + $lib->name = $libName; + $result[] = $lib; + } + + $lib = new stdclass(); + $lib->id = 'files'; + $lib->name = $this->lang->doclib->files; + $result[] = $lib; + + return $this->send(200, array('libs' => array_values($result))); + } +} diff --git a/api/v1/entries/docs.php b/api/v1/entries/docs.php new file mode 100644 index 0000000000..7eb899539e --- /dev/null +++ b/api/v1/entries/docs.php @@ -0,0 +1,38 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class docsEntry extends Entry +{ + /** + * GET method. + * + * @access public + * @return void + */ + public function get($libID = 0) + { + if(empty($libID)) $libID = $this->param('lib', 0); + if(empty($libID)) return $this->sendError(400, 'Need lib id.'); + + $docTree = $this->loadModel('doc')->getDocTree($libID); + + foreach($docTree as $i => $module) + { + if(empty($module->id)) + { + unset($docTree[$i]); + foreach($module->children as $doc) $docTree[] = $doc; + } + } + + return $this->send(200, array_values($docTree)); + } +} diff --git a/config/routes.php b/config/routes.php index 52acdeedc5..f0072833e6 100644 --- a/config/routes.php +++ b/config/routes.php @@ -97,6 +97,11 @@ $routes['/risks/:id'] = 'risk'; $routes['/departments'] = 'departments'; $routes['/departments/:id'] = 'department'; +$routes['/doclibs'] = 'doclibs'; +$routes['/doclibs/:id'] = 'docs'; +$routes['/docs'] = 'docs'; +$routes['/docs/:id'] = 'doc'; + $routes['/reports'] = 'reports'; $routes['/z/folders'] = 'zfolders'; diff --git a/module/bug/model.php b/module/bug/model.php index 87c7e7950d..22a539f85f 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1511,7 +1511,7 @@ class bugModel extends model ->beginIF(!empty($productID))->andWhere('product')->eq($productID)->fi() ->beginIF($type == 'unresolved')->andWhere('status')->eq('active')->fi() ->beginIF($type == 'noclosed')->andWhere('status')->ne('closed')->fi() - ->beginIF($type == 'assigntome')->andWhere('assignedTo')->eq($this->app->user->account)->fi() + ->beginIF($type == 'assignedtome')->andWhere('assignedTo')->eq($this->app->user->account)->fi() ->beginIF($type == 'openedbyme')->andWhere('openedBy')->eq($this->app->user->account)->fi() ->beginIF($build)->andWhere("CONCAT(',', openedBuild, ',') like '%,$build,%'")->fi() ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi() diff --git a/module/common/view/kindeditor.html.php b/module/common/view/kindeditor.html.php index b155782660..19d2831692 100755 --- a/module/common/view/kindeditor.html.php +++ b/module/common/view/kindeditor.html.php @@ -52,7 +52,7 @@ $uid = uniqid(''); cssData: 'html,body {background: none}.article-content{overflow:visible}.article-content, .article-content table td, .article-content table th {line-height: 1.3846153846; font-size: 13px;}.article-content .table-auto {width: auto!important; max-width: 100%;}', placeholder: noticePasteImg);?>, placeholderStyle: {fontSize: '13px', color: '#888'}, - pasteImage: {postUrl: createLink('file', 'ajaxPasteImage', 'uid=' + kuid)}, + pasteImage: {postUrl: createLink('file', 'ajaxPasteImg', 'uid=' + kuid)}, syncAfterBlur: true, allowFileManager: false, spellcheck: false @@ -90,7 +90,7 @@ $uid = uniqid(''); { items: editorTool, placeholder: $editor.attr('placeholder') || options.placeholder || '', - pasteImage: {postUrl: createLink('file', 'ajaxPasteImage', 'uid=' + kuid), placeholder: $editor.attr('placeholder') || noticePasteImg);?>}, + pasteImage: {postUrl: createLink('file', 'ajaxPasteImg', 'uid=' + kuid), placeholder: $editor.attr('placeholder') || noticePasteImg);?>}, }); try diff --git a/module/doc/model.php b/module/doc/model.php index a49064b751..0e93e7039e 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -80,6 +80,7 @@ class docModel extends model ->where('deleted')->eq(0) ->beginIF($type)->andWhere('type')->eq($type)->fi() ->beginIF(!$type)->andWhere('type')->ne('api')->fi() + ->beginIF($objectID and strpos(',product,project,execution,', ",$type,"))->andWhere($type)->eq($objectID)->fi() ->orderBy('`order`, id desc')->query(); } @@ -88,7 +89,7 @@ class docModel extends model $executions = $this->loadModel('execution')->getPairs(); $libPairs = array(); - while ($lib = $stmt->fetch()) + while($lib = $stmt->fetch()) { if($lib->product != 0 and !isset($products[$lib->product])) continue; if($lib->execution != 0 and !isset($executions[$lib->execution])) continue; @@ -110,7 +111,7 @@ class docModel extends model if(!empty($appendLibs)) { $stmt = $this->dao->select('*')->from(TABLE_DOCLIB)->where('id')->in($appendLibs)->orderBy('`order`, id desc')->query(); - while ($lib = $stmt->fetch()) + while($lib = $stmt->fetch()) { if(!isset($libPairs[$lib->id]) and $this->checkPrivLib($lib, $extra)) $libPairs[$lib->id] = $lib->name; } @@ -1623,10 +1624,7 @@ class docModel extends model static $docGroups; if(empty($docGroups)) { - $docs = $this->dao->select('*')->from(TABLE_DOC) - ->where('lib')->eq((int)$libID) - ->andWhere('deleted')->eq(0) - ->fetchAll(); + $docs = $this->dao->select('*')->from(TABLE_DOC)->where('lib')->eq((int)$libID)->andWhere('deleted')->eq(0)->fetchAll(); $docGroups = array(); foreach($docs as $doc) { diff --git a/module/file/control.php b/module/file/control.php index b36252c3c3..b25ccae783 100644 --- a/module/file/control.php +++ b/module/file/control.php @@ -333,7 +333,7 @@ class file extends control * @access public * @return void */ - public function ajaxPasteImage($uid = '') + public function ajaxPasteImg($uid = '') { if($_POST) die($this->file->pasteImage($this->post->editor, $uid)); } From 6aa55f501136be1f832737a4d896aa6d8a4a724a Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Thu, 18 Nov 2021 03:52:39 +0000 Subject: [PATCH 089/129] * Finish task 44503. Add branch name before version name. --- module/execution/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/model.php b/module/execution/model.php index 7d8f0cdbbd..a5e5040986 100644 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -3096,7 +3096,7 @@ class executionModel extends model foreach($products as $product) { $productModules = $this->loadModel('tree')->getOptionMenu($product->id); - $productBuilds = $this->loadModel('build')->getProductBuildPairs($product->id, 0, $params = 'noempty|notrunk'); + $productBuilds = $this->loadModel('build')->getProductBuildPairs($product->id, 0, $params = 'noempty|notrunk|withbranch'); foreach($productModules as $moduleID => $moduleName) { $modules[$moduleID] = ((count($products) >= 2 and $moduleID) ? $product->name : '') . $moduleName; From 15c1ec6c42b84f0899f1b84fd03f19316ca1777a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 13:16:38 +0800 Subject: [PATCH 090/129] * code for task #44330. --- .../{executionStories.php => executionstories.php} | 14 +++++++------- api/v1/entries/projectstories.php | 5 +---- 2 files changed, 8 insertions(+), 11 deletions(-) rename api/v1/entries/{executionStories.php => executionstories.php} (72%) diff --git a/api/v1/entries/executionStories.php b/api/v1/entries/executionstories.php similarity index 72% rename from api/v1/entries/executionStories.php rename to api/v1/entries/executionstories.php index cf6ba73b58..22e84cf0b5 100644 --- a/api/v1/entries/executionStories.php +++ b/api/v1/entries/executionstories.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class executionStoriesEntry extends entry +class executionStoriesEntry extends entry { /** * GET method. @@ -20,8 +20,11 @@ class executionStoriesEntry extends entry */ public function get($executionID) { + if(empty($executionID)) $this->param('execution', 0); + if(empty($executionID)) return $this->sendError(400, 'Need executiion id.'); + $control = $this->loadController('execution', 'story'); - $control->story($executionID, $this->param('order', ''), $this->param('type', 'all'), 0, $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1)); + $control->story($executionID, $this->param('order', 'id_desc'), $this->param('type', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') @@ -33,13 +36,10 @@ class executionStoriesEntry extends entry { $result[] = $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time'); } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'executionStories' => $result)); + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); } - if(isset($data->status) and $data->status == 'fail') - { - return $this->sendError(400, $data->message); - } + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); return $this->sendError(400, 'error'); } diff --git a/api/v1/entries/projectstories.php b/api/v1/entries/projectstories.php index 867d58a9a1..b8be4683ab 100644 --- a/api/v1/entries/projectstories.php +++ b/api/v1/entries/projectstories.php @@ -39,10 +39,7 @@ class projectStoriesEntry extends entry return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result)); } - if(isset($data->status) and $data->status == 'fail') - { - return $this->sendError(400, $data->message); - } + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); return $this->sendError(400, 'error'); } From 745a2e3feab0e1b20ac6730772c6954bfeecde3d Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 13:42:47 +0800 Subject: [PATCH 091/129] * Code for test-bug. --- module/build/control.php | 1 - module/build/model.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/module/build/control.php b/module/build/control.php index 99ab327ba6..dc78ee7426 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -350,7 +350,6 @@ class build extends control */ public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 0, $index = 0, $type = 'normal') { - $branch = $branch ? "0,$branch" : $branch; $isJsonView = $this->app->getViewType() == 'json'; if($varName == 'openedBuild' ) { diff --git a/module/build/model.php b/module/build/model.php index 9aa8594e56..f0e246c0fe 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -227,7 +227,6 @@ class buildModel extends model */ public function getExecutionBuildPairs($executionID, $productID, $branch = 0, $params = '', $buildIdList = '') { - $branch = str_replace('0,', '', $branch); if($branch == 'all') $branch = 0; $sysBuilds = array(); $selectedBuilds = array(); @@ -271,7 +270,6 @@ class buildModel extends model */ public function getProductBuildPairs($products, $branch = 0, $params = 'noterminate, nodone', $replace = true) { - $branch = str_replace('0,', '', $branch); if($branch == 'all') $branch = 0; $sysBuilds = array(); if(strpos($params, 'noempty') === false) $sysBuilds = array('' => ''); From 26b110b73ac6cacaec5ea79c4407a430f1f02727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 13:45:32 +0800 Subject: [PATCH 092/129] * code for task #44331. --- api/v1/entries/executionbugs.php | 54 ++++++++++++++++++++++++++++++++ api/v1/entries/projectbugs.php | 2 +- config/routes.php | 9 +++--- module/doc/model.php | 1 + 4 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 api/v1/entries/executionbugs.php diff --git a/api/v1/entries/executionbugs.php b/api/v1/entries/executionbugs.php new file mode 100644 index 0000000000..e9a86f0d4c --- /dev/null +++ b/api/v1/entries/executionbugs.php @@ -0,0 +1,54 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class executionBugsEntry extends entry +{ + /** + * GET method. + * + * @param int $executionID + * @access public + * @return void + */ + public function get($executionID = 0) + { + if(!$executionID) $executionID = $this->param('execution', 0); + if(empty($executionID)) return $this->sendError(400, 'Need execution id.'); + + $control = $this->loadController('execution', 'bug'); + $control->bug($executionID, $this->param('product', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); + + $data = $this->getData(); + + if(isset($data->status) and $data->status == 'success') + { + $bugs = $data->data->bugs; + $pager = $data->data->pager; + $result = array(); + foreach($bugs as $bug) + { + $status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]); + if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed); + if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed); + if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs); + $bug->status = $status; + + $result[] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); + } + + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => $result)); + } + + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + return $this->sendError(400, 'error'); + } +} diff --git a/api/v1/entries/projectbugs.php b/api/v1/entries/projectbugs.php index 711e239970..589afe1940 100644 --- a/api/v1/entries/projectbugs.php +++ b/api/v1/entries/projectbugs.php @@ -9,7 +9,7 @@ * @version 1 * @link http://www.zentao.net */ -class projectbugsEntry extends entry +class projectBugsEntry extends entry { /** * GET method. diff --git a/config/routes.php b/config/routes.php index f0072833e6..e782bf3b79 100644 --- a/config/routes.php +++ b/config/routes.php @@ -39,10 +39,11 @@ $routes['/executions/:id/stories'] = 'executionStories'; $routes['/stories/:id'] = 'story'; $routes['/stories/:id/change'] = 'storyChange'; -$routes['/products/:id/bugs'] = 'bugs'; -$routes['/projects/:id/bugs'] = 'projectBugs'; -$routes['/bugs'] = 'bugs'; -$routes['/bugs/:id'] = 'bug'; +$routes['/products/:id/bugs'] = 'bugs'; +$routes['/projects/:id/bugs'] = 'projectBugs'; +$routes['/executions/:id/bugs'] = 'executionBugs'; +$routes['/bugs'] = 'bugs'; +$routes['/bugs/:id'] = 'bug'; $routes['/programs/:id/projects'] = 'projects'; $routes['/projects'] = 'projects'; diff --git a/module/doc/model.php b/module/doc/model.php index 0e93e7039e..46199a50f1 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -1647,6 +1647,7 @@ class docModel extends model $docItem->type = 'doc'; $docItem->id = $doc->id; $docItem->title = $doc->title; + $docItem->acl = $doc->acl; $docItem->url = helper::createLink('doc', 'view', "doc=$doc->id"); $buttons = ''; From 5e473398be741f9e71059ec260f10a7915caa55c Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 13:49:04 +0800 Subject: [PATCH 093/129] * Batch modify the judgment of the branch to which the bug belongs. --- module/bug/control.php | 31 ++++++++++++++++++++++++++++--- module/bug/lang/en.php | 1 + module/bug/lang/zh-cn.php | 1 + module/bug/model.php | 5 ++--- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index a48fc1ec09..b475b2f01e 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -1133,10 +1133,35 @@ class bug extends control { if($this->post->bugIDList) { - $bugIDList = $this->post->bugIDList; - $bugIDList = array_unique($bugIDList); + $bugIDList = $this->post->bugIDList; + $bugIDList = array_unique($bugIDList); + $oldBugs = $this->bug->getByList($bugIDList); + $skipBugIDList = ''; unset($_POST['bugIDList']); - $allChanges = $this->bug->batchChangeBranch($bugIDList, $branchID); + + /* Remove condition mismatched bugs. */ + foreach($bugIDList as $key => $bugID) + { + $oldBug = $oldBugs[$bugID]; + if($branchID == $oldBug->branch) + { + unset($bugIDList[$key]); + continue; + } + elseif($branchID != $oldBug->branch and !empty($oldBug->module)) + { + $skipBugIDList .= '[' . $bugID . ']'; + unset($bugIDList[$key]); + continue; + } + } + + if(!empty($skipBugIDList)) + { + echo js::alert(sprintf($this->lang->bug->noSwitchBranch, $skipBugIDList)); + } + + $allChanges = $this->bug->batchChangeBranch($bugIDList, $branchID, $oldBugs); if(dao::isError()) die(js::error(dao::getError())); foreach($allChanges as $bugID => $changes) { diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php index cfb0dba87c..1a37219fd3 100644 --- a/module/bug/lang/en.php +++ b/module/bug/lang/en.php @@ -192,6 +192,7 @@ $lang->bug->skipClose = 'Bug %s is active. You cannot close it.'; $lang->bug->executionAccessDenied = "You access to the {$lang->executionCommon} to which this bug belongs is denied!"; $lang->bug->stepsNotEmpty = "The reproduction step cannot be empty."; $lang->bug->confirmUnlinkBuild = "Replacing the solution version will disassociate the bug from the old version. Are you sure you want to disassociate the bug from %s?"; +$lang->bug->noSwitchBranch = 'The linked module of Bug%s is not in the current branch. It will be omitted.'; /* Template. */ $lang->bug->tplStep = "

[Steps]


"; diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index 058bd29008..0aa5536766 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -192,6 +192,7 @@ $lang->bug->skipClose = 'Bug %s 不是已解决状态,不能关闭 $lang->bug->executionAccessDenied = "您无权访问该Bug所属的{$lang->executionCommon}!"; $lang->bug->stepsNotEmpty = "重现步骤不能为空。"; $lang->bug->confirmUnlinkBuild = "更换解决版本将取消与旧版本的关联,您确定取消该bug与%s的关联吗?"; +$lang->bug->noSwitchBranch = 'Bug%s所属模块不在当前分支下,将自动忽略。'; /* 模板。*/ $lang->bug->tplStep = "

[步骤]


"; diff --git a/module/bug/model.php b/module/bug/model.php index 8e8b91b1a1..33f99c0160 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1043,18 +1043,17 @@ class bugModel extends model * * @param array $bugIDList * @param int $branchID + * @param array $oldBugs * @access public * @return array */ - public function batchChangeBranch($bugIDList, $branchID) + public function batchChangeBranch($bugIDList, $branchID, $oldBugs) { $now = helper::now(); $allChanges = array(); - $oldBugs = $this->getByList($bugIDList); foreach($bugIDList as $bugID) { $oldBug = $oldBugs[$bugID]; - if($branchID == $oldBug->branch) continue; $bug = new stdclass(); $bug->lastEditedBy = $this->app->user->account; From 0e51961266aec75fc61c93a049f20b8ef35e38f4 Mon Sep 17 00:00:00 2001 From: zhengrunyu Date: Thu, 18 Nov 2021 13:51:25 +0800 Subject: [PATCH 094/129] *Finish task #16378. --- module/bug/control.php | 1 - 1 file changed, 1 deletion(-) diff --git a/module/bug/control.php b/module/bug/control.php index 3052e26bef..f260aa268c 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -519,7 +519,6 @@ class bug extends control $builds = $this->loadModel('build')->getProductBuildPairs($productID, $branch, 'noempty,noterminate,nodone'); $stories = $this->story->getProductStoryPairs($productID, $branch); } - $builds[''] = ''; $moduleOwner = $this->bug->getModuleOwner($moduleID, $productID); From 2df3d6aa390fb9e29ad8e144358b8ef20b0943a2 Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 14:08:07 +0800 Subject: [PATCH 095/129] * Fix bug 16377 --- module/bug/view/create.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php index 2bbe2f801c..9371aaedf5 100644 --- a/module/bug/view/create.html.php +++ b/module/bug/view/create.html.php @@ -50,7 +50,7 @@ js::set('moduleID', $moduleID);
- type != 'normal' and isset($products[$productID])):?> + type != 'normal' and isset($products[$productID])):?>
From 91c8826f45e1329f71f5230769e307ff41de38da Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 14:08:21 +0800 Subject: [PATCH 096/129] * Fix bug 16377 --- module/bug/control.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index 0f9d9f0fbb..9570dd8737 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -433,10 +433,10 @@ class bug extends control } /* Get product, then set menu. */ - $productID = $this->product->saveState($productID, $this->products); - $product = $this->product->getById($productID); + $productID = $this->product->saveState($productID, $this->products); + $productInfo = $this->product->getById($productID); if($branch === '') $branch = (int)$this->cookie->preBranch; - $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); + $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); /* Init vars. */ $projectID = 0; @@ -631,7 +631,7 @@ class bug extends control $this->view->keywords = $keywords; $this->view->severity = $severity; $this->view->type = $type; - $this->view->product = $product; + $this->view->productInfo = $productInfo; $this->view->branch = $branch; $this->view->branches = $branches; $this->view->blockID = $blockID; From 03620d8454ba61d30e0f23e6ddfb6257b09e837b Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 14:24:29 +0800 Subject: [PATCH 097/129] * Fix bug #16364. --- module/project/control.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/module/project/control.php b/module/project/control.php index 86532a81f5..bb2e29974e 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1074,12 +1074,15 @@ class project extends control /* Set project builds. */ $projectBuilds = array(); $productList = $this->project->getProducts($projectID); + $this->app->loadLang('branch'); if(!empty($builds)) { foreach($builds as $build) { /* If product is normal, unset branch name. */ - if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = ''; + if (isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = ''; + else $build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main; + $projectBuilds[$build->product][] = $build; } } From 6df12ce1e9fcf9aa5bc0e5efe5bbf42fcdf95383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 14:41:58 +0800 Subject: [PATCH 098/129] * fix for bug storyChanged. --- api/v1/entries/executionbugs.php | 16 ++++++++++++++-- api/v1/entries/executionstories.php | 4 ++-- api/v1/entries/projectbugs.php | 16 ++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/api/v1/entries/executionbugs.php b/api/v1/entries/executionbugs.php index e9a86f0d4c..a40385adce 100644 --- a/api/v1/entries/executionbugs.php +++ b/api/v1/entries/executionbugs.php @@ -41,10 +41,22 @@ class executionBugsEntry extends entry if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs); $bug->status = $status; - $result[] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); + $result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => $result)); + $storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id') + ->where('t1.id')->in(array_keys($result)) + ->andWhere('t1.story')->ne('0') + ->andWhere('t1.storyVersion != t2.version') + ->fetchAll(); + foreach($storyChangeds as $bugID) + { + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $result[$bugID]->status = $status; + } + + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result))); } if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); diff --git a/api/v1/entries/executionstories.php b/api/v1/entries/executionstories.php index 22e84cf0b5..54a1f971e4 100644 --- a/api/v1/entries/executionstories.php +++ b/api/v1/entries/executionstories.php @@ -21,10 +21,10 @@ class executionStoriesEntry extends entry public function get($executionID) { if(empty($executionID)) $this->param('execution', 0); - if(empty($executionID)) return $this->sendError(400, 'Need executiion id.'); + if(empty($executionID)) return $this->sendError(400, 'Need execution id.'); $control = $this->loadController('execution', 'story'); - $control->story($executionID, $this->param('order', 'id_desc'), $this->param('type', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); + $control->story($executionID, $this->param('order', 'id_desc'), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1)); $data = $this->getData(); if(isset($data->status) and $data->status == 'success') diff --git a/api/v1/entries/projectbugs.php b/api/v1/entries/projectbugs.php index 589afe1940..6c96fa7edb 100644 --- a/api/v1/entries/projectbugs.php +++ b/api/v1/entries/projectbugs.php @@ -41,10 +41,22 @@ class projectBugsEntry extends entry if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs); $bug->status = $status; - $result[] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); + $result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool'); } - return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => $result)); + $storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id') + ->where('t1.id')->in(array_keys($result)) + ->andWhere('t1.story')->ne('0') + ->andWhere('t1.storyVersion != t2.version') + ->fetchAll(); + foreach($storyChangeds as $bugID) + { + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $result[$bugID]->status = $status; + } + + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result))); } if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); From 49b3b22630cad6e939a94a89d04081db6537eab4 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 14:48:05 +0800 Subject: [PATCH 099/129] * Fix bug #16364. --- module/project/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/project/control.php b/module/project/control.php index bb2e29974e..2c31117088 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1080,7 +1080,7 @@ class project extends control foreach($builds as $build) { /* If product is normal, unset branch name. */ - if (isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = ''; + if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = ''; else $build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main; $projectBuilds[$build->product][] = $build; From 22fdf1f0fcb9ea8423607f656717cbcf0f1226f5 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 14:48:21 +0800 Subject: [PATCH 100/129] * Modify code. --- module/story/view/batchedit.html.php | 2 +- module/testcase/control.php | 8 ++++---- module/testcase/js/batchedit.js | 2 +- module/testcase/view/batchcreate.html.php | 2 +- module/testcase/view/batchedit.html.php | 3 ++- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/module/story/view/batchedit.html.php b/module/story/view/batchedit.html.php index 5e3f65d5cb..cc21916e2c 100644 --- a/module/story/view/batchedit.html.php +++ b/module/story/view/batchedit.html.php @@ -78,7 +78,7 @@ foreach(explode(',', $showFields) as $field) foreach($branches as $branchID => $branchName) $branches[$branchID] = '/' . $product->name . '/' . $branchName; } - if(!isset($modules[$story->branch])) $modules[$story->branch] = $this->tree->getOptionMenu($story->product, $viewType = 'story', 0, $story->branch); + if(!isset($modules[$story->branch])) $modules[$story->branch] = $this->tree->getOptionMenu($story->product, 'story', 0, $story->branch); foreach($modules[$story->branch] as $moduleID => $moduleName) $modules[$story->branch][$moduleID] = '/' . $product->name . $moduleName; $productPlans = $this->productplan->getPairs($story->product, $branch); diff --git a/module/testcase/control.php b/module/testcase/control.php index bd5634bc20..dbd207a29b 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -522,9 +522,9 @@ class testcase extends control $this->app->tab == 'project' ? $this->loadModel('project')->setMenu($this->session->project) : $this->testcase->setMenu($this->products, $productID, $branch); /* Set story list. */ - $story = $storyID ? $this->story->getByID($storyID) : ''; - $storyList = $this->loadModel('story')->getProductStoryPairs($productID, $branch === 'all' ? 0 : $branch); - $storyList += $storyID ? array($storyID => $story->id . ':' . $story->title) : array(''); + $story = $storyID ? $this->story->getByID($storyID) : ''; + $storyPairs = $this->loadModel('story')->getProductStoryPairs($productID, $branch === 'all' ? 0 : $branch); + $storyPairs += $storyID ? array($storyID => $story->id . ':' . $story->title) : array(''); /* Set module option menu. */ $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch === 'all' ? 0 : $branch); @@ -553,7 +553,7 @@ class testcase extends control $this->view->product = $product; $this->view->productID = $productID; $this->view->story = $story; - $this->view->storyList = $storyList; + $this->view->storyPairs = $storyPairs; $this->view->productName = $this->products[$productID]; $this->view->moduleOptionMenu = $moduleOptionMenu; $this->view->currentModuleID = $currentModuleID; diff --git a/module/testcase/js/batchedit.js b/module/testcase/js/batchedit.js index a9cc368d19..a8bbaa48bd 100644 --- a/module/testcase/js/batchedit.js +++ b/module/testcase/js/batchedit.js @@ -43,7 +43,7 @@ $(function() { removeDitto(); //Remove 'ditto' in first row. $('#subNavbar li[data-id="testcase"]').addClass('active'); - if($("[name^='story']").length > 0) + if(hasStory) { $("[name^='story']").each(function() { diff --git a/module/testcase/view/batchcreate.html.php b/module/testcase/view/batchcreate.html.php index a5c29bf3d0..6c85306db3 100644 --- a/module/testcase/view/batchcreate.html.php +++ b/module/testcase/view/batchcreate.html.php @@ -84,7 +84,7 @@ '> ' style='overflow:visible'> - ' style='overflow:visible'> id : '', 'class="form-control chosen"');?> + ' style='overflow:visible'> id : '', 'class="form-control chosen"');?>
diff --git a/module/testcase/view/batchedit.html.php b/module/testcase/view/batchedit.html.php index bc98616b26..ae088659cd 100644 --- a/module/testcase/view/batchedit.html.php +++ b/module/testcase/view/batchedit.html.php @@ -68,7 +68,7 @@ branch; + $caseBranch = isset($cases[$caseID]->branch) ? $cases[$caseID]->branch : 0; if((!$productID and !$cases[$caseID]->lib) or $app->tab != 'qa') { $product = $this->product->getByID($cases[$caseID]->product); @@ -141,4 +141,5 @@
+ From 504e284d633f4f44dcb34ebe0b897a89a7af7974 Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 14:48:41 +0800 Subject: [PATCH 101/129] * Fix bug 16377. --- module/bug/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/bug/control.php b/module/bug/control.php index 9570dd8737..bb6eba7a83 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -435,8 +435,8 @@ class bug extends control /* Get product, then set menu. */ $productID = $this->product->saveState($productID, $this->products); $productInfo = $this->product->getById($productID); - if($branch === '') $branch = (int)$this->cookie->preBranch; $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); + if($branch === '') $branch = (int)$this->cookie->preBranch; /* Init vars. */ $projectID = 0; From 073deec2158dcb94c943d5e20f05d0ec230e3bfb Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 15:05:56 +0800 Subject: [PATCH 102/129] * Fix bug 16377 --- module/bug/control.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index bb6eba7a83..049c95a886 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -433,9 +433,9 @@ class bug extends control } /* Get product, then set menu. */ - $productID = $this->product->saveState($productID, $this->products); - $productInfo = $this->product->getById($productID); - $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); + $productID = $this->product->saveState($productID, $this->products); + $productInfo = $this->product->getById($productID); + $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); if($branch === '') $branch = (int)$this->cookie->preBranch; /* Init vars. */ From c26fb976856f43d4ca979a388d8ded9fd9f1cf8d Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 15:07:42 +0800 Subject: [PATCH 103/129] * Fix bug #16364. --- module/project/control.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/module/project/control.php b/module/project/control.php index 2c31117088..6eb93ad269 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1080,8 +1080,14 @@ class project extends control foreach($builds as $build) { /* If product is normal, unset branch name. */ - if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') $build->branchName = ''; - else $build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main; + if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal') + { + $build->branchName = ''; + } + else + { + $build->branchName = isset($build->branchName) ? $build->branchName : $this->lang->branch->main; + } $projectBuilds[$build->product][] = $build; } From 0a03aea29a83e841d400a963265be9bc96694472 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 15:07:51 +0800 Subject: [PATCH 104/129] * Fix bug #16396. --- module/build/control.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/module/build/control.php b/module/build/control.php index dc78ee7426..31dfd5e946 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -71,11 +71,14 @@ class build extends control $products = array(); /* Set branches and products. */ - if($productGroups[$productID]->type != 'normal' and isset($branchGroups[$productID])) + if(!empty($productGroups) and isset($productGroups[$productID])) { - foreach($branchGroups[$productID] as $branchID => $branch) + if($productGroups[$productID]->type != 'normal' and isset($branchGroups[$productID])) { - $branches[$branchID] = $branchPairs[$branchID]; + foreach($branchGroups[$productID] as $branchID => $branch) + { + $branches[$branchID] = $branchPairs[$branchID]; + } } } From eac30e46993b2bce6c180243e938fa5b23f9d88d Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 15:12:38 +0800 Subject: [PATCH 105/129] * Modify code. --- module/build/control.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/module/build/control.php b/module/build/control.php index 31dfd5e946..aa1dc47bef 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -71,14 +71,11 @@ class build extends control $products = array(); /* Set branches and products. */ - if(!empty($productGroups) and isset($productGroups[$productID])) + if(isset($productGroups[$productID]) and $productGroups[$productID]->type != 'normal' and isset($branchGroups[$productID])) { - if($productGroups[$productID]->type != 'normal' and isset($branchGroups[$productID])) + foreach($branchGroups[$productID] as $branchID => $branch) { - foreach($branchGroups[$productID] as $branchID => $branch) - { - $branches[$branchID] = $branchPairs[$branchID]; - } + $branches[$branchID] = $branchPairs[$branchID]; } } From 039784e21228cc72e80dd29ddef47271d4ce9767 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 15:24:15 +0800 Subject: [PATCH 106/129] * Fix code error. --- module/project/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/project/control.php b/module/project/control.php index 8557b12e70..a1b3cebc40 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1080,7 +1080,7 @@ class project extends control /* Set project builds. */ $projectBuilds = array(); - $productList = $this->project->getProducts($projectID); + $productList = $this->product->getProducts($projectID); $this->app->loadLang('branch'); if(!empty($builds)) { From 662a1960f5025ec1c7a473cb9310d9c2b5c0fe9f Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 15:35:54 +0800 Subject: [PATCH 107/129] * Fix bug #16431. --- module/bug/model.php | 2 +- module/build/view/create.html.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/module/bug/model.php b/module/bug/model.php index f9d176f0e6..5489eeaf3b 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -623,7 +623,7 @@ class bugModel extends model $now = helper::now(); $bug = fixer::input('post') - ->cleanInt('product,module,severity,execution,story,task,branch') + ->cleanInt('product,module,severity,project,execution,story,task,branch') ->stripTags($this->config->bug->editor->edit['id'], $this->config->allowedTags) ->setDefault('product,module,execution,story,task,duplicateBug,branch', 0) ->setDefault('openedBuild', '') diff --git a/module/build/view/create.html.php b/module/build/view/create.html.php index d52933ca40..2be6f03c99 100644 --- a/module/build/view/create.html.php +++ b/module/build/view/create.html.php @@ -34,7 +34,6 @@ type != 'normal') { - $branches = $branches[$product->id]; echo "" . html::select('branch', $branches, key($product->branches), "class='form-control chosen'"); } ?> From 75b387619369e640331e9eaa736ce35114830988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 15:47:54 +0800 Subject: [PATCH 108/129] * adjust for bug changed status. --- api/v1/entries/docs.php | 2 +- api/v1/entries/executionbugs.php | 4 ++-- api/v1/entries/projectbugs.php | 4 ++-- api/v1/entries/user.php | 4 ++-- module/bug/lang/zh-cn.php | 1 + module/doc/model.php | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/api/v1/entries/docs.php b/api/v1/entries/docs.php index 7eb899539e..86453efe5d 100644 --- a/api/v1/entries/docs.php +++ b/api/v1/entries/docs.php @@ -33,6 +33,6 @@ class docsEntry extends Entry } } - return $this->send(200, array_values($docTree)); + return $this->send(200, array('docs' => array_values($docTree))); } } diff --git a/api/v1/entries/executionbugs.php b/api/v1/entries/executionbugs.php index a40385adce..786fe343ef 100644 --- a/api/v1/entries/executionbugs.php +++ b/api/v1/entries/executionbugs.php @@ -49,10 +49,10 @@ class executionBugsEntry extends entry ->where('t1.id')->in(array_keys($result)) ->andWhere('t1.story')->ne('0') ->andWhere('t1.storyVersion != t2.version') - ->fetchAll(); + ->fetchPairs('id', 'id'); foreach($storyChangeds as $bugID) { - $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed); $result[$bugID]->status = $status; } diff --git a/api/v1/entries/projectbugs.php b/api/v1/entries/projectbugs.php index 6c96fa7edb..df5c2de092 100644 --- a/api/v1/entries/projectbugs.php +++ b/api/v1/entries/projectbugs.php @@ -49,10 +49,10 @@ class projectBugsEntry extends entry ->where('t1.id')->in(array_keys($result)) ->andWhere('t1.story')->ne('0') ->andWhere('t1.storyVersion != t2.version') - ->fetchAll(); + ->fetchPairs('id', 'id'); foreach($storyChangeds as $bugID) { - $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed); $result[$bugID]->status = $status; } diff --git a/api/v1/entries/user.php b/api/v1/entries/user.php index 65c2932aae..dc3e23579a 100644 --- a/api/v1/entries/user.php +++ b/api/v1/entries/user.php @@ -224,10 +224,10 @@ class userEntry extends Entry ->where('t1.id')->in(array_keys($bugs)) ->andWhere('t1.story')->ne('0') ->andWhere('t1.storyVersion != t2.version') - ->fetchAll(); + ->fetchPairs('id', 'id'); foreach($storyChangeds as $bugID) { - $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->storyChanged); + $status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed); $bugs[$bugID]->status = $status; } diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index fe7157f155..ec0e6032b1 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -158,6 +158,7 @@ $lang->bug->noModule = '
您现在还没有模块信息
请 $lang->bug->delayWarning = " 延期%s天 "; $lang->bug->labelConfirmed = '已确认'; $lang->bug->labelPostponed = '被延期'; +$lang->bug->changed = '已变动'; $lang->bug->storyChanged = '需求变动'; /* 页面标签。*/ diff --git a/module/doc/model.php b/module/doc/model.php index 46199a50f1..0fe8fc9241 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -80,7 +80,7 @@ class docModel extends model ->where('deleted')->eq(0) ->beginIF($type)->andWhere('type')->eq($type)->fi() ->beginIF(!$type)->andWhere('type')->ne('api')->fi() - ->beginIF($objectID and strpos(',product,project,execution,', ",$type,"))->andWhere($type)->eq($objectID)->fi() + ->beginIF($objectID and strpos(',product,project,execution,', ",$type,") !== false)->andWhere($type)->eq($objectID)->fi() ->orderBy('`order`, id desc')->query(); } From 27bd5770b129cc36970898fbcdc110a2ef50fdb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 16:03:06 +0800 Subject: [PATCH 109/129] * code for task #44332. --- api/v1/entries/execution.php | 4 +++ api/v1/entries/executioncases.php | 49 +++++++++++++++++++++++++++++++ config/routes.php | 7 +++-- module/testcase/model.php | 24 ++++++++++++++- 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 api/v1/entries/executioncases.php diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php index 4134a3c3d3..ce54d2ebb5 100644 --- a/api/v1/entries/execution.php +++ b/api/v1/entries/execution.php @@ -33,6 +33,10 @@ class executionEntry extends Entry } $execution = $this->format($data->data->execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); + + $this->app->loadConfig('testcase'); + $execution->caseReview = ($config->testcase->needReview or !empty($config->testcase->forceReview)); + if(!$fields) $this->send(200, $execution); /* Set other fields. */ diff --git a/api/v1/entries/executioncases.php b/api/v1/entries/executioncases.php new file mode 100644 index 0000000000..f0431fb2a6 --- /dev/null +++ b/api/v1/entries/executioncases.php @@ -0,0 +1,49 @@ + + * @package entries + * @version 1 + * @link http://www.zentao.net + */ +class executionCasesEntry extends entry +{ + /** + * GET method. + * + * @param int $executionID + * @access public + * @return void + */ + public function get($executionID = 0) + { + if(!$executionID) $executionID = $this->param('execution', 0); + if(empty($executionID)) return $this->sendError(400, 'Need execution id.'); + + $control = $this->loadController('execution', 'testcase'); + $control->testcase($executionID, $this->param('status', 'all'), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1)); + + $data = $this->getData(); + + if(isset($data->status) and $data->status == 'success') + { + $cases = $data->data->cases; + $pager = $data->data->pager; + $result = array(); + foreach($cases as $case) + { + $case->status = array('code' => $case->status, 'name' => $this->lang->testcase->statusList[$case->status]); + $result[] = $this->format($case, 'openedDate:time,reviewedDate:date,lastEditedDate:time,lastRunDate:time'); + } + + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'cases' => $result)); + } + + if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); + + return $this->sendError(400, 'error'); + } +} diff --git a/config/routes.php b/config/routes.php index e782bf3b79..0a3d96dd15 100644 --- a/config/routes.php +++ b/config/routes.php @@ -83,9 +83,10 @@ $routes['/projects/:projectID/builds'] = 'builds'; $routes['/builds'] = 'builds'; $routes['/builds/:id'] = 'build'; -$routes['/products/:id/testcases'] = 'testcases'; -$routes['/testcases'] = 'testcases'; -$routes['/testcases/:id'] = 'testcase'; +$routes['/products/:id/testcases'] = 'testcases'; +$routes['/executions/:id/testcases'] = 'executioncases'; +$routes['/testcases'] = 'testcases'; +$routes['/testcases/:id'] = 'testcase'; $routes['/projects/:projectID/testtasks'] = 'testtasks'; $routes['/testtasks'] = 'testtasks'; diff --git a/module/testcase/model.php b/module/testcase/model.php index 6da824b03d..8c0123742b 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -302,12 +302,27 @@ class testcaseModel extends model * @param int $executionID * @param string $orderBy * @param object $pager - * @param string $browseType + * @param string $browseType all|wait|needconfirm * @access public * @return array */ public function getExecutionCases($executionID, $orderBy = 'id_desc', $pager = null, $browseType = '') { + if($browseType == 'needconfirm') + { + return $this->dao->select('distinct t1.*, t2.*')->from(TABLE_PROJECTCASE)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') + ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') + ->where('t1.project')->eq((int)$executionID) + ->beginIF($browseType != 'all')->andWhere('t2.status')->eq($browseType)->fi() + ->andWhere('t2.deleted')->eq('0') + ->andWhere('t3.version > t2.storyVersion') + ->andWhere("t3.status")->eq('active') + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + } + return $this->dao->select('distinct t1.*, t2.*')->from(TABLE_PROJECTCASE)->alias('t1') ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id') ->where('t1.project')->eq((int)$executionID) @@ -1701,6 +1716,13 @@ class testcaseModel extends model return false; } + /** + * Summary cases + * + * @param array $cases + * @access public + * @return string + */ public function summary($cases) { $executed = 0; From 8bf4523777c3c3548aa07a2eccdc08ae03eec981 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 16:03:19 +0800 Subject: [PATCH 110/129] * Fix bug #16407. --- module/testcase/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index 53cd578829..cc57a05dfc 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -481,7 +481,7 @@ class testcase extends control $this->view->steps = $steps; $this->view->users = $this->user->getPairs('noletter|noclosed|nodeleted'); $this->view->branch = $branch; - $this->view->branches = $this->session->currentProductType != 'normal' ? $this->loadModel('branch')->getPairs($productID) : array(); + $this->view->branches = $this->session->currentProductType != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array(); $this->display(); } From 940e79bf1f84c034135201eaf1bb339026f608c9 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 16:08:28 +0800 Subject: [PATCH 111/129] * Fix bug #16406. --- module/testcase/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index cc57a05dfc..fb6ff972f2 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -575,7 +575,7 @@ class testcase extends control $this->view->moduleOptionMenu = $moduleOptionMenu; $this->view->currentModuleID = $currentModuleID; $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID); + $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); $this->view->needReview = $this->testcase->forceNotReview() == true ? 0 : 1; $this->display(); From e55bc34ee61363632af5b42454f171d3c3d64ba4 Mon Sep 17 00:00:00 2001 From: zhouxin Date: Thu, 18 Nov 2021 16:26:29 +0800 Subject: [PATCH 112/129] Fix bug 16408. --- module/branch/lang/en.php | 2 ++ module/branch/lang/zh-cn.php | 2 ++ module/group/lang/resource.php | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/module/branch/lang/en.php b/module/branch/lang/en.php index 81588bcc14..6cca8b2078 100644 --- a/module/branch/lang/en.php +++ b/module/branch/lang/en.php @@ -11,11 +11,13 @@ $lang->branch->main = 'Main'; $lang->branch->edit = 'Edit'; $lang->branch->editAction = 'Edit %s'; +$lang->branch->editBranch = 'Edit Branch'; $lang->branch->activate = 'Activate'; $lang->branch->activateAction = 'Activate Branch'; $lang->branch->close = 'Close'; $lang->branch->closeAction = 'Close Branch'; $lang->branch->create = 'Create %s'; +$lang->branch->createBranch = 'Create Branch'; $lang->branch->merge = 'Merge'; $lang->branch->batchEdit = 'Batch Edit'; $lang->branch->defaultBranch = 'Default Branch'; diff --git a/module/branch/lang/zh-cn.php b/module/branch/lang/zh-cn.php index 3e8846ae00..b1d2ee5ed8 100644 --- a/module/branch/lang/zh-cn.php +++ b/module/branch/lang/zh-cn.php @@ -11,11 +11,13 @@ $lang->branch->main = '主干'; $lang->branch->edit = '编辑'; $lang->branch->editAction = '编辑%s'; +$lang->branch->editBranch = '编辑分支'; $lang->branch->activate = '激活'; $lang->branch->activateAction = '激活分支'; $lang->branch->close = '关闭'; $lang->branch->closeAction = '关闭分支'; $lang->branch->create = '新增%s'; +$lang->branch->createBranch = '新增分支'; $lang->branch->merge = '合并'; $lang->branch->batchEdit = '批量编辑'; $lang->branch->defaultBranch = '默认分支'; diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index f08660dd09..d582ce1d2e 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -421,8 +421,8 @@ $lang->product->methodOrder[105] = 'unbindWhitelist'; /* Branch. */ $lang->resource->branch = new stdclass(); $lang->resource->branch->manage = 'manage'; -$lang->resource->branch->create = 'create'; -$lang->resource->branch->edit = 'editAction'; +$lang->resource->branch->create = 'createBranch'; +$lang->resource->branch->edit = 'editBranch'; $lang->resource->branch->close = 'closeAction'; $lang->resource->branch->activate = 'activateAction'; $lang->resource->branch->sort = 'sort'; From d03b905ffdfb6a4e2defb3c3bb59254c082d60d7 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 16:30:07 +0800 Subject: [PATCH 113/129] * Fix bug #16407. --- module/testcase/control.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index fb6ff972f2..ac0f94e510 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -213,7 +213,7 @@ class testcase extends control $this->view->param = $param; $this->view->cases = $cases; $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID); + $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); $this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID); $this->view->suiteID = $suiteID; $this->view->setModule = true; @@ -814,7 +814,7 @@ class testcase extends control } $this->view->productID = $productID; - $this->view->branches = $this->session->currentProductType == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); + $this->view->branches = $this->session->currentProductType == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID, 'active'); $this->view->productName = $this->products[$productID]; $this->view->moduleOptionMenu = $moduleOptionMenu; $this->view->stories = $this->story->getProductStoryPairs($productID, $case->branch); @@ -899,7 +899,7 @@ class testcase extends control $modules = array(); if($product->type != 'normal') { - $branches = $this->loadModel('branch')->getPairs($productID); + $branches = $this->loadModel('branch')->getPairs($productID, 'active'); if($branch === 'all') { $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, 0); From 9c6c4dfc9cac69780b3e9dd9be42816ac95e22f5 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Thu, 18 Nov 2021 16:30:45 +0800 Subject: [PATCH 114/129] * Fix bug #16429. --- module/bug/control.php | 28 ++++++++++++++++- module/bug/js/batchcreate.js | 47 ---------------------------- module/bug/js/common.js | 49 ++++++++++++++++++++++++++++++ module/bug/model.php | 1 + module/bug/view/batchedit.html.php | 16 +++++----- 5 files changed, 86 insertions(+), 55 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index 099c5d7da1..788af51d62 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -1013,12 +1013,38 @@ class bug extends control $plans = $this->loadModel('productplan')->getPairs($productID, $branch); $plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans; + /* Set branches and modules. */ + $branches = array(); + $modules = array(); + if($product->type != 'normal') + { + $branches = $this->loadModel('branch')->getPairs($productID); + if($branch === 'all') + { + $modules[0] = $this->tree->getOptionMenu($productID, 'bug', 0, 0); + foreach($branches as $branchID => $branchName) + { + $modules[$branchID] = $this->tree->getOptionMenu($productID, 'bug', 0, $branchID); + } + } + else + { + $modules[$branch] = $this->tree->getOptionMenu($productID, 'bug', 0, $branch); + } + } + else + { + $modules[0] = $this->tree->getOptionMenu($productID, 'bug', 0, 0); + } + /* Set product menu. */ $this->qa->setMenu($this->products, $productID, $branch); + $this->view->title = $product->name . $this->lang->colon . "BUG" . $this->lang->bug->batchEdit; $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID&branch=$branch"), $this->products[$productID]); $this->view->plans = $plans; - $this->view->branches = $product->type == 'normal' ? array() : array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->loadModel('branch')->getPairs($product->id); + $this->view->branches = $branches; + $this->view->modules = $modules; } /* The bugs of my. */ else diff --git a/module/bug/js/batchcreate.js b/module/bug/js/batchcreate.js index a7ae9e9e8a..107911a375 100644 --- a/module/bug/js/batchcreate.js +++ b/module/bug/js/batchcreate.js @@ -6,53 +6,6 @@ $(function() if($titleCol.width() < 150) $titleCol.width(150); }) -/** - * Set branch related. - * - * @param int $branchID - * @param int $productID - * @param int $num - * @access public - * @return void - */ -function setBranchRelated(branchID, productID, num) -{ - moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=bug&branch=' + branchID + '&num=' + num); - $.get(moduleLink, function(modules) - { - if(!modules) modules = ''; - $('#modules' + num).replaceWith(modules); - $("#modules" + num + "_chosen").remove(); - $("#modules" + num).next('.picker').remove(); - $("#modules" + num).chosen(); - }); - - executionLink = createLink('product', 'ajaxGetExecutions', 'productID=' + productID + '&projectID=0&branch=' + branchID + '&num=' + num); - $.get(executionLink, function(executions) - { - if(!executions) executions = ''; - $('#executions' + num).replaceWith(executions); - $("#executions" + num + "_chosen").remove(); - $("#executions" + num).next('.picker').remove(); - $("#executions" + num).chosen(); - }); - - buildLink = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + "&varName=openedBuilds&build=&branch=" + branchID + "&index=" + num); - - /* If the branch of the current row is inconsistent with the one below, clear the module and execution of the nex row. */ - var nextBranchID = $('#branch' + (num + 1)).val(); - if(nextBranchID != branchID) - { - $('#modules' + (num + 1)).find("option[value='ditto']").remove(); - $('#modules' + (num + 1)).trigger("chosen:updated"); - - $('#executions' + (num + 1)).find("option[value='ditto']").remove(); - $('#executions' + (num + 1)).trigger("chosen:updated"); - } - - setOpenedBuilds(buildLink, num); -} - /** * Set opened builds. * diff --git a/module/bug/js/common.js b/module/bug/js/common.js index 232bdc991e..6d798c1c4c 100644 --- a/module/bug/js/common.js +++ b/module/bug/js/common.js @@ -612,3 +612,52 @@ function notice() } } } + +/** + * Set branch related. + * + * @param int $branchID + * @param int $productID + * @param int $num + * @access public + * @return void + */ +function setBranchRelated(branchID, productID, num) +{ + moduleLink = createLink('tree', 'ajaxGetModules', 'productID=' + productID + '&viewType=bug&branch=' + branchID + '&num=' + num); + $.get(moduleLink, function(modules) + { + if(!modules) modules = ''; + $('#modules' + num).replaceWith(modules); + $("#modules" + num + "_chosen").remove(); + $("#modules" + num).next('.picker').remove(); + $("#modules" + num).chosen(); + }); + + executionLink = createLink('product', 'ajaxGetExecutions', 'productID=' + productID + '&projectID=0&branch=' + branchID + '&num=' + num); + $.get(executionLink, function(executions) + { + if(!executions) executions = ''; + $('#executions' + num).replaceWith(executions); + $("#executions" + num + "_chosen").remove(); + $("#executions" + num).next('.picker').remove(); + $("#executions" + num).chosen(); + }); + + buildLink = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + "&varName=openedBuilds&build=&branch=" + branchID + "&index=" + num); + + /* If the branch of the current row is inconsistent with the one below, clear the module and execution of the nex row. */ + if(config.currentMethod == 'batchCreate') + { + var nextBranchID = $('#branch' + (num + 1)).val(); + if(nextBranchID != branchID) + { + $('#modules' + (num + 1)).find("option[value='ditto']").remove(); + $('#modules' + (num + 1)).trigger("chosen:updated"); + + $('#executions' + (num + 1)).find("option[value='ditto']").remove(); + $('#executions' + (num + 1)).trigger("chosen:updated"); + } + setOpenedBuilds(buildLink, num); + } +} diff --git a/module/bug/model.php b/module/bug/model.php index 5489eeaf3b..a35bc19d65 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -742,6 +742,7 @@ class bugModel extends model $bug->title = $data->titles[$bugID]; $bug->plan = empty($data->plans[$bugID]) ? 0 : $data->plans[$bugID]; $bug->branch = empty($data->branches[$bugID]) ? 0 : $data->branches[$bugID]; + $bug->module = $data->modules[$bugID]; $bug->assignedTo = $data->assignedTos[$bugID]; $bug->deadline = $data->deadlines[$bugID]; $bug->resolvedBy = $data->resolvedBys[$bugID]; diff --git a/module/bug/view/batchedit.html.php b/module/bug/view/batchedit.html.php index 86a92f7867..48b9906c41 100644 --- a/module/bug/view/batchedit.html.php +++ b/module/bug/view/batchedit.html.php @@ -51,10 +51,11 @@ '>bug->type;?> '>bug->severity;?> '>bug->pri;?> - bug->title;?> + bug->title;?> - '>bug->branch;?> + bug->branch;?> + '> bug->module;?> '>bug->productplan;?> '>bug->assignedTo;?> '>bug->deadline;?> @@ -78,14 +79,14 @@ { $product = $this->product->getByID($bug->product); - $plans = $this->loadModel('productplan')->getPairs($bug->product, $branch); - $plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans; + $bugBranch = isset($bug->branch) ? $bug->branch : 0; + $plans = $this->loadModel('productplan')->getPairs($bug->product, $branch); $branches = $product->type == 'normal' ? array('' => '') : $this->loadModel('branch')->getPairs($product->id); if($product->type != 'normal') { foreach($branches as $branchID => $branchName) $branches[$branchID] = '/' . $product->name . '/' . $branchName; - $branches = array('ditto' => $this->lang->story->ditto) + $branches; + $modules[$bugBranch] = $this->tree->getOptionMenu($bug->product, $viewType = 'case', 0, $bugBranch); } } ?> @@ -109,12 +110,13 @@
- ' style='overflow:visible'> + id;?> type == 'normal') ? "disabled='disabled'" : '';?> - branch, "class='form-control chosen' $disabled");?> + branch, "class='form-control chosen' $disabled onchange='setBranchRelated(this.value, $bug->product, $bug->id)'");?> + branch], $bug->module, "class='form-control chosen'");?> ' style='overflow:visible'>plan, "class='form-control chosen'");?> ' style='overflow:visible'>assignedTo, "class='form-control chosen'");?> ' style='overflow:visible'>deadline, "class='form-control form-date'");?> From 5dd63cd0212e4d54d0e353153b7e39cb0d2ec2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 16:31:27 +0800 Subject: [PATCH 115/129] * fix doclibs order and fix loadModule testcase. --- api/v1/entries/doclibs.php | 1 + api/v1/entries/execution.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/v1/entries/doclibs.php b/api/v1/entries/doclibs.php index 6438a5abb2..b41d8270f4 100644 --- a/api/v1/entries/doclibs.php +++ b/api/v1/entries/doclibs.php @@ -31,6 +31,7 @@ class doclibsEntry extends Entry $lib->name = $libName; $result[] = $lib; } + krsort($result); $lib = new stdclass(); $lib->id = 'files'; diff --git a/api/v1/entries/execution.php b/api/v1/entries/execution.php index ce54d2ebb5..e668ba5c39 100644 --- a/api/v1/entries/execution.php +++ b/api/v1/entries/execution.php @@ -34,8 +34,8 @@ class executionEntry extends Entry $execution = $this->format($data->data->execution, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'); - $this->app->loadConfig('testcase'); - $execution->caseReview = ($config->testcase->needReview or !empty($config->testcase->forceReview)); + $this->loadModel('testcase'); + $execution->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview)); if(!$fields) $this->send(200, $execution); From 3a48a570472e5444cfd0382749fdf39a383017af Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 16:42:27 +0800 Subject: [PATCH 116/129] * Fix bug #16406. --- module/bug/control.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index 099c5d7da1..4f0ce4ce30 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -232,7 +232,7 @@ class bug extends control $this->view->moduleID = $moduleID; $this->view->memberPairs = $this->user->getPairs('noletter|nodeleted'); $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID); + $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); $this->view->executions = $executions; $this->view->plans = $this->loadModel('productplan')->getPairs($productID); $this->view->stories = $storyList; @@ -435,7 +435,7 @@ class bug extends control /* Get product, then set menu. */ $productID = $this->product->saveState($productID, $this->products); $productInfo = $this->product->getById($productID); - $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); + $branches = $productInfo->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID, 'active'); if($branch === '') $branch = (int)$this->cookie->preBranch; /* Init vars. */ @@ -738,7 +738,7 @@ class bug extends control $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch === 'all' ? 0 : $branch); $this->view->moduleID = $moduleID; $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID); + $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); $this->display(); } @@ -788,7 +788,7 @@ class bug extends control /* Get product info. */ $productID = $bug->product; $product = $this->loadModel('product')->getByID($productID); - $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product); + $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product, 'active'); $this->executeHooks($bugID); @@ -950,7 +950,7 @@ class bug extends control $this->view->currentModuleID = $currentModuleID; $this->view->executions = array(0 => '') + $this->product->getExecutionPairsByProduct($bug->product, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID); $this->view->stories = $bug->execution ? $this->story->getExecutionStoryPairs($bug->execution) : $this->story->getProductStoryPairs($bug->product, $bug->branch); - $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product); + $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product, 'active'); $this->view->tasks = $this->task->getExecutionTaskPairs($bug->execution); $this->view->testtasks = $this->loadModel('testtask')->getPairs($bug->product, $bug->execution, $bug->testtask); $this->view->users = $this->user->getPairs('nodeleted', "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy,$bug->openedBy"); @@ -1018,7 +1018,7 @@ class bug extends control $this->view->title = $product->name . $this->lang->colon . "BUG" . $this->lang->bug->batchEdit; $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID&branch=$branch"), $this->products[$productID]); $this->view->plans = $plans; - $this->view->branches = $product->type == 'normal' ? array() : array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->loadModel('branch')->getPairs($product->id); + $this->view->branches = $product->type == 'normal' ? array() : array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->loadModel('branch')->getPairs($product->id, 'active'); } /* The bugs of my. */ else From 8b7f4096450149cbab57853b5d7279adf7f297da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E8=B7=83?= Date: Thu, 18 Nov 2021 08:45:20 +0000 Subject: [PATCH 117/129] Update control.php --- module/testcase/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index cc57a05dfc..53cd578829 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -481,7 +481,7 @@ class testcase extends control $this->view->steps = $steps; $this->view->users = $this->user->getPairs('noletter|noclosed|nodeleted'); $this->view->branch = $branch; - $this->view->branches = $this->session->currentProductType != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array(); + $this->view->branches = $this->session->currentProductType != 'normal' ? $this->loadModel('branch')->getPairs($productID) : array(); $this->display(); } From 88938892b057e3bd9b59c8590c25a7ef55029ed9 Mon Sep 17 00:00:00 2001 From: zhouxin Date: Thu, 18 Nov 2021 16:49:11 +0800 Subject: [PATCH 118/129] Add realBegan for program. --- module/common/model.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/common/model.php b/module/common/model.php index 4bca64e290..06ad9ee399 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -103,7 +103,8 @@ class commonModel extends model ->orderBy('id_desc') ->fetchPairs(); - $this->dao->update(TABLE_PROGRAM)->set('status')->eq('doing')->where('id')->in($waitList)->exec(); + $now = helper::now(); + $this->dao->update(TABLE_PROGRAM)->set('status')->eq('doing')->set('realBegan')->eq($now)->where('id')->in($waitList)->exec(); foreach($waitList as $programID) { $this->loadModel('action')->create('program', $programID, 'syncprogram'); From fa3fa5d9ca200a7d0b48d19923ffad2882b0cf5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 16:54:42 +0800 Subject: [PATCH 119/129] * fix for program progress. --- api/v1/entries/programs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index 96f2e53891..eb751b4cba 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -38,7 +38,7 @@ class programsEntry extends Entry $result = array(); foreach($programs as $program) { - $program->progress = zget($progressList, $program->id, 0); + if(isset($progressList[$program->id])) $program->progress = $progressList[$program->id]; $param = $this->format($program, 'begin:date,end:date,realBegan:date,realEnd:date,openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time,deleted:bool'); if($mergeChildren) From 084dc50d15039be51b6424e1b86ea921bf66aa64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 16:57:21 +0800 Subject: [PATCH 120/129] * convert to array. --- api/v1/entries/programs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/entries/programs.php b/api/v1/entries/programs.php index eb751b4cba..0333e849b5 100644 --- a/api/v1/entries/programs.php +++ b/api/v1/entries/programs.php @@ -33,7 +33,7 @@ class programsEntry extends Entry if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); $programs = (array)$data->data->programs; - $progressList = $data->data->progressList; + $progressList = (array)$data->data->progressList; $users = $data->data->users; $result = array(); foreach($programs as $program) From e011da6fd2d3c4d0e24d554ac28e210619fe285c Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Thu, 18 Nov 2021 09:02:45 +0000 Subject: [PATCH 121/129] - Finish task 44503. Remove usless variable. --- module/bug/model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/bug/model.php b/module/bug/model.php index 6a556db39e..192a1258e4 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1313,7 +1313,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')->getProductBuildPairs($productID, 0, $params = 'withbranch'); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID, 0, 'withbranch'); $this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values']; if($this->session->currentProductType == 'normal') { From 1f9f382aa0506cd7a731d71f8bd9bf55ed933c65 Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 17:06:44 +0800 Subject: [PATCH 122/129] * Fix bug 16376 --- module/build/view/create.html.php | 1 - 1 file changed, 1 deletion(-) diff --git a/module/build/view/create.html.php b/module/build/view/create.html.php index 2be6f03c99..1ede2bdad7 100644 --- a/module/build/view/create.html.php +++ b/module/build/view/create.html.php @@ -93,5 +93,4 @@
- From f92a67b62a6ebf656c1668b6e718fadbe46fe21e Mon Sep 17 00:00:00 2001 From: songchenxuan Date: Thu, 18 Nov 2021 17:09:42 +0800 Subject: [PATCH 123/129] * Fix bug 16376 --- module/build/js/common.js | 1 + 1 file changed, 1 insertion(+) diff --git a/module/build/js/common.js b/module/build/js/common.js index 0726ba7db2..71897d5bdc 100644 --- a/module/build/js/common.js +++ b/module/build/js/common.js @@ -15,6 +15,7 @@ function loadBranches(productID) oldBranch = productGroups[productID]['branches']; } + executionID = $('#execution').val(); $.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0¶m=&projectID=' + executionID), function(data) { if(data) From adc2aa1c9b8500f0d1f1846751da999a9d6be1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A1=E6=A0=8B?= Date: Thu, 18 Nov 2021 17:10:01 +0800 Subject: [PATCH 124/129] * code for task #44312. --- api/v1/entries/productplans.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/v1/entries/productplans.php b/api/v1/entries/productplans.php index 665d2f5c92..ea7ddbdbfd 100644 --- a/api/v1/entries/productplans.php +++ b/api/v1/entries/productplans.php @@ -32,9 +32,10 @@ class productplansEntry extends entry { $result = array(); $plans = $data->data->plans; + $pager = $data->data->pager; foreach($plans as $plan) $result[] = $plan; - return $this->send(200, array('plans' => $result)); + return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'plans' => array_values($result))); } if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message); From 1e57264ff4580e9f8fd8cd2087165bac98a6717a Mon Sep 17 00:00:00 2001 From: wangjianhua Date: Thu, 18 Nov 2021 09:16:07 +0000 Subject: [PATCH 125/129] * finish task 44491. Load branch lang before using. --- module/productplan/model.php | 1 + 1 file changed, 1 insertion(+) diff --git a/module/productplan/model.php b/module/productplan/model.php index a0ea6eef3c..3f6a0aadf6 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -209,6 +209,7 @@ class productplanModel extends model $plans = $this->reorder4Children($plans); $planPairs = array(); $parentTitle = array(); + $this->app->loadLang('branch'); foreach($plans as $plan) { if($plan->parent == '-1') $parentTitle[$plan->id] = $plan->title; From bff4aebfd443867fefe20e6dcb5065d10ec1554a Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 17:24:00 +0800 Subject: [PATCH 126/129] * Fix bug #16406. --- module/bug/control.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/bug/control.php b/module/bug/control.php index 4f0ce4ce30..27292ea69d 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -232,7 +232,7 @@ class bug extends control $this->view->moduleID = $moduleID; $this->view->memberPairs = $this->user->getPairs('noletter|nodeleted'); $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); + $this->view->branches = $this->loadModel('branch')->getPairs($productID); $this->view->executions = $executions; $this->view->plans = $this->loadModel('productplan')->getPairs($productID); $this->view->stories = $storyList; @@ -788,7 +788,7 @@ class bug extends control /* Get product info. */ $productID = $bug->product; $product = $this->loadModel('product')->getByID($productID); - $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product, 'active'); + $branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product); $this->executeHooks($bugID); @@ -950,7 +950,7 @@ class bug extends control $this->view->currentModuleID = $currentModuleID; $this->view->executions = array(0 => '') + $this->product->getExecutionPairsByProduct($bug->product, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID); $this->view->stories = $bug->execution ? $this->story->getExecutionStoryPairs($bug->execution) : $this->story->getProductStoryPairs($bug->product, $bug->branch); - $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product, 'active'); + $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product); $this->view->tasks = $this->task->getExecutionTaskPairs($bug->execution); $this->view->testtasks = $this->loadModel('testtask')->getPairs($bug->product, $bug->execution, $bug->testtask); $this->view->users = $this->user->getPairs('nodeleted', "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy,$bug->openedBy"); @@ -1018,7 +1018,7 @@ class bug extends control $this->view->title = $product->name . $this->lang->colon . "BUG" . $this->lang->bug->batchEdit; $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID&branch=$branch"), $this->products[$productID]); $this->view->plans = $plans; - $this->view->branches = $product->type == 'normal' ? array() : array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->loadModel('branch')->getPairs($product->id, 'active'); + $this->view->branches = $product->type == 'normal' ? array() : array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->loadModel('branch')->getPairs($product->id); } /* The bugs of my. */ else From 1d9fc9d47612b993f7ac9fd503caa328c2b9eb18 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 18 Nov 2021 17:26:27 +0800 Subject: [PATCH 127/129] * Fix bug #16407. --- module/testcase/control.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/testcase/control.php b/module/testcase/control.php index ac0f94e510..fb6ff972f2 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -213,7 +213,7 @@ class testcase extends control $this->view->param = $param; $this->view->cases = $cases; $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active'); + $this->view->branches = $this->loadModel('branch')->getPairs($productID); $this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID); $this->view->suiteID = $suiteID; $this->view->setModule = true; @@ -814,7 +814,7 @@ class testcase extends control } $this->view->productID = $productID; - $this->view->branches = $this->session->currentProductType == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID, 'active'); + $this->view->branches = $this->session->currentProductType == 'normal' ? array() : $this->loadModel('branch')->getPairs($productID); $this->view->productName = $this->products[$productID]; $this->view->moduleOptionMenu = $moduleOptionMenu; $this->view->stories = $this->story->getProductStoryPairs($productID, $case->branch); @@ -899,7 +899,7 @@ class testcase extends control $modules = array(); if($product->type != 'normal') { - $branches = $this->loadModel('branch')->getPairs($productID, 'active'); + $branches = $this->loadModel('branch')->getPairs($productID); if($branch === 'all') { $modules[0] = $this->tree->getOptionMenu($productID, $viewType = 'case', 0, 0); From b8783ecd5c26dbf649a44e1569e2e2ae28449e26 Mon Sep 17 00:00:00 2001 From: zhouxin Date: Thu, 18 Nov 2021 17:32:02 +0800 Subject: [PATCH 128/129] Fix bug 16408. --- module/branch/lang/en.php | 7 +++---- module/branch/lang/zh-cn.php | 7 +++---- module/branch/view/edit.html.php | 2 +- module/group/lang/resource.php | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/module/branch/lang/en.php b/module/branch/lang/en.php index 6cca8b2078..605a120986 100644 --- a/module/branch/lang/en.php +++ b/module/branch/lang/en.php @@ -9,15 +9,14 @@ $lang->branch->manageTitle = '%s Management'; $lang->branch->all = 'All '; $lang->branch->main = 'Main'; -$lang->branch->edit = 'Edit'; -$lang->branch->editAction = 'Edit %s'; -$lang->branch->editBranch = 'Edit Branch'; +$lang->branch->edit = 'Edit %s'; +$lang->branch->editAction = 'Edit Branch'; $lang->branch->activate = 'Activate'; $lang->branch->activateAction = 'Activate Branch'; $lang->branch->close = 'Close'; $lang->branch->closeAction = 'Close Branch'; $lang->branch->create = 'Create %s'; -$lang->branch->createBranch = 'Create Branch'; +$lang->branch->createAction = 'Create Branch'; $lang->branch->merge = 'Merge'; $lang->branch->batchEdit = 'Batch Edit'; $lang->branch->defaultBranch = 'Default Branch'; diff --git a/module/branch/lang/zh-cn.php b/module/branch/lang/zh-cn.php index b1d2ee5ed8..16ac4aa7be 100644 --- a/module/branch/lang/zh-cn.php +++ b/module/branch/lang/zh-cn.php @@ -9,15 +9,14 @@ $lang->branch->manageTitle = '%s管理'; $lang->branch->all = '所有'; $lang->branch->main = '主干'; -$lang->branch->edit = '编辑'; -$lang->branch->editAction = '编辑%s'; -$lang->branch->editBranch = '编辑分支'; +$lang->branch->edit = '编辑%s'; +$lang->branch->editAction = '编辑分支'; $lang->branch->activate = '激活'; $lang->branch->activateAction = '激活分支'; $lang->branch->close = '关闭'; $lang->branch->closeAction = '关闭分支'; $lang->branch->create = '新增%s'; -$lang->branch->createBranch = '新增分支'; +$lang->branch->createAction = '新增分支'; $lang->branch->merge = '合并'; $lang->branch->batchEdit = '批量编辑'; $lang->branch->defaultBranch = '默认分支'; diff --git a/module/branch/view/edit.html.php b/module/branch/view/edit.html.php index 8bcb450e4e..69d6fcf4ee 100644 --- a/module/branch/view/edit.html.php +++ b/module/branch/view/edit.html.php @@ -13,7 +13,7 @@
-

branch->editAction, $lang->product->branchName[$product->type]);?>

+

branch->edit, $lang->product->branchName[$product->type]);?>

diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index d582ce1d2e..786d2cf8b8 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -421,8 +421,8 @@ $lang->product->methodOrder[105] = 'unbindWhitelist'; /* Branch. */ $lang->resource->branch = new stdclass(); $lang->resource->branch->manage = 'manage'; -$lang->resource->branch->create = 'createBranch'; -$lang->resource->branch->edit = 'editBranch'; +$lang->resource->branch->create = 'createAction'; +$lang->resource->branch->edit = 'editAction'; $lang->resource->branch->close = 'closeAction'; $lang->resource->branch->activate = 'activateAction'; $lang->resource->branch->sort = 'sort'; From 4a07c2324f8fe030f27f359f0906737f2e487eda Mon Sep 17 00:00:00 2001 From: hufangzhou Date: Thu, 18 Nov 2021 21:41:48 +0800 Subject: [PATCH 129/129] * Fix bug #16385 and fix an error. --- module/group/view/manageview.html.php | 2 +- module/stakeholder/model.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/group/view/manageview.html.php b/module/group/view/manageview.html.php index 77b2cb578f..ddaa99e4e2 100644 --- a/module/group/view/manageview.html.php +++ b/module/group/view/manageview.html.php @@ -26,7 +26,7 @@ mainNav as $menuKey => $menu):?> - +
diff --git a/module/stakeholder/model.php b/module/stakeholder/model.php index 18b6e47045..f400c73c09 100644 --- a/module/stakeholder/model.php +++ b/module/stakeholder/model.php @@ -328,7 +328,7 @@ class stakeholderModel extends model } } - if(empty($parents)) return false; + if(empty($parents)) return array(); /* Get all parent stakeholders.*/ $parentStakeholders = $this->dao->select('objectID, user')->from(TABLE_STAKEHOLDER)->where('objectID')->in(array_keys($parents))->andWhere('deleted')->eq('0')->fetchAll();