-
+

id;?> diff --git a/module/bug/zen.php b/module/bug/zen.php index 0c55c80e28..4a7af9d80a 100644 --- a/module/bug/zen.php +++ b/module/bug/zen.php @@ -29,52 +29,6 @@ class bugZen extends bug return $bug; } - - /** - * 处理更新请求数据。 - * Processing request data. - * - * @param form $formData - * @access protected - * @return object - */ - protected function beforeUpdate(form $formData): object - { - $now = helper::now(); - $bug = $formData->add('id', $bugID) - ->setDefault('product', $oldBug->product) - ->setDefault('deleteFiles', array()) //deleteFiles? - ->setDefault('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->join('openedBuild,mailto,linkBug,os,browser', ',') - ->setIF(strpos($this->config->bug->edit->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline) - ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) - ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) - ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) - ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) - ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) - ->setIF($this->post->assignedTo == '' and $oldBug->status == 'closed', 'assignedTo', 'closed') - ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') - ->setIF($this->post->resolution != '', 'confirmed', 1) - ->setIF($this->post->resolution != '' and $this->post->resolution != 'duplicate', 'duplicateBug', 0) - ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->setIF(!$this->post->linkBug, 'linkBug', '') - ->setIF($this->post->case === '', 'case', 0) - ->stripTags($this->config->bug->editor->edit['id'], $this->config->allowedTags) - ->get(); - - $bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->create['id'], $formData->rawdata->uid); - - return $bug; - } - /** * 创建bug。 * Create a bug. @@ -146,75 +100,156 @@ class bugZen extends bug } /** - * 更新完以后的相关处理。 - * Process after updating bug. + * 处理更新请求数据。 + * Processing request data. * * @param string $bugID + * @param form $formData + * @access protected + * @return object|false + */ + protected function prepareEditExtras(form $formData, object $oldBug): object|false + { + if($oldBug->lastEditedDate != $formData->data->lastEditedDate) + { + dao::$errors[] = $this->lang->error->editedByOther; + return false; + } + + $now = helper::now(); + $bug = $formData->add('id', $oldBug->id) + ->setDefault('product', $oldBug->product) + ->setDefault('deleteFiles', array()) + ->setDefault('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->join('openedBuild,mailto,linkBug,os,browser', ',') + ->setIF($formData->data->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) + ->setIF($formData->data->resolvedBy != '' && $formData->data->resolvedDate == '', 'resolvedDate', $now) + ->setIF($formData->data->resolution != '' && $formData->data->resolvedDate == '', 'resolvedDate', $now) + ->setIF($formData->data->resolution != '' && $formData->data->resolvedBy == '', 'resolvedBy', $this->app->user->account) + ->setIF($formData->data->closedDate != '' && $formData->data->closedBy == '', 'closedBy', $this->app->user->account) + ->setIF($formData->data->closedBy != '' && $formData->data->closedDate == '', 'closedDate', $now) + ->setIF($formData->data->closedBy != '' || $formData->data->closedDate != '', 'assignedTo', 'closed') + ->setIF($formData->data->closedBy != '' || $formData->data->closedDate != '', 'assignedDate', $now) + ->setIF($formData->data->resolution != '' || $formData->data->resolvedDate != '', 'status', 'resolved') + ->setIF($formData->data->closedBy != '' || $formData->data->closedDate != '', 'status', 'closed') + ->setIF(($formData->data->resolution != '' || $formData->data->resolvedDate != '') && $formData->data->assignedTo == '', 'assignedTo', $oldBug->openedBy) + ->setIF(($formData->data->resolution != '' || $formData->data->resolvedDate != '') && $formData->data->assignedTo == '', 'assignedDate', $now) + ->setIF($formData->data->resolution == '' && $formData->data->resolvedDate == '', 'status', 'active') + ->setIF($formData->data->resolution != '' && $formData->data->resolution != 'duplicate', 'duplicateBug', 0) + ->setIF($formData->data->assignedTo == '' && $oldBug->status == 'closed', 'assignedTo', 'closed') + ->setIF($formData->data->resolution != '', 'confirmed', 1) + ->setIF($formData->data->story && $formData->data->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($formData->data->story)) + ->stripTags($this->config->bug->editor->edit['id'], $this->config->allowedTags) + ->get(); + + $bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->create['id'], $bug->uid); + + return $bug; + } + + + /** + * 返回错误信息。 + * return error. + * + * @access protected + * @return array|viod + */ + protected function errorEdit() + { + if(defined('RUN_MODE') && RUN_MODE == 'api') return array('status' => 'error', 'message' => dao::getError()); + + return array('result' => 'fail', 'message' => dao::getError()); + } + + /** + * 更新成功后的相关处理。 + * Relevant processing after updating bug. + * + * @param int $bugID + * @param string $comment * @param array $changes * @access protected * @return void */ - protected function afterUpdate(string $bugID, array $changes) + protected function processAfterEdit(int $bugID, string $comment, array $changes) { - /* 记录历史记录。*/ - /* Record history. */ - if($this->post->comment != '' or !empty($changes)) + if($this->post->comment || !empty($changes)) { $action = !empty($changes) ? 'Edited' : 'Commented'; - $actionID = $this->action->create('bug', $bugID, $action, $this->post->comment); + $actionID = $this->action->create('bug', $bugID, $action, $comment); + $this->action->logHistory($actionID, $changes); } + } + /** + * 返回不同的结果。 + * Response after updating bug. + * + * @param string $bugID + * @param array $changes + * @param string $kanbanGroup + * @access protected + * @return array + */ + protected function responseAfterEdit(string $bugID, array $changes, string $kanbanGroup): array + { if(defined('RUN_MODE') && RUN_MODE == 'api') return array('status' => 'success', 'data' => $bugID); - $this->executeHooks($bugID); - /* 如果bug转任务,如果bug的状态发生变化,提示是否更新任务状态。*/ /* This bug has been converted to a task, update the status of the relatedtask or not. */ - $bug = $this->bug->getById($bugID); + $bug = $this->bug->getByID($bugID); if($bug->toTask and !empty($changes)) { foreach($changes as $change) { if($change['field'] != 'status') continue; - $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); - $cancelURL = $this->server->HTTP_REFERER; - - return print(js::confirm(sprintf($this->lang->bug->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent')); + return array('result' => 'success', 'confirm' => array('note' => $this->lang->bug->remindTask, 'confirmURL' => $this->createLink('task', 'view', "taskID=$bug->toTask"), 'cancelURL' => $this->server->HTTP_REFERER)); } } + /* 弹窗里编辑bug的返回。*/ + /* Response when edit in modal. */ if(isonlybody()) { + /* 在执行应用下,编辑看板中的bug数据时,更新看板数据。*/ + /* Update kanban data after edited bug in kanban. */ if($this->app->tab == 'execution') { + $this->loadModel('kanban'); + $execution = $this->loadModel('execution')->getByID($bug->execution); $execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all'; - $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; - if(isset($execution->type) and $execution->type == 'kanban') + /* 1.看板类型的执行。*/ + /* 1.The kanban exectuion. */ + if(isset($execution->type) && $execution->type == 'kanban') { $rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue); + $kanbanData = $this->kanban->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue); $kanbanData = json_encode($kanbanData); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)")); + return array('result' => 'success', 'closeModal' => true, 'callback' => "updateKanban($kanbanData)"); } + /* 2.执行中的看板。*/ + /* 2.The kanban of execution. */ else { + $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; $taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue); + $kanbanData = $this->kanban->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue); $kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData); $kanbanData = json_encode($kanbanData[$kanbanType]); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)")); + return array('result' => 'success', 'closeModal' => true, 'callback' => "updateKanban(\"bug\", $kanbanData)"); } } - else - { - return print(js::closeModal('parent.parent')); - } + + return array('result' => 'success', 'closeModal' => true); } - return print(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + + return array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('bug', 'view', "bugID=$bugID")); } /** @@ -755,6 +790,7 @@ class bugZen extends bug if($this->app->tab == 'project') $this->project->setMenu($bug->project); if($this->app->tab == 'execution') $this->execution->setMenu($bug->execution); if($this->app->tab == 'qa') $this->qa->setMenu($this->products, $bug->product, $bug->branch); + /* 是否有用?*/ if($this->app->tab == 'devops') { session_write_close(); @@ -788,8 +824,8 @@ class bugZen extends bug $this->loadModel('execution'); $this->loadModel('build'); - $product = $this->product->getByID($bug->product); - $execution = $this->execution->getByID($bug->execution); + $product = $this->product->getByID($bug->product); + $execution = $this->execution->getByID($bug->execution); /* 获取影响版本列表和解决版本列表。*/ /* Get the openedBuilds and resolvedBuilds. */ @@ -799,11 +835,11 @@ class bugZen extends bug $allBuilds = $this->loadModel('build')->getBuildPairs($bug->product, 'all', 'noempty'); $openedBuilds = $this->build->getBuildPairs($bug->product, $bug->branch, $params = 'noempty,noterminate,nodone,withbranch,noreleased', $objectID, $objectType, $bug->openedBuild); $resolvedBuilds = $openedBuilds; - if(($bug->resolvedBuild) and isset($allBuilds[$bug->resolvedBuild])) $resolvedBuilds[$bug->resolvedBuild] = $allBuilds[$bug->resolvedBuild]; + if(($bug->resolvedBuild) && isset($allBuilds[$bug->resolvedBuild])) $resolvedBuilds[$bug->resolvedBuild] = $allBuilds[$bug->resolvedBuild]; /* 获取分支列表。*/ /* Get the branch options. */ - if($this->app->tab == 'execution' or $this->app->tab == 'project') $objectID = $this->app->tab == 'project' ? $bug->project : $bug->execution; + if($this->app->tab == 'execution' || $this->app->tab == 'project') $objectID = $this->app->tab == 'project' ? $bug->project : $bug->execution; $branches = $this->branch->getList($bug->product, isset($objectID) ? $objectID : 0, 'all'); $branchTagOption = array(); @@ -812,11 +848,8 @@ class bugZen extends bug if(!isset($branchTagOption[$bug->branch])) { $bugBranch = $this->branch->getById($bug->branch, $bug->product, ''); - if($bug->branch == BRANCH_MAIN) - { - $branchTagName = $bugBranch; - } - else + if($bug->branch == BRANCH_MAIN) $branchTagName = $bugBranch; + if($bug->branch != BRANCH_MAIN) { $branchTagName = $bugBranch->name; if($bugBranch->status == 'closed') $branchTagName .= " ({$this->lang->branch->statusList['closed']})"; From aa30b979131c03b00ad17136ee802a4d99082093 Mon Sep 17 00:00:00 2001 From: daitingting Date: Mon, 8 May 2023 01:38:39 +0000 Subject: [PATCH 03/59] * Update test of update. --- module/bug/test/bug.class.php | 1 - module/bug/test/model/update.php | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/module/bug/test/bug.class.php b/module/bug/test/bug.class.php index 4406979f52..084419b479 100644 --- a/module/bug/test/bug.class.php +++ b/module/bug/test/bug.class.php @@ -795,7 +795,6 @@ class bugTest $_POST[$field] = $value; } } - //$_POST['closedDate'] = ''; $_POST['deleteFiles'] = array(); $object->files = array(); diff --git a/module/bug/test/model/update.php b/module/bug/test/model/update.php index eb684be340..a2601b1843 100755 --- a/module/bug/test/model/update.php +++ b/module/bug/test/model/update.php @@ -1,6 +1,7 @@ #!/usr/bin/env php update(); timeout=0 cid=1 -- 执行bug模块的updateObject方法,参数是$bugIdList[0], $t_uptitle +- 测试更新bug名称 - 第0条的field属性 @title - 第0条的old属性 @BUG1 - 第0条的new属性 @john -- 执行bug模块的updateObject方法,参数是$bugIdList[0], $t_uptype +- 测试更新bug类型 - 第0条的field属性 @type - 第0条的old属性 @codeerror - 第0条的new属性 @config -- 执行bug模块的updateObject方法,参数是$bugIdList[0], $t_untitle @没有数据更新 +- 测试不更改bug名称 @没有数据更新 -- 执行bug模块的updateObject方法,参数是$bugIdList[0], $t_untype @没有数据更新 +- 测试不更改bug类型 @没有数据更新 @@ -54,9 +55,8 @@ $t_uptype = array('type' => 'config'); $t_untitle = array('title' => 'john'); $t_untype = array('type' => 'config'); -global $tester; -$tester->loadModel('bug'); -r($tester->bug->updateObject($bugIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称 -r($tester->bug->updateObject($bugIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型 -r($tester->bug->updateObject($bugIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称 -r($tester->bug->updateObject($bugIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型 +$bug = new bugTest(); +r($bug->updateObject($bugIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称 +r($bug->updateObject($bugIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型 +r($bug->updateObject($bugIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称 +r($bug->updateObject($bugIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型 \ No newline at end of file From 5fedf3e02c23fa9267a5b9db1d95fe56631c3130 Mon Sep 17 00:00:00 2001 From: sunhao Date: Mon, 8 May 2023 11:01:09 +0800 Subject: [PATCH 04/59] * zin: refactor "static" keyword instead of "self". --- lib/zin/core/wg.class.php | 2 +- lib/zin/core/zin.class.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/zin/core/wg.class.php b/lib/zin/core/wg.class.php index 0f8ae6077e..d661ba8d2f 100644 --- a/lib/zin/core/wg.class.php +++ b/lib/zin/core/wg.class.php @@ -64,7 +64,7 @@ class wg { $this->props = new props(); - $this->gid = self::nextGid(); + $this->gid = static::nextGid(); $this->setDefaultProps(static::getDefaultProps()); $this->add(func_get_args()); $this->created(); diff --git a/lib/zin/core/zin.class.php b/lib/zin/core/zin.class.php index 61cb210a55..6417b47bc4 100644 --- a/lib/zin/core/zin.class.php +++ b/lib/zin/core/zin.class.php @@ -25,28 +25,28 @@ class zin public static function getData($namePath, $defaultValue = NULL) { - return \zin\utils\deepGet(self::$data, $namePath, $defaultValue); + return \zin\utils\deepGet(static::$data, $namePath, $defaultValue); } public static function setData($namePath, $value) { - \zin\utils\deepSet(self::$data, $namePath, $value); + \zin\utils\deepSet(static::$data, $namePath, $value); } public static function enableGlobalRender() { - self::$enabledGlobalRender = true; + static::$enabledGlobalRender = true; } public static function disableGlobalRender() { - self::$enabledGlobalRender = false; + static::$enabledGlobalRender = false; } public static function renderInGlobal() { - if(!self::$enabledGlobalRender) return false; + if(!static::$enabledGlobalRender) return false; - self::$globalRenderList = array_merge(self::$globalRenderList, func_get_args()); + static::$globalRenderList = array_merge(static::$globalRenderList, func_get_args()); } } From 4f852d7641afe64b196cf8190b628dc2ba119a05 Mon Sep 17 00:00:00 2001 From: Guanxiying Date: Mon, 8 May 2023 11:03:30 +0800 Subject: [PATCH 05/59] * Fix code smell of $$statusVar. --- module/execution/model.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/module/execution/model.php b/module/execution/model.php index 5a3b2cef7e..862121cec9 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -4334,34 +4334,37 @@ class executionModel extends model */ public function summary($tasks) { - $taskSum = $statusWait = $statusDone = $statusDoing = $statusClosed = $statusCancel = $statusPause = 0; + $taskSum = 0; $totalEstimate = $totalConsumed = $totalLeft = 0.0; + $summations = array(); + $this->app->loadLang('task'); + /* 当前只需要显示wait 和 doing 状态,但是从代码分析将来可能需要统计其他状态的,所以取全部状态。 */ + foreach($this->lang->task->statusList as $statusCode => $statusName) $summations[$statusCode] = 0; + foreach($tasks as $task) { if(!isset($tasks[$task->parent]) or $task->parent <= 0) { - $totalEstimate += $task->estimate; - $totalConsumed += $task->consumed; + $totalEstimate += $task->estimate; + $totalConsumed += $task->consumed; if($task->status != 'cancel' and $task->status != 'closed') $totalLeft += $task->left; } - $statusVar = 'status' . ucfirst($task->status); - $$statusVar ++; + if(isset($summations[$task->status])) $summations[$task->status] ++; if(isset($task->children)) { - foreach($task->children as $children) + foreach($task->children as $child) { - $statusVar = 'status' . ucfirst($children->status); - $$statusVar ++; + if(isset($summations[$child->status])) $summations[$child->status] ++; $taskSum ++; } } $taskSum ++; } - return sprintf($this->lang->execution->taskSummary, $taskSum, $statusWait, $statusDoing, round($totalEstimate, 1), round($totalConsumed, 1), round($totalLeft, 1)); + return sprintf($this->lang->execution->taskSummary, $taskSum, $summations['wait'], $summations['doing'], round($totalEstimate, 1), round($totalConsumed, 1), round($totalLeft, 1)); } /** From e6b85b927e1ebc84c276fac499f4f3fc854ed369 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 8 May 2023 11:05:06 +0800 Subject: [PATCH 06/59] * Modify test case. --- module/execution/model.php | 2 -- module/project/test/project.class.php | 18 ++++++++++++ module/project/test/tao/createproduct.php | 34 +++++++++++------------ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/module/execution/model.php b/module/execution/model.php index 5a3b2cef7e..bc05d638ce 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -1767,7 +1767,6 @@ class executionModel extends model ->andWhere('vision')->eq($this->config->vision) ->beginIF($type == 'all')->andWhere('type')->in('sprint,stage,kanban')->fi() ->beginIF($type != 'all')->andWhere('type')->eq($type)->fi() - ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() ->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi() ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() ->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi() @@ -1820,7 +1819,6 @@ class executionModel extends model ->orWhere('t2.account')->eq($this->app->user->account) ->markRight(1) ->andWhere('t1.type')->in('sprint,stage,kanban') - ->beginIF($projectID)->andWhere('t1.project')->eq($projectID)->fi() ->orderBy('t1.order_desc') ->beginIF($limit)->limit($limit)->fi() ->fetchAll('id'); diff --git a/module/project/test/project.class.php b/module/project/test/project.class.php index 05aa216d19..238a34e4f3 100644 --- a/module/project/test/project.class.php +++ b/module/project/test/project.class.php @@ -252,4 +252,22 @@ class Project $projects = $this->project->fetchProjectListByQuery($queryType, $param, $orderBy, 15, ''); return $projects; } + + /** + * testCreateProduct + * + * @param int $projectID + * @param object $project + * @param object $postData + * @param object $program + * @access public + * @return string|array + */ + public function testCreateProduct($projectID, $project, $postData, $program) + { + $result = $this->project->createProduct($projectID, $project, $postData, $program); + if(!$result) return dao::getError(); + + return '1'; + } } diff --git a/module/project/test/tao/createproduct.php b/module/project/test/tao/createproduct.php index c39df607c9..442cabed7b 100755 --- a/module/project/test/tao/createproduct.php +++ b/module/project/test/tao/createproduct.php @@ -12,24 +12,15 @@ $program->code->range('项目集代号'); $program->desc->range('测试项目集'); $program->gen(1); +zdTable('team')->gen(0); +zdTable('product')->gen(0); + /** title=测试 projectModel->create(); timeout=0 cid=1 -- 执行projectClass模块的create方法,参数是$normalProject, $postData属性name @测试新增项目一 - -- 执行projectClass模块的create方法,参数是$emptyNameProject, $postData @『项目名称』不能为空。 - -- 执行projectClass模块的create方法,参数是$emptyEndProject, $postData @『计划完成』不能为空。 - -- 执行projectClass模块的create方法,参数是$beginGtEndProject, $postData @『计划完成』应当大于『2022-02-07』。 - -- 执行projectClass模块的create方法,参数是$emptyBeginProject, $postData @『计划开始』不能为空。 - - - */ global $tester; @@ -54,16 +45,23 @@ $project->hasProduct = 1; $project->openedBy = 'admin'; $project->openedDate = '2023-01-01'; +$emptyNameProject = clone $project; +unset($emptyNameProject->name); + +$hasProductProject = clone $project; +$hasProductProject->hasProduct = 1; +$hasProductProject->name = '测试新增产品一'; + $postData = new stdclass(); $postData->rawdata = clone $project; $postData->rawdata->uid = '64dda2xc'; $postData->rawdata->delta = 0; $postData->rawdata->products = array(1); -$projectID = $projectClass->create($normalProject, $postData); +$project = $projectClass->create($project, $postData); +$projectID = $project->id; -r($projectClass->createProduct($projectID, $project, $postData, $program)) && p('name') && e('测试新增项目一'); -//r($projectClass->createProduct($emptyNameProject, $postData)) && p('message[name]:0') && e('『项目名称』不能为空。'); -//r($projectClass->createProduct($emptyEndProject, $postData)) && p('message[end]:0') && e('『计划完成』不能为空。'); -//r($projectClass->createProduct($beginGtEndProject, $postData)) && p('message[end]:0') && e('『计划完成』应当大于『2022-02-07』。'); -//r($projectClass->createProduct($emptyBeginProject, $postData)) && p('message[begin]:0') && e('『计划开始』不能为空。'); +r($projectClass->testCreateProduct($projectID, $project, $postData, $program)) && p() && e('1'); +r($projectClass->testCreateProduct($projectID, $emptyNameProject, $postData, $program)) && p('name:0') && e('『产品名称』不能为空。'); +r($projectClass->testCreateProduct($projectID, $project, $postData, $program)) && p('name:0') && e('『产品名称』已经有『测试新增项目一』这条记录了。'); +r($projectClass->testCreateProduct($projectID, $hasProductProject, $postData, $program)) && p() && e('1'); From 0e30961651af96edf0be9724a49cbf6d5179bcb4 Mon Sep 17 00:00:00 2001 From: xushenjie Date: Mon, 8 May 2023 03:06:36 +0000 Subject: [PATCH 07/59] + Added the unit test script of todoTao::buildCycleTodo() method. --- module/todo/test/tao/buildcycletodo.php | 30 ++++++++++++++++ .../yaml/buildcycletodo/buildcycletodo.yaml | 36 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100755 module/todo/test/tao/buildcycletodo.php create mode 100644 module/todo/test/tao/yaml/buildcycletodo/buildcycletodo.yaml diff --git a/module/todo/test/tao/buildcycletodo.php b/module/todo/test/tao/buildcycletodo.php new file mode 100755 index 0000000000..b2d9f2e7fe --- /dev/null +++ b/module/todo/test/tao/buildcycletodo.php @@ -0,0 +1,30 @@ +#!/usr/bin/env php +config('buildcycletodo')->gen(5); +} + +/** + +title=测试 todoTao::buildCycleTodo(); +timeout=0 +cid=1 + +- 执行todo模块的buildCycleTodo方法,参数是$todo + - 属性name @我的待办 + - 属性type @cycle + - 属性status @wait + +*/ + +initData(); + +global $tester; +$tester->loadModel('todo'); +$todo = $tester->todo->getByID(1); + +r($tester->todo->buildCycleTodo($todo)) && p('name,type,status') && e('我的待办,cycle,wait'); diff --git a/module/todo/test/tao/yaml/buildcycletodo/buildcycletodo.yaml b/module/todo/test/tao/yaml/buildcycletodo/buildcycletodo.yaml new file mode 100644 index 0000000000..0e201a83f7 --- /dev/null +++ b/module/todo/test/tao/yaml/buildcycletodo/buildcycletodo.yaml @@ -0,0 +1,36 @@ +title: buildcycletodo +author: xushenjie +version: "1.0" +fields: + - field: id + range: 1-100 + - field: account + range: 'admin' + - field: name + range: '我的待办' + - field: date + range: 1-9 + prefix: '2023-04-2' + - field: begin + range: 1000-1100 + - field: end + range: 1200-1300 + - field: type + range: 'custom' + - field: cycle + range: 0 + - field: pri + range: 3 + - field: desc + range: 1-5 + prefix: '这是待办描述' + - field: status + range: 'wait,doing,done' + - field: vision + range: 'rnd,litle' + - field: finishedDate + range: 1-9 + prefix: '2023-04-2' + - field: closedDate + range: 1-9 + prefix: '2023-04-2' From 90529a68fee4c23ceec275d994f9691b1867529e Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 8 May 2023 11:10:51 +0800 Subject: [PATCH 08/59] * Modify dao error and page style. --- module/project/model.php | 5 ++++- module/project/tao.php | 12 ++++++++++-- module/project/ui/create.html.php | 13 +++++++++---- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/module/project/model.php b/module/project/model.php index 8222494957..16d3c05fd4 100755 --- a/module/project/model.php +++ b/module/project/model.php @@ -1226,7 +1226,10 @@ class projectModel extends model /* If $_POST has product name, create it. */ $linkedProductsCount = $this->projectTao->getLinkedProductsCount($project, $postData->rawdata); - if(!$project->hasProduct or isset($postData->rawdata->newProduct) or (!$project->parent and empty($linkedProductsCount))) $this->createProduct($projectID, $project, $postData, $program); + if(!$project->hasProduct or isset($postData->rawdata->newProduct) or (!$project->parent and empty($linkedProductsCount))) + { + if(!$this->createProduct($projectID, $project, $postData, $program)) return false; + } /* Save order. */ $this->dao->update(TABLE_PROJECT)->set('`order`')->eq($projectID * 5)->where('id')->eq($projectID)->exec(); diff --git a/module/project/tao.php b/module/project/tao.php index f13ad36510..5309562ff8 100755 --- a/module/project/tao.php +++ b/module/project/tao.php @@ -215,6 +215,8 @@ class projectTao extends projectModel */ protected function setProjectTeam(int $projectID, object $project, object $postData): array { + $this->loadModel('execution'); + /* Set team of project. */ $members = isset($postData->rawdata->teamMembers) ? $postData->rawdata->teamMembers : array(); array_push($members, $project->PM, $project->openedBy); @@ -304,7 +306,7 @@ class projectTao extends projectModel { /* If parent not empty, link products or create products. */ $product = new stdclass(); - $product->name = $project->hasProduct && $postData->rawdata->productName ? $postData->rawdata->productName : $project->name; + $product->name = $project->hasProduct && !empty($postData->rawdata->productName) ? $postData->rawdata->productName : zget($project, 'name', ''); $product->shadow = zget($project, 'vision', 'rnd') == 'rnd' ? (int)empty($project->hasProduct) : 1; $product->bind = $postData->rawdata->parent ? 0 : 1; $product->program = $project->parent ? current(array_filter(explode(',', $program->path))) : 0; @@ -321,7 +323,13 @@ class projectTao extends projectModel $product->createdVersion = $this->config->version; $product->vision = zget($project, 'vision', 'rnd'); - $this->dao->insert(TABLE_PRODUCT)->data($product)->exec(); + $this->app->loadConfig('product'); + $this->dao->insert(TABLE_PRODUCT)->data($product) + ->batchCheck($this->config->product->create->requiredFields, 'notempty') + ->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'") + ->exec(); + if(dao::isError()) return false; + $productID = $this->dao->lastInsertId(); if(!$project->hasProduct) $this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID); $this->loadModel('action')->create('product', $productID, 'opened'); diff --git a/module/project/ui/create.html.php b/module/project/ui/create.html.php index f213abafc6..828143061c 100644 --- a/module/project/ui/create.html.php +++ b/module/project/ui/create.html.php @@ -9,7 +9,7 @@ foreach($lang->project->modelList as $key => $text) $projectModelItems[] = array ( 'active' => ($key == $model), - 'url' => '', + 'url' => $this->createLink("project", "create", "model=$key&programID=$programID©ProjectID=0&extra=productID=$productID,branchID=$branchID"), 'text' => $text, 'data-type' => 'ajax' ); @@ -110,12 +110,16 @@ formPanel set::seg(true), btn ( - setClass('primary-pale'), + setClass('primary-pale project-type-1'), + on::click('changeType(1)'), $lang->project->projectTypeList[1] ), - btn($lang->project->projectTypeList[0]) + btn( + setClass('project-type-0'), + on::click('changeType(0)'), + $lang->project->projectTypeList[0] + ) ), - /* TODO change value with button click event */ formHidden('hasProduct', 1) ), formGroup @@ -215,6 +219,7 @@ formPanel formGroup ( set::width('1/2'), + set('id', 'linkProduct'), set::label($lang->project->manageProducts), inputGroup ( From cacfce57c1482af5ac9a0227c93ba6963171bd1a Mon Sep 17 00:00:00 2001 From: Lufei Date: Mon, 8 May 2023 11:13:21 +0800 Subject: [PATCH 09/59] + Support make xhprof. --- Makefile | 14 +++++++++++--- framework/base/router.class.php | 8 ++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 61bf4d6b48..081ac8421a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ -VERSION = $(shell head -n 1 VERSION) -XUANVERSION = $(shell head -n 1 extension/xuanxuan/XUANVERSION) -XVERSION = $(shell head -n 1 extension/xuanxuan/XVERSION) +VERSION = $(shell head -n 1 VERSION) +XUANVERSION = $(shell head -n 1 extension/xuanxuan/XUANVERSION) +XVERSION = $(shell head -n 1 extension/xuanxuan/XVERSION) +XHPROF_VERSION = 2.3.9 XUANPATH := $(XUANXUAN_SRC_PATH) BUILD_PATH := $(if $(ZENTAO_BUILD_PATH),$(ZENTAO_BUILD_PATH),$(shell pwd)) @@ -345,3 +346,10 @@ ci: mv ZenTaoALM.$(VERSION).int.php*.zip ZenTaoPMS.$(VERSION).php*.zip $(RELEASE_PATH)/pmsPack mv *.deb $(RELEASE_PATH)/pmsPack/deb/ mv *.rpm $(RELEASE_PATH)/pmsPack/rpm/ +xhprof: + wget https://pecl.php.net/get/xhprof-$(XHPROF_VERSION).tgz + tar -zxvf xhprof-$(XHPROF_VERSION).tgz + rm -rf www/xhprof/xhprof_html www/xhprof/xhprof_lib + mkdir -p www/xhprof + mv xhprof-$(XHPROF_VERSION)/xhprof_html xhprof-$(XHPROF_VERSION)/xhprof_lib www/xhprof/ + rm -rf xhprof-$(XHPROF_VERSION)* package.xml diff --git a/framework/base/router.class.php b/framework/base/router.class.php index 9d64eea4be..6e0bb6f523 100644 --- a/framework/base/router.class.php +++ b/framework/base/router.class.php @@ -750,16 +750,12 @@ class baseRouter $outputDir = ini_get('xhprof.output_dir'); if(!is_dir($xhprofPath)) return false; + if(!$outputDir) $outputDir = $xhprofPath . DS . 'xhprof_runs'; + if(!is_dir($outputDir)) mkdir($outputDir, 0777, true); include_once $libUtilsPath . 'xhprof_lib.php'; include_once $libUtilsPath . 'xhprof_runs.php'; - if(!$outputDir) - { - $outputDir = $xhprofPath . DS . 'xhprof_runs'; - if(!is_dir($outputDir)) mkdir($outputDir, 0777, true); - } - $xhprofRuns = new \XHProfRuns_Default($outputDir); $type = "{$this->moduleName}_{$this->methodName}"; $runID = $xhprofRuns->save_run($log, $type); From c0511322e63aa10b4efa6cf3381d073ad1c9ef2f Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Mon, 8 May 2023 11:15:33 +0800 Subject: [PATCH 10/59] * Modify test case ignore comment line. --- test/lib/init.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/init.php b/test/lib/init.php index 8817f52152..653c7b5b23 100644 --- a/test/lib/init.php +++ b/test/lib/init.php @@ -74,7 +74,7 @@ $poolID = getenv('ZTF_POOL_ID'); $dbPool = empty($config->dbPool) ? array() : $config->dbPool; /* 根据ztf设置的poolID环境变量设置连接的数据库 */ -if(!empty($dbPool) && !empty($poolID)) +if(!empty($dbPool) && !empty($poolID)) { $selectDB = $dbPool[$poolID%count($dbPool)]; @@ -346,7 +346,7 @@ function genModuleAndMethod($rParams) */ function genParamsByRPE($rpe) { - preg_match_all("/r\((.*?)\)\s*&&\s*p\((.*?)\)\s*&&\s*e\((.*?)\);(.*)/", $rpe, $matches); + preg_match_all("/^r\((.*?)\)\s*&&\s*p\((.*?)\)\s*&&\s*e\((.*?)\);(.*)/", $rpe, $matches); $rParams = !empty($matches[1]) ? $matches[1] : array(); $pParams = !empty($matches[2]) ? $matches[2] : array(); $eParams = !empty($matches[3]) ? $matches[3] : array(); From 4bb7e6d32754a48405011fe33f461787ffe5ccde Mon Sep 17 00:00:00 2001 From: Wangyuting <851424971@qq.com> Date: Mon, 8 May 2023 11:23:39 +0800 Subject: [PATCH 11/59] * Optimize project statistic block code. --- .../block/ui/projectstatisticblock.html.php | 529 ++++++++++-------- 1 file changed, 298 insertions(+), 231 deletions(-) diff --git a/module/block/ui/projectstatisticblock.html.php b/module/block/ui/projectstatisticblock.html.php index 39dd54d3da..96a93ba55e 100644 --- a/module/block/ui/projectstatisticblock.html.php +++ b/module/block/ui/projectstatisticblock.html.php @@ -11,275 +11,342 @@ declare(strict_types=1); namespace zin; -$isChineseLang = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')); -$blockNavID = 'nav-' . uniqid(); -$selected = key($projects); -$navTabs = array(); - -/* 展示左侧的项目列表。 */ -foreach($projects as $project) +/** + * 获取区块左侧的项目列表. + * Get project tabs on the left side. + * + * @param array $projects + * @param string $blockNavCode + * @access public + * @return array + */ +function getProjectTabs($projects, $blockNavCode): array { - $navTabs[] = li - ( - set('class', 'nav-item' . ($project->id == $selected ? ' active' : '')), - a + $navTabs = array(); + $selected = key($projects); + foreach($projects as $project) + { + $navTabs[] = li ( - set('class', 'ellipsis'), - set('data-toggle', 'tab'), - set('href', "#tab3{$blockNavID}Content{$project->id}"), - $project->name - - ), - a - ( - set('class', 'link flex-1 text-right hidden'), - set('href', helper::createLink('project', 'index', "projectID=$project->id")), - icon + set('class', 'nav-item' . ($project->id == $selected ? ' active' : '')), + a ( - set('class', 'rotate-90 text-primary'), - 'export' + set('class', 'ellipsis'), + set('data-toggle', 'tab'), + set('href', "#tab3{$blockNavCode}Content{$project->id}"), + $project->name + + ), + a + ( + set('class', 'link flex-1 text-right hidden'), + set('href', helper::createLink('project', 'index', "projectID=$project->id")), + icon + ( + set('class', 'rotate-90 text-primary'), + 'export' + ) ) - ) - ); + ); + } + return $navTabs; } -$tabItems = array(); -foreach($projects as $project) +/** + * 获取区块右侧显示的项目信息. + * Get project statistical information. + * + * @param object $projects + * @param string $blockNavID + * @access public + * @return array + */ +function getProjectInfo($projects, $blockNavID): array { - if(in_array($project->model, array('scrum', 'kanban', 'agileplus'))) + $selected = key($projects); + $tabItems = array(); + foreach($projects as $project) { - /* 展示右侧的项目统计项。 */ - $cells = array(); - foreach($config->block->projectstatistic->dtable as $module => $items) - { - $cellItems = array(); - foreach($items as $item) - { - $field = $item['field']; - $unit = $item['unit']; - $cellItems[] = div - ( - set('class', 'flex py-4'), - cell - ( - set('width', '50%'), - set('class', 'text-right text-gray'), - span($lang->block->projectstatistic->{$field} . ' :') - ), - cell - ( - set('width', '50%'), - set('class', 'text-left'), - span - ( - set('class', 'font-bold text-black'), - zget($project, $field, 0) - ), - span($lang->block->projectstatistic->{$unit}) - ) - ); - } - $cells[] = cell + $tabItems[] = div + ( + set('class', 'tab-pane' . ($project->id == $selected ? ' active' : '')), + set('id', "tab3{$blockNavID}Content{$project->id}"), + in_array($project->model, array('scrum', 'kanban', 'agileplus')) ? getScrumProjectInfo($project) : getWaterfallProjectInfo($project) + ); + } + return $tabItems; +} + +/** + * 获取敏捷类项目的统计信息. + * Get scrum project info. + * + * @param object $project + * @access public + * @return void + */ +function getScrumProjectInfo($project) +{ + global $lang; + + $scrumProjectInfo = div + ( + /* 区块右侧顶部的项目概况。 */ + div + ( + set('class', 'flex bg-white h-10 leading-9 px-4 shadow-sm'), + cell ( - set('class', 'flex-1 px-2 py-4'), - div + set('class', 'text-left mr-6'), + span ( - set('class', 'px-2'), + set('class', 'text-gray'), + '距离项目结束还剩', span ( - set('class', 'font-bold'), - $lang->block->projectstatistic->{$module} + set('class', 'font-bold text-black px-1'), + zget($project, 'remainingDays' , 0) ), + $lang->block->projectstatistic->day + ) + ), + cell + ( + set('class', 'flex-1 text-left'), + span + ( + set('class', 'text-gray mr-5'), + '存在风险 : ', + span + ( + set('class', 'font-bold text-warning'), + '3' + ) ), - $cellItems + span + ( + set('class', 'text-gray'), + '存在问题 : ', + span + ( + set('class', 'font-bold text-warning'), + '1' + ) + ) + ), + (!empty($project->executions) and $project->multiple) ? cell + ( + /* 项目最近的一次执行。 */ + set('class', 'flex-1 text-right'), + span + ( + set('class', 'text-gray'), + '最近执行 ', + a + ( + set('href', helper::createLink('execution', 'task', "executionID={$project->executions[0]->id}")), + set('title', $project->executions[0]->name), + $project->executions[0]->name, + ) + ) + ) : null + ), + div + ( + /* 区块右侧主体显示的项目统计项。 */ + set('class', 'flex'), + getProjectStatisticItems($project) + ) + ); + return $scrumProjectInfo; +} + +/** + * 获取项目的统计项. + * get project statistic items. + * + * @param object $project + * @access public + * @return array + */ +function getProjectStatisticItems($project): array +{ + global $config, $lang; + + $cells = array(); + foreach($config->block->projectstatistic->dtable as $module => $items) + { + $cellItems = array(); + foreach($items as $item) + { + $field = $item['field']; + $unit = $item['unit']; + $cellItems[] = div + ( + set('class', 'flex py-4'), + cell + ( + set('width', '50%'), + set('class', 'text-right text-gray'), + span($lang->block->projectstatistic->{$field} . ' :') + ), + cell + ( + set('width', '50%'), + set('class', 'text-left'), + span + ( + set('class', 'font-bold text-black'), + zget($project, $field, 0) + ), + span($lang->block->projectstatistic->{$unit}) + ) ); } + $cells[] = cell + ( + set('class', 'flex-1 px-2 py-4'), + div + ( + set('class', 'px-2'), + span + ( + set('class', 'font-bold'), + $lang->block->projectstatistic->{$module} + ), + ), + $cellItems + ); } - /* 展示右侧顶部的项目状况。 */ - $tabItems[] = div - ( - set('class', 'tab-pane' . ($project->id == $selected ? ' active' : '')), - set('id', "tab3{$blockNavID}Content{$project->id}"), + return $cells; +} - in_array($project->model, array('scrum', 'kanban', 'agileplus')) ? div +/** + * 获取瀑布类项目的统计信息. + * get waterfall project info. + * + * @param object $project + * @access public + * @return void + */ +function getWaterfallProjectInfo($project) +{ + global $app, $lang; + $isChineseLang = in_array($app->getClientLang(), array('zh-cn','zh-tw')); + $waterfallProjectInfo = div + ( + /* 瀑布项目展示概况。 */ + set('class', 'weekly-row'), + div ( - /* 敏捷、看板等项目展示概况。 */ - div + span ( - set('class', 'flex bg-white h-10 leading-9 px-4 shadow-sm'), - cell - ( - set('class', 'text-left mr-6'), - span - ( - set('class', 'text-gray'), - '距离项目结束还剩', - span - ( - set('class', 'font-bold text-black px-1'), - zget($project, 'remainingDays' , 0) - ), - $lang->block->projectstatistic->day - ) - ), - cell - ( - set('class', 'flex-1 text-left'), - span - ( - set('class', 'text-gray mr-5'), - '存在风险 : ', - span - ( - set('class', 'font-bold text-warning'), - '3' - ) - ), - span - ( - set('class', 'text-gray'), - '存在问题 : ', - span - ( - set('class', 'font-bold text-warning'), - '1' - ) - ) - ), - (!empty($project->executions) and $project->multiple) ? cell - ( - set('class', 'flex-1 text-right'), - span - ( - set('class', 'text-gray'), - '最近执行 ', - a - ( - set('href', $this->createLink('execution', 'task', "executionID={$project->executions[0]->id}")), - set('title', $project->executions[0]->name), - $project->executions[0]->name, - ) - ) - ) : null + set('class', 'weekly-title'), + $lang->project->weekly ), - div + span ( - set('class', 'flex'), - $cells + set('class', 'weekly-stage'), + $project->current ) - ) : div + ), + div ( - /* 瀑布项目展示概况。 */ - set('class', 'weekly-row'), + set('class', 'flex'), div ( - span - ( - set('class', 'weekly-title'), - $lang->project->weekly - ), - span - ( - set('class', 'weekly-stage'), - $project->current - ) - ), - div - ( - set('class', 'flex'), + set('class', 'flex-1'), div ( - set('class', 'flex-1'), + set('class', 'progress'), + span + ( + set('class', 'mr-4'), + $lang->project->progress . ' : ' . $project->progress . '%' + ), div ( - set('class', 'progress'), - span - ( - set('class', 'mr-4'), - $lang->project->progress . ' : ' . $project->progress . '%' - ), - div - ( - set('class', 'progress-bar'), - set('role', 'progressbar'), - setStyle(['width' => $project->progress . '%']), - ) + set('class', 'progress-bar'), + set('role', 'progressbar'), + setStyle(['width' => $project->progress . '%']), ) - ), - div - ( - set('class', 'flex-1 text-center'), - $lang->project->teamCount . ' : ' . $project->teamCount - ), - div - ( - set('class', 'flex-1 text-left'), - $lang->project->budget . ' : ' . ($project->budget != 0 ? $project->budget : $this->lang->project->future) - ), - div(set('class', 'flex-1')) - ), - div - ( - set('class', 'flex'), - div - ( - set('class', 'flex-1'), - $isChineseLang ? $lang->project->pv . '(' . $lang->project->pvTitle . ')' : $lang->project->pv - ), - div - ( - set('class', 'flex-1'), - $isChineseLang ? $lang->project->ev . '(' . $lang->project->evTitle . ')' : $lang->project->ev - ), - div - ( - set('class', 'flex-1'), - $isChineseLang ? $lang->project->ac . '(' . $lang->project->acTitle . ')' : $lang->project->ac - ), - div - ( - set('class', 'flex-1'), - $isChineseLang ? $lang->project->sv . '(' . $lang->project->svTitle . ')' : $lang->project->sv - ), - div - ( - set('class', 'flex-1'), - $isChineseLang ? $lang->project->cv . '(' . $lang->project->cvTitle . ')' : $lang->project->cv ) ), div ( - set('class', 'flex'), - div - ( - set('class', 'flex-1'), - $project->pv - ), - div - ( - set('class', 'flex-1'), - $project->ev - ), - div - ( - set('class', 'flex-1'), - $project->ac - ), - div - ( - set('class', 'flex-1'), - $project->sv - ), - div - ( - set('class', 'flex-1'), - $project->cv - ) + set('class', 'flex-1 text-center'), + $lang->project->teamCount . ' : ' . $project->teamCount + ), + div + ( + set('class', 'flex-1 text-left'), + $lang->project->budget . ' : ' . ($project->budget != 0 ? $project->budget : $lang->project->future) + ), + div(set('class', 'flex-1')) + ), + div + ( + set('class', 'flex'), + div + ( + set('class', 'flex-1'), + $isChineseLang ? $lang->project->pv . '(' . $lang->project->pvTitle . ')' : $lang->project->pv + ), + div + ( + set('class', 'flex-1'), + $isChineseLang ? $lang->project->ev . '(' . $lang->project->evTitle . ')' : $lang->project->ev + ), + div + ( + set('class', 'flex-1'), + $isChineseLang ? $lang->project->ac . '(' . $lang->project->acTitle . ')' : $lang->project->ac + ), + div + ( + set('class', 'flex-1'), + $isChineseLang ? $lang->project->sv . '(' . $lang->project->svTitle . ')' : $lang->project->sv + ), + div + ( + set('class', 'flex-1'), + $isChineseLang ? $lang->project->cv . '(' . $lang->project->cvTitle . ')' : $lang->project->cv + ) + ), + div + ( + set('class', 'flex'), + div + ( + set('class', 'flex-1'), + $project->pv + ), + div + ( + set('class', 'flex-1'), + $project->ev + ), + div + ( + set('class', 'flex-1'), + $project->ac + ), + div + ( + set('class', 'flex-1'), + $project->sv + ), + div + ( + set('class', 'flex-1'), + $project->cv ) ) ); + return $waterfallProjectInfo; } +$blockNavCode = 'nav-' . uniqid(); div ( set('class', 'projectstatistic-block'), @@ -293,14 +360,14 @@ div ul ( set('class', 'nav nav-tabs nav-stacked'), - $navTabs, + getProjectTabs($projects, $blockNavCode) ), ), cell ( set('class', 'tab-content'), set('width', '75%'), - $tabItems + getProjectInfo($projects, $blockNavCode) ) ) ); From 4ce1b83e3cac2036ee6d56f926e73b85cb47b827 Mon Sep 17 00:00:00 2001 From: chentao Date: Mon, 8 May 2023 11:24:37 +0800 Subject: [PATCH 12/59] * product: fix param type. --- module/product/tao.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/product/tao.php b/module/product/tao.php index a1c405497b..76d4c5ba05 100644 --- a/module/product/tao.php +++ b/module/product/tao.php @@ -608,14 +608,14 @@ class productTao extends productModel * Get products by project ID. * * @param int $projectID - * @param array $views + * @param string $productIdListStr '1,2,3' * @param string $status * @param string $orderBy * @param bool $noDeleted * @access protected * @return int */ - protected function getProductsByProjectID(int $projectID, array $views, string $status, string $orderBy, bool $noDeleted): array + protected function getProductsByProjectID(int $projectID, string $productIdListStr, string $status, string $orderBy, bool $noDeleted): array { return $this->dao->select("t1.branch, t1.plan, t2.*") ->from(TABLE_PROJECTPRODUCT)->alias('t1') @@ -623,7 +623,7 @@ class productTao extends productModel ->where('1=1') ->beginIF($noDeleted)->andWhere('t2.deleted')->eq(0)->fi() ->beginIF(!empty($projectID))->andWhere('t1.project')->in($projectID)->fi() - ->beginIF(!$this->app->user->admin and $this->config->vision == 'rnd')->andWhere('t2.id')->in($views)->fi() + ->beginIF(!$this->app->user->admin and $this->config->vision == 'rnd')->andWhere('t2.id')->in($productIdListStr)->fi() ->andWhere('t2.vision')->eq($this->config->vision) ->beginIF(strpos($status, 'noclosed') !== false)->andWhere('t2.status')->ne('closed')->fi() ->orderBy($orderBy . 't2.order asc') From 509ca47047256eb7c3e5deb30c549b912971fb65 Mon Sep 17 00:00:00 2001 From: guofeilong Date: Mon, 8 May 2023 11:25:26 +0800 Subject: [PATCH 13/59] * Code for function refactors project update. --- .../test/tao/deleteextramembersbyproject.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 module/project/test/tao/deleteextramembersbyproject.php diff --git a/module/project/test/tao/deleteextramembersbyproject.php b/module/project/test/tao/deleteextramembersbyproject.php new file mode 100644 index 0000000000..900f25d99a --- /dev/null +++ b/module/project/test/tao/deleteextramembersbyproject.php @@ -0,0 +1,22 @@ +#!/usr/bin/env php +loadModel('project'); + +$project = new stdClass; +$team = new stdClass; +$members = new stdClass; + +r($tester->project->deleteextramembersbyproject(2, $project, $team, $members)) && p() && e(1); From 595999ff6655a7d51c8ae7316a44bc6f4be788d0 Mon Sep 17 00:00:00 2001 From: guofeilong Date: Mon, 8 May 2023 11:26:20 +0800 Subject: [PATCH 14/59] * Code refactors for function project update . --- db/update18.4.alpha1.sql | 4 + db/zentao.sql | 2 +- module/execution/control.php | 4 +- module/execution/model.php | 6 +- .../execution/test/model/data/sql/project.sql | 2 +- module/execution/view/create.html.php | 8 +- module/execution/view/edit.html.php | 8 +- module/programplan/model.php | 4 +- module/programplan/view/create.html.php | 2 +- module/programplan/view/gantt.html.php | 2 +- module/project/control.php | 2 +- module/project/css/create.css | 2 +- module/project/js/create.js | 12 +- module/project/js/edit.js | 8 +- module/project/js/execution.js | 2 +- module/project/js/manageproducts.js | 8 +- module/project/lang/de.php | 12 +- module/project/lang/en.php | 12 +- module/project/lang/fr.php | 12 +- module/project/lang/vi.php | 8 +- module/project/lang/zh-cn.php | 12 +- module/project/model.php | 344 +++++++++++------- module/project/tao.php | 7 +- module/project/test/model/stageProduct.php | 21 ++ .../test/model/unlinkproductsbyproject.php | 23 ++ module/project/test/model/update.php | 19 +- .../test/model/updateteammembersbyproject.php | 23 ++ .../test/model/updateuserviewbyproject.php | 23 ++ .../test/model/updatewhitelistbyproject.php | 23 ++ .../test/model/yaml/stageproduct/project.yaml | 24 ++ .../yaml/unLinkproductsbyproject/project.yaml | 24 ++ .../test/model/yaml/update/project.yaml | 24 ++ .../project.yaml | 0 .../projectproduct.yaml | 0 .../updateteammembersbyproject/project.yaml | 24 ++ .../yaml/updateuserviewbyproject/project.yaml | 24 ++ .../updatewhitelistbyproject/project.yaml | 24 ++ module/project/view/create.html.php | 8 +- module/project/view/edit.html.php | 10 +- module/project/view/execution.html.php | 6 +- module/project/view/manageproducts.html.php | 4 +- module/project/zen.php | 63 +++- module/task/model.php | 2 +- module/tutorial/model.php | 2 +- module/user/test/model/data/sql/project.sql | 2 +- 45 files changed, 633 insertions(+), 223 deletions(-) create mode 100644 db/update18.4.alpha1.sql create mode 100644 module/project/test/model/stageProduct.php create mode 100644 module/project/test/model/unlinkproductsbyproject.php create mode 100644 module/project/test/model/updateteammembersbyproject.php create mode 100644 module/project/test/model/updateuserviewbyproject.php create mode 100644 module/project/test/model/updatewhitelistbyproject.php create mode 100644 module/project/test/model/yaml/stageproduct/project.yaml create mode 100644 module/project/test/model/yaml/unLinkproductsbyproject/project.yaml create mode 100644 module/project/test/model/yaml/update/project.yaml rename module/project/test/model/yaml/{updatePlanIdListByProject => updateplanIdlistbyproject}/project.yaml (100%) rename module/project/test/model/yaml/{updatePlanIdListByProject => updateplanIdlistbyproject}/projectproduct.yaml (100%) create mode 100644 module/project/test/model/yaml/updateteammembersbyproject/project.yaml create mode 100644 module/project/test/model/yaml/updateuserviewbyproject/project.yaml create mode 100644 module/project/test/model/yaml/updatewhitelistbyproject/project.yaml diff --git a/db/update18.4.alpha1.sql b/db/update18.4.alpha1.sql new file mode 100644 index 0000000000..e3cec0f886 --- /dev/null +++ b/db/update18.4.alpha1.sql @@ -0,0 +1,4 @@ +ALTER TABLE `zt_project` ADD `stageBy` enum('project', 'product') NOT NULL DEFAULT 'product' AFTER `division`; +UPDATE `zt_project` SET `stageBy` = 'project' WHERE `division` = '0'; +UPDATE `zt_project` SET `stageBy` = 'product' WHERE `division` = '1'; +ALTER TABLE `zt_project` DROP `division`; diff --git a/db/zentao.sql b/db/zentao.sql index 06b2dea9c9..1f1fca3af5 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -1354,7 +1354,7 @@ CREATE TABLE IF NOT EXISTS `zt_project` ( `whitelist` text NULL, `order` mediumint(8) unsigned NOT NULL DEFAULT '0', `vision` varchar(10) NOT NULL DEFAULT 'rnd', - `division` enum('0','1') NOT NULL DEFAULT '1', + `stageBy` enum('project','product') NOT NULL DEFAULT 'product', `displayCards` smallint(6) NOT NULL default '0', `fluidBoard` enum('0','1') NOT NULL DEFAULT '0', `multiple` enum('0','1') NOT NULL DEFAULT '1', diff --git a/module/execution/control.php b/module/execution/control.php index e6dc952c14..ca6f804aee 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -1770,7 +1770,7 @@ class execution extends control $this->view->linkedBranches = $linkedBranches; } - if(!empty($project) and !$project->division) + if(!empty($project) and $project->stageBy == 'project') { $products = $this->loadModel('product')->getProducts($projectID); $branches = $this->project->getBranchesByProject($projectID); @@ -1916,7 +1916,7 @@ class execution extends control $this->view->from = $this->app->tab; $this->view->isStage = (isset($project->model) and ($project->model == 'waterfall' or $project->model == 'waterfallplus')) ? true : false; $this->view->project = $project; - $this->view->division = !empty($project) ? $project->division : 1; + $this->view->stageBy = $project->stageBy; $this->view->type = $type; $this->display(); } diff --git a/module/execution/model.php b/module/execution/model.php index 44bf967d40..f1aa8f66c7 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -2052,7 +2052,7 @@ class executionModel extends model if(isset($project->model) and in_array($project->model, array('waterfall', 'waterfallplus'))) { $executionProducts = array(); - if($project->hasProduct and $project->division) + if($project->hasProduct and ($project->stageBy == 'product')) { $executionList = array(); $executionProducts = $this->dao->select('t1.project, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') @@ -5267,7 +5267,7 @@ class executionModel extends model } } } - if(!empty($execution->division) and $execution->hasProduct) echo "{$execution->productName}"; + if(($execution->stageBy == 'project') and $execution->hasProduct) echo "{$execution->productName}"; echo "" . zget($this->lang->project->statusList, $execution->status) . ''; echo '' . zget($users, $execution->PM) . ''; echo helper::isZeroDate($execution->begin) ? '' : '' . $execution->begin . ''; @@ -5322,7 +5322,7 @@ class executionModel extends model { foreach($execution->children as $child) { - $child->division = $execution->division; + $child->stageBy = $execution->stageBy; $this->printNestedList($child, true, $users, $productID); } } diff --git a/module/execution/test/model/data/sql/project.sql b/module/execution/test/model/data/sql/project.sql index bb14bbcb80..4a40c242e7 100644 --- a/module/execution/test/model/data/sql/project.sql +++ b/module/execution/test/model/data/sql/project.sql @@ -73,7 +73,7 @@ CREATE TABLE `zt_project` ( `whitelist` text NOT NULL, `order` mediumint(8) unsigned NOT NULL, `vision` varchar(10) NOT NULL DEFAULT 'rnd', - `division` enum('0','1') NOT NULL DEFAULT '1', + `stageBy` enum('product','project') NOT NULL DEFAULT 'product', `displayCards` smallint(6) NOT NULL DEFAULT 0, `fluidBoard` enum('0','1') NOT NULL DEFAULT '0', `multiple` enum('0','1') NOT NULL DEFAULT '1', diff --git a/module/execution/view/create.html.php b/module/execution/view/create.html.php index 2781a20e1a..a3876d7efb 100644 --- a/module/execution/view/create.html.php +++ b/module/execution/view/create.html.php @@ -157,9 +157,9 @@ type != 'normal' and isset($branchGroups[$product->id]);?>
'> productCommon;?> - division) ? "disabled='disabled'" : '';?> + stageBy == 'project') ? "disabled='disabled'" : '';?> id, "class='form-control chosen' $disabled onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?> - division) echo html::hidden("products[$i]", $product->id);?> + stageBy == 'project') echo html::hidden("products[$i]", $product->id);?>

'> @@ -177,7 +177,7 @@ product->plan;?> id)) echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), isset($product->plans) ? $product->plans : '', "class='form-control chosen' multiple");?> id) echo html::select("plans[$product->id][]", !empty($productPlan) ? $productPlan : array(), isset($productPlan[$plan->id]) ? $plan->id : '', "class='form-control chosen' multiple");?> - division)):?> + stageBy == 'project')):?>
> @@ -225,7 +225,7 @@
product->plan;?> - division)):?> + stageBy == 'product')):?>
diff --git a/module/execution/view/edit.html.php b/module/execution/view/edit.html.php index e3b878b4ef..d420db2c7e 100644 --- a/module/execution/view/edit.html.php +++ b/module/execution/view/edit.html.php @@ -169,9 +169,9 @@ type != 'normal' and isset($branchGroups[$product->id]);?>
'> productCommon;?> - type == 'stage' and !$execution->division) ? "disabled='disabled'" : '';?> + type == 'stage' and $execution->stageBy == 'project') ? "disabled='disabled'" : '';?> id, "class='form-control chosen' $disabled onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?> - type == 'stage' and !$execution->division) echo html::hidden("products[$i]", $product->id);?> + type == 'stage' and $execution->stageBy == 'project') echo html::hidden("products[$i]", $product->id);?>
'> @@ -187,7 +187,7 @@
> product->plan;?> id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), $product->plans, "class='form-control chosen' multiple");?> - type == 'stage' and !$execution->division)):?> + type == 'stage' and $execution->stageBy == 'project')):?>
> @@ -262,7 +262,7 @@ productCommon;?> model == 'waterfall' or $project->model == 'waterfallplus') ? "disabled='disabled'" : '';?> id, "class='form-control chosen' $disabled onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?> - type == 'stage' and !$project->division) echo html::hidden("products[$i]", $product->id);?> + type == 'stage' and $project->stageBy == 'product') echo html::hidden("products[$i]", $product->id);?>
'> diff --git a/module/programplan/model.php b/module/programplan/model.php index d98a32ecc9..c8e7ea712a 100755 --- a/module/programplan/model.php +++ b/module/programplan/model.php @@ -873,7 +873,7 @@ class programplanModel extends model $linkProducts = array(); $linkBranches = array(); $productList = $this->loadModel('product')->getProducts($projectID); - if($project->division) + if($project->stageBy == 'product') { $linkProducts = array(0 => $productID); $linkBranches = array(0 => $productList[$productID]->branches); @@ -954,7 +954,7 @@ class programplanModel extends model { unset($plan->id); $plan->status = 'wait'; - $plan->division = $project->division; + $plan->stageBy = $project->stageBy; $plan->version = 1; $plan->parentVersion = $plan->parent == 0 ? 0 : $this->dao->findByID($plan->parent)->from(TABLE_PROJECT)->fetch('version'); $plan->team = substr($plan->name,0, 30); diff --git a/module/programplan/view/create.html.php b/module/programplan/view/create.html.php index 22981125a1..b40b383cad 100644 --- a/module/programplan/view/create.html.php +++ b/module/programplan/view/create.html.php @@ -23,7 +23,7 @@ echo "{$title}"; ?> - division):?> + stageBy == 'product'):?>
diff --git a/module/programplan/view/gantt.html.php b/module/programplan/view/gantt.html.php index f8cc583dcd..eccfe89e77 100755 --- a/module/programplan/view/gantt.html.php +++ b/module/programplan/view/gantt.html.php @@ -86,7 +86,7 @@ form {display: block; margin-top: 0em; margin-block-end: 1em;} app->getModuleName() == 'programplan'):?>
- division)):?> + stageBy == 'product'):?> product->allProduct;?>