diff --git a/ci.json b/ci.json index 202f5e4a34..3f2ce494b1 100644 --- a/ci.json +++ b/ci.json @@ -6,13 +6,13 @@ }, "zentaoext": { "gitRepo": "zentao/zentaoext", - "gitVersion": "release/12.3" + "gitVersion": "release/12.4" }, "zentaomax": { - "gitVersion": "release/7.3" + "gitVersion": "release/7.4" }, "zentaoipd": { - "gitVersion": "release/4.3" + "gitVersion": "release/4.4" }, "devops": { "gitRepo": "zentao/devops" @@ -43,7 +43,7 @@ } }, "downgrade": { - "versions": "8.1,7.2,7.1,7.0" + "versions": "8.4,8.1,7.2,7.1,7.0" }, "upload": { "bucket": "download", diff --git a/db/update21.7.3.sql b/db/update21.7.3.sql index 495ebd2b28..0027cb057a 100644 --- a/db/update21.7.3.sql +++ b/db/update21.7.3.sql @@ -16,6 +16,11 @@ ALTER TABLE `zt_bug` CHANGE `injection` `injection` varchar(30) NOT NULL DEFAULT '', CHANGE `identify` `identify` varchar(30) NOT NULL DEFAULT ''; +ALTER TABLE `zt_task` MODIFY `path` varchar(255) NOT NULL DEFAULT ''; + +CREATE INDEX `parent` ON `zt_story` (`parent`); +CREATE INDEX `path` ON `zt_task` (`path`); + UPDATE `zt_project` SET `workflowGroup` = (SELECT `id` FROM `zt_workflowgroup` WHERE `code` = 'kanbanproduct' AND `main` = '1' LIMIT 1) WHERE `type` = 'project' AND `model` = 'kanban' AND `hasProduct` = '1'; UPDATE `zt_project` SET `workflowGroup` = (SELECT `id` FROM `zt_workflowgroup` WHERE `code` = 'kanbanproject' AND `main` = '1' LIMIT 1) WHERE `type` = 'project' AND `model` = 'kanban' AND `hasProduct` = '0'; @@ -70,20 +75,5 @@ WHERE `bug`.`identify` != 0 AND `object`.`category` NOT IN ('HLDS', 'DDS', 'DBDS UPDATE `zt_bug` SET `injection` = '' WHERE `injection` = '0'; UPDATE `zt_bug` SET `identify` = '' WHERE `identify` = '0'; -ALTER TABLE `zt_doc` ADD `isDeliverable` tinyint(1) NOT NULL DEFAULT 0 AFTER `acl`; -ALTER TABLE `zt_deliverable` ADD `workflowGroup` int(8) NOT NULL DEFAULT '0' AFTER `id`; -ALTER TABLE `zt_deliverable` ADD `activity` int(8) unsigned NOT NULL DEFAULT '0' AFTER `name`; -ALTER TABLE `zt_deliverable` ADD `trimmable` char(30) NOT NULL DEFAULT '0' AFTER `activity`; -ALTER TABLE `zt_deliverable` ADD `trimRule` varchar(255) NOT NULL AFTER `trimmable`; -ALTER TABLE `zt_deliverable` ADD `template` text NOT NULL AFTER `trimRule`; -ALTER TABLE `zt_deliverable` ADD `status` varchar(30) NOT NULL DEFAULT 'enabled' AFTER `name`; - -CREATE TABLE IF NOT EXISTS `zt_deliverablestage` ( - `id` int(8) unsigned NOT NULL AUTO_INCREMENT, - `deliverable` int(8) unsigned NOT NULL DEFAULT 0, - `stage` varchar(30) NOT NULL, - `required` varchar(30) NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE UNIQUE INDEX `unique` ON `zt_deliverablestage`(`deliverable`,`stage`); -ALTER TABLE `zt_module` ADD `extra` varchar(30) NOT NULL DEFAULT ''; +INSERT INTO `zt_workflowaction` (`group`, `module`, `action`, `method`, `name`, `type`, `batchMode`, `extensionType`, `open`, `position`, `layout`, `show`, `order`, `buildin`, `role`, `virtual`, `conditions`, `verifications`, `hooks`, `linkages`, `js`, `css`, `toList`, `blocks`, `desc`, `status`, `vision`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES +(0, 'project', 'execution', 'browse', '执行列表', 'single', 'different', 'none', 'normal', 'browse', 'normal', 'direct', 0, 1, 'buildin', 0, NULL, NULL, NULL, NULL, NULL, NULL, '', NULL, NULL, 'enable', 'rnd', 'admin', '2025-01-08 09:41:02', '', NULL); diff --git a/db/update22.0.sql b/db/update22.0.sql new file mode 100644 index 0000000000..005fcd02ae --- /dev/null +++ b/db/update22.0.sql @@ -0,0 +1,17 @@ +ALTER TABLE `zt_doc` ADD `isDeliverable` tinyint(1) NOT NULL DEFAULT 0 AFTER `acl`; +ALTER TABLE `zt_deliverable` ADD `workflowGroup` int(8) NOT NULL DEFAULT '0' AFTER `id`; +ALTER TABLE `zt_deliverable` ADD `activity` int(8) unsigned NOT NULL DEFAULT '0' AFTER `name`; +ALTER TABLE `zt_deliverable` ADD `trimmable` char(30) NOT NULL DEFAULT '0' AFTER `activity`; +ALTER TABLE `zt_deliverable` ADD `trimRule` varchar(255) NOT NULL AFTER `trimmable`; +ALTER TABLE `zt_deliverable` ADD `template` text NOT NULL AFTER `trimRule`; +ALTER TABLE `zt_deliverable` ADD `status` varchar(30) NOT NULL DEFAULT 'enabled' AFTER `name`; + +CREATE TABLE IF NOT EXISTS `zt_deliverablestage` ( + `id` int(8) unsigned NOT NULL AUTO_INCREMENT, + `deliverable` int(8) unsigned NOT NULL DEFAULT 0, + `stage` varchar(30) NOT NULL, + `required` varchar(30) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE UNIQUE INDEX `unique` ON `zt_deliverablestage`(`deliverable`,`stage`); +ALTER TABLE `zt_module` ADD `extra` varchar(30) NOT NULL DEFAULT ''; \ No newline at end of file diff --git a/db/zentao.sql b/db/zentao.sql index 43cfb15cce..05451ec559 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -2019,6 +2019,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` ( `deleted` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE INDEX `parent` ON `zt_story` (`parent`); CREATE INDEX `product` ON `zt_story` (`product`); CREATE INDEX `root` ON `zt_story` (`root`); CREATE INDEX `status` ON `zt_story` (`status`); @@ -2092,7 +2093,7 @@ CREATE TABLE IF NOT EXISTS `zt_task` ( `parent` mediumint(8) NOT NULL DEFAULT '0', `isParent` tinyint(1) NOT NULL DEFAULT '0', `isTpl` tinyint(1) unsigned NOT NULL DEFAULT '0', - `path` text NULL, + `path` varchar(255) NOT NULL DEFAULT '', `execution` mediumint(8) unsigned NOT NULL DEFAULT '0', `module` mediumint(8) unsigned NOT NULL DEFAULT '0', `design` mediumint(8) unsigned NOT NULL DEFAULT '0', @@ -2152,6 +2153,7 @@ CREATE TABLE IF NOT EXISTS `zt_task` ( CREATE INDEX `execution` ON `zt_task` (`execution`); CREATE INDEX `story` ON `zt_task` (`story`); CREATE INDEX `parent` ON `zt_task` (`parent`); +CREATE INDEX `path` ON `zt_task` (`path`); CREATE INDEX `assignedTo` ON `zt_task` (`assignedTo`); CREATE INDEX `order` ON `zt_task` (`order`); diff --git a/framework/helper.class.php b/framework/helper.class.php index 8075e939b9..3395ec5c9c 100644 --- a/framework/helper.class.php +++ b/framework/helper.class.php @@ -812,11 +812,19 @@ function getVisions(): array /** * Save debug log to the php log file which prefix with 'debug.'. * - * @param mixed $message + * @param mixed ...$messages * @return void */ -function debug($message = ''): void +function debug(mixed ...$messages): void { + if(count($messages) > 1) + { + foreach($messages as $message) debug($message); + return; + } + + $message = current($messages); + static $times = []; $time = microtime(true); $duration = $times ? $time - end($times) : 0; diff --git a/lib/base/dao/dao.class.php b/lib/base/dao/dao.class.php index 6a804a6fef..68bc8e6198 100644 --- a/lib/base/dao/dao.class.php +++ b/lib/base/dao/dao.class.php @@ -899,7 +899,7 @@ class baseDAO { $alias = preg_match("/`$table`\s+as\s+(\w+)/i", $sql, $matches) ? $matches[1] : ''; - $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe (`isTpl` = '0' OR `isTpl` IS NULL) AND"; + $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe `isTpl` = '0' AND"; $sql = preg_replace("/wHeRE/i", $replace, $sql, 1); } else @@ -912,7 +912,7 @@ class baseDAO if(strpos($sql, "`$table`") !== false) { $alias = preg_match("/`$table`\s+as\s+(\w+)/i", $sql, $mainMatches) ? $mainMatches[1] : ''; - $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe (`isTpl` = '0' OR `isTpl` IS NULL) AND"; + $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe `isTpl` = '0' AND"; $sql = preg_replace("/wHeRE/i", $replace, $sql, 1); } @@ -921,7 +921,7 @@ class baseDAO if(strpos($sql, "`$table`") !== false && !preg_match("/`isTpl`\s*=\s*('1'|1)/", $subSQL)) { $alias = preg_match("/`$table`\s+as\s+(\w+)/i", $subSQL, $subMatches) ? $subMatches[1] : ''; - $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe (`isTpl` = '0' OR `isTpl` IS NULL) AND"; + $replace = $alias ? "wHeRe ($alias.`isTpl` = '0' OR $alias.`isTpl` IS NULL) AND" : "wHeRe `isTpl` = '0' AND"; $subSQL = preg_replace("/wHeRE/i", $replace, $subSQL, 1); } $sql = str_ireplace("$$index", $subSQL, $sql); diff --git a/lib/zin/wg/backbtn/v1.php b/lib/zin/wg/backbtn/v1.php index 64b47d813b..00ef3a7e5f 100644 --- a/lib/zin/wg/backbtn/v1.php +++ b/lib/zin/wg/backbtn/v1.php @@ -44,11 +44,11 @@ class backBtn extends btn $backs = array( 'task' => 'execution-task,my-work,my-contribute,execution-tree,execution-grouptask,project-execution,product-track,repo-view,story-change,execution-kanban,execution-taskkanban,my-index,feedback-adminview,projectstory-track,execution-calendar,my-effort,company-effort,company-calendar,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,task-view', - 'story' => 'product-browse,projectstory-story,execution-story,my-work,my-contribute,productplan-view,build-view,projectbuild-view,product-track,repo-view,testcase-zerocase,my-index,feedback-adminview,projectstory-track,task-view,my-effort,company-effort,company-calendar,demandpool-track,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,ticket-browse,ticket-view,roadmap-view,charter-view,demand-view,review-assess,review-audit,action-trash', + 'story' => 'product-browse,projectstory-story,execution-story,my-work,my-contribute,productplan-view,build-view,projectbuild-view,product-track,repo-view,testcase-zerocase,my-index,feedback-adminview,projectstory-track,task-view,my-effort,company-effort,company-calendar,demandpool-track,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,ticket-browse,ticket-view,roadmap-view,charter-view,demand-view,review-assess,review-audit,action-trash,execution-task,testcase-browse', 'bug' => 'bug-browse,project-bug,my-work,my-contribute,execution-bug,bug-view,qa-index,execution-task,product-track,execution-task,task-view,repo-view,story-change,repo-review,feedback-adminview,my-index,projectstory-track,my-effort,company-effort,company-calendar,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,ticket-browse,ticket-view,productplan-view', 'testcase' => 'testcase-browse,testcase-browseScene,project-testcase,my-work,my-contribute,execution-testcase,testtask-cases,testsuite-view,product-browse,testcase-view,qa-index,caselib-browse,product-track,story-change,my-index,projectstory-track,my-effort,company-effort,company-calendar,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,testreport-view,bug-browse,project-bug,bug-view', 'testsuite' => 'testsuite-browse,testsuite-view,testtask-cases,my-index,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view', - 'testtask' => 'testtask-browse,testtask-cases,qa-index,testcase-browse,execution-build,my-index,my-effort,company-effort,company-calendar,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,project-testcase', + 'testtask' => 'testtask-browse,testtask-cases,qa-index,testcase-browse,execution-build,my-index,my-effort,company-effort,company-calendar,product-dynamic,project-dynamic,execution-dynamic,project-view,execution-view,project-testcase,project-testtask,execution-testtask', 'testreport' => 'testreport-browse,project-testreport,execution-testreport,execution-testtask', 'tree' => 'product-browse,project-browse,execution-task,bug-browse,projectstory-story,host-browse,execution-story,feedback-admin,ticket-browse,testcase-browse,caselib-browse,dataview-browse,deliverable-browse', 'doc' => 'doc-mySpace,doc-productSpace,doc-projectSpace,doc-teamSpace,doc-view,execution-doc', diff --git a/lib/zin/wg/docapp/js/v1.js b/lib/zin/wg/docapp/js/v1.js index 5e42012c0f..96c0b574f7 100644 --- a/lib/zin/wg/docapp/js/v1.js +++ b/lib/zin/wg/docapp/js/v1.js @@ -644,6 +644,7 @@ function handleSaveDoc(doc) space : spaceType, uid : (doc.uid || `doc${doc.id}`), }; + if(Array.isArray(doc.files)) docData.files = doc.files.map(f => typeof f === 'object' ? f.id : f).join(','); if(doc.fromVersion) docData.fromVersion = doc.fromVersion; if(savingDocData[doc.id]) diff --git a/lib/zin/wg/gantt/js/v1.js b/lib/zin/wg/gantt/js/v1.js index 40f4506095..ad7d54a134 100644 --- a/lib/zin/wg/gantt/js/v1.js +++ b/lib/zin/wg/gantt/js/v1.js @@ -695,20 +695,18 @@ function initGantt() /* 添加关联关系前的校验。 */ gantt.attachEvent("onBeforeLinkAdd", function(id, link) { - const source = link.source; - const target = link.target; - if(source.indexOf('-') === -1 || target.indexOf('-') === -1) + const sourceTask = gantt.getTask(link.source); + const targetTask = gantt.getTask(link.target); + if(sourceTask.type != 'task' || targetTask.type != 'task') { let message = ganttLang.wrongRelation; - if(source.indexOf('-') === -1) message += ganttLang.wrongRelationSource; - if(target.indexOf('-') === -1) message += ganttLang.wrongRelationTarget; + if(sourceTask.type != 'task') message += ganttLang.wrongRelationSource; + if(targetTask.type != 'task') message += ganttLang.wrongRelationTarget; zui.Messager.show({content: message, type: 'danger-outline', icon: 'exclamation-sign'}); return false; } - const sourceTask = gantt.getTask(link.source); - const targetTask = gantt.getTask(link.target); if(sourceTask.allowLinks === false || targetTask.allowLinks === false) { zui.Messager.show({content: ganttLang.wrongKanbanTasks, type: 'danger-outline', icon: 'exclamation-sign'}); diff --git a/module/admin/lang/menu.php b/module/admin/lang/menu.php index 31e25235ce..efaaa42e5f 100644 --- a/module/admin/lang/menu.php +++ b/module/admin/lang/menu.php @@ -73,7 +73,6 @@ $lang->admin->menuList->feature['subMenu']['project'] = array('link' => "{$l $lang->admin->menuList->feature['subMenu']['execution'] = array('link' => "{$lang->execution->common}|custom|required|module=execution", 'exclude' => 'required,set', 'alias' => 'execution,limittaskdate', 'subModule' => 'stage'); $lang->admin->menuList->feature['subMenu']['qa'] = array('link' => "{$lang->qa->common}|custom|required|module=bug", 'exclude' => 'set,required'); $lang->admin->menuList->feature['subMenu']['kanban'] = array('link' => "{$lang->kanban->common}|custom|kanban|"); -$lang->admin->menuList->feature['subMenu']['doc'] = array('link' => "{$lang->doc->common}|custom|required|module=doc", 'exclude' => 'required'); $lang->admin->menuList->feature['subMenu']['user'] = array('link' => "{$lang->user->common}|custom|required|module=user", 'links' => array('custom|set|module=user&field=roleList'), 'exclude' => 'set,required'); $lang->admin->menuList->feature['tabMenu']['my']['todo'] = array('link' => "{$lang->todo->common}|custom|set|module=todo&field=priList", 'exclude' => 'custom-set'); diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index 6ecee66daa..1dcb90943f 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -793,7 +793,7 @@ $lang->navGroup->featureconfig = 'admin'; $lang->navGroup->doctemplate = 'admin'; $lang->navGroup->notifysetting = 'admin'; $lang->navGroup->holidayseason = 'admin'; -$lang->navGroup->system = 'devops'; +$lang->navGroup->system = 'system'; $lang->navGroup->serverroom = 'devops'; $lang->navGroup->holiday = 'admin'; $lang->navGroup->cache = 'admin'; diff --git a/module/common/model.php b/module/common/model.php index d3dc7d1902..4ed79d0210 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -1143,6 +1143,7 @@ class commonModel extends model if(empty($maintenance)) return true; $maintenance = json_decode($maintenance); + if($this->app->moduleName == 'user' && $this->app->methodName == 'login') return true; if(!empty($this->app->user->admin)) return true; if(isset($maintenance->action) && in_array($maintenance->action, array('upgrade', 'downgrade', 'restore'))) helper::setStatus(503); diff --git a/module/common/test/model/checkmaintenance.php b/module/common/test/model/checkmaintenance.php new file mode 100644 index 0000000000..ce4ca68281 --- /dev/null +++ b/module/common/test/model/checkmaintenance.php @@ -0,0 +1,40 @@ +#!/usr/bin/env php +loadModel('common'); + +$app->moduleName = 'user'; +$app->methodName = 'login'; +r($tester->common->checkMaintenance()) && p() && e('1'); // 检查是否处于维护状态 + +$app->moduleName = 'execution'; +$app->methodName = 'task'; +r($tester->common->checkMaintenance()) && p() && e('1'); // 检查是否处于维护状态 + +$app->moduleName = 'program'; +$app->methodName = 'view'; +r($tester->common->checkMaintenance()) && p() && e('1'); // 检查是否处于维护状态 + +$app->moduleName = 'bug'; +$app->methodName = 'view'; +r($tester->common->checkMaintenance()) && p() && e('1'); // 检查是否处于维护状态 + +$app->moduleName = 'task'; +$app->methodName = 'view'; +r($tester->common->checkMaintenance()) && p() && e('1'); // 检查是否处于维护状态 diff --git a/module/custom/js/set.ui.js b/module/custom/js/set.ui.js index 3055f5f889..e2a4f97d8a 100644 --- a/module/custom/js/set.ui.js +++ b/module/custom/js/set.ui.js @@ -51,41 +51,3 @@ window.changeUnit = function() $defaultCurrencyPicker.render({items: defaultCurrencyItems}); $defaultCurrencyPicker.$.setValue(defaultCurrency); } - -window.savaTestcaseReview = function() -{ - const url = $("#settingForm").attr('action'); - const form = new FormData($("#settingForm")[0]); - if(stopSubmit && oldNeedReview) - { - stopSubmit = false; - - const needReview = $('input[name="needReview"]:checked').val(); - if(needReview == 0) - { - $.ajaxSubmit({ - url: $.createLink('testcase', 'ajaxGetReviewAmount'), - onComplete: function(count) - { - stopSubmit = true; - - if(count == 0) - { - $.ajaxSubmit({url, data:form}); - return true; - } - - zui.Modal.confirm(confirmReviewCase).then((result) => - { - if(result) form.append('reviewCase', '1'); - $.ajaxSubmit({url, data:form}); - }) - } - }); - - return false; - } - } - - $.ajaxSubmit({url, data:form}); -} diff --git a/module/custom/ui/set.html.php b/module/custom/ui/set.html.php index 359929813d..04a5248214 100644 --- a/module/custom/ui/set.html.php +++ b/module/custom/ui/set.html.php @@ -274,12 +274,6 @@ elseif(in_array($module, array('epic', 'story', 'requirement', 'demand', 'testca ); $actionWidth = 'w-2/3'; - $formActions = array(array( - 'text' => $lang->save, - 'type' => 'primary', - 'btnType' => 'button', - 'onclick' => 'savaTestcaseReview()' - )); } } elseif($module == 'bug' && $field == 'longlife') diff --git a/module/custom/zen.php b/module/custom/zen.php index 4a453f888e..e43e9a1331 100644 --- a/module/custom/zen.php +++ b/module/custom/zen.php @@ -388,15 +388,6 @@ class customZen extends custom } $this->loadModel('setting')->setItems("system.testcase", $data); - $reviewCase = isset($data['reviewCase']) ? $data['reviewCase'] : 0; - if($data['needReview'] == 0 && $reviewCase) - { - $waitProductCases = $this->loadModel('testcase')->getByStatus(0, 0, 'all', 'wait'); - $waitLibCases = $this->loadModel('caselib')->getLibCases(0, 'wait'); - $waitCaseIdList = array_merge(array_keys($waitProductCases), array_keys($waitLibCases)); - $this->testcase->batchReview($waitCaseIdList, 'pass'); - } - return !dao::isError(); } } diff --git a/module/doc/config/form.php b/module/doc/config/form.php index 81da6e5973..e209cc0996 100644 --- a/module/doc/config/form.php +++ b/module/doc/config/form.php @@ -89,6 +89,8 @@ $config->doc->form->edit['mailto'] = array('type' => 'array', 'require $config->doc->form->edit['editedBy'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->edit['editedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now); $config->doc->form->edit['isDeliverable'] = array('type' => 'string', 'required' => false); +$config->doc->form->edit['fromVersion'] = array('type' => 'string', 'required' => false, 'default' => ''); +$config->doc->form->edit['files'] = array('type' => 'string', 'required' => false, 'default' => ''); $config->doc->form->edittemplate = $config->doc->form->edit; $config->doc->form->edittemplate['templateDesc'] = array('type' => 'string', 'required' => false, 'default' => ''); diff --git a/module/doc/control.php b/module/doc/control.php index 76e52c7feb..88eac08958 100755 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -2330,6 +2330,7 @@ class doc extends control $data = array('spaceID' => (int)$spaceID); $libs = $this->doc->getLibsOfSpace($type, $spaceID); $libIds = array_keys($libs); + foreach($libs as $lib) $lib->order = (int)$lib->order; if($noPicks || strpos($picks, ',space,') !== false) $data['spaces'] = $spaces; if($noPicks || strpos($picks, ',lib,') !== false) $data['libs'] = array_values($libs); diff --git a/module/doc/model.php b/module/doc/model.php index 797d7d9453..1bf7b67df8 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -1678,8 +1678,9 @@ class docModel extends model $docContent->doc = $docID; $docContent->addedBy = $docContent->editedBy; $docContent->addedDate = $docContent->editedDate; - $docContent->files = implode(',', $files); + $docContent->files = (!empty($docData->files) && is_string($docData->files)) ? (',' . $docData->files) : implode(',', $files); $docContent->fromVersion = isset($docData->fromVersion) ? $docData->fromVersion : max(0, ($version - 1)); + $this->dao->insert(TABLE_DOCCONTENT)->data($docContent)->exec(); $docContent->id = $this->dao->lastInsertID(); } @@ -1752,6 +1753,7 @@ class docModel extends model $doc->path = $path; } + unset($doc->files); $this->dao->update(TABLE_DOC)->data($doc, 'content,contentType,rawContent,fromVersion') ->autoCheck() ->batchCheck($requiredFields, 'notempty') diff --git a/module/execution/config/form.php b/module/execution/config/form.php index 3360016d92..4f8684499b 100644 --- a/module/execution/config/form.php +++ b/module/execution/config/form.php @@ -49,26 +49,27 @@ $config->execution->form->create['whitelist'] = array('type' => 'array', 'r $config->execution->form->create['openedVersion'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => $config->version); $config->execution->form->create['vision'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => $config->vision); -$config->execution->form->edit['project'] = array('type' => 'int', 'required' => false, 'control' => 'select', 'default' => 0); -$config->execution->form->edit['name'] = array('type' => 'string', 'required' => true, 'control' => 'text', 'default' => '', 'filter' => 'trim'); -$config->execution->form->edit['begin'] = array('type' => 'date', 'required' => true, 'control' => 'date', 'default' => null); -$config->execution->form->edit['end'] = array('type' => 'date', 'required' => true, 'control' => 'date', 'default' => null); -$config->execution->form->edit['days'] = array('type' => 'int', 'required' => false, 'control' => 'text', 'default' => 0); -$config->execution->form->edit['lifetime'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); -$config->execution->form->edit['attribute'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); -$config->execution->form->edit['percent'] = array('type' => 'float', 'required' => false, 'control' => 'text', 'default' => 0); -$config->execution->form->edit['products'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->execution->form->edit['branch'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->execution->form->edit['plans'] = array('type' => 'array', 'required' => false, 'default' => array()); -$config->execution->form->edit['team'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); -$config->execution->form->edit['status'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => 'wait'); -$config->execution->form->edit['PM'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); -$config->execution->form->edit['PO'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); -$config->execution->form->edit['QD'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); -$config->execution->form->edit['RD'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); -$config->execution->form->edit['desc'] = array('type' => 'string', 'required' => false, 'control' => 'editor', 'default' => ''); -$config->execution->form->edit['acl'] = array('type' => 'string', 'required' => false, 'control' => 'radio', 'default' => ''); -$config->execution->form->edit['whitelist'] = array('type' => 'array', 'required' => false, 'control' => 'select', 'default' => array(), 'filter' => 'join'); +$config->execution->form->edit['project'] = array('type' => 'int', 'required' => false, 'control' => 'select', 'default' => 0); +$config->execution->form->edit['name'] = array('type' => 'string', 'required' => true, 'control' => 'text', 'default' => '', 'filter' => 'trim'); +$config->execution->form->edit['begin'] = array('type' => 'date', 'required' => true, 'control' => 'date', 'default' => null); +$config->execution->form->edit['end'] = array('type' => 'date', 'required' => true, 'control' => 'date', 'default' => null); +$config->execution->form->edit['days'] = array('type' => 'int', 'required' => false, 'control' => 'text', 'default' => 0); +$config->execution->form->edit['lifetime'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); +$config->execution->form->edit['attribute'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); +$config->execution->form->edit['percent'] = array('type' => 'float', 'required' => false, 'control' => 'text', 'default' => 0); +$config->execution->form->edit['products'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->execution->form->edit['branch'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->execution->form->edit['plans'] = array('type' => 'array', 'required' => false, 'default' => array()); +$config->execution->form->edit['team'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => ''); +$config->execution->form->edit['status'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => 'wait'); +$config->execution->form->edit['PM'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); +$config->execution->form->edit['PO'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); +$config->execution->form->edit['QD'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); +$config->execution->form->edit['RD'] = array('type' => 'string', 'required' => false, 'control' => 'select', 'default' => ''); +$config->execution->form->edit['desc'] = array('type' => 'string', 'required' => false, 'control' => 'editor', 'default' => ''); +$config->execution->form->edit['acl'] = array('type' => 'string', 'required' => false, 'control' => 'radio', 'default' => ''); +$config->execution->form->edit['whitelist'] = array('type' => 'array', 'required' => false, 'control' => 'select', 'default' => array(), 'filter' => 'join'); +$config->execution->form->edit['syncStories'] = array('type' => 'string', 'required' => false, 'default' => 'no'); if(!empty($config->setCode)) $config->execution->form->edit['code'] = array('type' => 'string', 'required' => false, 'control' => 'text', 'default' => '', 'filter' => 'trim'); $config->execution->form->importBug['id'] = array('type' => 'int', 'required' => false, 'default' => 0, 'base' => true); diff --git a/module/execution/test/lib/grouptaskinlite.ui.class.php b/module/execution/test/lib/grouptaskinlite.ui.class.php new file mode 100644 index 0000000000..0b66f775ff --- /dev/null +++ b/module/execution/test/lib/grouptaskinlite.ui.class.php @@ -0,0 +1,74 @@ +switchVision('lite', 5); + $form = $this->initForm('execution', 'grouptask', array('execution' => '2', 'groupBy' => $groupData ), 'appIframe-project'); + preg_match_all('/\d+(?:\.\d+)?/', $form->dom->task->getText(), $matches); + if($matches[0][0] != $nums['tasks']) return $this->failed('总任务数目错误'); + if($matches[0][1] != $nums['waiting']) return $this->failed('未开始任务数目错误'); + if($matches[0][2] != $nums['doing']) return $this->failed('进行中任务数目错误'); + preg_match_all('/\d+(?:\.\d+)?/', $form->dom->time->getText(), $params); + if($params[0][0] != $nums['estimates']) return $this->failed('总预计工时错误'); + if($params[0][1] != $nums['cost']) return $this->failed('已消耗工时错误'); + if($params[0][2] != $nums['left']) return $this->failed('剩余工时错误'); + return $this->success('数据正确'); + } + + /** + * 检查已关联研发需求的任务数据统计。 + * Check the data of the group. + * + * @param array $nums + * @access public + * @return void + */ + public function checkTaskLinkedStory($nums) + { + $form = $this->initForm('execution', 'grouptask', array('execution' => '2', 'groupBy' => 'story' ), 'appIframe-project'); + $form->dom->taskLinkedStoryBtn->click(); + $form->wait(1); + preg_match_all('/\d+(?:\.\d+)?/', $form->dom->task->getText(), $matches); + if($matches[0][0] != $nums['tasks']) return $this->failed('总任务数目错误'); + if($matches[0][1] != $nums['waiting']) return $this->failed('未开始任务数目错误'); + if($matches[0][2] != $nums['doing']) return $this->failed('进行中任务数目错误'); + preg_match_all('/\d+(?:\.\d+)?/', $form->dom->time->getText(), $params); + if($params[0][0] != $nums['estimates']) return $this->failed('总预计工时错误'); + if($params[0][1] != $nums['cost']) return $this->failed('已消耗工时错误'); + if($params[0][2] != $nums['left']) return $this->failed('剩余工时错误'); + return $this->success('数据正确'); + } + + /** + * 检查折叠后的数据统计。 + * Check the data of the group. + * + * @param array $nums + * @access public + * @return void + */ + public function checkCollapse($nums) + { + $form = $this->initForm('execution', 'grouptask', array('execution' => '2', 'groupBy' => 'story' ), 'appIframe-project'); + $form->dom->collapseBtn->click(); + $form->wait(1); + if($form->dom->rtask->getText() != $nums['tasks']) return $this->failed('总任务数目错误'); + if($form->dom->rdoing->getText() != $nums['doing']) return $this->failed('进行中任务数目错误'); + if($form->dom->rwaiting->getText() != $nums['waiting']) return $this->failed('未开始任务数目错误'); + if($form->dom->restimates->getText() != $nums['estimates']) return $this->failed('总预计工时错误'); + if($form->dom->rcost->getText() != $nums['cost']) return $this->failed('已消耗工时错误'); + if($form->dom->rleft->getText() != $nums['left']) return $this->failed('剩余工时错误'); + return $this->success('数据正确'); + } +} diff --git a/module/execution/test/lib/treeinlite.ui.class.php b/module/execution/test/lib/treeinlite.ui.class.php new file mode 100644 index 0000000000..3b3b92bb0b --- /dev/null +++ b/module/execution/test/lib/treeinlite.ui.class.php @@ -0,0 +1,43 @@ +switchVision('lite', 5); + $form = $this->initForm('execution', 'tree', array('kanbanID' => '2'), 'appIframe-project'); + $form->wait(1); + if($click) $form->dom->onlyStoryBtn->click(); + $form->wait(1); + if(count($form->dom->getElementList($form->dom->xpath[$level])->element) != $num) return $this->failed('数据错误'); + return $this->success('数据正确'); + } + + /** + * 检查树状图中的任务、目标详情显示。 + * Check detail data. + * + * @access public + * @return object + */ + public function checkDetail() + { + $form = $this->initForm('execution', 'tree', array('kanbanID' => '2'), 'appIframe-project'); + $form->wait(1); + $form->dom->detail->click(); + $form->wait(1); + + if($form->dom->detail->getText() == $form->dom->titleInLite->getText()) return $this->success('详情数据正确'); + return $this->failed('详情数据错误'); + } +} diff --git a/module/execution/test/ui/grouptaskinlite.php b/module/execution/test/ui/grouptaskinlite.php new file mode 100644 index 0000000000..c17cb14488 --- /dev/null +++ b/module/execution/test/ui/grouptaskinlite.php @@ -0,0 +1,239 @@ +#!/usr/bin/env php +id->range('1-100'); +$user->account->range('admin, user1, user2, user3, user4, user5'); +$user->realname->range('admin, USER1, USER2, USER3, USER4, USER5'); +$user->password->range($config->uitest->defaultPassword)->format('md5'); +$user->visions->range('`rnd,lite`'); +$user->gen(6); + +$product = zenData('product'); +$product->id->range('1-100'); +$product->name->range('运营'); +$product->shadow->range('1'); +$product->bind->range('1'); +$product->type->range('normal'); +$product->vision->range('lite'); +$product->gen(1); + +$project = zenData('project'); +$project->id->range('1-100'); +$project->project->range('0, 1'); +$project->model->range('kanban, []'); +$project->type->range('project, kanban'); +$project->auth->range('[]'); +$project->storyType->range('[]'); +$project->parent->range('0, 1'); +$project->path->range('`,1,`, `,1,2,`'); +$project->grade->range('1'); +$project->name->range('运营项目, 看板'); +$project->begin->range('(-2M)-(-M):1D')->type('timestamp')->format('YY/MM/DD'); +$project->end->range('(+2M)-(+3M):1D')->type('timestamp')->format('YY/MM/DD'); +$project->openedBy->range('user1'); +$project->acl->range('open'); +$project->status->range('doing'); +$project->vision->range('lite'); +$project->gen(2); + +$projectProduct = zenData('projectproduct'); +$projectProduct->project->range('1, 2'); +$projectProduct->product->range('1'); +$projectProduct->branch->range('0'); +$projectProduct->plan->range('0'); +$projectProduct->gen(2); + +$story = zenData('story'); +$story->id->range('1-100'); +$story->vision->range('lite'); +$story->parent->range('0'); +$story->isParent->range('0'); +$story->root->range('1-100'); +$story->path->range('`,1,`, `,2,`, `,3,`'); +$story->grade->range('1'); +$story->product->range('1'); +$story->module->range('0'); +$story->plan->range('0'); +$story->title->range('1-100'); +$story->type->range('story'); +$story->estimate->range('0'); +$story->status->range('active'); +$story->stage->range('projected'); +$story->assignedTo->range('[]'); +$story->version->range('1'); +$story->gen(2); + +$storySpec = zenData('storyspec'); +$storySpec->story->range('1-100'); +$storySpec->version->range('1'); +$storySpec->title->range('1-100'); +$storySpec->gen(2); + +$projectStory = zenData('projectstory'); +$projectStory->project->range('1{2}, 2'); +$projectStory->product->range('1'); +$projectStory->branch->range('0'); +$projectStory->story->range('1, 2, 1'); +$projectStory->version->range('1'); +$projectStory->order->range('1, 2, 1'); +$projectStory->gen(3); + +$task = zenData('task'); +$task->id->range('1-100'); +$task->project->range('1'); +$task->execution->range('2'); +$task->story->range('1{5}, 0{99}'); +$task->storyVersion->range('1'); +$task->name->range('1-100'); +$task->type->range('devel, study, affair{100}'); +$task->estimate->range('1'); +$task->consumed->range('0{3}, 1-100'); +$task->left->range('1{3}, 2{3}, 0{2}, 2{100}'); +$task->deadline->range(' (-5D)-(-4D):1D, []{11}')->type('timestamp')->format('YY/MM/DD'); +$task->status->range('wait{3}, doing{3}, done{2}, cancel, closed{3}'); +$task->openedBy->range('admin{6}, user1{6}'); +$task->assignedTo->range('[]{2}, user1{5}, admin{2}, closed{3}'); +$task->finishedBy->range('[]{6}, admin, user1{2}, admin, user1{2}'); +$task->canceledBy->range('[]{8}, admin, []{3}'); +$task->closedBy->range('[]{9}, admin{2}, user1'); +$task->deleted->range('0{11}, 1'); +$task->vision->range('lite'); +$task->gen(12); + +$taskSpec = zenData('taskspec'); +$taskSpec->task->range('1-100'); +$taskSpec->version->range('0'); +$taskSpec->name->range('1-100'); +$taskSpec->gen(12); + +zenData('taskteam')->gen(0); + +$tester = new grouptaskTester(); +$tester->login(); + +$nums = array( + 'story' => array( + 'tasks' => '6', + 'waiting' => '0', + 'doing' => '1', + 'estimates' => '6', + 'cost' => '33', + 'left' => '2', + ), + 'status' => array( + 'tasks' => '3', + 'waiting' => '3', + 'doing' => '0', + 'estimates' => '3', + 'cost' => '0', + 'left' => '3', + ), + 'pri' => array( + 'tasks' => '3', + 'waiting' => '1', + 'doing' => '1', + 'estimates' => '3', + 'cost' => '8', + 'left' => '3', + ), + 'assignedTo' => array( + 'tasks' => '2', + 'waiting' => '2', + 'doing' => '0', + 'estimates' => '2', + 'cost' => '0', + 'left' => '2', + ), + 'finishedBy' => array( + 'tasks' => '6', + 'waiting' => '3', + 'doing' => '3', + 'estimates' => '6', + 'cost' => '6', + 'left' => '9', + ), + 'closedBy' => array( + 'tasks' => '9', + 'waiting' => '3', + 'doing' => '3', + 'estimates' => '9', + 'cost' => '21', + 'left' => '9', + ), + 'type' => array( + 'tasks' => '9', + 'waiting' => '1', + 'doing' => '3', + 'estimates' => '9', + 'cost' => '36', + 'left' => '7', + ), + 'linked' => array( + 'tasks' => '5', + 'waiting' => '3', + 'doing' => '2', + 'estimates' => '5', + 'cost' => '3', + 'left' => '7', + ), + 'collapse' => array( + 'tasks' => '6', + 'waiting' => '0', + 'doing' => '1', + 'estimates' => '6h', + 'cost' => '33h', + 'left' => '2h', + ) +); + +r($tester->checkGroupData('story',$nums['story'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('status',$nums['status'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('pri',$nums['pri'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('assignedTo',$nums['assignedTo'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('finishedBy',$nums['finishedBy'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('closedBy',$nums['closedBy'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkGroupData('type',$nums['type'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTaskLinkedStory($nums['linked'])) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkCollapse($nums['collapse'])) && p('status,message') && e('SUCCESS,数据正确'); +$tester->closeBrowser(); diff --git a/module/execution/test/ui/page/tree.php b/module/execution/test/ui/page/tree.php index fed30a7e2e..9bdd44434b 100644 --- a/module/execution/test/ui/page/tree.php +++ b/module/execution/test/ui/page/tree.php @@ -11,8 +11,9 @@ class treePage extends page 'thirdLevelB' => "//*[@id='mainContent']/div/div[1]/div/menu/li[2]/menu/li[1]/menu/li[@z-type='item']", 'fourthLevelB' => "//*[@id='mainContent']/div/div[1]/div/menu/li[2]/menu/li[1]/menu/li[1]/menu/li[@z-type='item']", 'onlyStoryBtn' => "//*[@id='featureBar']/menu/div/label", - 'detail' => "//*[@id='mainContent']/div/div[1]/div/menu/li[2]/menu/li/menu/li[1]/div/div/div/div/span[3]", - 'title' => "//*[@id='detailBlock']/div[1]/div[1]/span[2]" + 'detail' => "//*[@id='mainContent']/div/div[1]/div/menu/li[1]/menu/li/menu/li[1]//span[3]", + 'title' => "//*[@id='detailBlock']/div[1]/div[1]/span[2]", + 'titleInLite' => "//*[@id='detailBlock']/div[1]/div[1]/span[3]" ); $this->dom->xpath = array_merge($this->dom->xpath, $xpath); } diff --git a/module/execution/test/ui/treeinlite.php b/module/execution/test/ui/treeinlite.php new file mode 100644 index 0000000000..135f68688e --- /dev/null +++ b/module/execution/test/ui/treeinlite.php @@ -0,0 +1,150 @@ +#!/usr/bin/env php +id->range('1-100'); +$product->name->range('运营项目'); +$product->shadow->range('1'); +$product->bind->range('1'); +$product->type->range('normal'); +$product->vision->range('lite'); +$product->gen(1); + +$project = zenData('project'); +$project->id->range('1-100'); +$project->project->range('0, 1'); +$project->model->range('kanban, []'); +$project->type->range('project, kanban'); +$project->auth->range('[]'); +$project->storyType->range('[]'); +$project->parent->range('0, 1'); +$project->path->range('`,1,`, `,1,2,`'); +$project->grade->range('1'); +$project->name->range('运营项目, 看板'); +$project->hasProduct->range('0'); +$project->begin->range('(-2M)-(-M):1D')->type('timestamp')->format('YY/MM/DD'); +$project->end->range('(+2M)-(+3M):1D')->type('timestamp')->format('YY/MM/DD'); +$project->openedBy->range('user1'); +$project->acl->range('open'); +$project->status->range('doing'); +$project->vision->range('lite'); +$project->gen(2); + +$projectProduct = zenData('projectproduct'); +$projectProduct->project->range('1, 2'); +$projectProduct->product->range('1'); +$projectProduct->branch->range('0'); +$projectProduct->plan->range('0'); +$projectProduct->gen(2); + +$story = zenData('story'); +$story->id->range('1-100'); +$story->vision->range('lite'); +$story->parent->range('0'); +$story->isParent->range('0'); +$story->root->range('1-100'); +$story->path->range('`,1,`, `,2,`, `,3,`'); +$story->grade->range('1'); +$story->product->range('1'); +$story->module->range('1{2}, 2'); +$story->plan->range('0'); +$story->title->range('1-100'); +$story->type->range('story'); +$story->estimate->range('0'); +$story->status->range('active'); +$story->stage->range('projected'); +$story->assignedTo->range('[]'); +$story->version->range('1'); +$story->gen(3); + +$storySpec = zenData('storyspec'); +$storySpec->story->range('1-100'); +$storySpec->version->range('1'); +$storySpec->title->range('1-100'); +$storySpec->gen(3); + +$projectStory = zenData('projectstory'); +$projectStory->project->range('1{3}, 2{2}'); +$projectStory->product->range('1'); +$projectStory->branch->range('0'); +$projectStory->story->range('1, 2, 3'); +$projectStory->version->range('1'); +$projectStory->order->range('1, 2, 3'); +$projectStory->gen(5); + +$module = zenData('module'); +$module->id->range('1-100'); +$module->root->range('1, 1, 2'); +$module->branch->range('0'); +$module->name->range('产品模块1, 产品模块2, 看板模块1'); +$module->parent->range('0'); +$module->path->range('`,1,`, `,2,`, `,3,`'); +$module->grade->range('1'); +$module->type->range('story{2}, task'); +$module->short->range('0'); +$module->gen(3); + +$task = zenData('task'); +$task->id->range('1-100'); +$task->project->range('1'); +$task->execution->range('2'); +$task->module->range('1{3}, 2, 3, 0{99}'); +$task->story->range('1, 1, 2, 3, 0{99}'); +$task->storyVersion->range('1'); +$task->name->range('1-100'); +$task->vision->range('lite'); +$task->gen(12); + +$taskSpec = zenData('taskspec'); +$taskSpec->task->range('1-100'); +$taskSpec->version->range('0'); +$taskSpec->name->range('1-100'); +$taskSpec->gen(12); + +$tester = new treeTester(); +$tester->login(); + +r($tester->checkTreeData('firstLevel', '3')) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('secondLevelA', '7')) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('secondLevelB', '2')) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('thirdLevelB', '2')) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('fourthLevelB', '1')) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('firstLevel', '1', true)) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkTreeData('secondLevelA', '2') ) && p('status,message') && e('SUCCESS,数据正确'); +r($tester->checkDetail()) && p('status,message') && e('SUCCESS,详情数据正确'); +$tester->closeBrowser(); diff --git a/module/gitlab/test/model/apideleteproject.php b/module/gitlab/test/model/apideleteproject.php index e66f3f6b5c..3108be55c0 100755 --- a/module/gitlab/test/model/apideleteproject.php +++ b/module/gitlab/test/model/apideleteproject.php @@ -3,15 +3,15 @@ include dirname(__FILE__, 5) . '/test/lib/init.php'; /** - title=测试 gitlabModel::apiDeleteProject(); timeout=0 cid=1 - 使用空的projectID删除项目 @0 - 使用错误gitlabID删除项目 @0 +- 使用空的GitlabID和空的projectID删除项目 @0 +- 使用错误projectID删除项目 @0 - 通过gitlabID,项目id正确删除项目属性message @202 Accepted - */ zenData('pipeline')->gen(5); @@ -32,13 +32,11 @@ $gitlab->apiCreateProject($gitlabID, $project); /* Get projectID. */ $gitlabProjects = $gitlab->apiGetProjects($gitlabID); +$unitTestList = array(); foreach($gitlabProjects as $gitlabProject) { - if($gitlabProject->name == $projectName) - { - $projectID = $gitlabProject->id; - break; - } + if($gitlabProject->name == $projectName) $projectID = $gitlabProject->id; + if(strpos($gitlabProject->name, 'unitTest') === 0 || strpos($gitlabProject->name, 'unitest') === 0) $unitTestList[] = $gitlabProject; } $project = new stdclass(); @@ -46,5 +44,15 @@ $project->description = 'apiUpdatedProject'; r($gitlab->apiDeleteProject($gitlabID, 0)) && p() && e('0'); //使用空的projectID删除项目 r($gitlab->apiDeleteProject(0, $projectID)) && p() && e('0'); //使用错误gitlabID删除项目 +r($gitlab->apiDeleteProject(0, 0)) && p() && e('0'); //使用空的GitlabID和空的projectID删除项目 +r($gitlab->apiDeleteProject(0, 99999)) && p() && e('0'); //使用错误projectID删除项目 r($gitlab->apiDeleteProject($gitlabID, $projectID)) && p('message') && e('202 Accepted'); //通过gitlabID,项目id正确删除项目 +//删除测试数据 +if(!empty($unitTestList)) +{ + foreach($unitTestList as $unitTestProject) + { + $gitlab->apiDeleteProject($gitlabID, $unitTestProject->id); + } +} diff --git a/module/metric/control.php b/module/metric/control.php index 79f43ee51a..61684130d8 100755 --- a/module/metric/control.php +++ b/module/metric/control.php @@ -360,7 +360,7 @@ class metric extends control $dateBegin = str_replace('_', '-', $dateBegin); $dateEnd = str_replace('_', '-', $dateEnd); - $options = array_filter(array('scope' => $scope, 'dateLabel' => $dateLabel, 'dateBegin' => $dateBegin, 'dateEnd' => $dateEnd)); + $options = array_filter(array('scope' => $scope, 'calcDate' => $dateLabel, 'dateBegin' => $dateBegin, 'dateEnd' => $dateEnd)); $this->app->loadClass('pager', true); $pager = new pager($recTotal, $recPerPage, $pageID); diff --git a/module/metric/js/preview.ui.js b/module/metric/js/preview.ui.js index b56a10535c..4d90660303 100644 --- a/module/metric/js/preview.ui.js +++ b/module/metric/js/preview.ui.js @@ -410,7 +410,7 @@ window.handleQueryClick = function(id, viewType = 'single') var formData = window.getFormData($form); var scopeValue = formData.get('scope') === null ? '' : formData.get('scope'); - var dateLabel = formData.get('dateLabel') === null ? '' : formData.get('dateLabel'); + var dateLabel = formData.get('calcDate') === null ? '' : formData.get('calcDate'); var dateBegin = formData.get('dateBegin') === null ? '' : formData.get('dateBegin').replace(/-/g, '_'); var dateEnd = formData.get('dateEnd') === null ? '' : formData.get('dateEnd').replace(/-/g, '_'); diff --git a/module/pivot/model.php b/module/pivot/model.php index 23741425cb..5b0546b1ef 100644 --- a/module/pivot/model.php +++ b/module/pivot/model.php @@ -2304,6 +2304,7 @@ class pivotModel extends model { if($this->config->edition != 'open') { + $this->app->loadConfig('dataview'); static $workflowFields = array(); if(!isset($workflowFields[$object])) $workflowFields[$object] = $this->loadModel('workflowfield')->getList($object); diff --git a/module/program/test/lib/unlinkstakeholder.ui.class.php b/module/program/test/lib/unlinkstakeholder.ui.class.php new file mode 100644 index 0000000000..99ddfd5d2a --- /dev/null +++ b/module/program/test/lib/unlinkstakeholder.ui.class.php @@ -0,0 +1,41 @@ +initForm('program', 'stakeholder', array('programID' => 1), 'appIframe-program'); + $linkNumBefore = $form->dom->stakeholderNum->getText(); + $form->dom->unlinkFirBtn->click(); // 点击第一行的单个移除按钮 + $form->wait(1); + $form->dom->alertModal(); // 模态框中点击确定 + $form->wait(2); + $linkNumAfter = $form->dom->stakeholderNum->getText(); // 移除干系人后数量 + return ($linkNumAfter == $linkNumBefore - 1) ? $this->success('单个移除干系人成功') : $this->failed('单个移除干系人失败'); + } + + /** + * Batch unlink stakeholder of program. + * 批量移除全部干系人 + * + * @access public + * @return object + */ + public function batchUnlinkStakeholders() + { + $form = $this->initForm('program', 'stakeholder', array('programID' => 1), 'appIframe-program'); + $form->dom->selectAllBtn->click(); // 全选干系人 + $form->dom->batchUnlinkBtn->click(); // 点击批量移除按钮 + $form->wait(1); + $form->dom->alertModal(); // 模态框中点击确定 + $form->wait(2); + return ($form->dom->stakeholderNum === false) ? $this->success('批量移除干系人成功') : $this->failed('批量移除干系人失败'); + } +} diff --git a/module/program/test/ui/page/stakeholder.php b/module/program/test/ui/page/stakeholder.php new file mode 100644 index 0000000000..f8ed2b2a6b --- /dev/null +++ b/module/program/test/ui/page/stakeholder.php @@ -0,0 +1,15 @@ + "//*[@id='table-program-stakeholder']/div[2]/div[3]/div/div[1]/div/nav/a/i", + 'stakeholderNum' => "//*[@id='table-program-stakeholder']/div[3]/div[2]/strong", + 'selectAllBtn' => "//*[@id='table-program-stakeholder']/div[1]/div[1]/div/div[1]/div/div/label", + 'batchUnlinkBtn' => "//*[@id='table-program-stakeholder']/div[3]/nav[1]/button", + ); + $this->dom->xpath = array_merge($this->dom->xpath, $xpath); + } +} diff --git a/module/program/test/ui/unlinkstakeholder.php b/module/program/test/ui/unlinkstakeholder.php new file mode 100755 index 0000000000..c66c0cb838 --- /dev/null +++ b/module/program/test/ui/unlinkstakeholder.php @@ -0,0 +1,63 @@ +#!/usr/bin/env php +id->range('1-3'); +$stakeholder->objectID->range('1'); +$stakeholder->objectType->range('program'); +$stakeholder->user->range('user1, user2, user3'); +$stakeholder->type->range('inside'); +$stakeholder->key->range('0'); +$stakeholder->from->range('company'); +$stakeholder->gen(3); + +$user = zenData('user'); +$user->id->range('1-5'); +$user->type->range('inside{4}, outside{1}'); +$user->dept->range('1'); +$user->account->range('admin, user1, user2, user3, user4'); +$user->realname->range('admin, user1, user2, user3, user4'); +$user->password->range($config->uitest->defaultPassword)->format('md5'); +$user->visions->range('rnd'); +$user->gen(5); + +$project = zenData('project'); +$project->id->range('1'); +$project->project->range('0'); +$project->type->range('program'); +$project->model->range('[]'); +$project->path->range('`,1,`'); +$project->grade->range('1'); +$project->name->range('项目集A'); +$project->hasProduct->range('1'); +$project->status->range('wait'); +$project->begin->range('(-72w)-(-71w):1D')->type('timestamp')->format('YY/MM/DD'); +$project->end->range('(+72w)-(+73w):1D')->type('timestamp')->format('YY/MM/DD'); +$project->acl->range('open'); +$project->gen(1); + +$tester = new unlinkStakeholderTester(); +$tester->login(); + +r($tester->unlinkStakeholder()) && p('message,status') && e('单个移除干系人成功, SUCCESS'); //单个移除干系人成功 +r($tester->batchUnlinkStakeholders()) && p('message,status') && e('批量移除干系人成功, SUCCESS'); //批量移除干系人成功 + +$tester->closeBrowser(); diff --git a/module/programplan/tao.php b/module/programplan/tao.php index 37a69f87f7..1bf9d712f2 100644 --- a/module/programplan/tao.php +++ b/module/programplan/tao.php @@ -216,7 +216,7 @@ class programplanTao extends programplanModel { $this->app->loadLang('stage'); - $datas = $stageIndex = $planIdList = $reviewDeadline = array(); + $datas = $stageIndex = $planIdList = $reviewDeadline = array(); $today = helper::today(); $isMilestone = " "; foreach($plans as $plan) diff --git a/module/project/ui/view.html.php b/module/project/ui/view.html.php index 44e26ef235..fb85352dd7 100644 --- a/module/project/ui/view.html.php +++ b/module/project/ui/view.html.php @@ -288,7 +288,7 @@ row ), div ( - set::className('detail-content mt-4 overflow-hidden desc-box'), + set::className('detail-content mt-4 overflow-hidden desc-box overflow-y-scroll scrollbar-thin scrollbar-hover'), set::title(strip_tags($project->desc)), html($project->desc) ) diff --git a/module/projectstory/test/lib/batchcreateinlite.ui.class.php b/module/projectstory/test/lib/batchcreateinlite.ui.class.php new file mode 100755 index 0000000000..638022dc88 --- /dev/null +++ b/module/projectstory/test/lib/batchcreateinlite.ui.class.php @@ -0,0 +1,71 @@ +switchVision('lite', 5); + $this->page->waitElement('//*[@id="app-project"]', 5); + $this->openURL('projectstory', 'story', $project, 'appIframe-project'); + $this->page->waitElement('//*[@id="app-project"]', 5); + $form = $this->initForm('story', 'batchCreate', $storyUrl, 'appIframe-project'); + $form->wait(2); + //设置表单内容 + if (isset($story->name)) $form->dom->title_0->setValue($story->name); + if (isset($story->reviewer)) $form->dom->reviewerPick->multiPicker($story->reviewer); + $form->dom->btn($this->lang->story->saveDraft)->click(); + $form->wait(2); + return $this->checkBatchCreate($project, $storyUrl, $story, $form); + } + + /** + * 检查批量创建目标的结果 + * Check the result of batch create story + * + * @param array $project + * @param array $storyUrl + * @param object $story + * @param object $form + * + * @return mixed + */ + public function checkBatchCreate($project, $storyUrl, $story, $form) + { + //创建失败时的校验 + if ($this->response('method') == 'batchCreate') + { + if (!isset($story->name) || $story->name == '') + { + $nameTip = $this->lang->story->errorEmptyStory; + return ($form->dom->alertModal('text') == $nameTip) + ? $this->success('目标名称必填提示信息正确') + : $this->failed('目标名称必填提示信息不正确'); + } + if (!isset($story->reviewer) || $story->reviewer == '') + { + $reviewerTip = sprintf($this->lang->error->notempty, $this->lang->story->reviewer); + return ($reviewerTip == $form->dom->reviewerTip->getText()) + ? $this->success('评审人必填提示信息正确') + : $this->failed('评审人必填提示信息不正确'); + } + } + else + { + $storyList = $this->initForm('projectstory', 'story', $project, 'appIframe-project'); + $storyList->dom->search(array("{$this->lang->story->name},=,{$story->name}")); + return ($storyList->dom->firstStory->getText() == $story->name) + ? $this->success('批量创建目标成功') + : $this->failed('批量创建目标失败'); + } + } +} diff --git a/module/projectstory/test/lib/changestoryinlite.ui.class.php b/module/projectstory/test/lib/changestoryinlite.ui.class.php new file mode 100755 index 0000000000..8c9723c868 --- /dev/null +++ b/module/projectstory/test/lib/changestoryinlite.ui.class.php @@ -0,0 +1,65 @@ +switchVision('lite', 8); + if($this->page->getCookie('vision') != 'lite') + { + $this->switchVision('lite', 8); + } + $form = $this->initForm('projectstory', 'story', array('projectID' => '1'), 'appIframe-project'); //变更目标前需要进入列表页面,获取项目ID + $form = $this->initForm('story', 'change', array('storyID' => '1', 'from' => 'project'), 'appIframe-project'); + $form->dom->title->setValue($storyName); + if($reviewer != NULL) + { + $form->dom->reviewer->click(); + $form->dom->reviewerAdmin->click(); + } + $form->dom->btn($this->lang->save)->click(); + $form->wait(3); + + //创建失败检查提示是否正确,名称为空和评审人为空提示 + if($this->response('method') != 'view') + { + $form = $this->loadPage('story', 'change'); + if($storyName == '') + { + $srCommon = $form->dom->srCommon->getText(); + $nameTip = sprintf($this->lang->error->notempty, $srCommon); + if($form->dom->alertModal('text') == $nameTip) return $this->success('变更目标页面名称为空提示正确'); + } + + if(empty($reviewer)) + { + $reviwerTip = sprintf($this->lang->error->notempty, $this->lang->story->reviewers); + if($form->dom->alertModal('text') == $reviwerTip) return $this->success('变更目标页面评审人为空提示正确'); + } + return $this->failed('变更目标页面提示信息不正确'); + } + + $viewPage = $this->loadPage('projectstory', 'view'); + if($viewPage->dom->storyName->getText() != $storyName) return $this->failed('目标名称不正确'); + if($viewPage->dom->storyStatus->getText() != $this->lang->story->statusList->reviewing) return $this->failed('目标状态不正确'); + + return $this->success('变更目标成功'); + } +} diff --git a/module/projectstory/test/lib/createstoryinlite.ui.class.php b/module/projectstory/test/lib/createstoryinlite.ui.class.php new file mode 100755 index 0000000000..551d4469be --- /dev/null +++ b/module/projectstory/test/lib/createstoryinlite.ui.class.php @@ -0,0 +1,80 @@ + '1', + 'branch' => '', + 'moduleID' => '0', + 'storyID' => '0', + 'projectID' => '1', + 'bugID' => '0', + 'planID' => '0', + 'todoID' => '0', + 'extra' => '', + 'storyType' => 'story' + ); + + $this->switchVision('lite', 8); + if($this->page->getCookie('vision') != 'lite') + { + $this->switchVision('lite', 8); + } + $form = $this->initForm('projectstory', 'story', array('projectID' => '1'), 'appIframe-project'); //由于创建目标后会跳转到记录了session的页面,所以先进入一次对应目标的列表页面 + $form = $this->initForm('story', 'create', $createStoryParam, 'appIframe-project'); //再进入创建目标页面 + $form->dom->titleInLite->setValue($storyName); + if($reviewer != NULL) + { + $form->dom->reviewer->click(); + $form->dom->reviewerAdmin->click(); + } + $form->dom->saveInLite->click(); + $form->wait(1); + + //创建失败检查提示是否正确,名称为空和评审人为空提示 + if($this->response('method') != 'story') + { + $form = $this->loadPage('story', 'create'); + if($storyName == '') + { + $srCommen = $form->dom->srCommen->getText(); + $nameTip = sprintf($this->lang->error->notempty, $srCommen); + if($form->dom->titleTip->getText() == $nameTip) return $this->success('创建目标页面名称为空提示正确'); + } + + if(empty($reviewer)) + { + $reviwerTip = sprintf($this->lang->error->notempty, $this->lang->story->reviewer); + if($form->dom->reviewerTip->getText() == $reviwerTip) return $this->success('创建目标页面评审人为空提示正确'); + } + return $this->failed('创建目标页面提示信息不正确'); + } + + $viewPage = $this->initForm('projectstory', 'view', array('storyID' => '1', 'projectID' => '1'), 'appIframe-project'); + if($viewPage->dom->storyName->getText() != $storyName) return $this->failed('目标名称不正确'); + if($viewPage->dom->storyStatus->getText() != $this->lang->story->statusList->reviewing) return $this->failed('目标状态不正确'); + $viewPage->dom->TargetLife->click(); + if(strpos($viewPage->dom->openedBy->getText() , 'admin') === false) return $this->failed('创建人不正确'); + + return $this->success('创建'.$storyName.'成功'); + } +} diff --git a/module/projectstory/test/ui/batchcreateinlite.php b/module/projectstory/test/ui/batchcreateinlite.php new file mode 100755 index 0000000000..e2cabdb2a5 --- /dev/null +++ b/module/projectstory/test/ui/batchcreateinlite.php @@ -0,0 +1,87 @@ +#!/usr/bin/env php +id->range('1'); +$project->model->range('kanban'); +$project->type->range('project'); +$project->name->range('运营项目'); +$project->hasProduct->range('0'); +$project->acl->range('open'); +$project->vision->range('lite'); +$project->gen(1); + +$product = zenData('product'); +$product->id->range('1'); +$product->program->range('0'); +$product->name->range('运营项目'); +$product->shadow->range('1'); +$product->type->range('normal'); +$product->acl->range('open'); +$product->vision->range('lite'); +$product->gen(1); + +$projectproduct = zenData('projectproduct'); +$projectproduct->project->range('1'); +$projectproduct->product->range('1'); +$projectproduct->branch->range('0'); +$projectproduct->plan->range('0'); +$projectproduct->gen(1); + +$team = ZenData('team'); +$team->id->range('1'); +$team->root->range('1'); +$team->type->range('project'); +$team->account->range('admin'); +$team->gen(1); + +$projectadmin = ZenData('projectadmin'); +$projectadmin->group->range('1'); +$projectadmin->account->range('admin'); +$projectadmin->projects->range('1'); +$projectadmin->gen(1); + +zendata('story')->loadYaml('story', false, 2)->gen(0); +zendata('storyspec')->loadYaml('storyspec', false, 2)->gen(0); +zendata('storyreview')->loadYaml('storyreview', false, 2)->gen(0); + +$storyUrl = array( + 'productID' => '1', + 'branch' => '', + 'moduleID' => '0', + 'storyID' => '0', + 'project' => 1, + 'plan' => '0', + 'storyType' => 'story' +); +$project = array( + 'projectID' => 1 +); + +$tester = new batchCreateStory(); +$tester->login(); + +$story = new stdClass(); +$story->name = ''; +r($tester->batchCreateStory($project, $storyUrl, $story)) && p('message,status') && e('目标名称必填提示信息正确,SUCCESS');//目标名称必填校验 + +$story->name = '目标A'; +r($tester->batchCreateStory($project, $storyUrl, $story)) && p('message,status') && e('评审人必填提示信息正确,SUCCESS');//评审人必填校验 + +$tester->closeBrowser(); diff --git a/module/projectstory/test/ui/changestoryinlite.php b/module/projectstory/test/ui/changestoryinlite.php new file mode 100755 index 0000000000..e3aad116d1 --- /dev/null +++ b/module/projectstory/test/ui/changestoryinlite.php @@ -0,0 +1,122 @@ +#!/usr/bin/env php +id->range('1'); +$product->program->range('0'); +$product->name->range('产品1'); +$product->shadow->range('1'); +$product->bind->range('0'); +$product->acl->range('open'); +$product->createdBy->range('admin'); +$product->vision->range('lite'); +$product->gen(1); + +$story = zenData('story'); +$story->id->range('1'); +$story->vision->range('lite'); +$story->root->range('1'); +$story->path->range('`,1,`'); +$story->grade->range('1'); +$story->product->range('1'); +$story->module->range('0'); +$story->plan->range('0'); +$story->source->range('[]'); +$story->title->range('运营界面目标1'); +$story->type->range('story'); +$story->stage->range('wait'); +$story->status->range('active'); +$story->openedBy->range('admin'); +$story->version->range('1'); +$story->assignedTo->range('[]'); +$story->reviewedBy->range('[]'); +$story->closedBy->range('[]'); +$story->closedReason->range('[]'); +$story->gen(1); + +$storyspec = zenData('storyspec'); +$storyspec->story->range('1'); +$storyspec->version->range('1'); +$storyspec->title->range('运营界面目标1'); +$storyspec->gen(1); + +$storyreview = zenData('storyreview'); +$storyreview->gen(0); + +$project = zenData('project'); +$project->id->range('1'); +$project->model->range('kanban'); +$project->type->range('project'); +$project->path->range('`,1,`'); +$project->team->range('运营项目1'); +$project->acl->range('open'); +$project->vision->range('lite'); +$project->name->range('运营项目1'); +$project->gen(1); + +$projectadmin = zenData('projectadmin'); +$projectadmin->group->range('1'); +$projectadmin->account->range('admin'); +$projectadmin->projects->range('`,`1`,`'); +$projectadmin->gen(1); + +$projectproduct = zenData('projectproduct'); +$projectproduct->project->range('1'); +$projectproduct->product->range('1'); +$projectproduct->gen(1); + +$action = zenData('action')->gen(0); + +$projectstory = zenData('projectstory'); +$projectstory->project->range('1'); +$projectstory->product->range('1'); +$projectstory->branch->range('0'); +$projectstory->story->range('1'); +$projectstory->version->range('1'); +$projectstory->order->range('1'); +$projectstory->gen(1); + +$team = zenData('team'); +$team->id->range('1'); +$team->root->range('1'); +$team->type->range('project'); +$team->account->range('admin'); +$team->limited->range('no'); +$team->gen(1); + +$tester = new changeStoryInLiteTester(); +$tester->login(); + +$storys = array(); +$storys['null'] = ''; +$storys['default'] = '变更后目标名称'; + +$reviewer = array(); +$reviewer['null'] = array(); +$reviewer['default'] = array('admin'); + +r($tester->changeStoryInLite($storys['default'], $reviewer['null'])) && p('message,status') && e('变更目标页面评审人为空提示正确,SUCCESS'); // 评审人不为空校验,变更失败 +r($tester->changeStoryInLite($storys['null'], $reviewer['default'])) && p('message,status') && e('变更目标页面名称为空提示正确,SUCCESS'); // 目标名称不为空校验,变更失败 +r($tester->changeStoryInLite($storys['default'], $reviewer['default'])) && p('message,status') && e('变更目标成功,SUCCESS'); // 使用默认选项变更需求,详情页信息对应 + +$tester->closeBrowser(); diff --git a/module/projectstory/test/ui/creatstoryinlite.php b/module/projectstory/test/ui/creatstoryinlite.php new file mode 100755 index 0000000000..566d66f0db --- /dev/null +++ b/module/projectstory/test/ui/creatstoryinlite.php @@ -0,0 +1,88 @@ +#!/usr/bin/env php +id->range('1'); +$product->program->range('0'); +$product->name->range('产品1'); +$product->shadow->range('0'); +$product->bind->range('0'); +$product->acl->range('open'); +$product->createdBy->range('admin'); +$product->vision->range('lite'); +$product->gen(1); + +$story = zenData('story'); +$story->gen(0); + +$storyspec = zenData('storyspec'); +$storyspec->gen(0); + +$storyreview = zenData('storyreview'); +$storyreview->gen(0); + +$project = zenData('project'); +$project->id->range('1'); +$project->model->range('kanban'); +$project->type->range('project'); +$project->path->range('`,1,`'); +$project->team->range('运营项目1'); +$project->acl->range('open'); +$project->vision->range('lite'); +$project->name->range('运营项目1'); +$project->gen(1); + +$projectadmin = zenData('projectadmin'); +$projectadmin->group->range('1'); +$projectadmin->account->range('admin'); +$projectadmin->projects->range('`,`1`,`'); +$projectadmin->gen(1); + +$projectproduct = zenData('projectproduct'); +$projectproduct->project->range('1'); +$projectproduct->product->range('1'); +$projectproduct->gen(1); + +$projectstory = zenData('projectstory')->gen(0); + +$action = zenData('action'); +$action->gen(0); + +$tester = new createStoryInLiteTester(); +$tester->login(); + +$storys = array( + 'null' => '', + 'story' => '运营界面目标' +); + +$reviewers = array( + 'null' => array(), + 'admin' => array('admin') +); + +r($tester->createDefault($storys['null'], $reviewers['admin'])) && p('message,status') && e('创建目标页面名称为空提示正确,SUCCESS'); // 名称必填校验,创建失败 +r($tester->createDefault($storys['story'], $reviewers['null'])) && p('message,status') && e('创建目标页面评审人为空提示正确,SUCCESS'); // 评审人必填校验,创建失败 +r($tester->createDefault($storys['story'], $reviewers['admin'])) && p('message,status') && e('创建运营界面目标成功,SUCCESS'); // 创建成功 + +$tester->closeBrowser(); diff --git a/module/search/control.php b/module/search/control.php index 13a6463962..d52d3d9feb 100644 --- a/module/search/control.php +++ b/module/search/control.php @@ -34,21 +34,9 @@ class search extends control $module = empty($module) ? $this->session->searchParams['module'] : $module; $searchParams = $module . 'searchParams'; $searchForm = $module . 'Form'; - $funcName = $_SESSION[$searchParams]['funcName'] ?? ''; - $funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? []; - if($funcName) - { - $funcArgs[] = true; // 处理选项列表。 - $this->loadModel($module)->$funcName(...$funcArgs); - $fields = empty($fields) ? $this->config->$module->search['fields'] : $fields; - $params = empty($params) ? $this->config->$module->search['params'] : $params; - } - else - { - $fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields; - $params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params; - } + $fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields; + $params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params; $_SESSION['searchParams']['module'] = $module; if(empty($_SESSION[$searchForm])) $this->search->initSession($module, $fields, $params); @@ -94,21 +82,9 @@ class search extends control $module = empty($module) ? $this->session->searchParams['module'] : $module; $searchParams = $module . 'searchParams'; $searchForm = $module . 'Form'; - $funcName = $_SESSION[$searchParams]['funcName'] ?? ''; - $funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? []; - if($funcName) - { - $funcArgs[] = true; // 处理选项列表。 - $this->loadModel($module)->$funcName(...$funcArgs); - $fields = empty($fields) ? $this->config->$module->search['fields'] : $fields; - $params = empty($params) ? $this->config->$module->search['params'] : $params; - } - else - { - $fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields; - $params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params; - } + $fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields; + $params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params; $_SESSION['searchParams']['module'] = $module; if(empty($_SESSION[$searchForm])) $this->search->initOldSession($module, $fields, $params); diff --git a/module/search/model.php b/module/search/model.php index 83539f10c7..796032ccb0 100644 --- a/module/search/model.php +++ b/module/search/model.php @@ -28,26 +28,13 @@ class searchModel extends model if($this->config->edition != 'open') $searchConfig = $this->searchTao->processBuildinFields($module, $searchConfig); - $searchParams['module'] = $searchConfig['module']; - $searchParams['actionURL'] = $searchConfig['actionURL']; - $searchParams['style'] = zget($searchConfig, 'style', 'full'); - $searchParams['onMenuBar'] = zget($searchConfig, 'onMenuBar', 'no'); - $searchParams['queryID'] = isset($searchConfig['queryID']) ? $searchConfig['queryID'] : 0; - - $funcArgs = func_get_args(); - $funcName = $funcArgs[1] ?? ''; - unset($funcArgs[0], $funcArgs[1]); - - if($funcName) - { - $searchParams['funcName'] = $funcName; - $searchParams['funcArgs'] = $funcArgs; - } - else - { - $searchParams['searchFields'] = json_encode($searchConfig['fields']); - $searchParams['fieldParams'] = json_encode($searchConfig['params']); - } + $searchParams['module'] = $searchConfig['module']; + $searchParams['searchFields'] = json_encode($searchConfig['fields']); + $searchParams['fieldParams'] = json_encode($searchConfig['params']); + $searchParams['actionURL'] = $searchConfig['actionURL']; + $searchParams['style'] = zget($searchConfig, 'style', 'full'); + $searchParams['onMenuBar'] = zget($searchConfig, 'onMenuBar', 'no'); + $searchParams['queryID'] = isset($searchConfig['queryID']) ? $searchConfig['queryID'] : 0; $this->session->set($module . 'searchParams', $searchParams); } @@ -110,23 +97,11 @@ class searchModel extends model /* Init vars. */ $module = $this->post->module; $searchParams = $module . 'searchParams'; + $searchFields = json_decode($_SESSION[$searchParams]['searchFields']); + $fieldParams = json_decode($_SESSION[$searchParams]['fieldParams']); $groupItems = $this->config->search->groupItems; $groupAndOr = strtoupper($this->post->groupAndOr); if($groupAndOr != 'AND' && $groupAndOr != 'OR') $groupAndOr = 'AND'; - $funcName = $_SESSION[$searchParams]['funcName'] ?? ''; - $funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? []; - if($funcName) - { - $funcArgs[] = true; // 处理选项列表。 - $this->loadModel($module)->$funcName(...$funcArgs); - $searchFields = json_decode(json_encode($this->config->$module->search['fields'])); - $fieldParams = json_decode(json_encode($this->config->$module->search['params'])); - } - else - { - $searchFields = json_decode($_SESSION[$searchParams]['searchFields']); - $fieldParams = json_decode($_SESSION[$searchParams]['fieldParams']); - } $queryForm = $this->searchTao->initSession($module, $searchFields, $fieldParams); diff --git a/module/task/zen.php b/module/task/zen.php index 8c8f2f46af..30a086df6a 100644 --- a/module/task/zen.php +++ b/module/task/zen.php @@ -1317,6 +1317,9 @@ class taskZen extends task $task->canceledDate = helper::isZeroDate($task->canceledDate) ? '' : substr($task->canceledDate, 0, 10); $task->closedDate = helper::isZeroDate($task->closedDate) ? '' : substr($task->closedDate, 0, 10); $task->lastEditedDate = helper::isZeroDate($task->lastEditedDate) ? '' : substr($task->lastEditedDate, 0, 10); + $task->rawEstimate = $task->estimate; + $task->rawConsumed = $task->consumed; + $task->rawLeft = $task->left; $task->estimate = $task->estimate . $this->lang->execution->workHourUnit; $task->consumed = $task->consumed . $this->lang->execution->workHourUnit; $task->left = $task->left . $this->lang->execution->workHourUnit; diff --git a/module/testcase/js/batchedit.ui.js b/module/testcase/js/batchedit.ui.js index 505bf92d1a..c67cd37091 100644 --- a/module/testcase/js/batchedit.ui.js +++ b/module/testcase/js/batchedit.ui.js @@ -17,6 +17,12 @@ window.handleRenderRow = function($row, index, row) $module.$.setValue(row.module); }); + $row.find('.form-batch-control[data-name="story"] .picker-box').on('inited', function(e, info) + { + let $story = info[0]; + $story.render({limitValueInList: false}); + }); + /* Set the scenes for the row. */ $row.find('.form-batch-control[data-name="scene"] .picker-box').on('inited', function(e, info) { diff --git a/module/testcase/zen.php b/module/testcase/zen.php index 6753532da6..f421634451 100755 --- a/module/testcase/zen.php +++ b/module/testcase/zen.php @@ -1039,6 +1039,8 @@ class testcaseZen extends testcase $scenePairs = array(); foreach($cases as $case) { + $case->story = $case->story ? $case->story : ''; + /* 设置用例模块。 */ /* Set case module. */ $objectID = $case->lib > 0 ? $case->lib : $case->product; diff --git a/module/user/test/model/checkbeforecreateoredit.php b/module/user/test/model/checkbeforecreateoredit.php old mode 100644 new mode 100755 index 23e886941d..035ce32959 --- a/module/user/test/model/checkbeforecreateoredit.php +++ b/module/user/test/model/checkbeforecreateoredit.php @@ -4,11 +4,14 @@ /** title=测试 userModel->checkBeforeCreateOrEdit(); +timeout=0 cid=0 - 使用系统预留用户名返回 false。属性result @0 - 使用系统预留用户名提示信息。第errors条的account属性 @用户名已被系统预留 - 使用正常用户名返回 true。属性result @1 +- 执行$user3属性account @user1 +- 执行$user3属性verifyPassword @8e2803f8b0a6fcbb9501f3799795c736 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; @@ -22,11 +25,15 @@ $random = updateSessionRandom(); $user1 = (object)array('account' => 'guest', 'verifyPassword' => ''); $user2 = (object)array('account' => 'admin', 'verifyPassword' => md5(md5('123456') . $random)); +$user3 = (object)array('account' => 'user1', 'verifyPassword' => md5(md5('Asd@123') . 'test')); $userTest = new userTest(); $result1 = $userTest->checkBeforeCreateOrEditTest($user1); -r($result1) && p('result') && e(0); // 使用系统预留用户名返回 false。 +r($result1) && p('result') && e(0); // 使用系统预留用户名返回 false。 r($result1) && p('errors:account') && e('用户名已被系统预留'); // 使用系统预留用户名提示信息。 r($userTest->checkBeforeCreateOrEditTest($user2, true)) && p('result') && e(1); // 使用正常用户名返回 true。 + +r($user3) && p('account') && e('user1'); // 查看$user3属性account @user1 +r($user3) && p('verifyPassword') && e('8e2803f8b0a6fcbb9501f3799795c736'); // 查看$user3属性verifyPassword @8e2803f8b0a6fcbb9501f3799795c736 \ No newline at end of file diff --git a/module/user/test/model/getcommiters.php b/module/user/test/model/getcommiters.php index 8ad60e7414..a7cc172e89 100755 --- a/module/user/test/model/getcommiters.php +++ b/module/user/test/model/getcommiters.php @@ -4,9 +4,13 @@ /** title=测试 userModel->getCommiters(); +timeout=0 cid=0 +- 获取源代码账号为user1的用户真实姓名属性user1 @用户1 +- 获取源代码账号为user2的用户真实姓名属性user2 @用户2 - 获取源代码账号为user10的用户真实姓名属性user10 @用户10 +- 获取源代码账号为admin的用户真实姓名属性admin @admin - 获取系统中源代码账号不为空的用户数量 @30 */ @@ -19,5 +23,8 @@ zenData('user')->gen(30); $user = new userTest(); $commiters = $user->getCommitersTest(); +r($commiters) && p('user1') && e('用户1'); //获取源代码账号为user1的用户真实姓名 +r($commiters) && p('user2') && e('用户2'); //获取源代码账号为user2的用户真实姓名 r($commiters) && p('user10') && e('用户10'); //获取源代码账号为user10的用户真实姓名 -r(count($commiters)) && p() && e('30'); //获取系统中源代码账号不为空的用户数量 +r($commiters) && p('admin') && e('admin'); //获取源代码账号为admin的用户真实姓名 +r(count($commiters)) && p() && e('30'); //获取系统中源代码账号不为空的用户数量 \ No newline at end of file diff --git a/module/user/test/model/getparentstageauthedusers.php b/module/user/test/model/getparentstageauthedusers.php index d57d59e270..78e5496fbb 100755 --- a/module/user/test/model/getparentstageauthedusers.php +++ b/module/user/test/model/getparentstageauthedusers.php @@ -4,11 +4,14 @@ /** title=测试 userModel->getParentStageAuthedUsers(); +timeout=0 cid=0 - 传入阶段ID为0获取有权限的用户 @0 -- 传入一个阶段ID为212获取有权限的用户属性dev12 @dev12 - 传入一个阶段ID为1获取有权限的用户 @0 +- 传入一个阶段ID为212获取有权限的用户属性dev12 @dev12 +- 传入一个阶段ID为100获取有权限的用户 @0 +- 传入一个阶段ID为999获取有权限的用户 @0 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; @@ -22,5 +25,7 @@ $userView->gen(400); $user = new userTest(); r($user->getParentStageAuthedUsersTest(0)) && p() && e('0'); //传入阶段ID为0获取有权限的用户 -r($user->getParentStageAuthedUsersTest(212)) && p('dev12') && e('dev12'); //传入一个阶段ID为212获取有权限的用户 r($user->getParentStageAuthedUsersTest(1)) && p() && e('0'); //传入一个阶段ID为1获取有权限的用户 +r($user->getParentStageAuthedUsersTest(212)) && p('dev12') && e('dev12'); //传入一个阶段ID为212获取有权限的用户 +r($user->getParentStageAuthedUsersTest(100)) && p() && e('0'); //传入一个阶段ID为100获取有权限的用户 +r($user->getParentStageAuthedUsersTest(999)) && p() && e('0'); //传入一个阶段ID为999获取有权限的用户 \ No newline at end of file diff --git a/module/user/test/model/getteammemberpairs.php b/module/user/test/model/getteammemberpairs.php index 94700674a2..e4b0c7b9ce 100755 --- a/module/user/test/model/getteammemberpairs.php +++ b/module/user/test/model/getteammemberpairs.php @@ -4,20 +4,29 @@ /** title=测试 userModel->getTeamMemberPairs(); +timeout=0 cid=0 - 获取ID为11的项目的团队成员数量 @1 - 获取ID为11的项目的团队成员数量,追加用户user1 @2 +- 获取ID为12的项目的团队成员数量 @1 +- 获取ID为13的项目的团队成员数量,追加用户user1 @2 +- 获取ID为14的项目的团队成员数量 @1 +- 获取ID为14的项目的团队成员用户名属性user5 @U:用户5 */ include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/user.unittest.class.php'; -zenData('project')->gen(11); -zenData('team')->gen(10); -zenData('user')->gen(10); +zenData('project')->gen(20); +zenData('team')->gen(20); +zenData('user')->gen(20); su('admin'); $user = new userTest(); -r(count($user->getTeamMemberPairsTest(11, 'project'))) && p() && e('1'); //获取ID为11的项目的团队成员数量 -r(count($user->getTeamMemberPairsTest(11, 'project', '', array('user1')))) && p() && e('2'); //获取ID为11的项目的团队成员数量,追加用户user1 +r(count($user->getTeamMemberPairsTest(11, 'project'))) && p() && e('1'); //获取ID为11的项目的团队成员数量 +r(count($user->getTeamMemberPairsTest(11, 'project', '', array('user1')))) && p() && e('2'); //获取ID为11的项目的团队成员数量,追加用户user1 +r(count($user->getTeamMemberPairsTest(12, 'project'))) && p() && e('1'); //获取ID为12的项目的团队成员数量 +r(count($user->getTeamMemberPairsTest(13, 'project', '', array('user1')))) && p() && e('2'); //获取ID为13的项目的团队成员数量,追加用户user1 +r(count($user->getTeamMemberPairsTest(14, 'project'))) && p() && e('1'); //获取ID为14的项目的团队成员数量 +r($user->getTeamMemberPairsTest(14, 'project')) && p('user5') && e('U:用户5'); //获取ID为14的项目的团队成员用户名 \ No newline at end of file