diff --git a/module/bug/model.php b/module/bug/model.php index b8bc244652..7405d1673e 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -2430,7 +2430,7 @@ class bugModel extends model $canBatchResolve = common::hasPriv('bug', 'batchResolve'); $canBatchAssignTo = common::hasPriv('bug', 'batchAssignTo'); - $canBatchAction = $canBatchEdit or $canBatchConfirm or $canBatchClose or $canBatchActivate or $canBatchChangeBranch or $canBatchChangeModule or $canBatchResolve or $canBatchAssignTo or $canBatchCancel; + $canBatchAction = $canBatchEdit or $canBatchConfirm or $canBatchClose or $canBatchActivate or $canBatchChangeBranch or $canBatchChangeModule or $canBatchResolve or $canBatchAssignTo; $canView = common::hasPriv('bug', 'view'); $bugLink = inlink('view', "bugID=$bug->id"); diff --git a/module/common/model.php b/module/common/model.php index 84ccfad48a..77ba607de0 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -1363,7 +1363,7 @@ EOD; if(strpos(",{$limitedProjects},", ",$objectID,") !== false) $limitedProject = true; if(empty($app->user->rights['rights']['my']['limited']) && !$limitedProject) return true; } - + if(empty($app->user->rights['rights']['my']['limited'])) return true; if(!is_null($method) && strpos($method, 'batch') === 0) return false; if(!is_null($method) && strpos($method, 'link') === 0) return false; diff --git a/module/custom/css/ajaxmenu.css b/module/custom/css/ajaxmenu.css index 7402724b98..b9fd5075b5 100644 --- a/module/custom/css/ajaxmenu.css +++ b/module/custom/css/ajaxmenu.css @@ -12,4 +12,5 @@ #menuEditor li > a .item-hidden-icon {display: none; margin-left: 3px;} #menuEditor .dropdown-menu > li > a .item-hidden-icon {margin-left: 10px;} #menuEditor li.menu-hidden > a .item-hidden-icon {display: inline-block;} -#menuEditor .nav > li.menu-hidden > a {opacity: .7; border: 1px dashed #ddd; background: rgba(0,0,0,.1); margin: 0 2px;} \ No newline at end of file +#menuEditor .nav > li.menu-hidden > a {opacity: .7; border: 1px dashed #ddd; background: rgba(0,0,0,.1); margin: 0 2px;} +#menuEditor .nav > li.menu-hidden > a > .dropdown{display: inline-block;} diff --git a/module/doc/model.php b/module/doc/model.php index 3a504b49b3..33ffe6bfda 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -35,11 +35,16 @@ class docModel extends model if($libID) { $lib = $this->getLibById($libID); - if($this->checkPriv($lib)) + if(!$this->checkPrivLib($lib)) { - $type = $lib->product ? 'product' : 'custom'; - $type = $lib->project ? 'project' : $type; + echo(js::alert($this->lang->doc->accessDenied)); + $loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login"; + if(strpos($this->server->http_referer, $loginLink) !== false) die(js::locate(inlink('index'))); + die(js::locate('back')); } + + $type = $lib->product ? 'product' : 'custom'; + $type = $lib->project ? 'project' : $type; } $mainLib = $type == 'custom' ? $this->lang->doc->customAB : $mainLib; @@ -191,7 +196,7 @@ class docModel extends model * @access public * @return array */ - public function getLibs($type = '') + public function getLibs($type = '', $extra = '') { if($type == 'product' or $type == 'project') { @@ -215,11 +220,49 @@ class docModel extends model $libPairs = array(); while($lib = $stmt->fetch()) { - if($this->checkPriv($lib)) $libPairs[$lib->id] = $lib->name; + if($this->checkPrivLib($lib, $extra)) $libPairs[$lib->id] = $lib->name; } return $libPairs; } + /** + * Get grant libs by doc. + * + * @access public + * @return array + */ + public function getPrivLibsByDoc() + { + static $libs; + if($libs === null) + { + $libs = array(); + $stmt = $this->dao->select('lib,groups,users')->from(TABLE_DOC)->where('acl')->ne('open')->andWhere("(groups != '' or users != '')")->query(); + + $account = ",{$this->app->user->account},"; + $userGroups = $this->app->user->groups; + while($lib = $stmt->fetch()) + { + if(strpos(",$lib->users,", $account) !== false) + { + $libs[$lib->lib] = $lib->lib; + } + else + { + foreach($userGroups as $groupID) + { + if(strpos(",$lib->groups,", ",$groupID,") !== false) + { + $libs[$lib->lib] = $lib->lib; + break; + } + } + } + } + } + return $libs; + } + /** * Create a library. * @@ -377,7 +420,7 @@ class docModel extends model ->fetchAll('id'); foreach($docs as $docID => $doc) { - if(!$this->checkPriv($doc)) unset($docs[$docID]); + if(!$this->checkPrivDoc($doc)) unset($docs[$docID]); } $docs = $this->dao->select('*')->from(TABLE_DOC) ->where('id')->in(array_keys($docs)) @@ -481,7 +524,7 @@ class docModel extends model $docIdList = array(); while($doc = $stmt->fetch()) { - if($this->checkPriv($doc)) $docIdList[$doc->id] = $doc->id; + if($this->checkPrivDoc($doc)) $docIdList[$doc->id] = $doc->id; } return $docIdList; } @@ -498,7 +541,7 @@ class docModel extends model { $doc = $this->dao->select('*')->from(TABLE_DOC)->where('id')->eq((int)$docID)->fetch(); if(!$doc) return false; - if(!$this->checkPriv($doc)) + if(!$this->checkPrivDoc($doc)) { echo(js::alert($this->lang->doc->accessDenied)); $loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login"; @@ -803,13 +846,14 @@ class docModel extends model } /** - * Check priv. + * Check priv for lib. * * @param object $object + * @param string $extra * @access public * @return bool */ - public function checkPriv($object, $type = 'lib') + public function checkPrivLib($object, $extra = '') { if($this->app->user->admin) return true; @@ -817,29 +861,26 @@ class docModel extends model if(!empty($object->product) and !empty($acls['products']) and !in_array($object->product, $acls['products'])) return false; if(!empty($object->project) and !empty($acls['projects']) and !in_array($object->project, $acls['projects'])) return false; - if(isset($object->lib)) - { - static $libs; - if(empty($libs)) $libs = $this->getLibs('all'); - if(!isset($libs[$object->lib])) return false; - } - if($object->acl == 'open') return true; $account = ',' . $this->app->user->account . ','; if(isset($object->addedBy) and $object->addedBy == $this->app->user->account) return true; - if($object->acl == 'private' and strpos(",$object->users,", $account) !== false) return true; + if(strpos(",$object->users,", $account) !== false) return true; if($object->acl == 'custom') { - if(strpos(",$object->users,", $account) !== false) return true; - $userGroups = $this->app->user->groups; foreach($userGroups as $groupID) { if(strpos(",$object->groups,", ",$groupID,") !== false) return true; } } - if(isset($object->lib)) return false; + + if(strpos($extra, 'notdoc') === false) + { + static $extraDocLibs; + if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc(); + if(isset($extraDocLibs[$object->id])) return true; + } if($object->project) { @@ -858,6 +899,42 @@ class docModel extends model return false; } + /** + * Check priv for doc. + * + * @param object $object + * @access public + * @return bool + */ + public function checkPrivDoc($object) + { + if($this->app->user->admin) return true; + + static $extraDocLibs; + if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc(); + + static $libs; + if($libs === null) $libs = $this->getLibs('all', 'notdoc'); + if(isset($libs[$object->lib]) and isset($extraDocLibs[$object->lib])) unset($extraDocLibs[$object->lib]); + if(!isset($libs[$object->lib]) and !isset($extraDocLibs[$object->lib])) return false; + + if($object->acl == 'open' and !isset($extraDocLibs[$object->lib])) return true; + + $account = ',' . $this->app->user->account . ','; + if(isset($object->addedBy) and $object->addedBy == $this->app->user->account) return true; + if(strpos(",$object->users,", $account) !== false) return true; + if($object->acl == 'custom') + { + $userGroups = $this->app->user->groups; + foreach($userGroups as $groupID) + { + if(strpos(",$object->groups,", ",$groupID,") !== false) return true; + } + } + + return false; + } + /** * Get all libs by type. * @@ -1017,7 +1094,7 @@ class docModel extends model { if($limit && $i > $limit) break; $key = ($type == 'product' or $type == 'project') ? $type : 'id'; - if($this->checkPriv($docLib) and !isset($libs[$docLib->$key])) + if($this->checkPrivLib($docLib) and !isset($libs[$docLib->$key])) { $libs[$docLib->$key] = $docLib->name; $i++; @@ -1062,7 +1139,7 @@ class docModel extends model { foreach($libs as $lib) { - if($this->checkPriv($lib)) $buildGroups[$objectID][$lib->id] = $lib->name; + if($this->checkPrivLib($lib)) $buildGroups[$objectID][$lib->id] = $lib->name; } if($type == 'product' and isset($hasProject[$objectID]) and common::hasPriv('doc', 'allLibs')) $buildGroups[$objectID]['project'] = $this->lang->doclib->project; if(common::hasPriv('doc', 'showFiles')) $buildGroups[$objectID]['files'] = $this->lang->doclib->files; @@ -1104,7 +1181,7 @@ class docModel extends model $libs = array(); foreach($objectLibs as $lib) { - if($this->checkPriv($lib)) $libs[$lib->id] = $lib; + if($this->checkPrivLib($lib)) $libs[$lib->id] = $lib; } $itemCounts = $this->statLibCounts(array_keys($libs)); @@ -1154,7 +1231,7 @@ class docModel extends model $docCounts = array(); foreach($docs as $doc) { - if(!$this->checkPriv($doc)) continue; + if(!$this->checkPrivDoc($doc)) continue; if(!isset($docCounts[$doc->lib])) $docCounts[$doc->lib] = 0; $docCounts[$doc->lib] ++; } @@ -1272,7 +1349,7 @@ class docModel extends model $docGroups = array(); foreach($docs as $doc) { - if($this->checkPriv($doc)) $docGroups[$doc->module][$doc->id] = $doc; + if($this->checkPrivDoc($doc)) $docGroups[$doc->module][$doc->id] = $doc; } } @@ -1326,7 +1403,7 @@ class docModel extends model if(empty($libID)) return ''; $lib = $this->getLibById($libID); - if(!$this->checkPriv($lib)) + if(!$this->checkPrivLib($lib)) { echo(js::alert($this->lang->doc->accessDenied)); $loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login"; diff --git a/module/file/model.php b/module/file/model.php index c96813bfdf..ab7a49ee2a 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -542,13 +542,13 @@ class fileModel extends model if($pos === false) { $data[$row][$col] .= "\n" . $line; - $data[$row][$col] = str_replace(',', ',', trim($data[$row][$col], '"')); + $data[$row][$col] = str_replace(',', ',', $data[$row][$col]); continue; } else { - $data[$row][$col] .= "\n" . substr($line, 0, $pos + 1); - $data[$row][$col] = trim(str_replace(',', ',', trim($data[$row][$col], '"'))); + $data[$row][$col] .= "\n" . substr($line, 0, $pos); + $data[$row][$col] = trim(str_replace(',', ',', $data[$row][$col])); $line = substr($line, $pos + 2); $col++; } @@ -561,20 +561,20 @@ class fileModel extends model /* the cell has '"', the delimiter is '",'. */ if($line{0} == '"') { - $pos = strpos($line, '",'); + $pos = strpos($line, '",'); if($pos === false) { - $data[$row][$col] = $line; + $data[$row][$col] = substr($line, 1); /* if line is not empty, then the data of cell is not end. */ if(strlen($line) >= 1) continue 2; $line = ''; } else { - $data[$row][$col] = substr($line, 0, $pos + 1); + $data[$row][$col] = substr($line, 1, $pos - 1); $line = substr($line, $pos + 2); } - $data[$row][$col] = str_replace(',', ',', trim($data[$row][$col], '"')); + $data[$row][$col] = str_replace(',', ',', $data[$row][$col]); } else { @@ -593,7 +593,7 @@ class fileModel extends model } } - $data[$row][$col] = trim(str_replace(',', ',', trim($data[$row][$col], '"'))); + $data[$row][$col] = trim(str_replace(',', ',', $data[$row][$col])); $col++; } } diff --git a/module/file/view/printfiles.html.php b/module/file/view/printfiles.html.php index 8ac6804d41..0e978e6449 100644 --- a/module/file/view/printfiles.html.php +++ b/module/file/view/printfiles.html.php @@ -78,10 +78,13 @@ $sessionString .= session_name() . '=' . session_id(); echo html::a($this->createLink('file', 'download', "fileID=$file->id") . $sessionString, $fileTitle . " ({$fileSize})", '_blank', "onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth)\""); - echo "  "; - common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='edit iframe text-primary' title='{$lang->file->edit}'"); - if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='text-primary' onclick='deleteFile($file->id)' title='$lang->delete'"); - echo ''; + if(common::hasPriv($file->objectType, 'edit', $file->objectID)) + { + echo "  "; + common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='edit iframe text-primary' title='{$lang->file->edit}'"); + if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='text-primary' onclick='deleteFile($file->id)' title='$lang->delete'"); + echo ''; + } echo ''; } } diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index e5b4c78c5a..51361c10c7 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -337,6 +337,8 @@ $lang->resource->project->updateOrder = 'updateOrder'; $lang->resource->project->kanban = 'kanban'; $lang->resource->project->printKanban = 'printKanban'; $lang->resource->project->tree = 'tree'; +$lang->resource->project->treeTask = 'treeTask'; +$lang->resource->project->treeStory = 'treeStory'; $lang->resource->project->all = 'all'; $lang->resource->project->kanbanHideCols = 'kanbanHideCols'; $lang->resource->project->kanbanColsColor = 'kanbanColsColor'; @@ -382,12 +384,14 @@ $lang->project->methodOrder[170] = 'updateOrder'; $lang->project->methodOrder[175] = 'kanban'; $lang->project->methodOrder[180] = 'printKanban'; $lang->project->methodOrder[185] = 'tree'; -$lang->project->methodOrder[190] = 'all'; -$lang->project->methodOrder[195] = 'kanbanHideCols'; -$lang->project->methodOrder[200] = 'kanbanColsColor'; -$lang->project->methodOrder[205] = 'export'; -$lang->project->methodOrder[210] = 'storyKanban'; -$lang->project->methodOrder[215] = 'storySort'; +$lang->project->methodOrder[190] = 'tree'; +$lang->project->methodOrder[195] = 'tree'; +$lang->project->methodOrder[200] = 'all'; +$lang->project->methodOrder[205] = 'kanbanHideCols'; +$lang->project->methodOrder[210] = 'kanbanColsColor'; +$lang->project->methodOrder[215] = 'export'; +$lang->project->methodOrder[220] = 'storyKanban'; +$lang->project->methodOrder[225] = 'storySort'; /* Task. */ $lang->resource->task = new stdclass(); diff --git a/module/productplan/js/create.js b/module/productplan/js/create.js index 480f5822d2..db1aff6aca 100644 --- a/module/productplan/js/create.js +++ b/module/productplan/js/create.js @@ -50,6 +50,14 @@ $('#end').on('change', function() $("input:radio[name='delta']").attr("checked", false); }); +$('form').submit(function() +{ + $('#submit').click(function() + { + return false; + }); +}) + $('#future').on('change', function() { if($(this).prop('checked')) diff --git a/module/project/lang/en.php b/module/project/lang/en.php index 45e311efc2..93e30b51e3 100644 --- a/module/project/lang/en.php +++ b/module/project/lang/en.php @@ -145,6 +145,8 @@ $lang->project->importPlanStories = 'Link Story From Plan'; $lang->project->importBug = 'Import Bugs'; $lang->project->updateOrder = 'Sort'; $lang->project->tree = 'Tree'; +$lang->project->treeTask = 'Show Task'; +$lang->project->treeStory = 'Show Story'; $lang->project->storyKanban = 'Story Kanban'; $lang->project->storySort = 'Sort Story'; $lang->project->importPlanStory = '' . $lang->projectCommon . ' is created!\nDo you want to iport stories linked to the plan?'; diff --git a/module/project/lang/zh-cn.php b/module/project/lang/zh-cn.php index 7f44be0252..73053d872b 100644 --- a/module/project/lang/zh-cn.php +++ b/module/project/lang/zh-cn.php @@ -145,6 +145,8 @@ $lang->project->importPlanStories = '按计划关联需求'; $lang->project->importBug = '导入Bug'; $lang->project->updateOrder = '排序'; $lang->project->tree = '树状图'; +$lang->project->treeTask = '只看任务'; +$lang->project->treeStory = '只看需求'; $lang->project->storyKanban = '需求看板'; $lang->project->storySort = '需求排序'; $lang->project->importPlanStory = '创建' . $lang->projectCommon . '成功!\n是否导入计划关联的相关需求?'; diff --git a/module/testcase/control.php b/module/testcase/control.php index d336618f8c..fe2735701e 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -1112,7 +1112,7 @@ class testcase extends control $case->stepExpect = ''; $case->real = ''; $result = isset($results[$case->id]) ? $results[$case->id] : array(); - if($case->lastRunResult == 'fail' and !isset($relatedSteps[$case->id]) and !empty($result)) $case->real = $result[0]['real']; + $case->real = $result[0]['real']; if(isset($relatedSteps[$case->id])) { $i = $childId = 0; @@ -1133,7 +1133,7 @@ class testcase extends control $sign = (in_array($this->post->fileType, array('html', 'xml'))) ? '
' : "\n"; $case->stepDesc .= $stepId . ". " . $step->desc . $sign; $case->stepExpect .= $stepId . ". " . $step->expect . $sign; - if($case->lastRunResult == 'fail') $case->real .= $stepId . ". " . (isset($result[$step->id]) ? $result[$step->id]['real'] : '') . $sign; + $case->real .= $stepId . ". " . (isset($result[$step->id]) ? $result[$step->id]['real'] : '') . $sign; $childId ++; } } diff --git a/module/user/model.php b/module/user/model.php index 14f0a372bd..f26e9727f3 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -767,9 +767,9 @@ class userModel extends model if(!empty($acl['projects'])) $acls['projects'] = !empty($acls['projects']) ? array_merge($acls['projects'], $acl['projects']) : $acl['projects']; } - if($productAllow && empty($acls['products'])) $acls['products'] = array(); - if($projectAllow && empty($acls['projects'])) $acls['projects'] = array(); - if($viewAllow && empty($acl['views'])) $acls['views'] = array(); + if($productAllow) $acls['products'] = array(); + if($projectAllow) $acls['projects'] = array(); + if($viewAllow) $acls['views'] = array(); $sql = $this->dao->select('module, method')->from(TABLE_USERGROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2') ->on('t1.group = t2.group')