diff --git a/db/demo.sql b/db/demo.sql index b03a8e5f4e..5e6f3d6366 100644 --- a/db/demo.sql +++ b/db/demo.sql @@ -585,13 +585,13 @@ INSERT INTO `zt_searchindex` (`id`, `objectType`, `objectID`, `title`, `content` (40, 'task', 16, ' 21806 21518 26381 21153 30340 35774 35745', ' 21806 21518 26381 21153 30340 35774 35745', '2021-04-28 13:16:15', '2021-04-28 13:16:15'), (41, 'task', 17, ' 21806 21518 26381 21153 30340 24320 21457', ' 21806 21518 26381 21153 30340 24320 21457', '2021-04-28 13:16:15', '2021-04-28 13:16:15'); INSERT INTO `zt_story` (`id`, `parent`, `product`, `branch`, `module`, `plan`, `source`, `sourceNote`, `fromBug`, `title`, `keywords`, `type`, `pri`, `estimate`, `status`, `subStatus`, `color`, `stage`, `stagedBy`, `mailto`, `openedBy`, `openedDate`, `assignedTo`, `assignedDate`, `lastEditedBy`, `lastEditedDate`, `reviewedBy`, `reviewedDate`, `closedBy`, `closedDate`, `closedReason`, `toBug`, `childStories`, `linkStories`, `duplicateStory`, `version`, `URChanged`, `deleted`) VALUES -(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'), -(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'); +(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'), +(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'); INSERT INTO `zt_storyspec` (`story`, `version`, `title`, `spec`, `verify`) VALUES (1, 1, '首页设计和开发', '作为一名本公司的用户,我希望可以在首页看到该公司网站的基本内容,例如最新动态、部分成果展示、联系信息、工商信息等。
', '开发并通过验收
'), (2, 1, '新闻中心的设计和开发。', '作为一名本公司的用户,我希望可以在新闻中心看到该公司网站的企业新闻,这样可以通过新闻了解企业的最新动态。
', ''), diff --git a/db/endemo.sql b/db/endemo.sql index b03a8e5f4e..5e6f3d6366 100644 --- a/db/endemo.sql +++ b/db/endemo.sql @@ -585,13 +585,13 @@ INSERT INTO `zt_searchindex` (`id`, `objectType`, `objectID`, `title`, `content` (40, 'task', 16, ' 21806 21518 26381 21153 30340 35774 35745', ' 21806 21518 26381 21153 30340 35774 35745', '2021-04-28 13:16:15', '2021-04-28 13:16:15'), (41, 'task', 17, ' 21806 21518 26381 21153 30340 24320 21457', ' 21806 21518 26381 21153 30340 24320 21457', '2021-04-28 13:16:15', '2021-04-28 13:16:15'); INSERT INTO `zt_story` (`id`, `parent`, `product`, `branch`, `module`, `plan`, `source`, `sourceNote`, `fromBug`, `title`, `keywords`, `type`, `pri`, `estimate`, `status`, `subStatus`, `color`, `stage`, `stagedBy`, `mailto`, `openedBy`, `openedDate`, `assignedTo`, `assignedDate`, `lastEditedBy`, `lastEditedDate`, `reviewedBy`, `reviewedDate`, `closedBy`, `closedDate`, `closedReason`, `toBug`, `childStories`, `linkStories`, `duplicateStory`, `version`, `URChanged`, `deleted`) VALUES -(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'), -(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), -(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'); +(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'), +(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'), +(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'); INSERT INTO `zt_storyspec` (`story`, `version`, `title`, `spec`, `verify`) VALUES (1, 1, '首页设计和开发', '作为一名本公司的用户,我希望可以在首页看到该公司网站的基本内容,例如最新动态、部分成果展示、联系信息、工商信息等。
', '开发并通过验收
'), (2, 1, '新闻中心的设计和开发。', '作为一名本公司的用户,我希望可以在新闻中心看到该公司网站的企业新闻,这样可以通过新闻了解企业的最新动态。
', ''), diff --git a/db/update15.0.sql b/db/update15.0.sql index 3330e6304c..f5ac829f93 100644 --- a/db/update15.0.sql +++ b/db/update15.0.sql @@ -23,5 +23,6 @@ ALTER TABLE `zt_project` CHANGE `lifetime` `lifetime` char(30) NOT NULL DEFAULT ALTER TABLE `zt_story` ADD `category` varchar(30) NOT NULL DEFAULT 'feature' AFTER `type`; ALTER TABLE `zt_testtask` ADD `type` varchar(255) NOT NULL DEFAULT '' AFTER `build`; ALTER TABLE `zt_testtask` ADD `testreport` mediumint(8) unsigned NOT NULL AFTER `status`; +ALTER TABLE `zt_story` MODIFY COLUMN `reviewedDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'; INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'story', '', 'reivewRules', 'allpass'); diff --git a/db/zentao.sql b/db/zentao.sql index da1d3b5cc9..655eb84b1e 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -838,7 +838,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` ( `lastEditedBy` varchar(30) NOT NULL default '', `lastEditedDate` datetime NOT NULL, `reviewedBy` varchar(255) NOT NULL, - `reviewedDate` date NOT NULL, + `reviewedDate` datetime NOT NULL default '0000-00-00 00:00:00', `closedBy` varchar(30) NOT NULL default '', `closedDate` datetime NOT NULL, `closedReason` varchar(30) NOT NULL, diff --git a/lib/spliter/spliter.class.php b/lib/spliter/spliter.class.php index c630596a22..f1ad87b7b8 100644 --- a/lib/spliter/spliter.class.php +++ b/lib/spliter/spliter.class.php @@ -8,22 +8,22 @@ * @package spliter * @version $Id$ * @link http://www.chanzhi.org - * @see http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html + * @see http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html * @see http://stackoverflow.com/questions/9361303/can-i-get-the-unicode-value-of-a-character-or-vise-versa-with-php */ class spliter { /** * Split a utf-8 string into words, computing unicode for every word. - * - * @param string $string + * + * @param string $string * @access public * @return array */ public function utf8Split($string) { $string = strtolower($string); - $i = 0; + $i = 0; $length = strlen($string); $dict = array(); $words = ''; @@ -50,12 +50,16 @@ class spliter $word .= $letter; $i++; } - + /* Process intigers. */ if(is_numeric($word) and (strpos($word, '.') === false)) $word = "|" . $word . "|"; $word = str_pad(strtolower($word), 5, '_'); $words .= ' ' . $word; } + elseif($ord == 32) + { + $words .= ' '; + } continue; } @@ -76,7 +80,14 @@ class spliter } else { - $words .= ' ' . $letter; + if(is_numeric(substr($words, strlen($words) - 1, 1))) + { + $words .= ' ' . $letter; + } + else + { + $words .= $letter; + } } $i += $offset; } @@ -86,13 +97,13 @@ class spliter } /** - * Return unicode value for a char. - * - * @param string $c + * Return unicode value for a char. + * + * @param string $c * @access public * @return int */ - public function unicode($c) + public function unicode($c) { if(ord($c{0}) >= 0 && ord($c{0}) <= 127) return ord($c{0}); if(ord($c{0}) >= 192 && ord($c{0}) <= 223) return (ord($c{0}) - 192) * 64 + (ord($c{1}) - 128); @@ -107,8 +118,8 @@ class spliter /** * Judge a char is Letter or not. - * - * @param string $letter + * + * @param string $letter * @access public * @return bool */ diff --git a/module/action/model.php b/module/action/model.php index db65634494..1d365c3063 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -220,8 +220,9 @@ class actionModel extends model if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project'); if($objectType == 'team') { - $team = $this->dao->select('type,root')->from(TABLE_TEAM)->where('id')->eq($objectID)->fetch(); - $record->{$team->type} = $team->root; + $team = $this->dao->select('type')->from(TABLE_PROJECT)->where('id')->eq($objectID)->fetch(); + $type = $team->type == 'project' ? 'project' : 'execution'; + $record->$type = $objectID; } if($objectType == 'task') { @@ -627,7 +628,11 @@ class actionModel extends model */ if(empty($desc)) { - if(isset($this->lang->$objectType) && isset($this->lang->$objectType->action->$actionType)) + if($action->objectType == 'story' and $action->action = 'reviewed' and strpos($action->extra, ',') !== false) + { + $desc = $this->lang->$objectType->action->rejectreviewed; + } + elseif(isset($this->lang->$objectType) && isset($this->lang->$objectType->action->$actionType)) { $desc = $this->lang->$objectType->action->$actionType; } @@ -668,14 +673,23 @@ class actionModel extends model /* Fix bug #741. */ if(isset($desc['extra'])) $desc['extra'] = $this->lang->$objectType->{$desc['extra']}; + $actionDesc = ''; if(isset($desc['extra'][$extra])) { - echo str_replace('$extra', $desc['extra'][$extra], $desc['main']); + $actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']); } else { - echo str_replace('$extra', $action->extra, $desc['main']); + $actionDesc = str_replace('$extra', $action->extra, $desc['main']); } + + if($action->objectType == 'story' and $action->action = 'reviewed' and strpos($action->extra, ',') !== false) + { + list($extra, $reason) = explode(',', $extra); + $desc['reason'] = $this->lang->$objectType->{$desc['reason']}; + $actionDesc = str_replace(array('$extra', '$reason'), array($desc['extra'][$extra], $desc['reason'][$reason]), $desc['main']); + } + echo $actionDesc; } else { @@ -944,16 +958,15 @@ class actionModel extends model } elseif($objectType == 'team') { - $objectInfo = $this->dao->select('t1.id as projectID,t2.id,t1.team as name,t1.type')->from(TABLE_PROJECT)->alias('t1') - ->leftJoin(TABLE_TEAM)->alias('t2')->on('t1.id=t2.root') - ->where('t2.id')->in($objectIds) + $objectInfo = $this->dao->select('id,team,type')->from(TABLE_PROJECT) + ->where('id')->in($objectIds) ->fetchAll(); $objectProject = array(); foreach($objectInfo as $object) { - $objectName[$object->id] = $object->name; - if($object->type == 'project') $objectProject[$object->id] = $object->projectID; + $objectName[$object->id] = $object->team; + if($object->type == 'project') $objectProject[$object->id] = $object->id; } } else diff --git a/module/execution/control.php b/module/execution/control.php index 2a2e177b79..660ac89976 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -2188,8 +2188,7 @@ class execution extends control if(!empty($_POST)) { $this->execution->manageMembers($executionID); - $teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq('execution')->fetch('id'); - $this->loadModel('action')->create('team', $teamID, 'managedTeam'); + $this->loadModel('action')->create('team', $executionID, 'managedTeam'); die(js::locate($this->createLink('execution', 'team', "executionID=$executionID"), 'parent')); } @@ -2258,8 +2257,7 @@ class execution extends control $this->execution->unlinkMember($executionID, $account); if(!dao::isError()) { - $teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq('execution')->fetch('id'); - $this->loadModel('action')->create('team', $teamID, 'managedTeam'); + $this->loadModel('action')->create('team', $executionID, 'managedTeam'); } /* if ajax request, send result. */ diff --git a/module/execution/js/storyestimate.js b/module/execution/js/storyestimate.js index 66712db016..98b0e4c576 100644 --- a/module/execution/js/storyestimate.js +++ b/module/execution/js/storyestimate.js @@ -39,6 +39,7 @@ function showNewEstimate() $('.th-new-estimate').removeClass('hide'); $('.new-estimate').removeClass('hide'); $('.form-actions').removeClass('hide'); + $('.empty-th').addClass('hide'); } function selectRound(round) diff --git a/module/execution/lang/de.php b/module/execution/lang/de.php index b0e44956c8..54e8c5b89c 100644 --- a/module/execution/lang/de.php +++ b/module/execution/lang/de.php @@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc $lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}"; $lang->execution->recent = 'Recent visits: '; $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.'; +$lang->execution->noTeam = 'No team members at the moment'; $lang->execution->start = 'Start'; $lang->execution->activate = 'Aktivieren'; diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index 347830d1b7..9589f58a7f 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc $lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}"; $lang->execution->recent = 'Recent visits: '; $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.'; +$lang->execution->noTeam = 'No team members at the moment'; $lang->execution->start = 'Start'; $lang->execution->activate = 'Activate'; diff --git a/module/execution/lang/fr.php b/module/execution/lang/fr.php index 2c52374fcb..304a5852e3 100644 --- a/module/execution/lang/fr.php +++ b/module/execution/lang/fr.php @@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc $lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}"; $lang->execution->recent = 'Recent visits: '; $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.'; +$lang->execution->noTeam = 'No team members at the moment'; $lang->execution->start = 'Démarrer'; $lang->execution->activate = 'Activer'; diff --git a/module/execution/lang/vi.php b/module/execution/lang/vi.php index 60dc6326c8..c65291be2c 100644 --- a/module/execution/lang/vi.php +++ b/module/execution/lang/vi.php @@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc $lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}"; $lang->execution->recent = 'Recent visits: '; $lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.'; +$lang->execution->noTeam = 'No team members at the moment'; $lang->execution->start = 'Bắt đầu'; $lang->execution->activate = 'Kích hoạt'; diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index fd1c351c39..6b1123d757 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -95,6 +95,7 @@ $lang->execution->oneProduct = "阶段只能关联一个{$lang->productComm $lang->execution->noLinkProduct = "阶段没有关联{$lang->productCommon}"; $lang->execution->recent = '近期访问:'; $lang->execution->copyNoExecution = '没有可用的' . $lang->executionCommon . '来复制'; +$lang->execution->noTeam = '暂时没有团队成员'; $lang->execution->start = "开始"; $lang->execution->activate = "激活"; diff --git a/module/execution/view/storyestimate.html.php b/module/execution/view/storyestimate.html.php index fd35adfca8..6dd16183d4 100644 --- a/module/execution/view/storyestimate.html.php +++ b/module/execution/view/storyestimate.html.php @@ -22,6 +22,11 @@

execution->storyEstimate;?>

+ +
+

execution->noTeam;?>

+
+
@@ -37,9 +42,10 @@ - - - + + + + @@ -76,5 +82,6 @@
execution->team;?> story->estimate;?>execution->newEstimate;?>execution->team;?> story->estimate;?>execution->newEstimate;?>
+
diff --git a/module/project/control.php b/module/project/control.php index 6e7fc98f29..393b90ff95 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1094,8 +1094,7 @@ class project extends control if(!empty($_POST)) { $this->project->manageMembers($projectID); - $teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($projectID)->andWhere('type')->eq('project')->fetch('id'); - $this->loadModel('action')->create('team', $teamID, 'ManagedTeam'); + $this->loadModel('action')->create('team', $projectID, 'ManagedTeam'); $link = $this->createLink('project', 'manageMembers', "projectID=$projectID"); $this->send(array('message' => $this->lang->saveSuccess, 'result' => 'success', 'locate' => $link)); diff --git a/module/search/view/index.html.php b/module/search/view/index.html.php index a0edb58275..724c638fcc 100644 --- a/module/search/view/index.html.php +++ b/module/search/view/index.html.php @@ -60,7 +60,7 @@ adjustMenuWidth();
diff --git a/module/story/config.php b/module/story/config.php index 3d8d626ca2..5db4554810 100644 --- a/module/story/config.php +++ b/module/story/config.php @@ -16,6 +16,7 @@ $config->story->review = new stdclass(); $config->story->create->requiredFields = 'title'; $config->story->change->requiredFields = 'title'; $config->story->close->requiredFields = 'closedReason'; +$config->story->review->requiredFields = ''; $config->story->editor = new stdclass(); $config->story->editor->create = array('id' => 'spec,verify', 'tools' => 'simpleTools'); diff --git a/module/story/control.php b/module/story/control.php index 51feca4f02..628ef68fba 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -609,9 +609,7 @@ class story extends control /* Get users. */ $users = $this->user->getPairs('pofirst|nodeleted', "$story->assignedTo,$story->openedBy,$story->closedBy"); - $reviewedBy = explode(',', trim($story->reviewedBy, ',')); - $reivewerList = ''; - foreach($reviewedBy as $reviewer) $reivewerList .= zget($users, $reviewer) . ' '; + $reviewerList = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->fetchPairs('reviewer'); $this->story->replaceURLang($story->type); @@ -623,7 +621,7 @@ class story extends control $this->view->product = $product; $this->view->products = $myProducts + $othersProducts; $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product); - $this->view->reviewers = $reivewerList; + $this->view->reviewers = implode(',', $reviewerList); $this->display(); } @@ -1004,9 +1002,11 @@ class story extends control if($changes) { - $result = $this->post->result; - $actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result)); - if($result == 'reject') $actionID = $this->action->create('story', $storyID, 'Closed', '', ucfirst($this->post->closedReason)); + $result = $this->post->result; + $reasonParam = $result == 'reject' ? ',' . $this->post->closedReason : ''; + $storyStatus = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch('status'); + $actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result) . $reasonParam); + if($storyStatus == 'closed') $actionID = $this->action->create('story', $storyID, 'ReviewClosed'); $this->action->logHistory($actionID, $changes); } @@ -1041,8 +1041,10 @@ class story extends control } /* Set the review result options. */ + $reviewers = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($story->version)->fetchAll('reviewer'); if($story->status == 'draft' and $story->version == 1) unset($this->lang->story->reviewResultList['revert']); if($story->status == 'changed') unset($this->lang->story->reviewResultList['reject']); + if(count($reviewers) > 1) unset($this->lang->story->reviewResultList['revert']); $this->view->title = $this->lang->story->review . "STORY" . $this->lang->colon . $story->title; $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name); diff --git a/module/story/lang/de.php b/module/story/lang/de.php index 2b48de3e45..944955d760 100644 --- a/module/story/lang/de.php +++ b/module/story/lang/de.php @@ -279,7 +279,9 @@ $lang->story->form->file = 'Wenn Dateien zu dieser Story gehören, laden Sie $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, geprüft von $actor. Das Ergebnis ist $extra.', 'extra' => 'reviewResultList'); +$lang->story->action->rejectreviewed = array('main' => '$date, geprüft von $actor. Das Ergebnis ist $extra, Der Grund ist $reason.', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); $lang->story->action->closed = array('main' => '$date, geschlossen von $actor. Der Grund ist $extra $appendLink.', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, closed by System. The reasion is Review Failed.'); $lang->story->action->linked2plan = array('main' => '$date, verknüpft von $actor mit Plan $extra'); $lang->story->action->unlinkedfromplan = array('main' => '$date, Verknüpfung aufgelöst durch $actor von Plan $extra.'); $lang->story->action->linked2execution = array('main' => '$date, verknüpft von $actor mit ' . $lang->executionCommon . ' $extra.'); diff --git a/module/story/lang/en.php b/module/story/lang/en.php index e20d8d92f9..c86902a956 100644 --- a/module/story/lang/en.php +++ b/module/story/lang/en.php @@ -280,7 +280,9 @@ $lang->story->form->file = 'If any file that is linked to a story, please cl $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, recorded by $actor. The result is $extra.', 'extra' => 'reviewResultList'); +$lang->story->action->rejectreviewed = array('main' => '$date, recorded by $actor. The result is $extra. The reasion is $reason.', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); $lang->story->action->closed = array('main' => '$date, closed by $actor. The reasion is $extra $appendLink.', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, closed by System. The reasion is Review Failed.'); $lang->story->action->linked2plan = array('main' => '$date, linked by $actor to Plan $extra'); $lang->story->action->unlinkedfromplan = array('main' => '$date, unlinked by $actor from Plan $extra.'); $lang->story->action->linked2execution = array('main' => '$date, linked by $actor to ' . $lang->executionCommon . ' $extra.'); diff --git a/module/story/lang/fr.php b/module/story/lang/fr.php index 501459903f..7e3a5794cb 100644 --- a/module/story/lang/fr.php +++ b/module/story/lang/fr.php @@ -279,7 +279,9 @@ $lang->story->form->file = 'Si certains fichiers sont associés à la story, $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, validée par $actor. Le résultat est $extra.', 'extra' => 'reviewResultList'); +$lang->story->action->rejectreviewed = array('main' => '$date, validée par $actor. Le résultat est $extra. La raison est $reason.', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); $lang->story->action->closed = array('main' => '$date, Fermée par $actor. La raison est $extra $appendLink.', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, closed by System. The reasion is Review Failed.'); $lang->story->action->linked2plan = array('main' => '$date, planifiée par $actor au Plan $extra'); $lang->story->action->unlinkedfromplan = array('main' => '$date, déplanifiée par $actor du Plan $extra.'); $lang->story->action->linked2execution = array('main' => '$date, associée au ' . $lang->executionCommon . ' $extra par $actor.'); diff --git a/module/story/lang/vi.php b/module/story/lang/vi.php index 2968e41c96..a7e5817728 100644 --- a/module/story/lang/vi.php +++ b/module/story/lang/vi.php @@ -279,7 +279,9 @@ $lang->story->form->file = 'Nếu bất kỳ tập tin mà liên kết tới $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, ghi nhận bởi $actor. Kết quả là $extra.', 'extra' => 'reviewResultList'); -$lang->story->action->closed = array('main' => '$date, được đóng bởi $actor.Lý do là $extra $appendLink.', 'extra' => 'reasonList'); +$lang->story->action->rejectreviewed = array('main' => '$date, ghi nhận bởi $actor. Kết quả là $extra. Lý do là $reason', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); +$lang->story->action->closed = array('main' => '$date, được đóng bởi $actor. Lý do là $extra $appendLink.', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, closed by System. The reasion is Review Failed.'); $lang->story->action->linked2plan = array('main' => '$date, liên kết bởi $actor tới kế hoạch $extra'); $lang->story->action->unlinkedfromplan = array('main' => '$date, bị hủy bởi $actor từ kế hoạch $extra.'); $lang->story->action->linked2execution = array('main' => '$date, liên kết bởi $actor tới ' . $lang->executionCommon . ' $extra.'); diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index 2d7b0e0819..9396ec8ca8 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -280,7 +280,9 @@ $lang->story->form->file = "附件,如果该{$lang->SRCommon}有相关文 $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, 由 $actor 记录评审结果,结果为 $extra。', 'extra' => 'reviewResultList'); +$lang->story->action->rejectreviewed = array('main' => '$date, 由 $actor 记录评审结果,结果为 $extra,原因为 $reason。', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); $lang->story->action->closed = array('main' => '$date, 由 $actor 关闭,原因为 $extra $appendLink。', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, 由 系统 关闭,原因为 评审失败。'); $lang->story->action->linked2plan = array('main' => '$date, 由 $actor 关联到计划 $extra。'); $lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 从计划 $extra 移除。'); $lang->story->action->linked2execution = array('main' => '$date, 由 $actor 关联到' . $lang->executionCommon . ' $extra。'); diff --git a/module/story/lang/zh-tw.php b/module/story/lang/zh-tw.php index 4deb510ae7..d1e844de88 100644 --- a/module/story/lang/zh-tw.php +++ b/module/story/lang/zh-tw.php @@ -278,7 +278,9 @@ $lang->story->form->file = "附件,如果該{$lang->SRCommon}有相關檔 $lang->story->action = new stdclass(); $lang->story->action->reviewed = array('main' => '$date, 由 $actor 記錄評審結果,結果為 $extra。', 'extra' => 'reviewResultList'); +$lang->story->action->rejectreviewed = array('main' => '$date, 由 $actor 記錄評審結果,結果為 $extra,原因為 $reason。', 'extra' => 'reviewResultList', 'reason' => 'reasonList'); $lang->story->action->closed = array('main' => '$date, 由 $actor 關閉,原因為 $extra $appendLink。', 'extra' => 'reasonList'); +$lang->story->action->reviewclosed = array('main' => '$date, 由 系統 關閉,原因為 評審失敗。'); $lang->story->action->linked2plan = array('main' => '$date, 由 $actor 關聯到計劃 $extra。'); $lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 從計劃 $extra 移除。'); $lang->story->action->linked2execution = array('main' => '$date, 由 $actor 關聯到' . $lang->executionCommon . ' $extra。'); diff --git a/module/story/model.php b/module/story/model.php index 4706b9d1c8..ca11a27c0b 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -670,7 +670,7 @@ class storyModel extends model ->join('mailto', ',') ->join('linkStories', ',') ->join('childStories', ',') - ->remove('files,labels,comment,contactListMenu,stages') + ->remove('files,labels,comment,contactListMenu,stages,reviewer') ->get(); if(isset($story->plan) and is_array($story->plan)) $story->plan = trim(join(',', $story->plan), ','); @@ -785,6 +785,21 @@ class storyModel extends model if(empty($oldStory->plan) or empty($story->plan)) $this->setStage($storyID); // Set new stage for this story. } + /* Update story reviewer. */ + $_POST['reviewer'] = array_filter($_POST['reviewer']); + $this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))->exec(); + $oldReviewerList = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->fetchPairs('reviewer'); + foreach($_POST['reviewer'] as $reviewer) + { + if(in_array($reviewer, $oldReviewerList)) continue; + + $reviewData = new stdclass(); + $reviewData->story = $storyID; + $reviewData->version = $oldStory->version; + $reviewData->reviewer = $reviewer; + $this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec(); + } + unset($oldStory->parent); unset($story->parent); return common::createChanges($oldStory, $story); @@ -1148,15 +1163,15 @@ class storyModel extends model $now = helper::now(); $date = helper::today(); $story = fixer::input('post') - ->setDefault('reviewedDate', $date) ->setDefault('lastEditedBy', $this->app->user->account) ->setDefault('lastEditedDate', $now) ->setIF($this->post->result == 'revert', 'version', $this->post->preVersion) ->setIF($this->post->result == 'revert', 'status', 'active') - ->setIF(strpos($oldStory->reviewedBy, $this->app->user->account) === false, 'reviewedBy', $oldStory->reviewedBy . ',' . $this->app->user->account) ->removeIF($this->post->result != 'reject', 'closedReason, duplicateStory, childStories') ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'duplicate', 'duplicateStory') ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'subdivided', 'childStories') + ->add('reviewedDate', $now) + ->add('reviewedBy', $oldStory->reviewedBy . ',' . $this->app->user->account) ->remove('result,preVersion,comment') ->get(); @@ -1166,36 +1181,41 @@ class storyModel extends model $this->dao->update(TABLE_STORYREVIEW)->set('result')->eq($this->post->result)->set('reviewDate')->eq($now)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->eq($this->app->user->account)->exec(); /* Update the story status by review rules. */ - $passCount = 0; - $rejectCount = 0; - $reviewRule = $this->config->story->reviewRules; $reviewerList = $this->dao->select('reviewer,result')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->fetchPairs('reviewer', 'result'); - foreach($reviewerList as $reviewer => $result) + $reviewedBy = explode(',', trim($story->reviewedBy, ',')); + if(!array_diff(array_keys($reviewerList), $reviewedBy)) { - $passCount = $result == 'pass' ? $passCount + 1 : $passCount; - $rejectCount = $result == 'reject' ? $rejectCount + 1 : $rejectCount; - } - if($reviewRule == 'allpass') - { - if($passCount == count($reviewerList)) $story->status = 'active'; - if($rejectCount == count($reviewerList)) $story->status = 'closed'; - } - if($reviewRule == 'halfpass') - { - if($passCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'active'; - if($rejectCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'closed'; - } - if($story->status == 'closed') - { - $story->closedBy = $this->app->user->account; - $story->closedDate = $now; - $story->assignedTo = 'closed'; - $story->stage = 'closed'; - if($this->post->closedReason == 'done') $story->stage = 'released'; + $passCount = 0; + $rejectCount = 0; + $reviewRule = $this->config->story->reviewRules; + foreach($reviewerList as $reviewer => $result) + { + $passCount = $result == 'pass' ? $passCount + 1 : $passCount; + $rejectCount = $result == 'reject' ? $rejectCount + 1 : $rejectCount; + } + if($reviewRule == 'allpass') + { + if($passCount == count($reviewerList)) $story->status = 'active'; + if($rejectCount == count($reviewerList)) $story->status = 'closed'; + } + if($reviewRule == 'halfpass') + { + if($passCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'active'; + if($rejectCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'closed'; + } + if($story->status == 'closed') + { + $story->closedBy = $this->app->user->account; + $story->closedDate = $now; + $story->assignedTo = 'closed'; + $story->stage = 'closed'; + if($this->post->closedReason == 'done') $story->stage = 'released'; + } } $this->dao->update(TABLE_STORY)->data($story) ->autoCheck() + ->batchCheck($this->config->story->review->requiredFields, 'notempty') ->checkIF($this->post->result == 'reject', 'closedReason', 'notempty') ->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'duplicate', 'duplicateStory', 'notempty') ->where('id')->eq($storyID)->exec(); @@ -3225,10 +3245,11 @@ class storyModel extends model if($story->parent < 0 and $action != 'edit' and $action != 'batchcreate') return false; global $config, $app, $dao; - $reviewers = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->andWhere('result')->ne('pass')->fetchAll('reviewer'); + $notReview = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->andWhere('result')->eq('')->fetchAll('reviewer'); + $reviewers = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->fetchAll('reviewer'); - if($action == 'change') return $story->status != 'closed'; - if($action == 'review') return in_array($app->user->account, array_keys($reviewers)) and ($story->status == 'draft' or $story->status == 'changed'); + if($action == 'change') return (count($reviewers) == 0 || count($notReview) == 0) and $story->status != 'closed'; + if($action == 'review') return in_array($app->user->account, array_keys($notReview)) and ($story->status == 'draft' or $story->status == 'changed'); if($action == 'close') return $story->status != 'closed'; if($action == 'activate') return $story->status == 'closed'; if($action == 'assignto') return $story->status != 'closed'; diff --git a/module/story/view/edit.html.php b/module/story/view/edit.html.php index 7c44d63ec8..37cbc6d09c 100644 --- a/module/story/view/edit.html.php +++ b/module/story/view/edit.html.php @@ -204,12 +204,10 @@ story->assignedTo;?> assignedTo, 'class="form-control chosen"');?> - story->reviewedBy;?> - + - status == 'closed'):?> story->closedBy;?> diff --git a/module/task/model.php b/module/task/model.php index 9f5c409dae..1c52542220 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -836,7 +836,7 @@ class taskModel extends model ->setIF($oldTask->parent < 0, 'estimate', $oldTask->estimate) ->setIF($oldTask->parent < 0, 'left', $oldTask->left) - ->setIF($oldTask->name != $task->name || $oldTask->estStarted != $task->estStarted || $oldTask->deadline != $task->deadline, 'version', $oldTask->version + 1) + ->setIF($oldTask->name != $this->post->name || $oldTask->estStarted != $this->post->estStarted || $oldTask->deadline != $this->post->deadline, 'version', $oldTask->version + 1) ->setDefault('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) @@ -947,7 +947,7 @@ class taskModel extends model } /* Record task version. */ - if($task->version > $oldTask->version) + if(isset($task->version) and $task->version > $oldTask->version) { $taskSpec = new stdClass(); $taskSpec->task = $taskID;