diff --git a/bin/init.bat b/bin/init.bat index 8643144b1e..04f534a605 100644 --- a/bin/init.bat +++ b/bin/init.bat @@ -39,7 +39,11 @@ echo %ztcli% > %baseDir%ztcli.bat echo ztcli.bat ok :: create backup.bat -SET backup= %phpcli% %baseDir%php\backup.php +if %requestType% == 'PATH_INFO' ( + SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/backup-backup.html" +)else ( + SET backup= %phpcli% %baseDir%ztcli "%pmsRoot%/index.php?m=backup&f=backup" +) echo %backup% > %baseDir%backup.bat echo backup.bat ok diff --git a/bin/init.sh b/bin/init.sh index 7dbf98b722..61fc4c5b47 100755 --- a/bin/init.sh +++ b/bin/init.sh @@ -42,7 +42,11 @@ echo $ztcli > $basePath/ztcli.sh echo "ztcli.sh ok" # backup database -backup="$phpcli $basePath/php/backup.php" +if [ $requestType == 'PATH_INFO' ]; then + backup="$phpcli $basePath/ztcli '$pmsRoot/backup-backup.html'"; +else + backup="$phpcli $basePath/ztcli '$pmsRoot/index.php?m=backup&f=backup'"; +fi echo $backup > $basePath/backup.sh echo "backup.sh ok" diff --git a/bin/php/backup.php b/bin/php/backup.php deleted file mode 100755 index 97f7d12e81..0000000000 --- a/bin/php/backup.php +++ /dev/null @@ -1,58 +0,0 @@ -db->host}; port={$config->db->port}; dbname={$config->db->name}"; -$dbh = new PDO($dsn, $config->db->user, $config->db->password, array(PDO::ATTR_PERSISTENT => $config->db->persistant)); -$dbh->exec("SET NAMES {$config->db->encoding}"); -echo "Backuping database,"; -$zdb = new zdb(); -$return = $zdb->dump($dbRawFile); -if($return->result) -{ - $dbZipFile = $destDir . "/" . str_replace("sql", "zip", $dbRawFile); - $archive = new pclzip($dbZipFile); - - if($archive->create($dbRawFile)) - { - unlink($dbRawFile); - echo " successfully saved to $dbZipFile\n"; - } - else - { - die("Error : " . $archive->errorInfo(true)); - } -} -else -{ - echo "Failed to backup database!\n"; -} - -/* Backup the attachments. */ -chdir(dirname(dirname(dirname(__FILE__))) . "/www"); -if(!is_dir('data/upload')) die(" No files needed backup.\n"); - -echo "Backuping files,"; -$attachFile = $destDir . "/" . "file." . date('Ymd', time()) . ".zip"; -$archive = new pclzip($attachFile); -if($archive->create("data/upload", PCLZIP_OPT_REMOVE_PATH, "data")) die(" successfully saved to $attachFile\n"); -die("Error : ".$archive->errorInfo(true)); diff --git a/config/config.php b/config/config.php index 60180e1c8d..b01c02e9c7 100644 --- a/config/config.php +++ b/config/config.php @@ -38,7 +38,7 @@ $config->langs['zh-tw'] = '繁體'; $config->langs['en'] = 'English'; /* 设备类型视图文件前缀。The prefix for view file for different device. */ -$config->devicePrefix['mhtml'] = 'm.'; +$config->devicePrefix['mhtml'] = ''; /* 默认值设置。Default settings. */ $config->default = new stdclass(); diff --git a/config/filter.php b/config/filter.php index ee9d0880b3..66e2c6ce16 100644 --- a/config/filter.php +++ b/config/filter.php @@ -199,3 +199,8 @@ $filter->user->login->get['account'] = 'account'; $filter->user->login->get['lang'] = 'reg::lang'; $filter->user->login->get['password'] = 'reg::any'; $filter->user->edit->get['from'] = 'reg::word'; + +$filter->git->cat->get['repoUrl'] = 'reg::base64'; +$filter->git->diff->get['repoUrl'] = 'reg::base64'; +$filter->svn->cat->get['repoUrl'] = 'reg::base64'; +$filter->svn->diff->get['repoUrl'] = 'reg::base64'; \ No newline at end of file diff --git a/db/update9.6.3.sql b/db/update9.6.3.sql new file mode 100644 index 0000000000..39bc5e846b --- /dev/null +++ b/db/update9.6.3.sql @@ -0,0 +1 @@ +ALTER TABLE `zt_productplan` ADD `order` TEXT NOT NULL AFTER `end`; diff --git a/db/zentao.sql b/db/zentao.sql index affac107d4..bafc633bfb 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -438,6 +438,7 @@ CREATE TABLE IF NOT EXISTS `zt_productplan` ( `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 `plan` (`product`,`end`) @@ -916,7 +917,7 @@ INSERT INTO `zt_group` (`id`, `name`, `role`, `desc`) VALUES (9, 'TOP', 'top', 'for top manager.'), (10, 'OTHERS', 'others', 'for others.'), (11, 'guest', 'guest', 'For guest'), -(12, 'limited', 'limited', 'For limited user'); +(12, 'LIMITED', 'limited', 'For limited user'); INSERT INTO `zt_grouppriv` (`group`, `module`, `method`) VALUES (1, 'action', 'editComment'), diff --git a/module/action/control.php b/module/action/control.php index 4bfd85b965..5916f33db9 100755 --- a/module/action/control.php +++ b/module/action/control.php @@ -104,6 +104,23 @@ class action extends control } } + /** + * Comment. + * + * @param string $objectType + * @param int $objectID + * @access public + * @return void + */ + public function comment($objectType, $objectID) + { + $actionID = $this->action->create($objectType, $objectID, 'Commented', $this->post->comment); + + $moduleName = $objectType == 'case' ? 'testcase' : $objectType; + $this->loadModel($moduleName)->sendmail($objectID, $actionID); + die(js::reload('parent')); + } + /** * Edit comment of a action. * diff --git a/module/action/lang/en.php b/module/action/lang/en.php index c82640c395..34e6c6c784 100755 --- a/module/action/lang/en.php +++ b/module/action/lang/en.php @@ -25,6 +25,7 @@ $lang->action->undelete = 'Restore'; $lang->action->hideOne = 'Hide'; $lang->action->hideAll = 'Hide All'; $lang->action->editComment = 'Edit'; +$lang->action->comment = 'Comment'; $lang->action->trashTips = 'Note: Delete in ZenTao is logic.'; $lang->action->textDiff = 'Text Format'; diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index b03587b84c..7021b27d0d 100755 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -25,6 +25,7 @@ $lang->action->undelete = '还原'; $lang->action->hideOne = '隐藏'; $lang->action->hideAll = '全部隐藏'; $lang->action->editComment = '修改备注'; +$lang->action->comment = '备注'; $lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。'; $lang->action->textDiff = '文本格式'; diff --git a/module/bug/config.php b/module/bug/config.php index 102a38f872..190b518f2d 100644 --- a/module/bug/config.php +++ b/module/bug/config.php @@ -6,7 +6,7 @@ $config->bug->longlife = 7; $config->bug->create = new stdclass(); $config->bug->edit = new stdclass(); $config->bug->resolve = new stdclass(); -$config->bug->create->requiredFields = 'title,openedBuild'; +$config->bug->create->requiredFields = 'title,openedBuild,module'; $config->bug->edit->requiredFields = $config->bug->create->requiredFields; $config->bug->resolve->requiredFields = 'resolution'; diff --git a/module/bug/control.php b/module/bug/control.php index 943a4d29dc..ad93f9e2a3 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -15,7 +15,7 @@ class bug extends control /** * Construct function, load some modules auto. - * + * * @access public * @return void */ @@ -43,7 +43,7 @@ class bug extends control /** * The index page, locate to browse. - * + * * @access public * @return void */ @@ -54,15 +54,15 @@ class bug extends control /** * Browse bugs. - * - * @param int $productID + * + * @param int $productID * @param string $branch - * @param string $browseType - * @param int $param - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID + * @param string $browseType + * @param int $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID * @access public * @return void */ @@ -171,11 +171,11 @@ class bug extends control /** * The report page. - * - * @param int $productID - * @param string $browseType + * + * @param int $productID + * @param string $browseType * @param int $branchID - * @param int $moduleID + * @param int $moduleID * @access public * @return void */ @@ -211,8 +211,8 @@ class bug extends control /** * Create a bug. - * - * @param int $productID + * + * @param int $productID * @param string $extras others params, forexample, projectID=10,moduleID=10 * @access public * @return void @@ -328,6 +328,9 @@ class bug extends control $projectMembers = $this->view->users; } + $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch); + if(empty($moduleOptionMenu)) die(js::locate(helper::createLink('tree', 'browse', "productID=$productID&view=story"))); + /* Set custom. */ foreach(explode(',', $this->config->bug->list->customCreateFields) as $field) $customFields[$field] = $this->lang->bug->$field; $this->view->customFields = $customFields; @@ -339,7 +342,7 @@ class bug extends control $this->view->productID = $productID; $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch); + $this->view->moduleOptionMenu = $moduleOptionMenu; $this->view->stories = $stories; $this->view->projects = $this->product->getProjectPairs($productID, $branch ? "0,$branch" : 0, $params = 'nodeleted'); $this->view->builds = $builds; @@ -372,11 +375,11 @@ class bug extends control } /** - * Batch create. - * - * @param int $productID - * @param int $projectID - * @param int $moduleID + * Batch create. + * + * @param int $productID + * @param int $projectID + * @param int $moduleID * @access public * @return void */ @@ -453,8 +456,8 @@ class bug extends control /** * View a bug. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ @@ -481,7 +484,7 @@ class bug extends control /* Get product info. */ $productID = $bug->product; $productName = $this->products[$productID]; - + /* Header and positon. */ $this->view->title = "BUG #$bug->id $bug->title - " . $this->products[$productID]; $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName); @@ -503,8 +506,8 @@ class bug extends control /** * Edit a bug. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ @@ -625,11 +628,11 @@ class bug extends control $this->bug->sendmail($bugID, $actionID); $bug = $this->bug->getById($bugID); - if($bug->toTask != 0) + if($bug->toTask != 0) { foreach($changes as $change) { - if($change['field'] == 'status') + if($change['field'] == 'status') { $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); $cancelURL = $this->server->HTTP_REFERER; @@ -727,7 +730,7 @@ class bug extends control } /** - * Update assign of bug. + * Update assign of bug. * * @param int $bugID * @access public @@ -763,6 +766,34 @@ class bug extends control $this->display(); } + /** + * Batch change branch. + * + * @param int $branchID + * @access public + * @return void + */ + public function batchChangeBranch($branchID) + { + if($this->post->bugIDList) + { + $bugIDList = $this->post->bugIDList; + $bugIDList = array_unique($bugIDList); + unset($_POST['bugIDList']); + $allChanges = $this->bug->batchChangeBranch($bugIDList, $branchID); + if(dao::isError()) die(js::error(dao::getError())); + foreach($allChanges as $bugID => $changes) + { + $this->loadModel('action'); + $actionID = $this->action->create('bug', $bugID, 'Edited'); + $this->action->logHistory($actionID, $changes); + $this->bug->sendmail($bugID, $actionID); + } + } + $this->loadModel('score')->create('ajax', 'batchOther'); + die(js::locate($this->session->bugList, 'parent')); + } + /** * Batch change the module of bug. * @@ -792,9 +823,9 @@ class bug extends control } /** - * Batch update assign of bug. - * - * @param int $projectID + * Batch update assign of bug. + * + * @param int $projectID * @access public * @return void */ @@ -823,8 +854,8 @@ class bug extends control /** * confirm a bug. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ @@ -856,8 +887,8 @@ class bug extends control } /** - * Batch confirm bugs. - * + * Batch confirm bugs. + * * @access public * @return void */ @@ -875,11 +906,11 @@ class bug extends control $this->loadModel('score')->create('ajax', 'batchOther'); die(js::locate($this->session->bugList, 'parent')); } - + /** * Resolve a bug. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ @@ -896,7 +927,7 @@ class bug extends control $this->bug->sendmail($bugID, $actionID); $bug = $this->bug->getById($bugID); - if($bug->toTask != 0) + if($bug->toTask != 0) { /* If task is not finished, update it's status. */ $task = $this->task->getById($bug->toTask); @@ -907,7 +938,7 @@ class bug extends control $cancelURL = $this->createLink('bug', 'view', "bugID=$bugID"); die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent.parent')); } - } + } if(isonlybody()) die(js::closeModal('parent.parent')); die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); } @@ -936,9 +967,9 @@ class bug extends control /** * Batch resolve bugs. - * - * @param string $resolution - * @param string $resolvedBuild + * + * @param string $resolution + * @param string $resolvedBuild * @access public * @return void */ @@ -995,8 +1026,8 @@ class bug extends control /** * Close a bug. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ @@ -1113,8 +1144,8 @@ class bug extends control } /** - * Batch close bugs. - * + * Batch close bugs. + * * @access public * @return void */ @@ -1225,7 +1256,7 @@ class bug extends control /** * Save current template. - * + * * @access public * @return string */ @@ -1238,7 +1269,7 @@ class bug extends control /** * Build the user templates selection code. - * + * * @access public * @return void */ @@ -1250,8 +1281,8 @@ class bug extends control /** * Delete a user template. - * - * @param int $templateID + * + * @param int $templateID * @access public * @return void */ @@ -1263,8 +1294,8 @@ class bug extends control /** * AJAX: get bugs of a user in html select. - * - * @param string $account + * + * @param string $account * @param string $id the id of the select control. * @access public * @return string @@ -1280,9 +1311,9 @@ class bug extends control /** * AJAX: Get bug owner of a module. - * - * @param int $moduleID - * @param int $productID + * + * @param int $moduleID + * @param int $productID * @access public * @return string */ @@ -1294,32 +1325,32 @@ class bug extends control /** * AJAX: get team members of the project as assignedTo list. - * - * @param int $projectID - * @param string $selectedUser + * + * @param int $projectID + * @param string $selectedUser * @access public * @return string */ public function ajaxLoadAssignedTo($projectID, $selectedUser = '') { $projectMembers = $this->loadModel('project')->getTeamMemberPairs($projectID); - + die(html::select('assignedTo', $projectMembers, $selectedUser, 'class="form-control"')); } /** * AJAX: get team members of the latest project of a product as assignedTo list. - * - * @param int $productID + * + * @param int $productID * x - * @param string $selectedUser + * @param string $selectedUser * @access public * @return string */ public function ajaxLoadProjectTeamMembers($productID, $selectedUser = '') { $latestProject = $this->product->getLatestProject($productID); - if(!empty($latestProject)) + if(!empty($latestProject)) { $projectMembers = $this->loadModel('project')->getTeamMemberPairs($latestProject->id, 'nodeleted'); } @@ -1346,9 +1377,9 @@ class bug extends control } /** - * AJAX: get actions of a bug. for web app. - * - * @param int $bugID + * AJAX: get actions of a bug. for web app. + * + * @param int $bugID * @access public * @return void */ @@ -1359,10 +1390,10 @@ class bug extends control } /** - * Get data to export - * - * @param string $productID - * @param string $orderBy + * Get data to export + * + * @param string $productID + * @param string $orderBy * @access public * @return void */ @@ -1550,8 +1581,8 @@ class bug extends control /** * Ajax get bug by ID. - * - * @param int $bugID + * + * @param int $bugID * @access public * @return void */ diff --git a/module/bug/js/common.js b/module/bug/js/common.js index e8dc98b4bf..6fcc8a9ae1 100644 --- a/module/bug/js/common.js +++ b/module/bug/js/common.js @@ -78,7 +78,7 @@ function loadBranch() $('#taskIdBox').innerHTML = ''; // Reset the task. $('#task').chosen(defaultChosenOptions); productID = $('#product').val(); - loadProductModules(productID); + loadProductModules(productID); loadProductProjects(productID); loadProductBuilds(productID); loadProductplans(productID); diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php index 2524661b50..8f983f6bb3 100644 --- a/module/bug/lang/en.php +++ b/module/bug/lang/en.php @@ -217,18 +217,18 @@ $lang->bug->browserList['other'] = 'Other'; $lang->bug->typeList[''] = ''; $lang->bug->typeList['codeerror'] = 'Code Error'; $lang->bug->typeList['interface'] = 'Interface Optimization'; -$lang->bug->typeList['designchange'] = 'Design Change'; -$lang->bug->typeList['newfeature'] = 'New Feature'; -$lang->bug->typeList['designdefect'] = 'Design Defect'; $lang->bug->typeList['config'] = 'Configuration'; $lang->bug->typeList['install'] = 'Install/Deploy'; $lang->bug->typeList['security'] = 'Security'; $lang->bug->typeList['performance'] = 'Performance'; $lang->bug->typeList['standard'] = 'Standard'; $lang->bug->typeList['automation'] = 'Testing Script'; -$lang->bug->typeList['trackthings'] = 'Issue Tracking'; $lang->bug->typeList['others'] = 'Other'; + + + + $lang->bug->statusList[''] = ''; $lang->bug->statusList['active'] = 'Active'; $lang->bug->statusList['resolved'] = 'Resolved'; diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index eb81221b4c..90b0fc7337 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -115,6 +115,7 @@ $lang->bug->byQuery = '搜索'; $lang->bug->needConfirm = '需求变动'; $lang->bug->allProduct = '所有' . $lang->productCommon; + $lang->bug->ditto = '同上'; $lang->bug->dittoNotice = '该bug与上一bug不属于同一产品!'; @@ -216,17 +217,17 @@ $lang->bug->browserList['other'] = '其他'; $lang->bug->typeList[''] = ''; $lang->bug->typeList['codeerror'] = '代码错误'; $lang->bug->typeList['interface'] = '界面优化'; -$lang->bug->typeList['designchange'] = '设计变更'; -$lang->bug->typeList['newfeature'] = '新增需求'; -$lang->bug->typeList['designdefect'] = '设计缺陷'; $lang->bug->typeList['config'] = '配置相关'; $lang->bug->typeList['install'] = '安装部署'; $lang->bug->typeList['security'] = '安全相关'; $lang->bug->typeList['performance'] = '性能问题'; $lang->bug->typeList['standard'] = '标准规范'; $lang->bug->typeList['automation'] = '测试脚本'; -$lang->bug->typeList['trackthings'] = '事务跟踪'; $lang->bug->typeList['others'] = '其他'; +$lang->bug->typeList['designchange'] = '设计变更'; +$lang->bug->typeList['newfeature'] = '新增需求'; +$lang->bug->typeList['designdefect'] = '设计缺陷'; +$lang->bug->typeList['trackthings'] = '事务跟踪'; $lang->bug->statusList[''] = ''; $lang->bug->statusList['active'] = '激活'; diff --git a/module/bug/model.php b/module/bug/model.php index 8b8b380b32..b6802cef13 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -113,7 +113,11 @@ class bugModel extends model for($i = 0; $i < $batchNum; $i++) { - if(!empty($data->title[$i]) and empty($data->openedBuilds[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->openedBuild))); + if(!empty($data->title[$i])) + { + if(empty($data->modules[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->module))); + if(empty($data->openedBuilds[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->openedBuild))); + } } /* Get pairs(moduleID => moduleOwner) for bug. */ @@ -865,6 +869,35 @@ class bugModel extends model $this->linkBugToBuild($bugID, $bug->resolvedBuild); } + /** + * Batch change branch. + * + * @param array $bugIDList + * @param int $branchID + * @access public + * @return array + */ + public function batchChangeBranch($bugIDList, $branchID) + { + $now = helper::now(); + $allChanges = array(); + $oldBugs = $this->getByList($bugIDList); + foreach($bugIDList as $bugID) + { + $oldBug = $oldBugs[$bugID]; + if($branchID == $oldBug->branch) continue; + + $bug = new stdclass(); + $bug->lastEditedBy = $this->app->user->account; + $bug->lastEditedDate = $now; + $bug->branch = $branchID; + + $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); + if(!dao::isError()) $allChanges[$bugID] = common::createChanges($oldBug, $bug); + } + return $allChanges; + } + /** * Batch change the module of bug. * diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php index 17fcbcae4e..4b6dda944d 100644 --- a/module/bug/view/batchcreate.html.php +++ b/module/bug/view/batchcreate.html.php @@ -39,7 +39,7 @@ foreach(explode(',', $showFields) as $field) idAB;?> '> product->branch;?> - '> bug->module;?> + '> bug->module;?> '>bug->project;?> bug->openedBuild;?> bug->title;?> diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php index 01e27a1313..d96aed6646 100644 --- a/module/bug/view/browse.html.php +++ b/module/bug/view/browse.html.php @@ -237,6 +237,23 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow $misc = common::hasPriv('bug', 'batchActivate') ? "onclick=\"setFormAction('$actionLink')\"" : $class; if($misc) echo "
  • " . html::a('javascript:;', $lang->bug->activate, '', $misc) . "
  • "; + if(common::hasPriv('bug', 'batchChangeBranch') and $this->session->currentProductType != 'normal') + { + $withSearch = count($branches) > 8; + echo "'; + } + if(common::hasPriv('bug', 'batchChangeModule')) { $withSearch = count($modules) > 8; diff --git a/module/bug/view/view.html.php b/module/bug/view/view.html.php index 566e8e240b..1f26194dbf 100644 --- a/module/bug/view/view.html.php +++ b/module/bug/view/view.html.php @@ -89,7 +89,7 @@
    deleted) echo $actionLinks;?>
    comment;?> -
    id&comment=true")?>'> + id")?>' target='hiddenwin'>
    diff --git a/module/build/control.php b/module/build/control.php index 6fe1f9d488..21a79b3d9d 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -174,7 +174,7 @@ class build extends control * @access public * @return void */ - public function view($buildID, $type = 'story', $link = 'false', $param = '') + public function view($buildID, $type = 'story', $link = 'false', $param = '', $orderBy = 'id_desc') { if($type == 'story')$this->session->set('storyList', $this->app->getURI(true)); if($type == 'bug') $this->session->set('bugList', $this->app->getURI(true)); @@ -189,7 +189,9 @@ class build extends control $product = $this->loadModel('product')->getById($build->product); if($product->type != 'normal') $this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]); - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->andWhere('deleted')->eq(0)->fetchAll(); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->andWhere('deleted')->eq(0) + ->beginIF($type == 'bug')->orderBy($orderBy)->fi() + ->fetchAll(); if($this->config->global->flow == 'onlyTest') { @@ -203,7 +205,9 @@ class build extends control } else { - $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->andWhere('deleted')->eq(0)->fetchAll('id'); + $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->andWhere('deleted')->eq(0) + ->beginIF($type == 'story')->orderBy($orderBy)->fi() + ->fetchAll('id'); $stages = $this->dao->select('*')->from(TABLE_STORYSTAGE)->where('story')->in($build->stories)->andWhere('branch')->eq($build->branch)->fetchPairs('story', 'stage'); foreach($stages as $storyID => $stage)$stories[$storyID]->stage = $stage; @@ -214,7 +218,7 @@ class build extends control $this->view->position[] = html::a($this->createLink('project', 'task', "projectID=$build->project"), $projects[$build->project]); $this->view->position[] = $this->lang->build->view; $this->view->stories = $stories; - $this->view->generatedBugs = $this->bug->getProjectBugs($build->project, $build->id, '', 0, 'status_desc,id_desc', null); + $this->view->generatedBugs = $this->bug->getProjectBugs($build->project, $build->id, '', 0, $type == 'newbug' ? $orderBy : 'status_desc,id_desc', null); $this->view->bugs = $bugs; $this->view->type = $type; } @@ -225,6 +229,7 @@ class build extends control $this->view->actions = $this->loadModel('action')->getList('build', $buildID); $this->view->link = $link; $this->view->param = $param; + $this->view->orderBy = $orderBy; $this->view->branchName = $build->productType == 'normal' ? '' : $this->loadModel('branch')->getById($build->branch); $this->display(); } diff --git a/module/build/css/view.css b/module/build/css/view.css index 95edbdd747..7d36be4c67 100644 --- a/module/build/css/view.css +++ b/module/build/css/view.css @@ -10,5 +10,8 @@ .table-actions {padding-left: 5px;} +#buildInfo {border-top: 1px solid #ddd;} +#buildInfo > div {padding-top: 15px;} + #querybox form {margin: 0px !important;} #moreOrLite {right: 0px !important;} diff --git a/module/build/view/linkbug.html.php b/module/build/view/linkbug.html.php index a4ebfc4e74..299881388e 100644 --- a/module/build/view/linkbug.html.php +++ b/module/build/view/linkbug.html.php @@ -10,6 +10,10 @@ * @link http://www.zentao.net */ ?> +app->getWebRoot() . "js/"; +include '../../common/view/tablesorter.html.php'; +?>
    id}&browseType=$browseType¶m=$param");?>'> diff --git a/module/build/view/linkstory.html.php b/module/build/view/linkstory.html.php index c32cbc64c6..e62a058945 100644 --- a/module/build/view/linkstory.html.php +++ b/module/build/view/linkstory.html.php @@ -10,6 +10,10 @@ * @link http://www.zentao.net */ ?> +app->getWebRoot() . "js/"; +include '../../common/view/tablesorter.html.php'; +?>
    id}&browseType=$browseType¶m=$param");?>'> diff --git a/module/build/view/view.html.php b/module/build/view/view.html.php index 469bec757f..06bca9ff92 100644 --- a/module/build/view/view.html.php +++ b/module/build/view/view.html.php @@ -79,9 +79,10 @@ tfoot tr td .table-actions .btn{display:none;}
    ' id='stories'> @@ -91,16 +92,17 @@ tfoot tr td .table-actions .btn{display:none;} id}")?>' id='linkedStoriesForm'> + id}&type=story&link=$link¶m=$param&orderBy=%s";?> - - - - - - - - + + + + + + + + @@ -150,16 +152,17 @@ tfoot tr td .table-actions .btn{display:none;} id");?>" id='linkedBugsForm'>
    idAB;?>priAB;?>story->title;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions;?> idAB);?> priAB);?>story->title);?> openedByAB);?> story->estimateAB);?> statusAB);?> story->stageAB);?> actions?>
    + id}&type=bug&link=$link¶m=$param&orderBy=%s";?> - - - - - - - - + + + + + + + + @@ -203,16 +206,18 @@ tfoot tr td .table-actions .btn{display:none;}
    ' id='newBugs'>
    idAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?>actions;?> idAB);?>bug->title);?> bug->status);?> openedByAB);?> bug->openedDateAB);?> bug->resolvedByAB);?> bug->resolvedDateAB);?> actions?>
    + id}&type=newbug&link=$link¶m=$param&orderBy=%s";?> - - - - - - - - + + + + + + + + + @@ -239,60 +244,62 @@ tfoot tr td .table-actions .btn{display:none;}
    idAB;?>bug->severityAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?> idAB);?>bug->severityAB);?> bug->title);?> bug->status);?> openedByAB);?> bug->openedDateAB);?> bug->resolvedByAB);?> bug->resolvedDateAB);?> actions?>
    +
    ' id='buildInfo'> +
    +
    +
    + build->basicInfo?> + + + + + + productType != 'normal'):?> + + + + + + + + + + + + + + + + + + + + + + + + + + config->global->flow != 'onlyTest'):?> + + + + + +
    build->product;?>productName;?>
    product->branch;?>
    build->name;?>name;?>
    build->builder;?>builder];?>
    build->date;?>date;?>
    build->scmPath;?>scmPath, $build->scmPath, '_blank')?>
    build->filePath;?>filePath, $build->filePath, '_blank');?>
    build->desc;?>
    desc;?>
    +
    + config->global->flow != 'onlyTest'):?> + fetch('file', 'printFiles', array('files' => $build->files, 'fieldset' => 'true'));?> + +
    +
    +
    +
    -
    -
    - config->global->flow != 'onlyTest'):?> -
    - build->desc;?> -
    desc;?>
    -
    - -
    - build->basicInfo?> - - - - - - productType != 'normal'):?> - - - - - - - - - - - - - - - - - - - - - - - - - -
    build->product;?>productName;?>
    product->branch;?>
    build->name;?>name;?>
    build->builder;?>builder];?>
    build->date;?>date;?>
    build->scmPath;?>scmPath, $build->scmPath, '_blank')?>
    build->filePath;?>filePath, $build->filePath, '_blank');?>
    -
    - config->global->flow != 'onlyTest'):?> - fetch('file', 'printFiles', array('files' => $build->files, 'fieldset' => 'true'));?> - - -
    -
    config->global->flow != 'onlyTest'):?> diff --git a/module/common/model.php b/module/common/model.php index abb20b1c12..0208b25cfb 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -48,7 +48,7 @@ class commonModel extends model /** * Set the commpany. * - * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default. + * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default. * After get the company, save it to session. * @access public * @return void @@ -72,7 +72,7 @@ class commonModel extends model /** * Set the user info. - * + * * @access public * @return void */ @@ -99,7 +99,7 @@ class commonModel extends model /** * Load configs from database and save it to config->system and config->personal. - * + * * @access public * @return void */ @@ -170,9 +170,9 @@ class commonModel extends model /** * Deny access. - * + * * @access public - * @return void + * @return mixed */ public function deny($module, $method) { @@ -207,7 +207,7 @@ class commonModel extends model /** * Print the run info. - * + * * @param mixed $startTime the start time. * @access public * @return array the run info array. @@ -223,7 +223,7 @@ class commonModel extends model /** * Print top bar. - * + * * @static * @access public * @return void @@ -293,8 +293,9 @@ class commonModel extends model /** * Create menu item link * - * @param object $menuItemLink - * @param boolean $isTutorialMode + * @param object $menuItem + * + * @static * @access public * @return string */ @@ -321,6 +322,8 @@ class commonModel extends model * Print the main menu. * * @param string $moduleName + * @param string $methodName + * * @static * @access public * @return void @@ -383,14 +386,14 @@ class commonModel extends model if($config->global->flow == 'onlyTask') $searchObject = 'task'; } - echo " diff --git a/module/git/control.php b/module/git/control.php index 88f37ce641..e513d6432f 100644 --- a/module/git/control.php +++ b/module/git/control.php @@ -32,7 +32,9 @@ class git extends control */ public function diff($path, $revision) { + if(isset($_GET['repoUrl'])) $path = $this->get->repoUrl; $path = helper::safe64Decode($path); + $this->view->path = $path; $this->view->revision = $revision; $this->view->diff = $this->git->diff($path, $revision); @@ -50,7 +52,9 @@ class git extends control */ public function cat($path, $revision) { + if(isset($_GET['repoUrl'])) $path = $this->get->repoUrl; $path = helper::safe64Decode($path); + $this->view->path = $path; $this->view->revision = $revision; $this->view->code = $this->git->cat($path, $revision); diff --git a/module/git/model.php b/module/git/model.php index ee564f1356..46b1d40502 100644 --- a/module/git/model.php +++ b/module/git/model.php @@ -643,9 +643,8 @@ class gitModel extends model { foreach($actionFiles as $file) { - $param = array('url' => helper::safe64Encode($repoRoot . $file), 'revision' => $log->revision); - $catLink = trim(html::a(helper::createLink('git', 'cat', $param, 'html'), 'view', '', "class='repolink'")); - $diffLink = trim(html::a(helper::createLink('git', 'diff', $param, 'html'), 'diff', '', "class='repolink'")); + $catLink = trim(html::a($this->buildURL('cat', $repoRoot . $file, $log->revision), 'view', '', "class='repolink'")); + $diffLink = trim(html::a($this->buildURL('diff', $repoRoot . $file, $log->revision), 'diff', '', "class='repolink'")); $diff .= $action . " " . $file . " $catLink "; $diff .= $action == 'M' ? "$diffLink\n" : "\n" ; } @@ -747,4 +746,21 @@ class gitModel extends model { echo helper::now() . " $log\n"; } + + /** + * Build URL. + * + * @param string $methodName + * @param string $url + * @param int $revision + * @access public + * @return string + */ + public function buildURL($methodName, $url, $revision) + { + $buildedURL = helper::createLink('git', $methodName, "path=&revision=$revision", 'html'); + $buildedURL .= strpos($buildedURL, '?') === false ? '?' : '&'; + $buildedURL .= 'repoUrl=' . helper::safe64Encode($url); + return $buildedURL; + } } diff --git a/module/git/view/diff.html.php b/module/git/view/diff.html.php index 20c035297d..3c710254db 100644 --- a/module/git/view/diff.html.php +++ b/module/git/view/diff.html.php @@ -11,7 +11,7 @@ */ ?> - +git->buildURL('cat', $path, $revision);?>
    <?php echo $diff;?>
    diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index b075352107..437461f233 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -1005,12 +1005,15 @@ $lang->resource->action->trash = 'trash'; $lang->resource->action->undelete = 'undelete'; $lang->resource->action->hideOne = 'hideOne'; $lang->resource->action->hideAll = 'hideAll'; +$lang->resource->action->comment = 'comment'; $lang->resource->action->editComment = 'editComment'; $lang->action->methodOrder[5] = 'trash'; $lang->action->methodOrder[10] = 'undelete'; $lang->action->methodOrder[15] = 'hideOne'; $lang->action->methodOrder[20] = 'hideAll'; +$lang->action->methodOrder[25] = 'comment'; +$lang->action->methodOrder[30] = 'editComment'; $lang->resource->backup = new stdclass(); $lang->resource->backup->index = 'index'; diff --git a/module/group/model.php b/module/group/model.php index 3565b60128..1e28da57ce 100644 --- a/module/group/model.php +++ b/module/group/model.php @@ -422,7 +422,6 @@ class groupModel extends model $action = strtolower($action); if($action == 'manageview' and $group->role == 'limited') return false; - if($action == 'edit' and $group->role == 'limited') return false; if($action == 'copy' and $group->role == 'limited') return false; return true; diff --git a/module/install/lang/en.php b/module/install/lang/en.php index 71f2c6203d..09e9e79755 100644 --- a/module/install/lang/en.php +++ b/module/install/lang/en.php @@ -126,26 +126,28 @@ $lang->install->account = 'Admin Account'; $lang->install->password = 'Admin Password'; $lang->install->errorEmptyPassword = 'Password should not be blank.'; -$lang->install->groupList['ADMIN']['name'] = 'Admin'; -$lang->install->groupList['ADMIN']['desc'] = 'System Administrator'; -$lang->install->groupList['DEV']['name'] = 'Dev'; -$lang->install->groupList['DEV']['desc'] = 'Dev Team'; -$lang->install->groupList['QA']['name'] = 'QA'; -$lang->install->groupList['QA']['desc'] = 'QA Team'; -$lang->install->groupList['PM']['name'] = 'PM'; -$lang->install->groupList['PM']['desc'] = 'for Project Manager'; -$lang->install->groupList['PO']['name'] = 'PO'; -$lang->install->groupList['PO']['desc'] = 'for Product Owner'; -$lang->install->groupList['TD']['name'] = 'Dev Manager'; -$lang->install->groupList['TD']['desc'] = 'for Dev Manager'; -$lang->install->groupList['PD']['name'] = 'PD'; -$lang->install->groupList['PD']['desc'] = 'for Product Director'; -$lang->install->groupList['QD']['name'] = 'QD'; -$lang->install->groupList['QD']['desc'] = 'for QA Director'; -$lang->install->groupList['TOP']['name'] = 'Senior'; -$lang->install->groupList['TOP']['desc'] = 'for Senior Manager'; -$lang->install->groupList['OTHERS']['name'] = 'Other'; -$lang->install->groupList['OTHERS']['desc'] = 'for Other'; +$lang->install->groupList['ADMIN']['name'] = 'Admin'; +$lang->install->groupList['ADMIN']['desc'] = 'System Administrator'; +$lang->install->groupList['DEV']['name'] = 'Dev'; +$lang->install->groupList['DEV']['desc'] = 'Dev Team'; +$lang->install->groupList['QA']['name'] = 'QA'; +$lang->install->groupList['QA']['desc'] = 'QA Team'; +$lang->install->groupList['PM']['name'] = 'PM'; +$lang->install->groupList['PM']['desc'] = 'for Project Manager'; +$lang->install->groupList['PO']['name'] = 'PO'; +$lang->install->groupList['PO']['desc'] = 'for Product Owner'; +$lang->install->groupList['TD']['name'] = 'Dev Manager'; +$lang->install->groupList['TD']['desc'] = 'for Dev Manager'; +$lang->install->groupList['PD']['name'] = 'PD'; +$lang->install->groupList['PD']['desc'] = 'for Product Director'; +$lang->install->groupList['QD']['name'] = 'QD'; +$lang->install->groupList['QD']['desc'] = 'for QA Director'; +$lang->install->groupList['TOP']['name'] = 'Senior'; +$lang->install->groupList['TOP']['desc'] = 'for Senior Manager'; +$lang->install->groupList['OTHERS']['name'] = 'Other'; +$lang->install->groupList['OTHERS']['desc'] = 'for Other'; +$lang->install->groupList['LIMITED']['name'] = 'Limited User'; +$lang->install->groupList['LIMITED']['desc'] = 'for Limited user (editing only content related to itself)'; $lang->install->cronList[''] = 'Monitor cron'; $lang->install->cronList['moduleName=project&methodName=computeburn'] = 'Update Burndown Chart'; diff --git a/module/install/lang/zh-cn.php b/module/install/lang/zh-cn.php index 2840984611..b11a4f4e00 100644 --- a/module/install/lang/zh-cn.php +++ b/module/install/lang/zh-cn.php @@ -126,26 +126,28 @@ $lang->install->account = '管理员帐号'; $lang->install->password = '管理员密码'; $lang->install->errorEmptyPassword = '密码不能为空'; -$lang->install->groupList['ADMIN']['name'] = '管理员'; -$lang->install->groupList['ADMIN']['desc'] = '系统管理员'; -$lang->install->groupList['DEV']['name'] = '研发'; -$lang->install->groupList['DEV']['desc'] = '研发人员'; -$lang->install->groupList['QA']['name'] = '测试'; -$lang->install->groupList['QA']['desc'] = '测试人员'; -$lang->install->groupList['PM']['name'] = '项目经理'; -$lang->install->groupList['PM']['desc'] = '项目经理'; -$lang->install->groupList['PO']['name'] = '产品经理'; -$lang->install->groupList['PO']['desc'] = '产品经理'; -$lang->install->groupList['TD']['name'] = '研发主管'; -$lang->install->groupList['TD']['desc'] = '研发主管'; -$lang->install->groupList['PD']['name'] = '产品主管'; -$lang->install->groupList['PD']['desc'] = '产品主管'; -$lang->install->groupList['QD']['name'] = '测试主管'; -$lang->install->groupList['QD']['desc'] = '测试主管'; -$lang->install->groupList['TOP']['name'] = '高层管理'; -$lang->install->groupList['TOP']['desc'] = '高层管理'; -$lang->install->groupList['OTHERS']['name'] = '其他'; -$lang->install->groupList['OTHERS']['desc'] = '其他'; +$lang->install->groupList['ADMIN']['name'] = '管理员'; +$lang->install->groupList['ADMIN']['desc'] = '系统管理员'; +$lang->install->groupList['DEV']['name'] = '研发'; +$lang->install->groupList['DEV']['desc'] = '研发人员'; +$lang->install->groupList['QA']['name'] = '测试'; +$lang->install->groupList['QA']['desc'] = '测试人员'; +$lang->install->groupList['PM']['name'] = '项目经理'; +$lang->install->groupList['PM']['desc'] = '项目经理'; +$lang->install->groupList['PO']['name'] = '产品经理'; +$lang->install->groupList['PO']['desc'] = '产品经理'; +$lang->install->groupList['TD']['name'] = '研发主管'; +$lang->install->groupList['TD']['desc'] = '研发主管'; +$lang->install->groupList['PD']['name'] = '产品主管'; +$lang->install->groupList['PD']['desc'] = '产品主管'; +$lang->install->groupList['QD']['name'] = '测试主管'; +$lang->install->groupList['QD']['desc'] = '测试主管'; +$lang->install->groupList['TOP']['name'] = '高层管理'; +$lang->install->groupList['TOP']['desc'] = '高层管理'; +$lang->install->groupList['OTHERS']['name'] = '其他'; +$lang->install->groupList['OTHERS']['desc'] = '其他'; +$lang->install->groupList['LIMITED']['name'] = '受限用户'; +$lang->install->groupList['LIMITED']['desc'] = '受限用户分组(只能编辑与自己相关的内容)'; $lang->install->cronList[''] = '监控定时任务'; $lang->install->cronList['moduleName=project&methodName=computeburn'] = '更新燃尽图'; diff --git a/module/mail/control.php b/module/mail/control.php index 93b1ffe344..3c9ad804f3 100755 --- a/module/mail/control.php +++ b/module/mail/control.php @@ -55,21 +55,26 @@ class mail extends control * @access public * @return void */ - public function detect() + public function detect($type = 'smtp') { - if($_POST) + if($_POST or $type == 'gmail') { set_time_limit(30); - $error = ''; - if($this->post->fromAddress == false) $error = sprintf($this->lang->error->notempty, $this->lang->mail->fromAddress); - if(!validater::checkEmail($this->post->fromAddress)) $error .= '\n' . sprintf($this->lang->error->email, $this->lang->mail->fromAddress); + if($type != 'gmail') + { + $error = ''; + if($this->post->fromAddress == false) $error = sprintf($this->lang->error->notempty, $this->lang->mail->fromAddress); + if(!validater::checkEmail($this->post->fromAddress)) $error .= '\n' . sprintf($this->lang->error->email, $this->lang->mail->fromAddress); - if($error) die(js::alert($error)); + if($error) die(js::alert($error)); + } + if($type == 'gmail' and empty($_POST['fromAddress'])) $_POST['fromAddress'] = '@gmail.com'; echo ""; $mailConfig = $this->mail->autoDetect($this->post->fromAddress); $mailConfig->fromAddress = $this->post->fromAddress; $mailConfig->domain = common::getSysURL(); + if($type == 'gmail') $mailConfig->fromAddress = ''; $this->session->set('mailConfig', $mailConfig); die(js::locate(inlink('edit'), 'parent')); diff --git a/module/mail/js/edit.js b/module/mail/js/edit.js index ad537f83eb..5d6d8bd632 100644 --- a/module/mail/js/edit.js +++ b/module/mail/js/edit.js @@ -1,4 +1,5 @@ $(document).ready() { - $('#password').focus(); + $('#fromAddress').focus(); + if($('#fromAddress').val() != '')$('#password').focus(); } diff --git a/module/mail/lang/en.php b/module/mail/lang/en.php index 9309052bba..72797bb7cc 100755 --- a/module/mail/lang/en.php +++ b/module/mail/lang/en.php @@ -10,6 +10,7 @@ $lang->mail->resend = 'Resend'; $lang->mail->browse = 'Email List'; $lang->mail->delete = 'Delete Email'; $lang->mail->ztCloud = 'ZenTao CloudMail'; +$lang->mail->gmail = 'GMAIL'; $lang->mail->sendCloud = 'Notice SendCloud'; $lang->mail->batchDelete = 'Batch Delete'; $lang->mail->sendcloudUser = 'Sync Contact'; diff --git a/module/mail/lang/zh-cn.php b/module/mail/lang/zh-cn.php index 47ea0a204f..2e3795408b 100755 --- a/module/mail/lang/zh-cn.php +++ b/module/mail/lang/zh-cn.php @@ -10,6 +10,7 @@ $lang->mail->resend = '重发'; $lang->mail->browse = '邮件列表'; $lang->mail->delete = '删除邮件'; $lang->mail->ztCloud = '禅道云发信'; +$lang->mail->gmail = 'GMAIL发信'; $lang->mail->sendCloud = 'Notice发信'; $lang->mail->batchDelete = '批量删除'; $lang->mail->sendcloudUser = '同步联系人'; diff --git a/module/mail/view/index.html.php b/module/mail/view/index.html.php index fad3d328a7..2dbfb9e2eb 100755 --- a/module/mail/view/index.html.php +++ b/module/mail/view/index.html.php @@ -24,6 +24,9 @@ include '../../common/view/header.html.php'; app->getClientLang() != 'en' and common::hasPriv('mail', 'ztCloud')):?> mail->ztCloud, '', "class='btn btn-sm w-120px'")?> + app->getClientLang() == 'en'):?> + mail->gmail, '', "class='btn btn-sm w-120px'")?> + mail->smtp, '', "class='btn btn-sm w-120px'")?> diff --git a/module/my/control.php b/module/my/control.php index b50db17dce..e1791ea6fe 100644 --- a/module/my/control.php +++ b/module/my/control.php @@ -406,18 +406,35 @@ class my extends control if($this->post->mode == 'new') { $listID = $this->user->createContactList($this->post->newList, $this->post->users); + $this->user->setGlobalContacts($listID, isset($_POST['share'])); if(isonlybody()) die(js::closeModal('parent.parent', '', 'function(){parent.parent.ajaxGetContacts(\'#mailtoGroup\')}')); die(js::locate(inlink('manageContacts', "listID=$listID"), 'parent')); } elseif($this->post->mode == 'edit') { $this->user->updateContactList($this->post->listID, $this->post->listName, $this->post->users); + $this->user->setGlobalContacts($this->post->listID, isset($_POST['share'])); die(js::locate(inlink('manageContacts', "listID={$this->post->listID}"), 'parent')); } } - $mode = empty($mode) ? 'edit' : $mode; - $lists = $this->user->getContactLists($this->app->user->account); + $mode = empty($mode) ? 'edit' : $mode; + $lists = $this->user->getContactLists($this->app->user->account); + + $globalContacts = isset($this->config->my->global->globalContacts) ? $this->config->my->global->globalContacts : ''; + $globalContacts = !empty($globalContacts) ? explode(',', $globalContacts) : array(); + + $myContacts = $this->user->getListByAccount($this->app->user->account); + $disabled = $globalContacts; + + if(!empty($myContacts) && !empty($globalContacts)) + { + foreach($globalContacts as $id) + { + if(in_array($id, array_keys($myContacts))) unset($disabled[array_search($id, $disabled)]); + } + } + $listID = $listID ? $listID : key($lists); if(!$listID) $mode = 'new'; @@ -434,10 +451,12 @@ class my extends control $this->view->list = $this->user->getContactListByID($listID); } - $this->view->mode = $mode; - $this->view->lists = $lists; - $this->view->listID = $listID; - $this->view->users = $this->user->getPairs('noletter|noempty|noclosed|noclosed'); + $this->view->mode = $mode; + $this->view->lists = $lists; + $this->view->listID = $listID; + $this->view->users = $this->user->getPairs('noletter|noempty|noclosed|noclosed'); + $this->view->disabled = $disabled; + $this->view->globalContacts = $globalContacts; $this->display(); } diff --git a/module/my/css/managecontacts.css b/module/my/css/managecontacts.css index ba39800635..ff377438c5 100644 --- a/module/my/css/managecontacts.css +++ b/module/my/css/managecontacts.css @@ -1,3 +1 @@ body.body-modal {padding-bottom: 20px; min-height: 400px} - -.list-group-item.active {color: #1A4F85} diff --git a/module/my/lang/en.php b/module/my/lang/en.php index e9a746aa4b..a5909c9093 100644 --- a/module/my/lang/en.php +++ b/module/my/lang/en.php @@ -17,6 +17,7 @@ $lang->my->changePassword = 'Edit Password'; $lang->my->unbind = 'Unbind Ranger'; $lang->my->manageContacts = 'Maintain Contact'; $lang->my->deleteContacts = 'Delete Contact'; +$lang->my->shareContacts = 'Share List'; $lang->my->limited = 'Restricted operation (editing only content related to itself)'; $lang->my->score = 'My Score'; $lang->my->scoreRule = 'Score Rule'; diff --git a/module/my/lang/zh-cn.php b/module/my/lang/zh-cn.php index 1c9adf8250..fe82f4cf71 100644 --- a/module/my/lang/zh-cn.php +++ b/module/my/lang/zh-cn.php @@ -17,6 +17,7 @@ $lang->my->changePassword = '修改密码'; $lang->my->unbind = '解除然之绑定'; $lang->my->manageContacts = '维护联系人'; $lang->my->deleteContacts = '删除联系人'; +$lang->my->shareContacts = '共享联系人列表'; $lang->my->limited = '受限操作(只能编辑与自己相关的内容)'; $lang->my->score = '我的积分'; $lang->my->scoreRule = '积分规则'; diff --git a/module/my/view/managecontacts.html.php b/module/my/view/managecontacts.html.php index 2f0f1ff76e..22954526c0 100644 --- a/module/my/view/managecontacts.html.php +++ b/module/my/view/managecontacts.html.php @@ -19,7 +19,8 @@ foreach($lists as $id => $listName) { $listClass = ($id == $listID) ? 'list-group-item active' : 'list-group-item'; - echo html::a(inlink('managecontacts', "listID=$id&mode=edit"), $listName, '', "class='{$listClass}'"); + $shareIcon = in_array($id, $globalContacts) ? ' ' : ''; + echo html::a(inlink('managecontacts', "listID=$id&mode=edit"), $shareIcon . $listName, '', "class='{$listClass}'"); } ?> @@ -44,13 +45,14 @@
    id, $disabled) ? ' readonly' : ''; if($mode == 'new') { echo html::input('newList', '', "class='form-control'"); } else { - echo html::input('listName', $list->listName, "class='form-control'"); + echo html::input('listName', $list->listName, "$readonly class='form-control'"); echo html::hidden('listID', $list->id); } ?> @@ -67,11 +69,22 @@ } else { - echo html::select('users[]', $users, $list->userList, "multiple class='form-control chosen'"); + echo html::select('users[]', $users, $list->userList, "multiple $readonly class='form-control chosen'"); } ?> + + + + + + + + + id, $disabled)):?> @@ -79,6 +92,7 @@ delete, 'hiddenwin', "class='btn btn-danger'");?> + diff --git a/module/product/js/browse.js b/module/product/js/browse.js index 086b549507..d9ae94d9ab 100644 --- a/module/product/js/browse.js +++ b/module/product/js/browse.js @@ -25,8 +25,49 @@ $(function() setTimeout(function(){fixedTheadOfList('#storyList')}, 100); if($('#storyList thead th.w-title').width() < 150) $('#storyList thead th.w-title').width(150); + + $(document).on('click', "#storyList tbody tr", function(){showCheckedSummary();}); + $(document).on('change', "#storyList :checkbox", function(){showCheckedSummary();}); + $(document).on('click', "#datatable-storyList table tr", function(){showCheckedSummary();}); }) +function showCheckedSummary() +{ + var $summary = $('tfoot .table-actions .text:last'); + if(!$summary.hasClass('readed')) + { + taskSummary = $summary.html(); + $summary.addClass('readed'); + } + + var checkedTotal = 0; + var checkedEstimate = 0; + var checkedCase = 0; + $('[name^="storyIDList"]').each(function() + { + if($(this).prop('checked')) + { + checkedTotal += 1; + var taskID = $(this).val(); + $tr = $("#storyList tbody tr[data-id='" + taskID + "']"); + checkedEstimate += Number($tr.data('estimate')); + if(Number($tr.data('cases')) > 0) checkedCase += 1; + } + }); + if(checkedTotal > 0) + { + rate = Math.round(checkedCase / checkedTotal * 10000) / 100 + '' + '%'; + summary = checkedSummary.replace('%total%', checkedTotal) + .replace('%estimate%', checkedEstimate) + .replace('%rate%', rate) + $('tfoot .table-actions .text:last').html(summary); + } + else + { + $('tfoot .table-actions .text:last').html(taskSummary); + } +} + function setQueryBar(queryID, title) { $('#bysearchTab').before("
  • " + title + "
  • "); diff --git a/module/product/lang/en.php b/module/product/lang/en.php index 317f7a2603..b80d3e5ee3 100644 --- a/module/product/lang/en.php +++ b/module/product/lang/en.php @@ -109,8 +109,9 @@ $lang->product->aclList['open'] = "Default (User with {$lang->productCommon} $lang->product->aclList['private'] = "Private {$lang->productCommon} ({$lang->projectCommon} team members only)"; $lang->product->aclList['custom'] = 'Custom (Team members and Whitelist members have access to it.)'; -$lang->product->storySummary = " %s Story(ies), %s hour(s) estimated, case coverage is %s on this page."; -$lang->product->noMatched = '"%s" cannot be found.' . $lang->productCommon; +$lang->product->storySummary = " %s Story(ies), %s hour(s) estimated, case coverage is %s on this page."; +$lang->product->checkedSummary = " %total% Checked, %estimate% hour(s) estimated, case coverage is %rate%."; +$lang->product->noMatched = '"%s" cannot be found.' . $lang->productCommon; $lang->product->mySelects['assignedtome'] = $lang->product->assignedToMe; $lang->product->mySelects['openedbyme'] = $lang->product->openedByMe; diff --git a/module/product/lang/zh-cn.php b/module/product/lang/zh-cn.php index 236ad7622f..e5fadf1a90 100644 --- a/module/product/lang/zh-cn.php +++ b/module/product/lang/zh-cn.php @@ -16,7 +16,7 @@ $lang->product->dynamic = "动态"; $lang->product->view = "{$lang->productCommon}概况"; $lang->product->edit = "编辑{$lang->productCommon}"; $lang->product->batchEdit = "批量编辑"; -$lang->product->create = "新增{$lang->productCommon}"; +$lang->product->create = "添加{$lang->productCommon}"; $lang->product->delete = "删除{$lang->productCommon}"; $lang->product->deleted = "已删除"; $lang->product->close = "关闭"; @@ -108,8 +108,9 @@ $lang->product->aclList['open'] = "默认设置(有{$lang->productCommon}视 $lang->product->aclList['private'] = "私有{$lang->productCommon}(只有{$lang->productCommon}相关负责人和{$lang->projectCommon}团队成员才能访问)"; $lang->product->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)'; -$lang->product->storySummary = "本页共 %s 个需求,预计 %s 个工时,用例覆盖率%s。"; -$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon; +$lang->product->storySummary = "本页共 %s 个需求,预计 %s 个工时,用例覆盖率%s。"; +$lang->product->checkedSummary = "选中 %total% 个需求,预计 %estimate% 个工时,用例覆盖率%rate%。"; +$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon; $lang->product->featureBar['browse']['unclosed'] = $lang->product->unclosed; $lang->product->featureBar['browse']['unplan'] = $lang->product->unplan; diff --git a/module/product/model.php b/module/product/model.php index eca7f65b77..9f9a0f8f3f 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -14,11 +14,16 @@ class productModel extends model { /** - * Set menu. - * - * @param array $products - * @param int $productID - * @param string $extra + * + * Set menu. + * + * @param array $products + * @param int $productID + * @param int $branch + * @param int $module + * @param string $moduleType + * @param string $extra + * * @access public * @return void */ @@ -53,13 +58,14 @@ class productModel extends model } /** - * Create the select code of products. - * - * @param array $products - * @param int $productID - * @param string $currentModule - * @param string $currentMethod - * @param string $extra + * Create the select code of products. + * + * @param array $products + * @param int $productID + * @param string $currentModule + * @param string $currentMethod + * @param string $extra + * * @access public * @return string */ @@ -115,8 +121,8 @@ class productModel extends model /** * Save the product id user last visited to session. - * - * @param int $productID + * + * @param int $productID * @param array $products * @access public * @return int @@ -148,8 +154,8 @@ class productModel extends model /** * Check privilege. - * - * @param int $product + * + * @param int $product * @access public * @return bool */ @@ -157,7 +163,7 @@ class productModel extends model { /* Is admin? */ $account = ',' . $this->app->user->account . ','; - if($this->app->user->admin) return true; + if($this->app->user->admin) return true; $acls = $this->app->user->rights['acls']; if(!empty($acls['products']) and !in_array($product->id, $acls['products'])) return false; @@ -172,8 +178,8 @@ class productModel extends model /** * Get product by id. - * - * @param int $productID + * + * @param int $productID * @access public * @return object */ @@ -188,8 +194,8 @@ class productModel extends model /** * Get by idList. - * - * @param array $productIDList + * + * @param array $productIDList * @access public * @return array */ @@ -200,9 +206,9 @@ class productModel extends model /** * Get products. - * - * @param string $status - * @param int $limit + * + * @param string $status + * @param int $limit * @param int $line * @access public * @return array @@ -227,9 +233,9 @@ class productModel extends model } /** - * Get product pairs. - * - * @param string $mode + * Get product pairs. + * + * @param string $mode * @return array */ public function getPairs($mode = '') @@ -273,7 +279,7 @@ class productModel extends model /** * Get grouped products. - * + * * @access public * @return void */ @@ -284,7 +290,7 @@ class productModel extends model /** * Create a product. - * + * * @access public * @return int */ @@ -325,8 +331,8 @@ class productModel extends model /** * Update a product. - * - * @param int $productID + * + * @param int $productID * @access public * @return array */ @@ -358,7 +364,7 @@ class productModel extends model /** * Batch update products. - * + * * @access public * @return void */ @@ -399,10 +405,10 @@ class productModel extends model $this->fixOrder(); return $allChanges; } - + /** * Close product. - * + * * @param int $productID. * @access public * @return void @@ -520,8 +526,8 @@ class productModel extends model /** * Get projects of a product in pairs. - * - * @param int $productID + * + * @param int $productID * @param string $param all|nodeleted * @access public * @return array @@ -549,8 +555,8 @@ class productModel extends model /** * Get roadmap of a proejct - * - * @param int $productID + * + * @param int $productID * @access public * @return array */ @@ -585,8 +591,8 @@ class productModel extends model /** * Get team members of a product from projects. - * - * @param object $product + * + * @param object $product * @access public * @return array */ @@ -624,9 +630,9 @@ class productModel extends model } /** - * Get product stat by id - * - * @param int $productID + * Get product stat by id + * + * @param int $productID * @access public * @return object|bool */ @@ -737,7 +743,7 @@ class productModel extends model ->where('deleted')->eq(0) ->andWhere('product')->in(array_keys($products)) ->groupBy('product') - ->fetchPairs(); + ->fetchPairs(); $unResolved = $this->dao->select('product,count(*) AS count') ->from(TABLE_BUG) ->where('status')->eq('active') @@ -803,8 +809,8 @@ class productModel extends model /** * Get the summary of product's stories. - * - * @param array $stories + * + * @param array $stories * @access public * @return string. */ @@ -834,9 +840,9 @@ class productModel extends model /** * Judge an action is clickable or not. - * - * @param object $product - * @param string $action + * + * @param object $product + * @param string $action * @access public * @return void */ @@ -851,10 +857,10 @@ class productModel extends model /** * Create the link from module,method,extra - * - * @param string $module - * @param string $method - * @param mix $extra + * + * @param string $module + * @param string $method + * @param mix $extra * @access public * @return void */ @@ -903,7 +909,7 @@ class productModel extends model /** * Fix order. - * + * * @access public * @return void */ @@ -925,7 +931,7 @@ class productModel extends model * get the latest project of the product. * * @param int $productID - * @access public + * @access public * @return object */ public function getLatestProject($productID) diff --git a/module/product/view/browse.html.php b/module/product/view/browse.html.php index b920baa3e2..3c4b2a4b7e 100644 --- a/module/product/view/browse.html.php +++ b/module/product/view/browse.html.php @@ -141,7 +141,7 @@ - + $value) $this->story->printCell($value, $story, $users, $branches, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');?> @@ -323,6 +323,7 @@ +product->checkedSummary);?>
    - + @@ -91,7 +105,7 @@ $storyLink = $this->createLink('story', 'view', "storyID=$story->id&version=$story->version&from=project¶m=$project->id"); $totalEstimate += $story->estimate; ?> - +
    @@ -218,6 +232,7 @@
    +product->checkedSummary);?> id);?> diff --git a/module/project/view/task.html.php b/module/project/view/task.html.php index 1d3c87c8c1..0d1af27552 100644 --- a/module/project/view/task.html.php +++ b/module/project/view/task.html.php @@ -49,8 +49,15 @@ js::set('browseType', $browseType); if($useDatatable) include '../../common/view/datatable.html.php'; $customFields = $this->datatable->getSetting('project'); - $widths = $this->datatable->setFixedFieldWidth($customFields); - $columns = 0; + if($project->type == 'ops') + { + foreach($customFields as $id => $customField) + { + if($customField->id == 'story') unset($customFields[$id]); + } + } + $widths = $this->datatable->setFixedFieldWidth($customFields); + $columns = 0; ?> table-selectable' id='taskList' data-checkable='true' data-fixed-left-width='' data-fixed-right-width='' data-custom-menu='true' data-checkbox-name='taskIDList[]'> @@ -69,14 +76,14 @@ js::set('browseType', $browseType); - + task->printCell($field, $task, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table');?> children)):?> children as $key => $child):?> children)) ? ' table-child-bottom' : '';?> - + task->printCell($field, $child, $users, $browseType, $branchGroups, $modulePairs, $useDatatable ? 'datatable' : 'table', true);?> @@ -166,6 +173,7 @@ js::set('browseType', $browseType);
    +project->checkedSummary);?>