diff --git a/VERSION b/VERSION
index 48f8d64e0c..546fe2354d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-11.6.2
+11.6.3
diff --git a/config/config.php b/config/config.php
index ee8f73de3b..e2d63a3b71 100644
--- a/config/config.php
+++ b/config/config.php
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
-$config->version = '11.6.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
+$config->version = '11.6.3'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.php.
diff --git a/db/standard/zentao11.6.3.sql b/db/standard/zentao11.6.3.sql
new file mode 100644
index 0000000000..436985846a
--- /dev/null
+++ b/db/standard/zentao11.6.3.sql
@@ -0,0 +1,937 @@
+CREATE TABLE `zt_action` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `objectType` varchar(30) NOT NULL DEFAULT '',
+ `objectID` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `product` varchar(255) NOT NULL,
+ `project` mediumint(9) NOT NULL,
+ `actor` varchar(30) NOT NULL DEFAULT '',
+ `action` varchar(30) NOT NULL DEFAULT '',
+ `date` datetime NOT NULL,
+ `comment` text NOT NULL,
+ `extra` text NOT NULL,
+ `read` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `date` (`date`),
+ KEY `actor` (`actor`),
+ KEY `project` (`project`),
+ KEY `objectID` (`objectID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_block` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `account` char(30) NOT NULL,
+ `module` varchar(20) NOT NULL,
+ `title` varchar(100) NOT NULL,
+ `source` varchar(20) NOT NULL,
+ `block` varchar(20) NOT NULL,
+ `params` text NOT NULL,
+ `order` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `grid` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `height` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `hidden` tinyint(1) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `accountModuleOrder` (`account`,`module`,`order`),
+ KEY `account` (`account`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_branch` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL,
+ `name` varchar(255) NOT NULL,
+ `order` smallint(5) unsigned NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_bug` (
+ `id` mediumint(8) NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `branch` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `module` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `project` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `plan` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `story` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `storyVersion` smallint(6) NOT NULL DEFAULT '1',
+ `task` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `toTask` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `toStory` mediumint(8) NOT NULL DEFAULT '0',
+ `title` varchar(255) NOT NULL,
+ `keywords` varchar(255) NOT NULL,
+ `severity` tinyint(4) NOT NULL DEFAULT '0',
+ `pri` tinyint(3) unsigned NOT NULL,
+ `type` varchar(30) NOT NULL DEFAULT '',
+ `os` varchar(30) NOT NULL DEFAULT '',
+ `browser` varchar(30) NOT NULL DEFAULT '',
+ `hardware` varchar(30) NOT NULL,
+ `found` varchar(30) NOT NULL DEFAULT '',
+ `steps` text NOT NULL,
+ `status` enum('active','resolved','closed') NOT NULL DEFAULT 'active',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `color` char(7) NOT NULL,
+ `confirmed` tinyint(1) NOT NULL DEFAULT '0',
+ `activatedCount` smallint(6) NOT NULL,
+ `activatedDate` datetime NOT NULL,
+ `mailto` text,
+ `openedBy` varchar(30) NOT NULL DEFAULT '',
+ `openedDate` datetime NOT NULL,
+ `openedBuild` varchar(255) NOT NULL,
+ `assignedTo` varchar(30) NOT NULL DEFAULT '',
+ `assignedDate` datetime NOT NULL,
+ `deadline` date NOT NULL,
+ `resolvedBy` varchar(30) NOT NULL DEFAULT '',
+ `resolution` varchar(30) NOT NULL DEFAULT '',
+ `resolvedBuild` varchar(30) NOT NULL DEFAULT '',
+ `resolvedDate` datetime NOT NULL,
+ `closedBy` varchar(30) NOT NULL DEFAULT '',
+ `closedDate` datetime NOT NULL,
+ `duplicateBug` mediumint(8) unsigned NOT NULL,
+ `linkBug` varchar(255) NOT NULL,
+ `case` mediumint(8) unsigned NOT NULL,
+ `caseVersion` smallint(6) NOT NULL DEFAULT '1',
+ `result` mediumint(8) unsigned NOT NULL,
+ `testtask` mediumint(8) unsigned NOT NULL,
+ `lastEditedBy` varchar(30) NOT NULL DEFAULT '',
+ `lastEditedDate` datetime NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `project` (`project`),
+ KEY `status` (`status`),
+ KEY `plan` (`plan`),
+ KEY `story` (`story`),
+ KEY `case` (`case`),
+ KEY `assignedTo` (`assignedTo`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_build` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `branch` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `project` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `name` char(150) NOT NULL,
+ `scmPath` char(255) NOT NULL,
+ `filePath` char(255) NOT NULL,
+ `date` date NOT NULL,
+ `stories` text NOT NULL,
+ `bugs` text NOT NULL,
+ `builder` char(30) NOT NULL DEFAULT '',
+ `desc` text NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `project` (`project`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_burn` (
+ `project` mediumint(8) unsigned NOT NULL,
+ `task` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `date` date NOT NULL,
+ `estimate` float NOT NULL,
+ `left` float NOT NULL,
+ `consumed` float NOT NULL,
+ PRIMARY KEY (`project`,`date`,`task`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_case` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `branch` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `lib` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `module` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `path` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `story` mediumint(30) unsigned NOT NULL DEFAULT '0',
+ `storyVersion` smallint(6) NOT NULL DEFAULT '1',
+ `title` varchar(255) NOT NULL,
+ `precondition` text NOT NULL,
+ `keywords` varchar(255) NOT NULL,
+ `pri` tinyint(3) unsigned NOT NULL DEFAULT '3',
+ `type` char(30) NOT NULL DEFAULT '1',
+ `stage` varchar(255) NOT NULL,
+ `howRun` varchar(30) NOT NULL,
+ `scriptedBy` varchar(30) NOT NULL,
+ `scriptedDate` date NOT NULL,
+ `scriptStatus` varchar(30) NOT NULL,
+ `scriptLocation` varchar(255) NOT NULL,
+ `status` char(30) NOT NULL DEFAULT '1',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `color` char(7) NOT NULL,
+ `frequency` enum('1','2','3') NOT NULL DEFAULT '1',
+ `order` tinyint(30) unsigned NOT NULL DEFAULT '0',
+ `openedBy` char(30) NOT NULL DEFAULT '',
+ `openedDate` datetime NOT NULL,
+ `reviewedBy` varchar(255) NOT NULL,
+ `reviewedDate` date NOT NULL,
+ `lastEditedBy` char(30) NOT NULL DEFAULT '',
+ `lastEditedDate` datetime NOT NULL,
+ `version` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `linkCase` varchar(255) NOT NULL,
+ `fromBug` mediumint(8) unsigned NOT NULL,
+ `fromCaseID` mediumint(8) unsigned NOT NULL,
+ `fromCaseVersion` mediumint(8) unsigned NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ `lastRunner` varchar(30) NOT NULL,
+ `lastRunDate` datetime NOT NULL,
+ `lastRunResult` char(30) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `story` (`story`),
+ KEY `module` (`module`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_casestep` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `parent` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `case` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `version` smallint(3) unsigned NOT NULL DEFAULT '0',
+ `type` varchar(10) NOT NULL DEFAULT 'step',
+ `desc` text NOT NULL,
+ `expect` text NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `case` (`case`),
+ KEY `version` (`version`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_company` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` char(120) DEFAULT NULL,
+ `phone` char(20) DEFAULT NULL,
+ `fax` char(20) DEFAULT NULL,
+ `address` char(120) DEFAULT NULL,
+ `zipcode` char(10) DEFAULT NULL,
+ `website` char(120) DEFAULT NULL,
+ `backyard` char(120) DEFAULT NULL,
+ `guest` enum('1','0') NOT NULL DEFAULT '0',
+ `admins` char(255) DEFAULT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_config` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `owner` char(30) NOT NULL DEFAULT '',
+ `module` varchar(30) NOT NULL,
+ `section` char(30) NOT NULL DEFAULT '',
+ `key` char(30) NOT NULL DEFAULT '',
+ `value` text NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `unique` (`owner`,`module`,`section`,`key`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_cron` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `m` varchar(20) NOT NULL,
+ `h` varchar(20) NOT NULL,
+ `dom` varchar(20) NOT NULL,
+ `mon` varchar(20) NOT NULL,
+ `dow` varchar(20) NOT NULL,
+ `command` text NOT NULL,
+ `remark` varchar(255) NOT NULL,
+ `type` varchar(20) NOT NULL,
+ `buildin` tinyint(1) NOT NULL DEFAULT '0',
+ `status` varchar(20) NOT NULL,
+ `lastTime` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `lastTime` (`lastTime`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_dept` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` char(60) NOT NULL,
+ `parent` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `path` char(255) NOT NULL DEFAULT '',
+ `grade` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `order` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `position` char(30) NOT NULL DEFAULT '',
+ `function` char(255) NOT NULL DEFAULT '',
+ `manager` char(30) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY `parent` (`parent`),
+ KEY `path` (`path`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_doc` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL,
+ `project` mediumint(8) unsigned NOT NULL,
+ `lib` varchar(30) NOT NULL,
+ `module` varchar(30) NOT NULL,
+ `title` varchar(255) NOT NULL,
+ `keywords` varchar(255) NOT NULL,
+ `type` varchar(30) NOT NULL,
+ `views` smallint(5) unsigned NOT NULL,
+ `collector` text NOT NULL,
+ `addedBy` varchar(30) NOT NULL,
+ `addedDate` datetime NOT NULL,
+ `editedBy` varchar(30) NOT NULL,
+ `editedDate` datetime NOT NULL,
+ `acl` varchar(10) NOT NULL DEFAULT 'open',
+ `groups` varchar(255) NOT NULL,
+ `users` text NOT NULL,
+ `version` smallint(5) unsigned NOT NULL DEFAULT '1',
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `project` (`project`),
+ KEY `lib` (`lib`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_doccontent` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `doc` mediumint(8) unsigned NOT NULL,
+ `title` varchar(255) NOT NULL,
+ `digest` varchar(255) NOT NULL,
+ `content` text NOT NULL,
+ `files` text NOT NULL,
+ `type` varchar(10) NOT NULL,
+ `version` smallint(5) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `doc_version` (`doc`,`version`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_doclib` (
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `type` varchar(30) NOT NULL,
+ `product` mediumint(8) unsigned NOT NULL,
+ `project` mediumint(8) unsigned NOT NULL,
+ `name` varchar(60) NOT NULL,
+ `acl` varchar(10) NOT NULL DEFAULT 'open',
+ `groups` varchar(255) NOT NULL,
+ `users` text NOT NULL,
+ `main` enum('0','1') NOT NULL DEFAULT '0',
+ `collector` text NOT NULL,
+ `order` tinyint(5) unsigned NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `project` (`project`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_effort` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `user` char(30) NOT NULL DEFAULT '',
+ `todo` enum('1','0') NOT NULL DEFAULT '1',
+ `date` date NOT NULL,
+ `begin` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `end` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `type` enum('1','2','3') NOT NULL DEFAULT '1',
+ `idvalue` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `name` char(30) NOT NULL DEFAULT '',
+ `desc` char(255) NOT NULL DEFAULT '',
+ `status` enum('1','2','3') NOT NULL DEFAULT '1',
+ PRIMARY KEY (`id`),
+ KEY `user` (`user`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE IF NOT EXISTS `zt_entry` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(50) NOT NULL,
+ `account` varchar(30) NOT NULL DEFAULT '',
+ `code` varchar(20) NOT NULL,
+ `key` varchar(32) NOT NULL,
+ `freePasswd` enum('0','1') NOT NULL DEFAULT '0',
+ `ip` varchar(100) NOT NULL,
+ `desc` text NOT NULL,
+ `createdBy` varchar(30) NOT NULL,
+ `createdDate` datetime NOT NULL,
+ `calledTime` int(10) unsigned NOT NULL DEFAULT '0',
+ `editedBy` varchar(30) NOT NULL,
+ `editedDate` datetime NOT NULL,
+ `deleted` enum('0', '1') NOT NULL DEFAULT '0',
+ PRIMARY KEY `id` (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_extension` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(150) NOT NULL,
+ `code` varchar(30) NOT NULL,
+ `version` varchar(50) NOT NULL,
+ `author` varchar(100) NOT NULL,
+ `desc` text NOT NULL,
+ `license` text NOT NULL,
+ `type` varchar(20) NOT NULL DEFAULT 'extension',
+ `site` varchar(150) NOT NULL,
+ `zentaoCompatible` varchar(100) NOT NULL,
+ `installedTime` datetime NOT NULL,
+ `depends` varchar(100) NOT NULL,
+ `dirs` mediumtext NOT NULL,
+ `files` mediumtext NOT NULL,
+ `status` varchar(20) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `code` (`code`),
+ KEY `name` (`name`),
+ KEY `installedTime` (`installedTime`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_file` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `pathname` char(100) NOT NULL,
+ `title` char(255) NOT NULL,
+ `extension` char(30) NOT NULL,
+ `size` int(10) unsigned NOT NULL DEFAULT '0',
+ `objectType` char(30) NOT NULL,
+ `objectID` mediumint(9) NOT NULL,
+ `addedBy` char(30) NOT NULL DEFAULT '',
+ `addedDate` datetime NOT NULL,
+ `downloads` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `extra` varchar(255) NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `objectType` (`objectType`),
+ KEY `objectID` (`objectID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_group` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `role` char(30) NOT NULL DEFAULT '',
+ `desc` char(255) NOT NULL DEFAULT '',
+ `acl` text,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_grouppriv` (
+ `group` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `module` char(30) NOT NULL DEFAULT '',
+ `method` char(30) NOT NULL DEFAULT '',
+ UNIQUE KEY `group` (`group`,`module`,`method`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_history` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `action` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `field` varchar(30) NOT NULL DEFAULT '',
+ `old` text NOT NULL,
+ `new` text NOT NULL,
+ `diff` mediumtext NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `action` (`action`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_lang` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `lang` varchar(30) NOT NULL,
+ `module` varchar(30) NOT NULL,
+ `section` varchar(30) NOT NULL,
+ `key` varchar(60) NOT NULL,
+ `value` text NOT NULL,
+ `system` enum('0','1') NOT NULL DEFAULT '1',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `lang` (`lang`,`module`,`section`,`key`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_log` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `objectType` varchar(30) NOT NULL,
+ `objectID` mediumint(8) unsigned NOT NULL,
+ `action` mediumint(8) unsigned NOT NULL,
+ `date` datetime NOT NULL,
+ `url` varchar(255) NOT NULL,
+ `contentType` varchar(30) NOT NULL,
+ `data` text NOT NULL,
+ `result` text NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `objectType` (`objectType`),
+ KEY `obejctID` (`objectID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_module` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `root` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `branch` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `name` char(60) NOT NULL DEFAULT '',
+ `parent` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `path` char(255) NOT NULL DEFAULT '',
+ `grade` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `order` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `type` char(30) NOT NULL,
+ `owner` varchar(30) NOT NULL,
+ `collector` text NOT NULL,
+ `short` varchar(30) NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `root` (`root`),
+ KEY `type` (`type`),
+ KEY `path` (`path`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_notify` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `objectType` varchar(50) NOT NULL,
+ `objectID` mediumint(8) unsigned NOT NULL,
+ `action` mediumint(9) NOT NULL,
+ `toList` varchar(255) NOT NULL,
+ `ccList` text NOT NULL,
+ `subject` varchar(255) NOT NULL,
+ `data` text NOT NULL,
+ `createdBy` char(30) NOT NULL,
+ `createdDate` datetime NOT NULL,
+ `sendTime` datetime NOT NULL,
+ `status` varchar(10) NOT NULL DEFAULT 'wait',
+ `failReason` text NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_product` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(90) NOT NULL,
+ `code` varchar(45) NOT NULL,
+ `line` mediumint(8) NOT NULL,
+ `type` varchar(30) NOT NULL DEFAULT 'normal',
+ `status` varchar(30) NOT NULL DEFAULT '',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `desc` text NOT NULL,
+ `PO` varchar(30) NOT NULL,
+ `QD` varchar(30) NOT NULL,
+ `RD` varchar(30) NOT NULL,
+ `acl` enum('open','private','custom') NOT NULL DEFAULT 'open',
+ `whitelist` text NOT NULL,
+ `createdBy` varchar(30) NOT NULL,
+ `createdDate` datetime NOT NULL,
+ `createdVersion` varchar(20) NOT NULL,
+ `order` mediumint(8) unsigned NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `order` (`order`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_productplan` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL,
+ `branch` mediumint(8) unsigned NOT NULL,
+ `parent` mediumint(9) NOT NULL DEFAULT '0',
+ `title` varchar(90) NOT NULL,
+ `desc` text NOT NULL,
+ `begin` date NOT NULL,
+ `end` date NOT NULL,
+ `order` text NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `end` (`end`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_project` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `isCat` enum('1','0') NOT NULL DEFAULT '0',
+ `catID` mediumint(8) unsigned NOT NULL,
+ `type` varchar(20) NOT NULL DEFAULT 'sprint',
+ `parent` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `name` varchar(90) NOT NULL,
+ `code` varchar(45) NOT NULL,
+ `begin` date NOT NULL,
+ `end` date NOT NULL,
+ `days` smallint(5) unsigned NOT NULL,
+ `status` varchar(10) NOT NULL,
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `statge` enum('1','2','3','4','5') NOT NULL DEFAULT '1',
+ `pri` enum('1','2','3','4') NOT NULL DEFAULT '1',
+ `desc` text NOT NULL,
+ `openedBy` varchar(30) NOT NULL DEFAULT '',
+ `openedDate` datetime NOT NULL,
+ `openedVersion` varchar(20) NOT NULL,
+ `closedBy` varchar(30) NOT NULL DEFAULT '',
+ `closedDate` datetime NOT NULL,
+ `canceledBy` varchar(30) NOT NULL DEFAULT '',
+ `canceledDate` datetime NOT NULL,
+ `PO` varchar(30) NOT NULL DEFAULT '',
+ `PM` varchar(30) NOT NULL DEFAULT '',
+ `QD` varchar(30) NOT NULL DEFAULT '',
+ `RD` varchar(30) NOT NULL DEFAULT '',
+ `team` varchar(90) NOT NULL,
+ `acl` enum('open','private','custom') NOT NULL DEFAULT 'open',
+ `whitelist` text NOT NULL,
+ `order` mediumint(8) unsigned NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `parent` (`parent`),
+ KEY `begin` (`begin`),
+ KEY `end` (`end`),
+ KEY `status` (`status`),
+ KEY `order` (`order`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_projectproduct` (
+ `project` mediumint(8) unsigned NOT NULL,
+ `product` mediumint(8) unsigned NOT NULL,
+ `branch` mediumint(8) unsigned NOT NULL,
+ `plan` mediumint(8) unsigned NOT NULL,
+ PRIMARY KEY (`project`,`product`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_projectstory` (
+ `project` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `product` mediumint(8) unsigned NOT NULL,
+ `story` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `version` smallint(6) NOT NULL DEFAULT '1',
+ `order` smallint(6) unsigned NOT NULL,
+ UNIQUE KEY `project` (`project`,`story`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_release` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `branch` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `build` mediumint(8) unsigned NOT NULL,
+ `name` varchar(255) NOT NULL DEFAULT '',
+ `marker` enum('0','1') NOT NULL DEFAULT '0',
+ `date` date NOT NULL,
+ `stories` text NOT NULL,
+ `bugs` text NOT NULL,
+ `leftBugs` text NOT NULL,
+ `desc` text NOT NULL,
+ `status` varchar(20) NOT NULL DEFAULT 'normal',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `build` (`build`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_score` (
+ `id` bigint(12) unsigned NOT NULL AUTO_INCREMENT,
+ `account` varchar(30) NOT NULL,
+ `module` varchar(30) NOT NULL DEFAULT '',
+ `method` varchar(30) NOT NULL,
+ `desc` varchar(250) NOT NULL DEFAULT '',
+ `before` int(11) NOT NULL DEFAULT '0',
+ `score` int(11) NOT NULL DEFAULT '0',
+ `after` int(11) NOT NULL DEFAULT '0',
+ `time` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `account` (`account`),
+ KEY `model` (`module`),
+ KEY `method` (`method`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE IF NOT EXISTS `zt_story` (
+ `id` mediumint(8) unsigned NOT NULL auto_increment,
+ `product` mediumint(8) unsigned NOT NULL default '0',
+ `branch` mediumint(8) unsigned NOT NULL default '0',
+ `module` mediumint(8) unsigned NOT NULL default '0',
+ `plan` text,
+ `source` varchar(20) NOT NULL,
+ `sourceNote` varchar(255) NOT NULL,
+ `fromBug` mediumint(8) unsigned NOT NULL default '0',
+ `title` varchar(255) NOT NULL,
+ `keywords` varchar(255) NOT NULL,
+ `type` varchar(30) NOT NULL default '',
+ `pri` tinyint(3) unsigned NOT NULL default '3',
+ `estimate` float unsigned NOT NULL,
+ `status` enum('','changed','active','draft','closed') NOT NULL default '',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `color` char(7) NOT NULL,
+ `stage` enum('','wait','planned','projected','developing','developed','testing','tested','verified','released', 'closed') NOT NULL DEFAULT 'wait',
+ `stagedBy` char(30) NOT NULL,
+ `mailto` text,
+ `openedBy` varchar(30) NOT NULL default '',
+ `openedDate` datetime NOT NULL,
+ `assignedTo` varchar(30) NOT NULL default '',
+ `assignedDate` datetime NOT NULL,
+ `lastEditedBy` varchar(30) NOT NULL default '',
+ `lastEditedDate` datetime NOT NULL,
+ `reviewedBy` varchar(255) NOT NULL,
+ `reviewedDate` date NOT NULL,
+ `closedBy` varchar(30) NOT NULL default '',
+ `closedDate` datetime NOT NULL,
+ `closedReason` varchar(30) NOT NULL,
+ `toBug` mediumint(8) unsigned NOT NULL,
+ `childStories` varchar(255) NOT NULL,
+ `linkStories` varchar(255) NOT NULL,
+ `duplicateStory` mediumint(8) unsigned NOT NULL,
+ `version` smallint(6) NOT NULL default '1',
+ `deleted` enum('0','1') NOT NULL default '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `status` (`status`),
+ KEY `assignedTo` (`assignedTo`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_storyspec` (
+ `story` mediumint(9) NOT NULL,
+ `version` smallint(6) NOT NULL,
+ `title` varchar(255) NOT NULL,
+ `spec` text NOT NULL,
+ `verify` text NOT NULL,
+ UNIQUE KEY `story` (`story`,`version`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE IF NOT EXISTS `zt_storystage` (
+ `story` mediumint(8) unsigned NOT NULL,
+ `branch` mediumint(8) unsigned NOT NULL,
+ `stage` varchar(50) NOT NULL,
+ `stagedBy` char(30) NOT NULL,
+ UNIQUE KEY `story_branch` (`story`,`branch`),
+ KEY `story` (`story`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_suitecase` (
+ `suite` mediumint(8) unsigned NOT NULL,
+ `product` mediumint(8) unsigned NOT NULL,
+ `case` mediumint(8) unsigned NOT NULL,
+ `version` smallint(5) unsigned NOT NULL,
+ UNIQUE KEY `suitecase` (`suite`,`case`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_task` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `parent` mediumint(8) NOT NULL DEFAULT '0',
+ `project` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `module` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `story` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `storyVersion` smallint(6) NOT NULL DEFAULT '1',
+ `fromBug` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `name` varchar(255) NOT NULL,
+ `type` varchar(20) NOT NULL,
+ `pri` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `estimate` float unsigned NOT NULL,
+ `consumed` float unsigned NOT NULL,
+ `left` float unsigned NOT NULL,
+ `deadline` date NOT NULL,
+ `status` enum('wait','doing','done','pause','cancel','closed') NOT NULL DEFAULT 'wait',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `color` char(7) NOT NULL,
+ `mailto` text,
+ `desc` text NOT NULL,
+ `openedBy` varchar(30) NOT NULL,
+ `openedDate` datetime NOT NULL,
+ `assignedTo` varchar(30) NOT NULL,
+ `assignedDate` datetime NOT NULL,
+ `estStarted` date NOT NULL,
+ `realStarted` date NOT NULL,
+ `finishedBy` varchar(30) NOT NULL,
+ `finishedDate` datetime NOT NULL,
+ `finishedList` text NOT NULL,
+ `canceledBy` varchar(30) NOT NULL,
+ `canceledDate` datetime NOT NULL,
+ `closedBy` varchar(30) NOT NULL,
+ `closedDate` datetime NOT NULL,
+ `closedReason` varchar(30) NOT NULL,
+ `lastEditedBy` varchar(30) NOT NULL,
+ `lastEditedDate` datetime NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `project` (`project`),
+ KEY `story` (`story`),
+ KEY `assignedTo` (`assignedTo`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_taskestimate` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `task` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `date` date NOT NULL,
+ `left` float unsigned NOT NULL DEFAULT '0',
+ `consumed` float unsigned NOT NULL,
+ `account` char(30) NOT NULL DEFAULT '',
+ `work` text,
+ PRIMARY KEY (`id`),
+ KEY `task` (`task`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_team` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `root` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `type` enum('project','task') NOT NULL DEFAULT 'project',
+ `account` char(30) NOT NULL DEFAULT '',
+ `role` char(30) NOT NULL DEFAULT '',
+ `limited` char(8) NOT NULL DEFAULT 'no',
+ `join` date NOT NULL DEFAULT '0000-00-00',
+ `days` smallint(5) unsigned NOT NULL,
+ `hours` float(2,1) unsigned NOT NULL DEFAULT '0.0',
+ `estimate` decimal(12,2) unsigned NOT NULL DEFAULT '0.00',
+ `consumed` decimal(12,2) unsigned NOT NULL DEFAULT '0.00',
+ `left` decimal(12,2) unsigned NOT NULL DEFAULT '0.00',
+ `order` tinyint(3) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `team` (`root`,`type`,`account`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_testreport` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL,
+ `project` mediumint(8) unsigned NOT NULL,
+ `tasks` varchar(255) NOT NULL,
+ `builds` varchar(255) NOT NULL,
+ `title` varchar(255) NOT NULL,
+ `begin` date NOT NULL,
+ `end` date NOT NULL,
+ `owner` char(30) NOT NULL,
+ `members` text NOT NULL,
+ `stories` text NOT NULL,
+ `bugs` text NOT NULL,
+ `cases` text NOT NULL,
+ `report` text NOT NULL,
+ `objectType` varchar(20) NOT NULL,
+ `objectID` mediumint(8) unsigned NOT NULL,
+ `createdBy` char(30) NOT NULL,
+ `createdDate` datetime NOT NULL,
+ `deleted` enum('0','1') NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_testresult` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `run` mediumint(8) unsigned NOT NULL,
+ `case` mediumint(8) unsigned NOT NULL,
+ `version` smallint(5) unsigned NOT NULL,
+ `caseResult` char(30) NOT NULL,
+ `stepResults` text NOT NULL,
+ `lastRunner` varchar(30) NOT NULL,
+ `date` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `case` (`case`),
+ KEY `version` (`version`),
+ KEY `run` (`run`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_testrun` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `task` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `case` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `version` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `assignedTo` char(30) NOT NULL DEFAULT '',
+ `lastRunner` varchar(30) NOT NULL,
+ `lastRunDate` datetime NOT NULL,
+ `lastRunResult` char(30) NOT NULL,
+ `status` char(30) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `task` (`task`,`case`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_testsuite` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `product` mediumint(8) unsigned NOT NULL,
+ `name` varchar(255) NOT NULL,
+ `desc` text NOT NULL,
+ `type` varchar(20) NOT NULL,
+ `addedBy` char(30) NOT NULL,
+ `addedDate` datetime NOT NULL,
+ `lastEditedBy` char(30) NOT NULL,
+ `lastEditedDate` datetime NOT NULL,
+ `deleted` enum('0','1') NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_testtask` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `name` char(90) NOT NULL,
+ `product` mediumint(8) unsigned NOT NULL,
+ `project` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `build` char(30) NOT NULL,
+ `owner` varchar(30) NOT NULL,
+ `pri` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `begin` date NOT NULL,
+ `end` date NOT NULL,
+ `mailto` text,
+ `desc` text NOT NULL,
+ `report` text NOT NULL,
+ `status` enum('blocked','doing','wait','done') NOT NULL DEFAULT 'wait',
+ `subStatus` varchar(30) NOT NULL DEFAULT '',
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `product` (`product`),
+ KEY `build` (`build`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_translation` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `lang` varchar(30) NOT NULL,
+ `module` varchar(30) NOT NULL,
+ `key` varchar(100) NOT NULL,
+ `value` text NOT NULL,
+ `referer` text NOT NULL,
+ `status` varchar(30) NOT NULL,
+ `translator` char(30) NOT NULL,
+ `translatedTime` datetime NOT NULL,
+ `reviewer` char(30) NOT NULL,
+ `reviewedTime` datetime NOT NULL,
+ `reason` text NOT NULL,
+ `version` varchar(20) NOT NULL,
+ `mode` varchar(20) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `lang_module_key_mode` (`lang`,`module`,`key`,`mode`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_todo` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `account` char(30) NOT NULL,
+ `date` date NOT NULL,
+ `begin` smallint(4) unsigned zerofill NOT NULL,
+ `end` smallint(4) unsigned zerofill NOT NULL,
+ `type` char(10) NOT NULL,
+ `cycle` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `idvalue` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `pri` tinyint(3) unsigned NOT NULL,
+ `name` char(150) NOT NULL,
+ `desc` text NOT NULL,
+ `status` enum('wait','doing','done','closed') NOT NULL DEFAULT 'wait',
+ `private` tinyint(1) NOT NULL,
+ `config` varchar(255) NOT NULL,
+ `assignedTo` varchar(30) NOT NULL DEFAULT '',
+ `assignedBy` varchar(30) NOT NULL DEFAULT '',
+ `assignedDate` datetime NOT NULL,
+ `finishedBy` varchar(30) NOT NULL DEFAULT '',
+ `finishedDate` datetime NOT NULL,
+ `closedBy` varchar(30) NOT NULL DEFAULT '',
+ `closedDate` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `account` (`account`),
+ KEY `assignedTo` (`assignedTo`),
+ KEY `finishedBy` (`finishedBy`),
+ KEY `date` (`date`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_user` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `dept` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `account` char(30) NOT NULL DEFAULT '',
+ `password` char(32) NOT NULL DEFAULT '',
+ `role` char(10) NOT NULL DEFAULT '',
+ `realname` varchar(100) NOT NULL DEFAULT '',
+ `nickname` char(60) NOT NULL DEFAULT '',
+ `commiter` varchar(100) NOT NULL,
+ `avatar` char(30) NOT NULL DEFAULT '',
+ `birthday` date NOT NULL DEFAULT '0000-00-00',
+ `gender` enum('f','m') NOT NULL DEFAULT 'f',
+ `email` char(90) NOT NULL DEFAULT '',
+ `skype` char(90) NOT NULL DEFAULT '',
+ `qq` char(20) NOT NULL DEFAULT '',
+ `mobile` char(11) NOT NULL DEFAULT '',
+ `phone` char(20) NOT NULL DEFAULT '',
+ `weixin` varchar(90) NOT NULL DEFAULT '',
+ `dingding` varchar(90) NOT NULL DEFAULT '',
+ `slack` varchar(90) NOT NULL DEFAULT '',
+ `whatsapp` varchar(90) NOT NULL DEFAULT '',
+ `address` char(120) NOT NULL DEFAULT '',
+ `zipcode` char(10) NOT NULL DEFAULT '',
+ `join` date NOT NULL DEFAULT '0000-00-00',
+ `visits` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `ip` char(15) NOT NULL DEFAULT '',
+ `last` int(10) unsigned NOT NULL DEFAULT '0',
+ `fails` tinyint(5) NOT NULL DEFAULT '0',
+ `locked` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `ranzhi` char(30) NOT NULL DEFAULT '',
+ `score` int(11) NOT NULL DEFAULT '0',
+ `scoreLevel` int(11) NOT NULL DEFAULT '0',
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `account` (`account`),
+ KEY `dept` (`dept`),
+ KEY `email` (`email`),
+ KEY `commiter` (`commiter`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_usercontact` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `account` char(30) NOT NULL,
+ `listName` varchar(60) NOT NULL,
+ `userList` text NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `account` (`account`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_usergroup` (
+ `account` char(30) NOT NULL DEFAULT '',
+ `group` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ UNIQUE KEY `account` (`account`,`group`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_userquery` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `account` char(30) NOT NULL,
+ `module` varchar(30) NOT NULL,
+ `title` varchar(90) NOT NULL,
+ `form` text NOT NULL,
+ `sql` text NOT NULL,
+ `shortcut` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `account` (`account`),
+ KEY `module` (`module`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_usertpl` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `account` char(30) NOT NULL,
+ `type` char(30) NOT NULL,
+ `title` varchar(150) NOT NULL,
+ `content` text NOT NULL,
+ `public` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `account` (`account`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_userview` (
+ `account` char(30) NOT NULL,
+ `products` mediumtext NOT NULL,
+ `projects` mediumtext NOT NULL,
+ UNIQUE KEY `account` (`account`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+CREATE TABLE `zt_webhook` (
+ `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
+ `type` varchar(10) NOT NULL DEFAULT 'default',
+ `name` varchar(50) NOT NULL,
+ `url` varchar(255) NOT NULL,
+ `domain` varchar(255) NOT NULL,
+ `contentType` varchar(30) NOT NULL DEFAULT 'application/json',
+ `sendType` enum('sync','async') NOT NULL DEFAULT 'sync',
+ `products` text NOT NULL,
+ `projects` text NOT NULL,
+ `params` varchar(100) NOT NULL,
+ `actions` text NOT NULL,
+ `desc` text NOT NULL,
+ `createdBy` varchar(30) NOT NULL,
+ `createdDate` datetime NOT NULL,
+ `editedBy` varchar(30) NOT NULL,
+ `editedDate` datetime NOT NULL,
+ `deleted` enum('0','1') NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/db/zentao.sql b/db/zentao.sql
index 5b0927f08c..eeb638d840 100644
--- a/db/zentao.sql
+++ b/db/zentao.sql
@@ -1026,7 +1026,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(1, 'admin', 'index'),
(1, 'admin', 'safe'),
(1, 'api', 'debug'),
-(1, 'api', 'getModel'),
(1, 'api', 'sql'),
(1, 'backup', 'backup'),
(1, 'backup', 'change'),
@@ -1433,7 +1432,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(1, 'user', 'view'),
(1, 'user', 'unbind'),
(2, 'action', 'editComment'),
-(2, 'api', 'getModel'),
(2, 'bug', 'activate'),
(2, 'bug', 'assignTo'),
(2, 'bug', 'batchAssignTo'),
@@ -1620,7 +1618,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(2, 'user', 'todo'),
(2, 'user', 'view'),
(3, 'action', 'editComment'),
-(3, 'api', 'getModel'),
(3, 'bug', 'activate'),
(3, 'bug', 'assignTo'),
(3, 'bug', 'batchClose'),
@@ -1847,7 +1844,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(4, 'action', 'trash'),
(4, 'action', 'undelete'),
(4, 'admin', 'index'),
-(4, 'api', 'getModel'),
(4, 'bug', 'activate'),
(4, 'bug', 'assignTo'),
(4, 'bug', 'batchAssignTo'),
@@ -2086,7 +2082,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(5, 'action', 'trash'),
(5, 'action', 'undelete'),
(5, 'admin', 'index'),
-(5, 'api', 'getModel'),
(5, 'bug', 'activate'),
(5, 'bug', 'assignTo'),
(5, 'bug', 'batchAssignTo'),
@@ -2351,7 +2346,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(6, 'action', 'trash'),
(6, 'action', 'undelete'),
(6, 'admin', 'index'),
-(6, 'api', 'getModel'),
(6, 'bug', 'activate'),
(6, 'bug', 'assignTo'),
(6, 'bug', 'batchAssignTo'),
@@ -2588,7 +2582,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(7, 'action', 'trash'),
(7, 'action', 'undelete'),
(7, 'admin', 'index'),
-(7, 'api', 'getModel'),
(7, 'bug', 'activate'),
(7, 'bug', 'assignTo'),
(7, 'bug', 'batchClose'),
@@ -2838,7 +2831,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(8, 'action', 'trash'),
(8, 'action', 'undelete'),
(8, 'admin', 'index'),
-(8, 'api', 'getModel'),
(8, 'bug', 'activate'),
(8, 'bug', 'assignTo'),
(8, 'bug', 'batchAssignTo'),
@@ -3098,7 +3090,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(9, 'action', 'trash'),
(9, 'action', 'undelete'),
(9, 'admin', 'index'),
-(9, 'api', 'getModel'),
(9, 'bug', 'browse'),
(9, 'bug', 'export'),
(9, 'bug', 'index'),
@@ -3266,7 +3257,6 @@ INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES
(9, 'user', 'view'),
(9, 'user', 'unbind'),
(10, 'action', 'editComment'),
-(10, 'api', 'getModel'),
(10, 'bug', 'activate'),
(10, 'bug', 'browse'),
(10, 'bug', 'close'),
diff --git a/doc/CHANGELOG b/doc/CHANGELOG
index 2808d98881..091185b9cb 100644
--- a/doc/CHANGELOG
+++ b/doc/CHANGELOG
@@ -1,3 +1,9 @@
+2019-09-24 11.6.3
+修复的Bug:
+2722 多人任务轮流完成之后状态异常
+2755 项目下需求页面搜索异常
+2766 导入用例时解析了js代码
+
2019-09-06 11.6.2
完成的需求:
4346 执行 init.sh生成的脚本和后台计划任务保持一致
diff --git a/framework/helper.class.php b/framework/helper.class.php
index b8bfde4127..1ef5f1ac61 100644
--- a/framework/helper.class.php
+++ b/framework/helper.class.php
@@ -96,7 +96,8 @@ class helper extends baseHelper
if($position !== false) $toEncoding = substr($toEncoding, 0, $position);
/* Check string encoding. */
- $encoding = strtolower(mb_detect_encoding($string, array('ASCII','UTF-8','GB2312','GBK','BIG5')));
+ $encodings = array_merge(array('GB2312','GBK','BIG5'), mb_list_encodings());
+ $encoding = strtolower(mb_detect_encoding($string, $encodings));
if($encoding == $toEncoding) return $string;
return mb_convert_encoding($string, $toEncoding, $encoding);
}
@@ -178,4 +179,4 @@ function autoloader($class)
}
}
-spl_autoload_register('autoloader');
\ No newline at end of file
+spl_autoload_register('autoloader');
diff --git a/lib/api/api.class.php b/lib/api/api.class.php
index 99ec4e2880..f5e1b00550 100755
--- a/lib/api/api.class.php
+++ b/lib/api/api.class.php
@@ -99,7 +99,7 @@ class ztclient
$controlAPI = $this->zentao->root . $module . $this->zentao->requestFix . $method . $this->zentao->requestFix;
if($vars)
{
- $vars = parse_str($vars);
+ parse_str($vars, $vars);
foreach($vars as $var) $controlAPI .= $var . $this->zentao->requestFix;
}
$controlAPI = rtrim($controlAPI, $this->zentao->requestFix) . '.json';
diff --git a/module/action/lang/en.php b/module/action/lang/en.php
index b971bdd570..e76cc268d3 100755
--- a/module/action/lang/en.php
+++ b/module/action/lang/en.php
@@ -137,6 +137,7 @@ $lang->action->desc->linkchildtask = '$date, $actor linked
$lang->action->desc->unlinkchildrentask = '$date, $actor unlinked a child task $extra。' . "\n";
$lang->action->desc->linkparenttask = '$date, $actor linked to a parent task $extra。' . "\n";
$lang->action->desc->unlinkparenttask = '$date, $actor unlinked a parent task $extra。' . "\n";
+$lang->action->desc->deletechildrentask = '$date, $actor deleted a child task $extra。' . "\n";
/* Historical record of actions when associating and removing cases. */
$lang->action->desc->linkrelatedcase = '$date, $actor linked a case $extra.' . "\n";
@@ -209,6 +210,7 @@ $lang->action->label->unlinkparenttask = "unlink from parent task";
$lang->action->label->batchcreate = "batch created tasks";
$lang->action->label->createchildren = "create child tasks";
$lang->action->label->managed = "managed";
+$lang->action->label->deletechildrentask = "delete children task";
/* Dynamic information is grouped by object. */
$lang->action->dynamicAction = new stdclass;
@@ -281,6 +283,7 @@ $lang->action->dynamicAction->task['canceled'] = 'Cancel Task';
$lang->action->dynamicAction->task['activated'] = 'Activate Task';
$lang->action->dynamicAction->task['createchildren'] = 'Create Child Task';
$lang->action->dynamicAction->task['unlinkparenttask'] = 'Unlink Parent Task';
+$lang->action->dynamicAction->task['deletechildrentask'] = 'Delete children task';
$lang->action->dynamicAction->task['linkparenttask'] = 'Link Parent Task';
$lang->action->dynamicAction->task['linkchildtask'] = 'Link Child Task';
$lang->action->dynamicAction->task['undeleted'] = 'Restore Task';
diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php
index e6d26c50d3..c5315de6ef 100755
--- a/module/action/lang/zh-cn.php
+++ b/module/action/lang/zh-cn.php
@@ -137,6 +137,7 @@ $lang->action->desc->linkchildtask = '$date, 由 $actor
$lang->action->desc->unlinkchildrentask = '$date, 由 $actor 移除子任务 $extra。' . "\n";
$lang->action->desc->linkparenttask = '$date, 由 $actor 关联到父任务 $extra。' . "\n";
$lang->action->desc->unlinkparenttask = '$date, 由 $actor 从父任务$extra取消关联。' . "\n";
+$lang->action->desc->deletechildrentask = '$date, 由 $actor 删除子任务$extra。' . "\n";
/* 关联用例和移除用例时的历史操作记录。*/
$lang->action->desc->linkrelatedcase = '$date, 由 $actor 关联相关用例 $extra。' . "\n";
@@ -209,6 +210,7 @@ $lang->action->label->unlinkparenttask = "从父任务取消关联";
$lang->action->label->batchcreate = "批量创建任务";
$lang->action->label->createchildren = "创建子任务";
$lang->action->label->managed = "维护";
+$lang->action->label->deletechildrentask = "删除子任务";
/* 动态信息按照对象分组 */
$lang->action->dynamicAction = new stdclass();
@@ -281,6 +283,7 @@ $lang->action->dynamicAction->task['canceled'] = '取消任务';
$lang->action->dynamicAction->task['activated'] = '激活任务';
$lang->action->dynamicAction->task['createchildren'] = '创建子任务';
$lang->action->dynamicAction->task['unlinkparenttask'] = '从父任务取消关联';
+$lang->action->dynamicAction->task['deletechildrentask'] = '删除子任务';
$lang->action->dynamicAction->task['linkparenttask'] = '关联到父任务';
$lang->action->dynamicAction->task['linkchildtask'] = '关联子任务';
$lang->action->dynamicAction->task['undeleted'] = '还原任务';
diff --git a/module/action/model.php b/module/action/model.php
index 304f139054..3eac992695 100755
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -303,7 +303,7 @@ class actionModel extends model
}
$action->extra = trim(trim($action->extra), ',');
}
- elseif($actionName == 'totask' or $actionName == 'linkchildtask' or $actionName == 'unlinkchildrentask' or $actionName == 'linkparenttask' or $actionName == 'unlinkparenttask')
+ elseif($actionName == 'totask' or $actionName == 'linkchildtask' or $actionName == 'unlinkchildrentask' or $actionName == 'linkparenttask' or $actionName == 'unlinkparenttask' or $actionName == 'deletechildrentask')
{
$name = $this->dao->select('name')->from(TABLE_TASK)->where('id')->eq($action->extra)->fetch('name');
if($name) $action->extra = common::hasPriv('task', 'view') ? html::a(helper::createLink('task', 'view', "taskID=$action->extra"), "#$action->extra " . $name) : "#$action->extra " . $name;
@@ -838,7 +838,7 @@ class actionModel extends model
}
$action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID));
- if($action->objectType == 'user') $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->actor));
+ if($action->objectType == 'user') $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectName));
$action->objectLabel = $objectLabel;
}
else
diff --git a/module/api/control.php b/module/api/control.php
index 31a5822d87..741d8f87b3 100644
--- a/module/api/control.php
+++ b/module/api/control.php
@@ -105,8 +105,9 @@ class api extends control
*/
public function sql($keyField = '')
{
- $sql = isset($_POST['sql']) ? $this->post->sql : '';
- $this->view->results = $this->api->sql($sql, $keyField);
- die($this->display());
+ die();
+ //$sql = isset($_POST['sql']) ? $this->post->sql : '';
+ //$this->view->results = $this->api->sql($sql, $keyField);
+ //die($this->display());
}
}
diff --git a/module/block/control.php b/module/block/control.php
index e19c413f9b..a16ca26ac6 100644
--- a/module/block/control.php
+++ b/module/block/control.php
@@ -346,7 +346,7 @@ class block extends control
}
else
{
- $html = "
" . htmlspecialchars_decode($block->params->html) .'
';
+ $html = "" . $block->params->html . '
';
}
}
elseif($block->source != '')
@@ -713,8 +713,20 @@ class block extends control
$pager = pager::init(0, $num , 1);
$productStats = $this->loadModel('product')->getStats('order_desc', $this->viewType != 'json' ? $pager : '', $type);
+ $projects = $this->loadModel('project')->getPairs();
$productIdList = array();
- foreach($productStats as $product) $productIdList[] = $product->id;
+ $this->loadModel('action');
+ foreach($productStats as $product)
+ {
+ $currentProjectID = $this->dao->select('objectID')->from(TABLE_ACTION)
+ ->where('objectType')->eq('project')
+ ->andWhere('action')->eq('managed')
+ ->andWhere("CONCAT(extra, ',,')")->like("%$product->id,,")
+ ->orderBy('id_desc')
+ ->fetch('objectID');
+ $product->currentProject = zget($projects, $currentProjectID, '');
+ $productIdList[] = $product->id;
+ }
$this->view->projects = $this->dao->select('t1.product,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
diff --git a/module/block/view/productblock.html.php b/module/block/view/productblock.html.php
index 7f2b3cab12..d6d00ede50 100644
--- a/module/block/view/productblock.html.php
+++ b/module/block/view/productblock.html.php
@@ -39,8 +39,8 @@
>
| name?> |
- id, '');?>
- id, '');?> |
+ currentProject ? $product->currentProject : zget($projects, $product->id, '');?>
+ |
plans?> |
releases?> |
diff --git a/module/bug/control.php b/module/bug/control.php
index 919d0495be..5e22a3f736 100644
--- a/module/bug/control.php
+++ b/module/bug/control.php
@@ -258,7 +258,7 @@ class bug extends control
if(!empty($_POST))
{
$response['result'] = 'success';
- $response['message'] = '';
+ $response['message'] = $this->lang->saveSuccess;
/* Set from param if there is a object to transfer bug. */
$bugResult = $this->bug->create($from = isset($fromObjectIDKey) ? $fromObjectIDKey : '');
@@ -408,7 +408,7 @@ class bug extends control
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]);
$this->view->position[] = $this->lang->bug->create;
- $this->view->products = $products;
+ $this->view->products = $products;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->moduleOptionMenu = $moduleOptionMenu;
diff --git a/module/bug/css/create.css b/module/bug/css/create.css
index f006a70179..2aa61ebd72 100644
--- a/module/bug/css/create.css
+++ b/module/bug/css/create.css
@@ -41,4 +41,6 @@ html[lang='en'] #deadlineTd .input-group-addon{padding: 5px 18px}
#mainContent .center-block{padding-bottom:40px;}
#typeBox {width:180px;}
+#typeBox .required:after {right: 1px;}
+#osBox .required:after {right: 1px;}
#osBox {width:190px;}
diff --git a/module/bug/model.php b/module/bug/model.php
index 009e72fb0b..841acec8be 100644
--- a/module/bug/model.php
+++ b/module/bug/model.php
@@ -632,6 +632,7 @@ class bugModel extends model
->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active')
->setIF($this->post->resolution != '', 'confirmed', 1)
->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
+ ->setIF(!$this->post->linkBug, 'linkBug', '')
->remove('comment,files,labels,uid,contactListMenu')
->get();
diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php
index f6bab1886b..d57f1ebdcf 100644
--- a/module/bug/view/create.html.php
+++ b/module/bug/view/create.html.php
@@ -38,7 +38,7 @@ js::set('flow', $config->global->flow);
- session->currentProductType != 'normal'):?>
+ session->currentProductType != 'normal' and isset($products[$productID])):?>
diff --git a/module/caselib/config.php b/module/caselib/config.php
new file mode 100644
index 0000000000..994c2381b4
--- /dev/null
+++ b/module/caselib/config.php
@@ -0,0 +1,16 @@
+caselib = new stdclass();
+$config->caselib->create = new stdclass();
+$config->caselib->createcase = new stdclass();
+$config->caselib->create->requiredFields = 'name';
+$config->caselib->createcase->requiredFields = 'title,type';
+
+$config->caselib->editor = new stdclass();
+$config->caselib->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
+
+$config->caselib->datatable = new stdclass();
+$config->caselib->datatable->defaultField = array('id', 'pri', 'title', 'type', 'assignedTo', 'lastRunner', 'lastRunDate', 'lastRunResult', 'status', 'bugs', 'results', 'actions');
+
+$config->caselib->custom = new stdclass();
+$config->caselib->custom->createFields = 'stage,pri,keywords';
+$config->caselib->customCreateFields = 'stage,pri,keywords';
diff --git a/module/caselib/control.php b/module/caselib/control.php
new file mode 100644
index 0000000000..90a3b807dd
--- /dev/null
+++ b/module/caselib/control.php
@@ -0,0 +1,737 @@
+
+ * @package caselib
+ * @version $Id: control.php 5114 2013-07-12 06:02:59Z chencongzhi520@gmail.com $
+ * @link http://www.zentao.net
+ */
+class caselib extends control
+{
+ public $products = array();
+
+ /**
+ * Index page, header to browse.
+ *
+ * @access public
+ * @return void
+ */
+ public function index()
+ {
+ $this->locate($this->createLink('caselib', 'browse'));
+ }
+
+ /**
+ * Create lib
+ *
+ * @access public
+ * @return void
+ */
+ public function create()
+ {
+ if(!empty($_POST))
+ {
+ $response['result'] = 'success';
+ $response['message'] = $this->lang->saveSuccess;
+ $libID = $this->caselib->create();
+ if(dao::isError())
+ {
+ $response['result'] = 'fail';
+ $response['message'] = dao::getError();
+ $this->send($response);
+ }
+ $this->loadModel('action')->create('caselib', $libID, 'opened');
+ $response['locate'] = $this->createLink('caselib', 'browse', "libID=$libID");
+ $this->send($response);
+ }
+
+ /* Set menu. */
+ $libraries = $this->caselib->getLibraries();
+ $libID = $this->caselib->saveLibState(0, $libraries);
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $this->view->title = $this->lang->caselib->common . $this->lang->colon . $this->lang->caselib->create;
+ $this->view->position[] = $this->lang->caselib->common;
+ $this->view->position[] = $this->lang->caselib->create;
+ $this->display();
+ }
+
+ /**
+ * Edit a case lib.
+ *
+ * @param int $lib
+ * @access public
+ * @return void
+ */
+ public function edit($libID)
+ {
+ $lib = $this->caselib->getById($libID);
+ if(!empty($_POST))
+ {
+ $response['result'] = 'success';
+ $response['message'] = $this->lang->saveSuccess;
+ $changes = $this->caselib->update($libID);
+ if(dao::isError())
+ {
+ $response['result'] = 'fail';
+ $response['message'] = dao::getError();
+ $this->send($response);
+ }
+ if($changes)
+ {
+ $actionID = $this->loadModel('action')->create('caselib', $libID, 'edited');
+ $this->action->logHistory($actionID, $changes);
+ }
+
+ $this->executeHooks($libID);
+
+ $response['locate'] = inlink('view', "libID=$libID");
+ $this->send($response);
+ }
+
+ /* Set lib menu. */
+ $libraries = $this->caselib->getLibraries();
+ $libID = $this->caselib->saveLibState($libID, $libraries);
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $this->view->title = $libraries[$libID] . $this->lang->colon . $this->lang->caselib->edit;
+ $this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $libraries[$libID]);
+ $this->view->position[] = $this->lang->caselib->common;
+ $this->view->position[] = $this->lang->caselib->edit;
+
+ $this->view->lib = $lib;
+ $this->display();
+ }
+
+ /**
+ * Delete a case lib.
+ *
+ * @param int $libID
+ * @param string $confirm yes|no
+ * @access public
+ * @return void
+ */
+ public function delete($libID, $confirm = 'no')
+ {
+ if($confirm == 'no')
+ {
+ die(js::confirm($this->lang->caselib->libraryDelete, inlink('delete', "libID=$libID&confirm=yes")));
+ }
+ else
+ {
+ $this->caselib->delete($libID);
+
+ $this->executeHooks($libID);
+
+ /* if ajax request, send result. */
+ if($this->server->ajax)
+ {
+ if(dao::isError())
+ {
+ $response['result'] = 'fail';
+ $response['message'] = dao::getError();
+ }
+ else
+ {
+ $response['result'] = 'success';
+ $response['message'] = '';
+ }
+ $this->send($response);
+ }
+ die(js::reload('parent'));
+ }
+ }
+
+ /**
+ * Show library case.
+ *
+ * @param int $libID
+ * @param string $browseType
+ * @param int $param
+ * @param string $orderBy
+ * @param int $recTotal
+ * @param int $recPerPage
+ * @param int $pageID
+ * @access public
+ * @return void
+ */
+ public function browse($libID = 0, $browseType = 'all', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ {
+ /* Set browse type. */
+ $browseType = strtolower($browseType);
+
+ $libraries = $this->caselib->getLibraries();
+ if(empty($libraries)) $this->locate(inlink('create'));
+
+ /* Save session. */
+ $this->session->set('caseList', $this->app->getURI(true));
+
+ /* Set menu. */
+ $libID = $this->caselib->saveLibState($libID, $libraries);
+ setcookie('preCaseLibID', $libID, $this->config->cookieLife, $this->config->webRoot);
+ if($this->cookie->preCaseLibID != $libID)
+ {
+ $_COOKIE['libCaseModule'] = 0;
+ setcookie('libCaseModule', 0, 0, $this->config->webRoot);
+ }
+
+ if($browseType == 'bymodule') setcookie('libCaseModule', (int)$param, 0, $this->config->webRoot);
+ if($browseType != 'bymodule') $this->session->set('libBrowseType', $browseType);
+ $moduleID = ($browseType == 'bymodule') ? (int)$param : ($browseType == 'bysearch' ? 0 : ($this->cookie->libCaseModule ? $this->cookie->libCaseModule : 0));
+ $queryID = ($browseType == 'bysearch') ? (int)$param : 0;
+
+ /* Set lib menu. */
+ $this->caselib->setLibMenu($libraries, $libID, $moduleID);
+
+ /* Load pager. */
+ $this->app->loadClass('pager', $static = true);
+ $pager = pager::init($recTotal, $recPerPage, $pageID);
+
+ /* Build the search form. */
+ $this->loadModel('testcase');
+ $actionURL = $this->createLink('caselib', 'browse', "libID=$libID&browseType=bySearch&queryID=myQueryID");
+ $this->caselib->buildSearchForm($libID, $libraries, $queryID, $actionURL);
+
+ /* Append id for secend sort. */
+ $sort = $this->loadModel('common')->appendOrder($orderBy);
+
+ /* save session .*/
+ $cases = $this->caselib->getLibCases($libID, $browseType, $queryID, $moduleID, $sort, $pager);
+ $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', true);
+
+ $this->loadModel('datatable');
+ $this->loadModel('tree');
+ $showModule = !empty($this->config->datatable->caselibLibrary->showModule) ? $this->config->datatable->caselibLibrary->showModule : '';
+ $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($libID, 'caselib', $showModule) : array();
+
+ $this->view->title = $this->lang->caselib->common . $this->lang->colon . $libraries[$libID];
+ $this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $libraries[$libID]);
+
+ $this->view->libID = $libID;
+ $this->view->libName = $libraries[$libID];
+ $this->view->cases = $cases;
+ $this->view->orderBy = $orderBy;
+ $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
+ $this->view->modules = $this->tree->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0);
+ $this->view->moduleTree = $this->tree->getTreeMenu($libID, $viewType = 'caselib', $startModuleID = 0, array('treeModel', 'createCaseLibLink'));
+ $this->view->pager = $pager;
+ $this->view->browseType = $browseType;
+ $this->view->moduleID = $moduleID;
+ $this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
+ $this->view->param = $param;
+ $this->view->setShowModule = true;
+
+ $this->display();
+ }
+
+ /**
+ * Create case for library.
+ *
+ * @param int $libID
+ * @param int $moduleID
+ * @access public
+ * @return void
+ */
+ public function createCase($libID, $moduleID = 0, $param = 0)
+ {
+ if(!empty($_POST))
+ {
+ $this->loadModel('testcase');
+ $this->config->testcase->create->requiredFields = $this->config->caselib->createcase->requiredFields;
+ $caseResult = $this->testcase->create($bugID = 0);
+ if(!$caseResult or dao::isError()) die(js::error(dao::getError()));
+
+ $caseID = $caseResult['id'];
+ if($caseResult['status'] == 'exists')
+ {
+ echo js::alert(sprintf($this->lang->duplicate, $this->lang->testcase->common));
+ die(js::locate($this->createLink('testcase', 'view', "caseID=$caseID"), 'parent'));
+ }
+
+ $this->loadModel('action')->create('case', $caseID, 'Opened');
+
+ /* If link from no head then reload. */
+ if(isonlybody()) die(js::reload('parent'));
+ die(js::locate($this->createLink('caselib', 'browse', "libID={$libID}&browseType=byModule¶m={$_POST['module']}"), 'parent'));
+ }
+ /* Set lib menu. */
+ $libraries = $this->caselib->getLibraries();
+ $libID = $this->caselib->saveLibState($libID, $libraries);
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $type = 'feature';
+ $stage = '';
+ $pri = 3;
+ $caseTitle = '';
+ $precondition = '';
+ $keywords = '';
+ $steps = array();
+
+ $this->loadModel('testcase');
+ if($param)
+ {
+ $testcase = $this->testcase->getById((int)$param);
+ $type = $testcase->type ? $testcase->type : 'feature';
+ $stage = $testcase->stage;
+ $pri = $testcase->pri;
+ $storyID = $testcase->story;
+ $caseTitle = $testcase->title;
+ $precondition = $testcase->precondition;
+ $keywords = $testcase->keywords;
+ $steps = $testcase->steps;
+ }
+
+ if(count($steps) < $this->config->testcase->defaultSteps)
+ {
+ $paddingCount = $this->config->testcase->defaultSteps - count($steps);
+ $step = new stdclass();
+ $step->type = 'item';
+ $step->desc = '';
+ $step->expect = '';
+ for($i = 1; $i <= $paddingCount; $i ++) $steps[] = $step;
+ }
+
+ $this->view->title = $libraries[$libID] . $this->lang->colon . $this->lang->testcase->create;
+ $this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $libraries[$libID]);
+ $this->view->position[] = $this->lang->caselib->common;
+ $this->view->position[] = $this->lang->testcase->create;
+
+ foreach(explode(',', $this->config->caselib->customCreateFields) as $field) $customFields[$field] = $this->lang->testcase->$field;
+ $this->view->showFields = $this->config->caselib->custom->createFields;
+ $this->view->customFields = $customFields;
+ $this->view->libraries = $libraries;
+ $this->view->libID = $libID;
+ $this->view->currentModuleID = (int)$moduleID;
+ $this->view->caseTitle = $caseTitle;
+ $this->view->type = $type;
+ $this->view->stage = $stage;
+ $this->view->pri = $pri;
+ $this->view->precondition = $precondition;
+ $this->view->keywords = $keywords;
+ $this->view->steps = $steps;
+ $this->view->moduleOptionMenu = $this->loadModel('tree')->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0);
+ $this->display();
+ }
+
+ /**
+ * Batch create case.
+ *
+ * @param int $libID
+ * @param int $moduleID
+ * @access public
+ * @return void
+ */
+ public function batchCreateCase($libID, $moduleID = 0)
+ {
+ $this->loadModel('testcase');
+ if(!empty($_POST))
+ {
+ $caseID = $this->caselib->batchCreateCase($libID);
+ if(dao::isError()) die(js::error(dao::getError()));
+ if(isonlybody()) die(js::closeModal('parent.parent', 'this'));
+ die(js::locate($this->createLink('caselib', 'browse', "libID=$libID&browseType=byModule¶m=$moduleID"), 'parent'));
+ }
+
+ $libraries = $this->caselib->getLibraries();
+ if(empty($libraries)) $this->locate(inlink('create'));
+
+ /* Set lib menu. */
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $currentModuleID = (int)$moduleID;
+
+ /* Set module option menu. */
+ $moduleOptionMenu = $this->loadModel('tree')->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0);
+ $moduleOptionMenu['ditto'] = $this->lang->testcase->ditto;
+
+ $this->view->title = $libraries[$libID] . $this->lang->colon . $this->lang->testcase->batchCreate;
+ $this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $libraries[$libID]);
+ $this->view->position[] = $this->lang->testcase->batchCreate;
+ $this->view->libID = $libID;
+ $this->view->moduleOptionMenu = $moduleOptionMenu;
+ $this->view->currentModuleID = $currentModuleID;
+
+ $this->display();
+ }
+
+ /**
+ * View library
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function view($libID)
+ {
+ $lib = $this->caselib->getById($libID, true);
+
+ /* Set lib menu. */
+ $libraries = $this->caselib->getLibraries();
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $this->loadModel('testcase');
+ $this->view->title = $lib->name . $this->lang->colon . $this->lang->caselib->view;
+ $this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $lib->name);
+ $this->view->position[] = $this->lang->caselib->common;
+ $this->view->position[] = $this->lang->caselib->view;
+
+ $this->view->lib = $lib;
+ $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
+ $this->view->actions = $this->loadModel('action')->getList('caselib', $libID);
+ $this->display();
+ }
+
+ /**
+ * Ajax get drop menu.
+ *
+ * @param int $libID
+ * @param string $module
+ * @param string $method
+ * @param string $extra
+ * @access public
+ * @return void
+ */
+ public function ajaxGetDropMenu($libID, $module, $method, $extra = '')
+ {
+ $this->view->link = $this->caselib->getLibLink($module, $method, $extra);
+ $this->view->libID = $libID;
+ $this->view->module = $module;
+ $this->view->method = $method;
+ $this->view->extra = $extra;
+
+ $libraries = $this->caselib->getLibraries();
+
+ $this->view->libraries = $libraries;
+ $this->view->librariesPinyin = common::convert2Pinyin($libraries);
+ $this->display();
+ }
+
+ /**
+ * The results page of search.
+ *
+ * @param string $keywords
+ * @param string $module
+ * @param string $method
+ * @param mix $extra
+ * @access public
+ * @return void
+ */
+ public function ajaxGetMatchedItems($keywords, $module, $method, $extra)
+ {
+ $libraries = $this->dao->select('*')->from(TABLE_TESTSUITE)->where('deleted')->eq(0)->andWhere('name')->like("%$keywords%")->andWhere('type')->eq('library')->orderBy('`id` desc')->fetchAll();
+ $this->view->link = $this->caselib->getLibLink($module, $method, $extra);
+ $this->view->libraries = $libraries;
+ $this->view->keywords = $keywords;
+ $this->display();
+ }
+
+ /**
+ * Export templet.
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function exportTemplet($libID)
+ {
+ $this->loadModel('testcase');
+ if($_POST)
+ {
+ $fields['module'] = $this->lang->testcase->module;
+ $fields['title'] = $this->lang->testcase->title;
+ $fields['precondition'] = $this->lang->testcase->precondition;
+ $fields['stepDesc'] = $this->lang->testcase->stepDesc;
+ $fields['stepExpect'] = $this->lang->testcase->stepExpect;
+ $fields['keywords'] = $this->lang->testcase->keywords;
+ $fields['pri'] = $this->lang->testcase->pri;
+ $fields['type'] = $this->lang->testcase->type;
+ $fields['stage'] = $this->lang->testcase->stage;
+
+ $fields[''] = '';
+ $fields['typeValue'] = $this->lang->testcase->lblTypeValue;
+ $fields['stageValue'] = $this->lang->testcase->lblStageValue;
+
+ $modules = $this->loadModel('tree')->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0);
+ $rows = array();
+ $num = (int)$this->post->num;
+ for($i = 0; $i < $num; $i++)
+ {
+ foreach($modules as $moduleID => $module)
+ {
+ $row = new stdclass();
+ $row->module = $module . "(#$moduleID)";
+ $row->stepDesc = "1. \n2. \n3.";
+ $row->stepExpect = "1. \n2. \n3.";
+
+ if(empty($rows))
+ {
+ $row->typeValue = join("\n", $this->lang->testcase->typeList);
+ $row->stageValue = join("\n", $this->lang->testcase->stageList);
+ }
+ $rows[] = $row;
+ }
+ }
+
+ $this->post->set('fields', $fields);
+ $this->post->set('kind', 'testcase');
+ $this->post->set('rows', $rows);
+ $this->post->set('extraNum', $num);
+ $this->post->set('fileName', 'templet');
+ $this->fetch('file', 'export2csv', $_POST);
+ }
+
+ $this->display();
+ }
+
+ /**
+ * Import case csv file.
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function import($libID)
+ {
+ $this->loadModel('testcase');
+ if($_FILES)
+ {
+ $file = $this->loadModel('file')->getUpload('file');
+ $file = $file[0];
+
+ $fileName = $this->file->savePath . $this->file->getSaveName($file['pathname']);
+ move_uploaded_file($file['tmpname'], $fileName);
+
+ $rows = $this->file->parseCSV($fileName);
+ $fields = $this->testcase->getImportFields($productID);
+ $fields = array_flip($fields);
+ $header = array();
+ foreach($rows[0] as $i => $rowValue)
+ {
+ if(empty($rowValue)) break;
+ $header[$i] = $rowValue;
+ }
+ unset($rows[0]);
+
+ $columnKey = array();
+ foreach($header as $title)
+ {
+ if(!isset($fields[$title])) continue;
+ $columnKey[] = $fields[$title];
+ }
+
+ if(count($columnKey) != count($header) or $this->post->encode != 'utf-8')
+ {
+ $fc = file_get_contents($fileName);
+ $encode = $this->post->encode != "utf-8" ? $this->post->encode : 'gbk';
+ $fc = helper::convertEncoding($fc, $encode, 'utf-8');
+ file_put_contents($fileName, $fc);
+
+ $rows = $this->file->parseCSV($fileName);
+ $columnKey = array();
+ $header = array();
+ foreach($rows[0] as $i => $rowValue)
+ {
+ if(empty($rowValue)) break;
+ $header[$i] = $rowValue;
+ }
+ unset($rows[0]);
+ foreach($header as $title)
+ {
+ if(!isset($fields[$title])) continue;
+ $columnKey[] = $fields[$title];
+ }
+ if(count($columnKey) != count($header)) die(js::alert($this->lang->testcase->errorEncode));
+ }
+
+ $this->session->set('importFile', $fileName);
+
+ die(js::locate(inlink('showImport', "libID=$libID"), 'parent.parent'));
+ }
+ $this->display();
+ }
+
+ /**
+ * Show import case.
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function showImport($libID)
+ {
+ $this->loadModel('testcase');
+ if($_POST)
+ {
+ $this->caselib->createFromImport($libID);
+ die(js::locate(inlink('browse', "libID=$libID"), 'parent'));
+ }
+
+ $libraries = $this->caselib->getLibraries();
+ if(empty($libraries)) $this->locate(inlink('create'));
+
+ $this->caselib->setLibMenu($libraries, $libID);
+
+ $file = $this->session->importFile;
+ $caseLang = $this->lang->testcase;
+ $caseConfig = $this->config->testcase;
+ $modules = $this->loadModel('tree')->getOptionMenu($libID, $viewType = 'caselib', $startModuleID = 0);
+
+ $fields = explode(',', $caseConfig->exportFields);
+ foreach($fields as $key => $fieldName)
+ {
+ $fieldName = trim($fieldName);
+ $fields[$fieldName] = isset($caseLang->$fieldName) ? $caseLang->$fieldName : $fieldName;
+ unset($fields[$key]);
+ }
+
+ $fields = array_flip($fields);
+ $rows = $this->loadModel('file')->parseCSV($file);
+ $header = array();
+ foreach($rows[0] as $i => $rowValue)
+ {
+ if(empty($rowValue)) break;
+ $header[$i] = $rowValue;
+ }
+ unset($rows[0]);
+
+ foreach($header as $title)
+ {
+ if(!isset($fields[$title])) continue;
+ $columnKey[] = $fields[$title];
+ }
+
+ $endField = end($fields);
+ $caseData = array();
+ $stepData = array();
+ $stepVars = 0;
+ foreach($rows as $row => $data)
+ {
+ $case = new stdclass();
+ foreach($columnKey as $key => $field)
+ {
+ if(!isset($data[$key])) continue;
+ $cellValue = $data[$key];
+ if($field == 'module')
+ {
+ $case->$field = 0;
+ if(strrpos($cellValue, '(#') !== false)
+ {
+ $id = trim(substr($cellValue, strrpos($cellValue,'(#') + 2), ')');
+ $case->$field = $id;
+ }
+ }
+ elseif(in_array($field, $caseConfig->export->listFields))
+ {
+ if($field == 'stage')
+ {
+ $stages = explode("\n", $cellValue);
+ foreach($stages as $stage) $case->stage[] = array_search($stage, $caseLang->{$field . 'List'});
+ $case->stage = join(',', $case->stage);
+ }
+ else
+ {
+ $case->$field = array_search($cellValue, $caseLang->{$field . 'List'});
+ }
+ }
+ elseif($field != 'stepDesc' and $field != 'stepExpect')
+ {
+ $case->$field = $cellValue;
+ }
+ else
+ {
+ $steps = (array)$cellValue;
+ if(strpos($cellValue, "\n"))
+ {
+ $steps = explode("\n", $cellValue);
+ }
+ elseif(strpos($cellValue, "\r"))
+ {
+ $steps = explode("\r", $cellValue);
+ }
+
+ $stepKey = str_replace('step', '', strtolower($field));
+ $caseStep = array();
+
+ foreach($steps as $step)
+ {
+ $step = trim($step);
+ if(empty($step)) continue;
+ if(preg_match('/^(([0-9]+)\.[0-9]+)([.、]{1})/U', $step, $out))
+ {
+ $num = $out[1];
+ $parent = $out[2];
+ $sign = $out[3];
+ $signbit = $sign == '.' ? 1 : 3;
+ $step = trim(substr($step, strlen($num) + $signbit));
+ if(!empty($step)) $caseStep[$num]['content'] = $step;
+ $caseStep[$num]['type'] = 'item';
+ $caseStep[$parent]['type'] = 'group';
+ }
+ elseif(preg_match('/^([0-9]+)([.、]{1})/U', $step, $out))
+ {
+ $num = $out[1];
+ $sign = $out[2];
+ $signbit = $sign == '.' ? 1 : 3;
+ $step = trim(substr($step, strlen($num) + $signbit));
+ if(!empty($step)) $caseStep[$num]['content'] = $step;
+ $caseStep[$num]['type'] = 'step';
+ }
+ elseif(isset($num))
+ {
+ if(!isset($caseStep[$num]['content'])) $caseStep[$num]['content'] = '';
+ $caseStep[$num]['content'] .= "\n" . $step;
+ }
+ else
+ {
+ if($field == 'stepDesc')
+ {
+ $num = 1;
+ $caseStep[$num]['content'] = $step;
+ $caseStep[$num]['type'] = 'step';
+ }
+ if($field == 'stepExpect' and isset($stepData[$row]['desc']))
+ {
+ end($stepData[$row]['desc']);
+ $num = key($stepData[$row]['desc']);
+ $caseStep[$num]['content'] = $step;
+ }
+ }
+ }
+ unset($num);
+ unset($sign);
+ $stepVars += count($caseStep, COUNT_RECURSIVE) - count($caseStep);
+ $stepData[$row][$stepKey] = $caseStep;
+ }
+ }
+
+ $caseData[$row] = $case;
+ unset($case);
+ }
+
+ if(empty($caseData))
+ {
+ unlink($this->session->importFile);
+ unset($_SESSION['importFile']);
+ echo js::alert($this->lang->error->noData);
+ die(js::locate($this->createLink('caselib', 'browse', "libID=$libID")));
+ }
+
+ /* Judge whether the editedTasks is too large and set session. */
+ $countInputVars = count($caseData) * 9 + $stepVars;
+ $showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
+ if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
+
+ $this->view->title = $this->lang->caselib->common . $this->lang->colon . $this->lang->testcase->showImport;
+ $this->view->position[] = $this->lang->testcase->showImport;
+
+ $this->view->modules = $modules;
+ $this->view->cases = $this->dao->select('id,module,stage,status,pri,type')->from(TABLE_CASE)->where('lib')->eq($libID)->andWhere('deleted')->eq(0)->andWhere('product')->eq(0)->fetchAll('id');
+ $this->view->caseData = $caseData;
+ $this->view->stepData = $stepData;
+ $this->view->libID = $libID;
+ $this->display();
+ }
+}
diff --git a/module/testsuite/css/batchcreatecase.css b/module/caselib/css/batchcreatecase.css
similarity index 100%
rename from module/testsuite/css/batchcreatecase.css
rename to module/caselib/css/batchcreatecase.css
diff --git a/module/testsuite/css/library.css b/module/caselib/css/browse.css
similarity index 100%
rename from module/testsuite/css/library.css
rename to module/caselib/css/browse.css
diff --git a/module/testsuite/css/createcase.css b/module/caselib/css/createcase.css
similarity index 100%
rename from module/testsuite/css/createcase.css
rename to module/caselib/css/createcase.css
diff --git a/module/testsuite/css/showimport.css b/module/caselib/css/showimport.css
similarity index 100%
rename from module/testsuite/css/showimport.css
rename to module/caselib/css/showimport.css
diff --git a/module/testsuite/js/library.js b/module/caselib/js/browse.js
similarity index 100%
rename from module/testsuite/js/library.js
rename to module/caselib/js/browse.js
diff --git a/module/testsuite/js/createcase.js b/module/caselib/js/createcase.js
similarity index 100%
rename from module/testsuite/js/createcase.js
rename to module/caselib/js/createcase.js
diff --git a/module/caselib/lang/en.php b/module/caselib/lang/en.php
new file mode 100644
index 0000000000..429aa86b8b
--- /dev/null
+++ b/module/caselib/lang/en.php
@@ -0,0 +1,37 @@
+
+ * @package caselib
+ * @version $Id: zh-cn.php 4490 2013-02-27 03:27:05Z wyd621@gmail.com $
+ * @link http://www.zentao.net
+ */
+$lang->caselib->common = 'Case Library';
+$lang->caselib->all = 'All Case Libraries';
+
+$lang->caselib->index = "Library Home";
+$lang->caselib->create = "Create Case Library";
+$lang->caselib->edit = 'Edit Case Library';
+$lang->caselib->browse = 'View Cases in Library';
+$lang->caselib->view = 'Library Detail';
+$lang->caselib->createCase = 'Create Case';
+$lang->caselib->delete = "Delete Suite";
+$lang->caselib->linkVersion = "Version";
+$lang->caselib->deleted = 'Deleted';
+$lang->caselib->exportTemplet = 'Export Template';
+$lang->caselib->batchCreateCase = 'Batch Create';
+$lang->caselib->import = 'Import';
+$lang->caselib->importAction = 'Import Case';
+$lang->caselib->showImport = 'Imported Data';
+
+$lang->caselib->id = 'ID';
+$lang->caselib->name = 'Name';
+$lang->caselib->desc = 'Description';
+
+$lang->caselib->legendDesc = 'Description';
+
+$lang->caselib->libraryDelete = 'Do you want to delete this library?';
+$lang->caselib->noModule = 'You have no modules. Manage it now. ';
diff --git a/module/caselib/lang/zh-cn.php b/module/caselib/lang/zh-cn.php
new file mode 100644
index 0000000000..e22369385b
--- /dev/null
+++ b/module/caselib/lang/zh-cn.php
@@ -0,0 +1,37 @@
+
+ * @package caselib
+ * @version $Id: zh-cn.php 4490 2013-02-27 03:27:05Z wyd621@gmail.com $
+ * @link http://www.zentao.net
+ */
+$lang->caselib->common = '用例库';
+$lang->caselib->all = '所有用例库';
+
+$lang->caselib->index = "用例库首页";
+$lang->caselib->create = "创建用例库";
+$lang->caselib->edit = '编辑用例库';
+$lang->caselib->browse = '浏览库用例';
+$lang->caselib->view = '查看库概况';
+$lang->caselib->createCase = '创建用例';
+$lang->caselib->delete = "删除";
+$lang->caselib->linkVersion = "版本";
+$lang->caselib->deleted = '已删除';
+$lang->caselib->exportTemplet = '导出模板';
+$lang->caselib->batchCreateCase = '批量创建用例';
+$lang->caselib->import = '导入';
+$lang->caselib->importAction = '导入用例';
+$lang->caselib->showImport = '显示导入数据';
+
+$lang->caselib->id = '编号';
+$lang->caselib->name = '名称';
+$lang->caselib->desc = '描述';
+
+$lang->caselib->legendDesc = '描述';
+
+$lang->caselib->libraryDelete = '您确认要删除该用例库吗?';
+$lang->caselib->noModule = '您现在还没有模块信息 请维护用例库模块 ';
diff --git a/module/caselib/model.php b/module/caselib/model.php
new file mode 100644
index 0000000000..ce16fc972c
--- /dev/null
+++ b/module/caselib/model.php
@@ -0,0 +1,640 @@
+
+ * @package caselib
+ * @version $Id: model.php 5114 2013-07-12 06:02:59Z chencongzhi520@gmail.com $
+ * @link http://www.zentao.net
+ */
+?>
+app->viewType == 'mhtml';
+ $selectHtml = '';
+ if(!empty($libraries))
+ {
+ if($isMobile)
+ {
+ $selectHtml = "{$currentLibName} ";
+ }
+ else
+ {
+ $dropMenuLink = helper::createLink('caselib', 'ajaxGetDropMenu', "objectID=$libID&module=caselib&method=browse");
+ $selectHtml = "";
+ }
+ }
+
+ if($this->config->global->flow == 'onlyTest')
+ {
+ $modules = $this->loadModel('tree')->getModulePairs($libID, 'caselib');
+ $moduleName = ($moduleID && isset($modules[$moduleID])) ? $modules[$moduleID] : $this->lang->tree->all;
+
+ if(!$isMobile)
+ {
+ $dropMenuLink = helper::createLink('tree', 'ajaxGetDropMenu', "objectID=$libID&module=caselib&method=browse");
+ $selectHtml .= "";
+ }
+ else
+ {
+ $selectHtml .= "{$moduleName} ";
+ }
+ }
+
+ setCookie("lastCaseLib", $libID, $this->config->cookieLife, $this->config->webRoot);
+
+ $pageNav = '';
+ $pageActions = '';
+ $isMobile = $this->app->viewType == 'mhtml';
+ if($isMobile)
+ {
+ $this->app->loadLang('qa');
+ $pageNav = html::a(helper::createLink('qa', 'index'), $this->lang->qa->index) . $this->lang->colon;
+ }
+ else
+ {
+ if($this->config->global->flow == 'full')
+ {
+ $this->app->loadLang('qa');
+ $pageNav .= '';
+ $pageNav .= ' ';
+ }
+ else
+ {
+ $this->app->loadLang('testcase');
+ $pageActions .= "";
+ if(common::hasPriv('caselib', 'exportTemplet'))
+ {
+ $link = helper::createLink('caselib', 'exportTemplet', "libID=$libID");
+ $pageActions .= html::a($link, " " . $this->lang->caselib->exportTemplet, '', "class='btn btn-link export'");
+ }
+ if(common::hasPriv('caselib', 'import'))
+ {
+ $link = helper::createLink('caselib', 'import', "libID=$libID");
+ $pageActions .= html::a($link, " " . $this->lang->testcase->importFile, '', "class='btn btn-link export'");
+ }
+ $pageActions .= ' ';
+ $params = "libID=$libID&moduleID=" . (isset($moduleID) ? $moduleID : 0);
+ if(common::hasPriv('caselib', 'batchCreateCase'))
+ {
+ $link = helper::createLink('caselib', 'batchCreateCase', $params);
+ $pageActions .= html::a($link, "" . $this->lang->testcase->batchCreate, '', "class='btn btn-secondary'");
+ }
+ if(common::hasPriv('caselib', 'createCase'))
+ {
+ $link = helper::createLink('caselib', 'createCase', $params);
+ $pageActions .= html::a($link, "" . $this->lang->testcase->create, '', "class='btn btn-primary'");
+ }
+ if(common::hasPriv('caselib', 'create'))
+ {
+ $link = helper::createLink('caselib', 'create');
+ $pageActions .= html::a($link, "" . $this->lang->caselib->create, '', "class='btn btn-primary'");
+ }
+ }
+ }
+ $pageNav .= $selectHtml;
+
+ $this->lang->modulePageNav = $pageNav;
+ $this->lang->modulePageActions = $pageActions;
+ foreach($this->lang->caselib->menu as $key => $value)
+ {
+ $replace = '';
+ if($this->config->global->flow == 'onlyTest') $replace = $libID;
+ common::setMenuVars($this->lang->caselib->menu, $key, $replace);
+ }
+ if($this->config->global->flow != 'full' && $this->app->getMethodName() != 'view') $this->lang->caselib->menu->bysearch = " {$this->lang->testcase->bySearch}";
+ }
+
+ /**
+ * Save lib state.
+ *
+ * @param int $libID
+ * @param array $libraries
+ * @access public
+ * @return int
+ */
+ public function saveLibState($libID = 0, $libraries = array())
+ {
+ if($libID > 0) $this->session->set('caseLib', (int)$libID);
+ if($libID == 0 and $this->cookie->lastCaseLib) $this->session->set('caseLib', $this->cookie->lastCaseLib);
+ if($libID == 0 and $this->session->caseLib == '') $this->session->set('caseLib', key($libraries));
+ if(!isset($libraries[$this->session->caseLib]))
+ {
+ $this->session->set('caseLib', key($libraries));
+ $libID = $this->session->caseLib;
+ }
+ return $this->session->caseLib;
+ }
+
+ /**
+ * Get caselib info by id.
+ *
+ * @param int $libID
+ * @param bool $setImgSize
+ * @access public
+ * @return object
+ */
+ public function getById($libID, $setImgSize = false)
+ {
+ $lib = $this->dao->select('*')->from(TABLE_TESTSUITE)->where('id')->eq((int)$libID)->fetch();
+ $lib = $this->loadModel('file')->replaceImgURL($lib, 'desc');
+ if($setImgSize) $lib->desc = $this->file->setImgSize($lib->desc);
+ return $lib;
+ }
+
+ /**
+ * Update a caselib.
+ *
+ * @param int $libID
+ * @access public
+ * @return bool|array
+ */
+ public function update($libID)
+ {
+ $oldLib = $this->dao->select("*")->from(TABLE_TESTSUITE)->where('id')->eq((int)$libID)->fetch();
+ $lib = fixer::input('post')
+ ->stripTags($this->config->caselib->editor->edit['id'], $this->config->allowedTags)
+ ->add('lastEditedBy', $this->app->user->account)
+ ->add('lastEditedDate', helper::now())
+ ->remove('uid')
+ ->get();
+ $lib = $this->loadModel('file')->processImgURL($lib, $this->config->caselib->editor->edit['id'], $this->post->uid);
+ $this->dao->update(TABLE_TESTSUITE)->data($lib)
+ ->autoCheck()
+ ->batchcheck($this->config->caselib->edit->requiredFields, 'notempty')
+ ->where('id')->eq($libID)
+ ->exec();
+ if(!dao::isError())
+ {
+ $this->file->updateObjectID($this->post->uid, $libID, 'caselib');
+ return common::createChanges($oldLib, $lib);
+ }
+ return false;
+ }
+
+ /**
+ * Delete library.
+ *
+ * @param int $libID
+ * @param string $table
+ * @access public
+ * @return bool
+ */
+ public function delete($libID, $table = '')
+ {
+ $this->dao->update(TABLE_TESTSUITE)->set('deleted')->eq(1)->where('id')->eq($libID)->exec();
+
+ $this->loadModel('action');
+ $this->action->create('caselib', $libID, 'deleted', '', ACTIONMODEL::CAN_UNDELETED);
+ }
+
+ /**
+ * Get libraries.
+ *
+ * @access public
+ * @return array
+ */
+ public function getLibraries()
+ {
+ return $this->dao->select("id,name")->from(TABLE_TESTSUITE)
+ ->where('product')->eq(0)
+ ->andWhere('deleted')->eq(0)
+ ->andWhere('type')->eq('library')
+ ->orderBy('id_desc')
+ ->fetchPairs('id', 'name');
+ }
+
+ /**
+ * Create lib.
+ *
+ * @access public
+ * @return int
+ */
+ public function create()
+ {
+ $lib = fixer::input('post')
+ ->stripTags($this->config->caselib->editor->create['id'], $this->config->allowedTags)
+ ->setForce('type', 'library')
+ ->add('addedBy', $this->app->user->account)
+ ->add('addedDate', helper::now())
+ ->remove('uid')
+ ->get();
+ $lib = $this->loadModel('file')->processImgURL($lib, $this->config->caselib->editor->create['id'], $this->post->uid);
+ $this->dao->insert(TABLE_TESTSUITE)->data($lib)
+ ->batchcheck($this->config->caselib->create->requiredFields, 'notempty')
+ ->check('name', 'unique', "deleted = '0'")
+ ->exec();
+ if(!dao::isError())
+ {
+ $libID = $this->dao->lastInsertID();
+ $this->file->updateObjectID($this->post->uid, $libID, 'caselib');
+ return $libID;
+ }
+ return false;
+ }
+
+ /**
+ * Get lib cases.
+ *
+ * @param int $libID
+ * @param string $browseType
+ * @param int $queryID
+ * @param int $moduleID
+ * @param string $sort
+ * @param object $pager
+ * @access public
+ * @return array
+ */
+ public function getLibCases($libID, $browseType, $queryID = 0, $moduleID = 0, $sort = 'id_desc', $pager = null)
+ {
+ $moduleIdList = $moduleID ? $this->loadModel('tree')->getAllChildId($moduleID) : '0';
+ $browseType = ($browseType == 'bymodule' and $this->session->libBrowseType and $this->session->libBrowseType != 'bysearch') ? $this->session->libBrowseType : $browseType;
+
+ $cases = array();
+ if($browseType == 'bymodule' or $browseType == 'all' or $browseType == 'wait')
+ {
+ $cases = $this->dao->select('*')->from(TABLE_CASE)
+ ->where('lib')->eq((int)$libID)
+ ->andWhere('product')->eq(0)
+ ->beginIF($moduleIdList)->andWhere('module')->in($moduleIdList)->fi()
+ ->beginIF($browseType == 'wait')->andWhere('status')->eq($browseType)->fi()
+ ->andWhere('deleted')->eq('0')
+ ->orderBy($sort)->page($pager)->fetchAll('id');
+ }
+ /* By search. */
+ elseif($browseType == 'bysearch')
+ {
+ if($queryID)
+ {
+ $query = $this->loadModel('search')->getQuery($queryID);
+ $this->session->set('caselibQuery', ' 1 = 1');
+ if($query)
+ {
+ $this->session->set('caselibQuery', $query->sql);
+ $this->session->set('caselibForm', $query->form);
+ }
+ }
+ else
+ {
+ if($this->session->caselibQuery == false) $this->session->set('caselibQuery', ' 1 = 1');
+ }
+
+ $queryLibID = $libID;
+ $allLib = "`lib` = 'all'";
+ $caseQuery = '(' . $this->session->caselibQuery;
+ if(strpos($this->session->caselibQuery, $allLib) !== false)
+ {
+ $caseQuery = str_replace($allLib, '1', $caseQuery);
+ $queryLibID = 'all';
+ }
+ $caseQuery .= ')';
+
+ $cases = $this->dao->select('*')->from(TABLE_CASE)->where($caseQuery)
+ ->beginIF($queryLibID != 'all')->andWhere('lib')->eq((int)$libID)->fi()
+ ->andWhere('product')->eq(0)
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($sort)->page($pager)->fetchAll();
+
+ }
+ return $cases;
+ }
+
+ /**
+ * Build search form.
+ *
+ * @param int $libID
+ * @param array $libraries
+ * @param int $queryID
+ * @param string $actionURL
+ * @access public
+ * @return void
+ */
+ public function buildSearchForm($libID, $libraries, $queryID, $actionURL)
+ {
+ $this->config->testcase->search['fields']['lib'] = $this->lang->testcase->lib;
+ $this->config->testcase->search['params']['lib']['values'] = array('' => '', $libID => $libraries[$libID], 'all' => $this->lang->caselib->all);
+ $this->config->testcase->search['params']['lib']['operator'] = '=';
+ $this->config->testcase->search['params']['lib']['control'] = 'select';
+ $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($libID, $viewType = 'caselib');
+ if(!$this->config->testcase->needReview) unset($this->config->testcase->search['params']['status']['values']['wait']);
+ unset($this->config->testcase->search['fields']['product']);
+ unset($this->config->testcase->search['params']['product']);
+ unset($this->config->testcase->search['fields']['branch']);
+ unset($this->config->testcase->search['params']['branch']);
+ unset($this->config->testcase->search['fields']['lastRunner']);
+ unset($this->config->testcase->search['params']['lastRunner']);
+ unset($this->config->testcase->search['fields']['lastRunResult']);
+ unset($this->config->testcase->search['params']['lastRunResult']);
+ unset($this->config->testcase->search['fields']['lastRunDate']);
+ unset($this->config->testcase->search['params']['lastRunDate']);
+
+ $this->config->testcase->search['module'] = 'caselib';
+ $this->config->testcase->search['actionURL'] = $actionURL;
+ $this->config->testcase->search['queryID'] = $queryID;
+
+ $this->loadModel('search')->setSearchParams($this->config->testcase->search);
+ }
+
+ /**
+ * Get lib link.
+ *
+ * @param string $module
+ * @param string $method
+ * @param string $extra
+ * @access public
+ * @return string
+ */
+ public function getLibLink($module, $method, $extra)
+ {
+ $link = '';
+ if($module == 'caselib')
+ {
+ if($module == 'caselib' && ($method == 'create'))
+ {
+ $link = helper::createLink($module, 'browse', "libID=%s");
+ }
+ else
+ {
+ $link = helper::createLink($module, $method, "libID=%s");
+ }
+ }
+ else if($module == 'tree')
+ {
+ $link = helper::createLink($module, $method, "libID=%s&type=caselib¤tModuleID=0");
+ }
+ else
+ {
+ $link = helper::createLink('caselib', 'browse', "libID=%s");
+ }
+ return $link;
+ }
+
+ /**
+ * Create from import.
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function createFromImport($libID)
+ {
+ $this->loadModel('action');
+ $this->loadModel('testcase');
+ $this->loadModel('file');
+ $now = helper::now();
+ $data = fixer::input('post')->get();
+
+ if(!empty($_POST['id']))
+ {
+ $oldSteps = $this->dao->select('t2.*')->from(TABLE_CASE)->alias('t1')
+ ->leftJoin(TABLE_CASESTEP)->alias('t2')->on('t1.id = t2.case')
+ ->where('t1.id')->in(($_POST['id']))
+ ->andWhere('t1.version=t2.version')
+ ->orderBy('t2.id')
+ ->fetchGroup('case');
+ $oldCases = $this->dao->select('*')->from(TABLE_CASE)->where('id')->in($_POST['id'])->fetchAll('id');
+ }
+
+ $cases = array();
+ foreach($data->lib as $key => $lib)
+ {
+ $caseData = new stdclass();
+
+ $caseData->lib = $lib;
+ $caseData->module = $data->module[$key];
+ $caseData->title = $data->title[$key];
+ $caseData->pri = (int)$data->pri[$key];
+ $caseData->type = $data->type[$key];
+ $caseData->status = $data->status[$key];
+ $caseData->stage = join(',', $data->stage[$key]);
+ $caseData->keywords = $data->keywords[$key];
+ $caseData->frequency = 1;
+ $caseData->precondition = $data->precondition[$key];
+
+ if(isset($this->config->testcase->create->requiredFields))
+ {
+ $requiredFields = explode(',', $this->config->testcase->create->requiredFields);
+ foreach($requiredFields as $requiredField)
+ {
+ $requiredField = trim($requiredField);
+ if(empty($caseData->$requiredField)) dao::$errors[] = sprintf($this->lang->testcase->noRequire, $key, $this->lang->testcase->$requiredField);
+ }
+ }
+
+ $cases[$key] = $caseData;
+ }
+ if(dao::isError()) die(js::error(dao::getError()));
+
+ $forceNotReview = $this->testcase->forceNotReview();
+ foreach($cases as $key => $caseData)
+ {
+ if(!empty($_POST['id'][$key]) and empty($_POST['insert']))
+ {
+ $caseID = $data->id[$key];
+ $stepChanged = false;
+ $steps = array();
+ $oldStep = isset($oldSteps[$caseID]) ? $oldSteps[$caseID] : array();
+ $oldCase = $oldCases[$caseID];
+
+ /* Remove the empty setps in post. */
+ $steps = array();
+ if(isset($_POST['desc'][$key]))
+ {
+ foreach($data->desc[$key] as $id => $desc)
+ {
+ $desc = trim($desc);
+ if(empty($desc)) continue;
+ $step = new stdclass();
+ $step->type = $data->stepType[$key][$id];
+ $step->desc = $desc;
+ $step->expect = trim($data->expect[$key][$id]);
+
+ $steps[] = $step;
+ }
+ }
+
+ /* If step count changed, case changed. */
+ if((!$oldStep != !$steps) or (count($oldStep) != count($steps)))
+ {
+ $stepChanged = true;
+ }
+ else
+ {
+ /* Compare every step. */
+ foreach($oldStep as $id => $oldStep)
+ {
+ if(trim($oldStep->desc) != trim($steps[$id]->desc) or trim($oldStep->expect) != $steps[$id]->expect)
+ {
+ $stepChanged = true;
+ break;
+ }
+ }
+ }
+
+ $version = $stepChanged ? $oldCase->version + 1 : $oldCase->version;
+ $caseData->version = $version;
+ $changes = common::createChanges($oldCase, $caseData);
+ if(!$changes and !$stepChanged) continue;
+
+ if($changes or $stepChanged)
+ {
+ $caseData->lastEditedBy = $this->app->user->account;
+ $caseData->lastEditedDate = $now;
+ if($stepChanged and !$forceNotReview) $caseData->status = 'wait';
+ $this->dao->update(TABLE_CASE)->data($caseData)->where('id')->eq($caseID)->autoCheck()->exec();
+ if($stepChanged)
+ {
+ $parentStepID = 0;
+ foreach($steps as $id => $step)
+ {
+ $step = (array)$step;
+ if(empty($step['desc'])) continue;
+ $stepData = new stdclass();
+ $stepData->type = ($step['type'] == 'item' and $parentStepID == 0) ? 'step' : $step['type'];
+ $stepData->parent = ($stepData->type == 'item') ? $parentStepID : 0;
+ $stepData->case = $caseID;
+ $stepData->version = $version;
+ $stepData->desc = $step['desc'];
+ $stepData->expect = $step['expect'];
+ $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec();
+ if($stepData->type == 'group') $parentStepID = $this->dao->lastInsertID();
+ if($stepData->type == 'step') $parentStepID = 0;
+ }
+ }
+ $oldCase->steps = $this->testcase->joinStep($oldStep);
+ $caseData->steps = $this->testcase->joinStep($steps);
+ $changes = common::createChanges($oldCase, $caseData);
+ $actionID = $this->action->create('case', $caseID, 'Edited');
+ $this->action->logHistory($actionID, $changes);
+ }
+ }
+ else
+ {
+ $caseData->version = 1;
+ $caseData->openedBy = $this->app->user->account;
+ $caseData->openedDate = $now;
+ $caseData->status = $forceNotReview ? 'normal' : 'wait';
+ $this->dao->insert(TABLE_CASE)->data($caseData)->autoCheck()->exec();
+
+ if(!dao::isError())
+ {
+ $caseID = $this->dao->lastInsertID();
+ $parentStepID = 0;
+ foreach($data->desc[$key] as $id => $desc)
+ {
+ $desc = trim($desc);
+ if(empty($desc)) continue;
+ $stepData = new stdclass();
+ $stepData->type = ($data->stepType[$key][$id] == 'item' and $parentStepID == 0) ? 'step' : $data->stepType[$key][$id];
+ $stepData->parent = ($stepData->type == 'item') ? $parentStepID : 0;
+ $stepData->case = $caseID;
+ $stepData->version = 1;
+ $stepData->desc = $desc;
+ $stepData->expect = $data->expect[$key][$id];
+ $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec();
+ if($stepData->type == 'group') $parentStepID = $this->dao->lastInsertID();
+ if($stepData->type == 'step') $parentStepID = 0;
+ }
+ $this->action->create('case', $caseID, 'Opened');
+ }
+ }
+ }
+
+ unlink($this->session->importFile);
+ unset($_SESSION['importFile']);
+ }
+
+ /**
+ * Batch create case for lib.
+ *
+ * @param int $libID
+ * @access public
+ * @return void
+ */
+ public function batchCreateCase($libID)
+ {
+ $this->loadModel('testcase');
+ $this->loadModel('action');
+
+ $now = helper::now();
+ $cases = fixer::input('post')->get();
+ $batchNum = count(reset($cases));
+
+ $result = $this->loadModel('common')->removeDuplicate('case', $cases, "lib={$libID}");
+ $cases = $result['data'];
+
+ for($i = 0; $i < $batchNum; $i++)
+ {
+ if(!empty($cases->title[$i]) and empty($cases->type[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->testcase->type)));
+ }
+
+ $module = 0;
+ $type = '';
+ $pri = 3;
+ for($i = 0; $i < $batchNum; $i++)
+ {
+ $module = $cases->module[$i] == 'ditto' ? $module : $cases->module[$i];
+ $type = $cases->type[$i] == 'ditto' ? $type : $cases->type[$i];
+ $pri = $cases->pri[$i] == 'ditto' ? $pri : $cases->pri[$i];
+ $cases->module[$i] = (int)$module;
+ $cases->type[$i] = $type;
+ $cases->pri[$i] = $pri;
+ }
+
+ $forceNotReview = $this->testcase->forceNotReview();
+ for($i = 0; $i < $batchNum; $i++)
+ {
+ if($cases->type[$i] != '' and $cases->title[$i] != '')
+ {
+ $data[$i] = new stdclass();
+ $data[$i]->lib = $libID;
+ $data[$i]->module = $cases->module[$i];
+ $data[$i]->type = $cases->type[$i];
+ $data[$i]->pri = $cases->pri[$i];
+ $data[$i]->stage = empty($cases->stage[$i]) ? '' : implode(',', $cases->stage[$i]);
+ $data[$i]->color = $cases->color[$i];
+ $data[$i]->title = $cases->title[$i];
+ $data[$i]->precondition = $cases->precondition[$i];
+ $data[$i]->keywords = $cases->keywords[$i];
+ $data[$i]->openedBy = $this->app->user->account;
+ $data[$i]->openedDate = $now;
+ $data[$i]->status = $forceNotReview ? 'normal' : 'wait';
+ $data[$i]->version = 1;
+
+ $this->dao->insert(TABLE_CASE)->data($data[$i])
+ ->autoCheck()
+ ->batchCheck($this->config->testcase->create->requiredFields, 'notempty')
+ ->exec();
+
+ if(dao::isError())
+ {
+ echo js::error(dao::getError());
+ die(js::reload('parent'));
+ }
+
+ $caseID = $this->dao->lastInsertID();
+ $actionID = $this->action->create('case', $caseID, 'Opened');
+ }
+ }
+ }
+}
diff --git a/module/testsuite/view/ajaxgetdropmenu.html.php b/module/caselib/view/ajaxgetdropmenu.html.php
similarity index 100%
rename from module/testsuite/view/ajaxgetdropmenu.html.php
rename to module/caselib/view/ajaxgetdropmenu.html.php
diff --git a/module/testsuite/view/batchcreatecase.html.php b/module/caselib/view/batchcreatecase.html.php
similarity index 98%
rename from module/testsuite/view/batchcreatecase.html.php
rename to module/caselib/view/batchcreatecase.html.php
index 1c211b319d..86c08b124f 100644
--- a/module/testsuite/view/batchcreatecase.html.php
+++ b/module/caselib/view/batchcreatecase.html.php
@@ -1,11 +1,11 @@
- * @package testsuite
+ * @package caselib
* @version $Id$
* @link http://www.zentao.net
*/
diff --git a/module/testsuite/view/library.html.php b/module/caselib/view/browse.html.php
similarity index 87%
rename from module/testsuite/view/library.html.php
rename to module/caselib/view/browse.html.php
index 1f1cee3ef4..c989800fac 100644
--- a/module/testsuite/view/library.html.php
+++ b/module/caselib/view/browse.html.php
@@ -1,11 +1,11 @@
- * @package testsuite
+ * @package caselib
* @version $Id: library.html.php 5108 2013-07-12 01:59:04Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
@@ -15,7 +15,7 @@ include '../../common/view/header.html.php';
include '../../common/view/datatable.fix.html.php';
js::set('browseType', $browseType);
js::set('moduleID', $moduleID);
-js::set('confirmDelete', $lang->testsuite->confirmDelete);
+js::set('confirmDelete', $lang->testcase->confirmDelete);
js::set('batchDelete', $lang->testcase->confirmBatchDelete);
js::set('flow', $config->global->flow);
?>
@@ -36,29 +36,29 @@ js::set('flow', $config->global->flow);
@@ -69,7 +69,7 @@ js::set('flow', $config->global->flow);
- testsuite->noModule;?>
+ caselib->noModule;?>
@@ -86,8 +86,8 @@ js::set('flow', $config->global->flow);
testcase->noCase;?>
-
- createLink('testsuite', 'createCase', "libID=$libID&moduleID=" . (isset($moduleID) ? $moduleID : 0)), " " . $lang->testcase->create, '', "class='btn btn-info'");?>
+
+ createLink('caselib', 'createCase', "libID=$libID&moduleID=" . (isset($moduleID) ? $moduleID : 0)), " " . $lang->testcase->create, '', "class='btn btn-info'");?>
diff --git a/module/testsuite/view/createlib.html.php b/module/caselib/view/create.html.php
similarity index 83%
rename from module/testsuite/view/createlib.html.php
rename to module/caselib/view/create.html.php
index f1b96e6ffe..21d55a3eac 100644
--- a/module/testsuite/view/createlib.html.php
+++ b/module/caselib/view/create.html.php
@@ -1,11 +1,11 @@
- * @package testsuite
+ * @package caselib
* @version $Id: create.html.php 4728 2013-05-03 06:14:34Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
@@ -15,16 +15,16 @@
- testsuite->createLib;?>
+ caselib->create;?>
|