Merge branch 'master' of https://github.com/easysoft/zentaopms
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;}
|
||||
#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;}
|
||||
|
||||
+104
-27
@@ -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";
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 "<span class='right-icon'> ";
|
||||
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 '</span>';
|
||||
if(common::hasPriv($file->objectType, 'edit', $file->objectID))
|
||||
{
|
||||
echo "<span class='right-icon'> ";
|
||||
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 '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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?';
|
||||
|
||||
@@ -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是否导入计划关联的相关需求?';
|
||||
|
||||
@@ -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'))) ? '<br />' : "\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 ++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user