Merge branch 'release/21.7.5' into feature/workflowgroup

This commit is contained in:
sunguangming
2025-08-07 08:40:40 +00:00
49 changed files with 1343 additions and 196 deletions
+4 -4
View File
@@ -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",
+7 -17
View File
@@ -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);
+17
View File
@@ -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 '';
+3 -1
View File
@@ -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`);
+10 -2
View File
@@ -812,11 +812,19 @@ function getVisions(): array
/**
* Save debug log to the php log file which prefix with 'debug.<today>'.
*
* @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;
+3 -3
View File
@@ -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);
+2 -2
View File
@@ -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',
+1
View File
@@ -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])
+5 -7
View File
@@ -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'});
-1
View File
@@ -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');
+1 -1
View File
@@ -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';
+1
View File
@@ -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);
@@ -0,0 +1,40 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
/**
title=测试 commonModel::checkMaintenance();
timeout=0
cid=1
- 检查是否处于维护状态 @0
- 检查是否处于维护状态 @0
- 检查是否处于维护状态 @0
- 检查是否处于维护状态 @0
- 检查是否处于维护状态 @0
*/
global $tester;
$tester->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'); // 检查是否处于维护状态
-38
View File
@@ -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});
}
-6
View File
@@ -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')
-9
View File
@@ -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();
}
}
+2
View File
@@ -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' => '');
+1
View File
@@ -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);
+3 -1
View File
@@ -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')
+21 -20
View File
@@ -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);
@@ -0,0 +1,74 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class grouptaskTester extends tester
{
/**
* 检查全部展开时分组下数据。
* Check the data of the group.
*
* @param string $groupData story|status|pri|assignedTo|finishedBy|closedBy|type
* @param array $nums
* @access public
* @return void
*/
public function checkGroupData($groupData, $nums)
{
$this->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('数据正确');
}
}
@@ -0,0 +1,43 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class treeTester extends tester
{
/**
* 检查树状图数据。
* Check tree data.
*
* @param string $level
* @param string $num
* @param bool $click
* @access public
* @return object
*/
public function checkTreeData($level, $num, $click = false)
{
$this->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('详情数据错误');
}
}
@@ -0,0 +1,239 @@
#!/usr/bin/env php
<?php
/**
title=执行下的分组视图
timeout=0
cid=1
- 执行tester模块的checkGroupData方法,参数是'story', $nums['story']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'status', $nums['status']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'pri', $nums['pri']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'assignedTo', $nums['assignedTo']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'finishedBy', $nums['finishedBy']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'closedBy', $nums['closedBy']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkGroupData方法,参数是'type', $nums['type']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTaskLinkedStory方法,参数是$nums['linked']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkCollapse方法,参数是$nums['collapse']
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
*/
chdir(__DIR__);
include '../lib/grouptaskinlite.ui.class.php';
global $config;
$user = zenData('user');
$user->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();
+3 -2
View File
@@ -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);
}
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env php
<?php
/**
title=运营界面树状图
timeout=0
cid=1
- 执行tester模块的checkTreeData方法,参数是'firstLevel', '3'
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'secondLevelA', '7'
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'secondLevelB', '2'
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'thirdLevelB', '2'
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'fourthLevelB', '1'
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'firstLevel', '1', true
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkTreeData方法,参数是'secondLevelA', '2')▫▫
- 最终测试状态 @SUCCESS
- 测试结果 @数据正确
- 执行tester模块的checkDetail方法▫
- 最终测试状态 @SUCCESS
- 测试结果 @详情数据正确
*/
chdir(__DIR__);
include '../lib/treeinlite.ui.class.php';
$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->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();
+15 -7
View File
@@ -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);
}
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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, '_');
+1
View File
@@ -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);
@@ -0,0 +1,41 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class unlinkStakeholderTester extends tester
{
/**
* Unlink a stakeholder of program.
* 单个移除干系人
*
* @access public
* @return object
*/
public function unlinkStakeholder()
{
$form = $this->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('批量移除干系人失败');
}
}
@@ -0,0 +1,15 @@
<?php
class stakeholderPage extends page
{
public function __construct($webdriver)
{
parent::__construct($webdriver);
$xpath = array(
'unlinkFirBtn' => "//*[@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);
}
}
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env php
<?php
/**
title=移除项目集下干系人测试
timeout=0
cid=73
- 单个移除干系人成功
- 测试结果 @单个移除干系人成功
- 最终测试状态 @ SUCCESS
- 批量移除干系人成功
- 测试结果 @批量移除干系人成功
- 最终测试状态 @ SUCCESS
*/
chdir(__DIR__);
include '../lib/unlinkstakeholder.ui.class.php';
global $config;
$stakeholder = zenData('stakeholder');
$stakeholder->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();
+1 -1
View File
@@ -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 = "<icon class='icon icon-flag icon-sm red'></icon> ";
foreach($plans as $plan)
+1 -1
View File
@@ -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)
)
@@ -0,0 +1,71 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class batchCreateStory extends tester
{
/**
* 运营界面批量创建目标
* batch create story in lite
*
* @param array $project
* @param array $storyUrl
* @param object $story
*
* @return mixed
*/
public function batchCreateStory($project, $storyUrl, $story)
{
$this->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('批量创建目标失败');
}
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
/**
* The control file of example module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author lijie
* @package story
* @link http://www.zentao.net
*/
include dirname(__FILE__, 5).'/test/lib/ui.php';
class changeStoryInLiteTester extends tester
{
/**
* Create a default story.
*
* @param string $storyName
* @access public
* @return object
*/
public function changeStoryInLite($storyName, $reviewer)
{
$this->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('变更目标成功');
}
}
@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
/**
* The control file of example module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author lijie
* @package story
* @link http://www.zentao.net
*/
include dirname(__FILE__, 5).'/test/lib/ui.php';
class createStoryInLiteTester extends tester
{
/**
* Create a default story.
*
* @param string $storyName
* @access public
* @return object
*/
public function createDefault($storyName, $reviewer)
{
$createStoryParam = array(
'product' => '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.'成功');
}
}
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env php
<?php
/**
title=运营界面批量创建目标
timeout=0
cid=0
- 目标名称必填校验
- 测试结果 @目标名称必填提示信息正确
- 最终测试状态 @SUCCESS
- 评审人必填校验
- 测试结果 @评审人必填提示信息正确
- 最终测试状态 @SUCCESS
*/
chdir(__DIR__);
include '../lib/batchcreateinlite.ui.class.php';
$project = zenData('project');
$project->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();
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
title=运营界面变更目标测试
timeout=0
cid=0
- 目标名称必填校验
- 测试结果 @目标名称必填提示信息正确
- 最终测试状态 @SUCCESS
- 评审人必填校验
- 测试结果 @评审人必填提示信息正确
- 最终测试状态 @SUCCESS
- 正常创建目标校验
- 测试结果 @批量创建目标成功
- 最终测试状态 @SUCCESS
*/
chdir(__DIR__);
include '../lib/changestoryinlite.ui.class.php';
$product = zenData('product');
$product->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();
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env php
<?php
/**
title=运营界面创建目标测试
timeout=0
cid=0
- 目标名称必填校验
- 测试结果 @目标名称必填提示信息正确
- 最终测试状态 @SUCCESS
- 评审人必填校验
- 测试结果 @评审人必填提示信息正确
- 最终测试状态 @SUCCESS
- 正常创建目标校验
- 测试结果 @创建目标成功
- 最终测试状态 @SUCCESS
*/
chdir(__DIR__);
include '../lib/createstoryinlite.ui.class.php';
$product = zenData('product');
$product->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();
+4 -28
View File
@@ -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);
+9 -34
View File
@@ -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);
+3
View File
@@ -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;
+6
View File
@@ -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)
{
+2
View File
@@ -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;
+8 -1
View File
@@ -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
+8 -1
View File
@@ -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'); //获取系统中源代码账号不为空的用户数量
@@ -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获取有权限的用户
+14 -5
View File
@@ -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的项目的团队成员用户名