Files
EasySoft-ZenTaoPMS/module/action/tao.php
T

1118 lines
45 KiB
PHP

<?php
declare(strict_types=1);
class actionTao extends actionModel
{
/**
* 获取一个action的基础数据。
* Fetch base info of a action.
*
* @param int $actionID
* @access protected
* @return object|bool
*/
protected function fetchBaseInfo(int $actionID): object|bool
{
return $this->dao->select('*')->from(TABLE_ACTION)->where('id')->eq($actionID)->fetch();
}
/**
* 获取一个基础对象的信息。
* Get object base info.
*
* @param string $table
* @param array $queryParam
* @param string $field
* @param string $orderby
* @access protected
* @return object|bool
*/
protected function getObjectBaseInfo(string $table, array $queryParam, string $field = '*', string $orderby = ''): object|bool
{
$querys = array_map(function($key, $query){return "`{$key}` = '{$query}'";}, array_keys($queryParam), $queryParam);
return $this->dao->select($field)->from($table)->where(implode(' and ', $querys))->orderby($orderby)->fetch();
}
/**
* 获取无需过滤的关联关系。
* Get no filter required relation.
*
* @param string $objectType
* @param int $objectID
* @access protected
* @return array
*/
protected function getNoFilterRequiredRelation(string $objectType, int $objectID): array
{
$product = array(0);
$project = $execution = 0;
switch($objectType)
{
case 'product':
$product = array($objectID);
break;
case 'project':
case 'execution':
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($objectID)->fetchPairs();
if($products) $product = $products;
${$objectType} = $objectID;
if($objectType == 'execution')
{
$project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($objectID)->fetch('project');
if(!$project) $project = 0;
}
break;
}
return array($product, $project, $execution);
}
/**
* 获取对象的产品项目以及执行。
* Get product, project, execution of the object.
*
* @param string $objectType
* @param int $objectID
* @param string $actionType
* @param string $extra
* @access public
* @return array
*/
protected function getNeedRelatedFields(string $objectType, int $objectID, string $actionType = '', string $extra = ''): array
{
$product = array(0);
$project = $execution = 0;
switch($objectType)
{
case 'story':
list($product, $project, $execution) = $this->getStoryActionRelated($objectType, $objectID, (int)$extra);
case 'productplan':
case 'branch':
$product = $objectID == 0 ? $extra : $this->dao->select('product')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch('product');
break;
case 'testcase':
case 'case':
list($product, $project, $execution) = $this->getCaseRelated($objectType, $actionType, $objectID, (int)$extra);
break;
case 'repo':
case 'kanbanlane':
$execution = $this->dao->select('execution')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch('execution');
break;
case 'release':
list($product, $project) = $this->getReleaseRelated($objectType, $objectID);
break;
case 'task':
list($product, $project, $execution) = $this->getTaskReleated($objectType, $objectID);
break;
case 'kanbancolumn':
$execution = $extra;
break;
case 'team':
$type = $this->dao->select('type')->from(TABLE_PROJECT)->where('id')->eq($objectID)->fetch('type');
if($type != 'project') $type = 'execution';
${$type} = $objectID;
break;
case 'whitelist':
if($extra == 'product' || $extra == 'project') ${$extra} = $objectID;
if($extra == 'sprint' || $extra == 'stage') $execution = $objectID;
break;
case 'module':
$module = $this->dao->select('type,root')->from(TABLE_MODULE)->where('id')->eq($actionType != 'deleted' ? $extra : $objectID)->fetch();
if(!empty($module) && $module->type == 'story') $product = $module->root;
break;
case 'review':
list($product, $project) = $this->getReviewRelated($objectType, $objectID);
break;
default:
list($product, $project, $execution) = $this->getGenerateRelated($objectType, $objectID);
break;
}
return array($product, $project, $execution);
}
/**
* 获取用户故事相关的产品、项目、阶段。
* Get story related product, project, stage.
*
* @param string $actionType
* @param int $objectID
* @param int $extra
* @access protected
* @return array
*/
protected function getStoryActionRelated(string $actionType, int $objectID, int $extra): array
{
$product = array(0);
$project = $execution = 0;
switch($actionType)
{
case 'linked2build':
case 'unlinkedfrombuild':
$build = $this->loadModel('build')->getByID($extra);
if($build)
{
$project = $build->project;
$execution = $build->execution;
}
break;
case 'estimated':
$project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq((int)$extra)->fetch('project');
$execution = (int)$extra;
break;
default:
$projectList = $this->dao->select('t2.id,t2.project,t2.type')->from(TABLE_PROJECTSTORY)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t1.story')->eq($objectID)
->fetchAll();
foreach($projectList as $projectInfo)
{
if($projectInfo->type == 'project')
{
$project = $projectInfo->id;
continue;
}
$project = $projectInfo->project;
$execution = $projectInfo->id;
}
break;
}
return array($product, $project, $execution);
}
/**
* 获取用例相关的产品、项目、阶段。
* Get case related product, project, stage.
*
* @param string $objectType
* @param string $actionType
* @param string $table
* @param int $objectID
* @param int $extra
* @access protected
* @return array
*/
protected function getCaseRelated(string $objectType, string $actionType, int $objectID, int $extra): array
{
list($product, $project, $execution) = $this->getGenerateRelated($objectType, $objectID);
if(in_array($actionType, array('linked2testtask', 'unlinkedfromtesttask', 'assigned', 'run')) && $extra)
{
$testtask = $this->dao->select('project,execution')->from(TABLE_TESTTASK)->where('id')->eq($extra)->fetch();
$project = $testtask->project;
$execution = $testtask->execution;
}
return array($product, $project, $execution);
}
/**
* 常规获取相关的产品、项目、执行。
* Get general related product, project, execution.
*
* @param string $objectType
* @param int $objectID
* @access protected
* @return array
*/
protected function getGenerateRelated(string $objectType, int $objectID): array
{
$product = array(0);
$project = $execution = 0;
$result = $this->dao->select('product,project,execution')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
if($result)
{
$product = array($result->product);
$project = $result->project;
$execution = $result->execution;
}
return array($product, $project, $execution);
}
/**
* 获取用例相关的产品、项目、执行。
* Get case related product, project, execution.
*
* @param string $objectType
* @param int $objectID
* @access protected
* @return array
*/
protected function getReleaseRelated(string $objectType, int $objectID): array
{
$product = array(0);
$project = 0;
$result = $this->dao->select('product, build')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
if($result)
{
$product = $result->product;
$project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($result->build)->fetch('project');
}
return array($product, $project);
}
/**
* 获取任务相关的产品、项目、执行。
* Get task related product, project, execution.
*
* @param string $objectType
* @param int $objectID
* @access protected
* @return array
*/
protected function getTaskReleated(string $objectType, int $objectID): array
{
$product = array(0);
$project = $execution = 0;
$result = $this->dao->select('project,execution,story')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
if($result)
{
$table = $result->story != 0 ? TABLE_STORY : TABLE_PROJECTPRODUCT;
$field = $result->story != 0 ? 'id' : 'project';
$value = $result->story != 0 ? $result->story : $result->execution;
$products = $this->dao->select('product')->from($table)->where($field)->eq($value)->fetchPairs();
if($products) $product = $products;
$project = $result->project;
$execution = $result->execution;
}
return array($product, $project, $execution);
}
/**
* 获取需求相关的产品、项目、执行。
* Get story related product, project, execution.
*
* @param string $objectType
* @param int $objectID
* @access protected
* @return array
*/
protected function getReviewRelated(string $objectType, int $objectID): array
{
$product = array(0);
$project = 0;
$result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
if($result)
{
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($result->project)->fetchPairs();
if($products) $product = $products;
$project = zget($result, 'project', 0);
}
return array($product, $project);
}
/**
* 根据类型和ID获取操作记录列表。
* Get action list by type and ID.
*
* @param string $objectType
* @param int $objectID
* @param array $modules
* @access protected
* @return array
*/
protected function getActionListByTypeAndID(string $objectType, array|int $objectID, array $modules): array
{
return $this->dao->select('*')->from(TABLE_ACTION)
->beginIF($objectType == 'project')
->where("objectType IN('project', 'testtask', 'build')")
->andWhere('project')->in($objectID)
->fi()
->beginIF($objectType == 'story')
->where('objectType')->in('story,requirement')
->andWhere('objectID')->in($objectID)
->fi()
->beginIF($objectType == 'case')
->where('objectType')->in('case,testcase')
->andWhere('objectID')->in($objectID)
->fi()
->beginIF($objectType == 'module')
->where('objectType')->eq($objectType)
->andWhere('((action')->ne('deleted')->andWhere('objectID')->in($objectID)->markRight(1)
->orWhere('(action')->eq('deleted')->andWhere('objectID')->in($modules)->markRight(1)->markRight(1)
->fi()
->beginIF(strpos('project,case,story,module', $objectType) === false)
->where('objectType')->eq($objectType)
->andWhere('objectID')->in($objectID)
->fi()
->orderBy('date, id')
->fetchAll('id');
}
/**
* 获取linked操作记录的附加信息。
* Get action extra info.
*
* @param object $action
* @param string $type
* @access protected
* @return bool
*/
protected function getLinked2Extra(object $action, string $type): bool
{
$table = $this->getTableByType($type);
if(empty($table)) return false;
$method = 'view';
if(in_array($type, array('execution', 'kanban')))
{
$execution = $this->fetchObjectInfoByID($table, (int)$action->extra, 'name, type, multiple');
if($execution->type != 'project' && empty($execution->multiple)) return false;
$name = $execution->name;
if($execution->type == 'kanban') $method = 'kanban';
if($name) $action->extra = !common::hasPriv('execution', $method) || ($method == 'kanban' && isonlybody()) ? $name : html::a(helper::createLink('execution', $method, "executionID={$action->execution}"), $name, '', "data-app='execution'");
}
elseif($type == 'project')
{
$project = $this->fetchObjectInfoByID($table, (int)$action->extra, 'name, model, multiple');
if(empty($project->multiple)) return false;
$name = $project->name;
if($project->model == 'kanban') $method = 'kanban';
if($name) $action->extra = common::hasPriv('project', $method) ? html::a(helper::createLink('project', $method, "projectID={$action->project}"), $name) : $name;
}
elseif($type == 'plan' || $type == 'productplan')
{
$plan = $this->fetchObjectInfoByID($table, (int)$action->extra, 'title');
if($plan && $plan->title) $action->extra = common::hasPriv('productplan', 'view') ? html::a(helper::createLink('productplan', $method, "planID={$action->extra}"), $plan->title) : $plan->title;
}
elseif(in_array($type, array('build', 'bug', 'release', 'testtask')))
{
$object = $this->fetchObjectInfoByID($table, (int)$action->extra, 'name');
if($object && $object->name) $action->extra = common::hasPriv($type, $method) ? html::a(helper::createLink($type, $method, $this->processParamString($action, $type), $object->name)) : $object->name;
}
elseif($type == 'revision')
{
$this->processRevision($action, $table);
}
return true;
}
/**
* 通过ID获取对象信息。
* Get object info by ID.
*
* @param string $table
* @param int $objectID
* @access protected
* @return object|bool
*/
protected function fetchObjectInfoByID(string $table, int $objectID, string $field = '*'): object|bool
{
return $this->dao->select($field)->from($table)->where('id')->eq($objectID)->fetch();
}
/**
* 获取unlinked操作记录的附加信息。
* Get unlinked action extra info.
*
* @param object $action
* @param string $type
* @access protected
* @return bool
*/
protected function getUnlinkedFromExtra(object $action, string $type): bool
{
if($type == 'plan') $type = 'productplan';
$table = $this->getTableByType($type);
if(empty($table)) return false;
$method = 'view';
if($type == 'revision')
{
$this->processRevision($action, $table);
}
elseif(in_array($type, array('execution', 'project', 'build', 'release', 'testtask', 'productplan')))
{
$fields = $type == 'productplan' ? 'title' : 'name';
$this->processActionExtra($table, $action, $fields, $type, $method);
}
return true;
}
/**
* 组建Action的extra信息。
* Build action extra info.
*
* @param string $table
* @param object $action
* @param string $fields
* @param string $type
* @param string $method
* @param bool $onlyBody
* @access protected
* @return void
*/
protected function processActionExtra(string $table, object $action, string $fields, string $type, string $method = 'view', bool $onlyBody = false): void
{
$object = $this->fetchObjectInfoByID($table, (int)$action->extra, $fields);
$condition = common::hasPriv($type, $method);
if($onlyBody) $condition = $condition && !isonlybody();
if($object && $object->{$fields}) $action->extra = $condition ? html::a(helper::createLink($type, $method, $this->processParamString($action, $type)), "#{$action->extra} " . $object->{$fields}) : "#{$action->extra} " . $object->{$fields};
}
/**
* 处理revision
* Process revision.
*
* @param object $action
* @param string $table
* @access protected
* @return void
*/
protected function processRevision(object $action, string $table)
{
$fields = 'repo, revision';
$commit = $this->fetchObjectInfoByID($table, $action->extra, $fields);
if($commit)
{
$revision = substr($commit->revision, 0, 10);
$action->extra = common::hasPriv('repo', 'revision') ? html::a(helper::createLink('repo', 'revision', "repoID={$commit->repo}&objectID=0&revision={$commit->revision}"), $revision) : $revision;
}
}
/**
* 根据类型获取对象表。
* Get object table by type.
*
* @param string $type
* @access protected
* @return string
*/
protected function getTableByType(string &$type): string
{
if($type == 'plan') $type = 'productplan';
if($type == 'revision') $type = 'repohistory';
if($type == 'bug') $type = 'build';
return $this->config->objectTables[$type] ?? '';
}
/**
* 处理属性。
* Process attribute.
*
* @param string $type
* @access protected
* @return string
*/
protected function processAttribute($type): string
{
if($type == 'testtask') $type = 'task';
return $type;
}
/**
* 处理参数字符串。
* Process param string.
*
* @param object $action
* @param string $type
* @access protected
* @return string
*/
protected function processParamString(object $action, string $type): string
{
$paramString = '';
switch($type)
{
case 'build':
case 'bug':
case 'release':
$attribute = $this->processAttribute($type);
$paramString = "{$attribute}ID={$action->extra}&type={$action->objectType}";
break;
case 'testtask':
$paramString = "taskID={$action->extra}";
break;
case 'execution':
case 'kanban':
case 'task':
$paramString = "{$type}ID={$action->extra}";
break;
case 'project':
$productID = trim($action->product, ',');
$paramString = "{$type}ID={$action->execution}&productID={$productID}";
break;
case 'productplan':
$paramString = "planID={$action->extra}";
break;
case 'caselib':
$paramString = "libID={$action->extra}";
break;
}
return $paramString;
}
/**
* 搭建创建子任务的Action的extra信息。
* Build create children action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function processCreateChildrenActionExtra(object $action): void
{
$names = $this->dao->select('id,name')->from(TABLE_TASK)->where('id')->in($action->extra)->fetchPairs();
$action->extra = '';
if($names)
{
foreach($names as $id => $name) $action->extra .= common::hasPriv('task', 'view') ? html::a(helper::createLink('task', 'view', "taskID={$id}"), "#{$id} " . $name) . ', ' : "#{$id} " . $name . ', ';
}
$action->extra = trim(trim($action->extra), ',');
}
/**
* 搭建创建需求的Action的extra信息。
* Build create requirement action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function processCreateRequirementsActionExtra(object $action): void
{
$names = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($action->extra)->fetchPairs('id', 'title');
$action->extra = '';
if($names)
{
foreach($names as $id => $name) $action->extra .= common::hasPriv('requriement', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$id"), "#{$id} " . $name) . ', ' : "#{$id} " . $name . ', ';
}
$action->extra = trim(trim($action->extra), ',');
}
/**
* 搭建关闭用户故事和解决bug的Action的extra信息。
* Build closed story and resolve bug action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function processClosedStoryAndResolvedBugActionExtra(object $action): void
{
$action->appendLink = '';
if(strpos($action->extra, '|') !== false) $action->extra = substr($action->extra, 0, strpos($action->extra, '|'));
if(strpos($action->extra, ':') !== false)
{
list($extra, $id) = explode(':', $action->extra);
$action->extra = $extra;
if($id)
{
$table = $action->objectType == 'story' ? TABLE_STORY : TABLE_BUG;
$name = $this->dao->select('title')->from($table)->where('id')->eq($id)->fetch('title');
if($name) $action->appendLink = html::a(helper::createLink($action->objectType, 'view', "id={$id}"), "#{$id} " . $name);
}
}
}
/**
* 结束待办Action的extra信息。
* Finish todo action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function finishToDoActionExtra(object $action): void
{
$action->appendLink = '';
if(strpos($action->extra, ':')!== false)
{
list($extra, $id) = explode(':', $action->extra);
$action->extra = strtolower($extra);
if($id)
{
$table = $this->config->objectTables[$action->extra];
$field = $this->config->action->objectNameFields[$action->extra];
$name = $this->dao->select($field)->from($table)->where('id')->eq($id)->fetch($field);
if($name) $action->appendLink = html::a(helper::createLink($action->extra, 'view', "id={$id}"), "#{$id} " . $name);
}
}
}
/**
* 执行和项目相关Action的extr信息。
* Build execution and project action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function processExecutionAndProjectActionExtra(object $action): void
{
$this->app->loadLang('execution');
$linkedProducts = $this->dao->select('id,name')->from(TABLE_PRODUCT)->where('id')->in($action->extra)->fetchPairs('id', 'name');
$action->extra = '';
if($linkedProducts && $this->config->vision == 'rnd')
{
foreach($linkedProducts as $productID => $productName) $linkedProducts[$productID] = html::a(helper::createLink('product', 'browse', "productID=$productID"), "#{$productID} {$productName}");
$action->extra = sprintf($this->lang->execution->action->extra, '<strong>' . join(', ', $linkedProducts) . '</strong>');
}
}
/**
* 搭建关联用户故事和bug的Action的extra信息。
* Build link story and bug action extra info.
*
* @param object $action
* @param string $module
* @param string $method
* @access protected
* @return void
*/
protected function processLinkStoryAndBugActionExtra(object $action, string $module, string $method): void
{
$extra = '';
foreach(explode(',', $action->extra) as $id) $extra .= common::hasPriv($module, $method) ? html::a(helper::createLink($module, $method, "{$module}ID=$id"), "#$id ") . ', ' : "#$id, ";
$action->extra = trim(trim($extra), ',');
}
/**
* 搭建与用户故事相关的Action的extra信息。
* Build story related action extra info.
*
* @param object $action
* @access protected
* @return void
*/
protected function processToStoryActionExtra(object $action): void
{
$productShadow = $this->dao->select('shadow')->from(TABLE_PRODUCT)->where('id')->in(trim($action->product, ','))->fetch('shadow');
$title = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($action->extra)->fetch('title');
$defaultExtra = "#$action->extra " . $title;
if($productShadow)
{
$projectID = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($action->extra)->fetch('project');
if($title) $action->extra = (common::hasPriv('projectstory', 'view') && $projectID) ? html::a(helper::createLink('projectstory', 'view', "storyID={$action->extra}&projectID=$projectID"), $defaultExtra) : $defaultExtra;
}
else
{
if($title) $action->extra = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$action->extra"), $defaultExtra) : $defaultExtra;
}
}
/**
* 生成用户访问权限检查sql。
* Build user access check sql.
*
* @param string|int $productID
* @param string|int $projectID
* @param string|int $executionID
* @param array $executions
* @access protected
* @return string
*/
protected function buildUserAclsSearchCondition(string|int $productID, string|int $projectID, string|int $executionID, array &$executions): string
{
/* 验证用户的产品/项目/执行权限。 */
/* Verify user's product/project/execution permissions。*/
$aclViews = isset($this->app->user->rights['acls']['views']) ? $this->app->user->rights['acls']['views'] : array();
if($productID == 'all') $grantedProducts = empty($aclViews) || !empty($aclViews['product']) ? $this->app->user->view->products : '0';
if($projectID == 'all') $grantedProjects = empty($aclViews) || !empty($aclViews['project']) ? $this->app->user->view->projects : '0';
if($executionID == 'all') $grantedExecutions = empty($aclViews) || !empty($aclViews['execution']) ? $this->app->user->view->sprints : '0';
if(empty($grantedProducts)) $grantedProducts = '0';
/* If product is selected, show related projects and executions. */
if(is_numeric($productID))
{
$projects = $this->loadModel('product')->getProjectPairsByProduct($productID);
$executions = $this->product->getExecutionPairsByProduct($productID) + array(0 => 0);
$grantedProjects = isset($grantedProjects) ? array_intersect(array_keys($projects), explode(',', $grantedProjects)) : array_keys($projects);
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
}
/* If project is selected, show related products and executions. */
if(is_numeric($projectID))
{
$products = $this->loadModel('product')->getProductPairsByProject($projectID);
$executions = $this->loadModel('execution')->fetchPairs($projectID) + array(0 => 0);
$grantedProducts = isset($grantedProducts) ? array_intersect(array_keys($products), explode(',', $grantedProducts)) : array_keys($products);
$grantedExecutions = isset($grantedExecutions) ? array_intersect(array_keys($executions), explode(',', $grantedExecutions)) : array_keys($executions);
}
/* 组建产品/项目/执行搜索条件。 */
/* Build product/project/execution search condition. */
if(isset($grantedProducts))
{
$productCondition = '';
foreach(explode(',', $grantedProducts) as $product) $productCondition = empty($productCondition) ? "(execution = '0' and project = '0' and (product LIKE '%,{$product},%'" : "{$productCondition} OR product LIKE '%,{$product},%'";
if(!empty($productCondition)) $productCondition .= '))';
}
else
{
$productCondition = "(execution = '0' and project = '0' and product like '%,{$productID},%')";
}
$projectCondition = isset($grantedProjects) ? "(execution = '0' and project != '0' and project " . helper::dbIN($grantedProjects) . ')' : "(execution = '0' and project = '{$projectID}')";
$executionCondition = isset($grantedExecutions) ? "(execution != '0' and execution " . helper::dbIN($grantedExecutions) . ')' : "(execution != '0' and execution = '{$executionID}')";
$condition = "((product =',0,' or product = '0' or product=',,') AND project = '0' AND execution = '0') OR {$productCondition} OR {$projectCondition} OR {$executionCondition}";
return $condition;
}
/**
* 处理工时相关查询条件。
* Process effort related search condition.
*
* @param string $condition
* @param string $period
* @param string $begin
* @param string $end
* @param string $beginDate
* @access protected
* @return void
*/
public function processEffortCondition(string &$condition, string $period, string $begin, string $end, string $beginDate): void
{
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)
->where($condition)
->beginIF($period != 'all')
->beginIF($begin)->andWhere('date')->gt($begin)->fi()
->beginIF($end)->andWhere('date')->lt($end)->fi()
->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
$condition .= " OR (`objectID` IN ({$efforts}) AND `objectType` = 'effort')";
}
/**
* 通过条件获取操作记录列表。
* Get action list by condition.
*
* @param string $condition
* @param string $date
* @param string $period
* @param string $begin
* @param string $end
* @param string $direction
* @param string $account
* @param string $beginDate
* @param string $productID
* @param string $projectID
* @param string $executionID
* @param array $executions
* @param string $actionCondition
* @param string $orderBy
* @param object $pager
* @access protected
* @return array|bool
*/
protected function getActionListByCondition(string $condition, string $date, string $period, string $begin, string $end, string $direction, string $account, string $beginDate, string $productID, string $projectID, string $executionID, array $executions, string $actionCondition, string $orderBy, object $pager = null): array|bool
{
return $this->dao->select('*')->from(TABLE_ACTION)
->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
->andWhere('vision')->eq($this->config->vision)
->beginIF($period != 'all')->andWhere('date')->gt($begin)->andWhere('date')->lt($end)->fi()
->beginIF($date)->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")->fi()
->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
->beginIF($beginDate)->andWhere('date')->ge($beginDate)->fi()
->beginIF(is_numeric($productID))->andWhere('product')->like("%,$productID,%")->fi()
->andWhere('1=1', true)
->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi()
->beginIF(!empty($executions))->andWhere('execution')->in(array_keys($executions))->fi()
->beginIF(is_numeric($executionID))->andWhere('execution')->eq($executionID)->fi()
->markRight(1)
/* lite模式下需要排除的一些类型。 */
/* Types excluded from Lite. */
->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->andWhere('product')->notlike('%,0,%')->fi()
->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi()
->beginIF($executionID == 'notzero')->andWhere('execution')->gt(0)->fi()
->andWhere($condition)
->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
/* 过滤客户端的登陆登出操作。 */
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan,editmr,removemr')
->orderBy($orderBy)
->page($pager)
->fetchAll();
}
/**
* 检查Action是否合法。
* Check if action is legal.
*
* @param object $action
* @param array $shadowProducts
* @param array $docList
* @param array $apiList
* @param array $docLibList
* @access protected
* @return bool
*/
protected function checkIsActionLegal(object $action, array $shadowProducts, array $docList, array $apiList, array $docLibList): bool
{
if($action->objectType == 'doc' && !isset($docList[$action->objectID])) return false;
if($action->objectType == 'api' && !isset($apiList[$action->objectID])) return false;
if($action->objectType == 'doclib' && !isset($docLibList[$action->objectID])) return false;
if($action->objectType == 'product' && isset($shadowProducts[$action->objectID])) return false;
return true;
}
/**
* 为Action添加对象名称。
* Add object name for action.
*
* @param object $action
* @param array $objectNames
* @access protected
* @return void
*/
protected function addObjectNameForAction(object $action, array $objectNames)
{
$action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : '';
if($action->objectType == 'program' && strpos('syncexecution,syncproject,syncprogram', $action->action) !== false)
{
$action->objectName .= $this->lang->action->label->startProgram;
}
elseif($action->objectType == 'branch' && $action->action == 'mergedbranch')
{
if($action->objectID == 0) $action->objectName = $this->lang->branch->main;
$action->objectName = '"' . $action->extra . ' "' . $this->lang->action->to . ' "' . $action->objectName . '"';
}
elseif($action->objectType == 'user')
{
$user = $this->dao->select('id,realname')->from(TABLE_USER)->where('id')->eq($action->objectID)->fetch();
if($user) $action->objectName = $user->realname;
}
elseif($action->objectType == 'kanbancard' && strpos($action->action, 'imported') !== false && $action->action != 'importedcard')
{
$objectType = str_replace('imported', '', $action->action);
$objectTable = zget($this->config->objectTables, $objectType);
$objectName = ($objectType == 'productplan' || $objectType == 'ticket') ? 'title' : 'name';
$action->objectName = $this->dao->select($objectName)->from($objectTable)->where('id')->eq($action->extra)->fetch($objectName);
}
elseif(strpos(',module,chartgroup,', ",$action->objectType,") !== false && !empty($action->extra) && $action->action != 'deleted')
{
$modules = $this->dao->select('id,name')->from(TABLE_MODULE)->where('id')->in(explode(',', $action->extra))->fetchPairs('id');
$action->objectName = implode(',', $modules);
}
elseif($action->objectType == 'mr' && $action->action == 'deleted')
{
$action->objectName = $action->extra;
}
elseif($action->objectType == 'pivot')
{
$pivotNames = json_decode($action->objectName, true);
$action->objectName = zget($pivotNames, $this->app->getClientLang(), '');
if(empty($action->objectName))
{
$pivotNames = array_filter($pivotNames);
$action->objectName = reset($pivotNames);
}
}
}
/**
* 旗舰版处理资产库的链接。
* Process doc link for max.
*
* @param object $action
* @param string $moduleName
* @param string $methodName
* @param string $vars
* @access protected
* @return void
*/
protected function processMaxDocObjectLink(object $action, string $moduleName, string $methodName, string $vars)
{
if($action->objectType == 'doc')
{
$assetLibType = $this->dao->select('assetLibType')->from(TABLE_DOC)->where('id')->eq($action->objectID)->fetch('assetLibType');
if($assetLibType) $method = $assetLibType == 'practice' ? 'practiceView' : 'componentView';
}
else
{
$method = $this->config->action->assetViewMethod[$action->objectType];
}
isset($method) ? $action->objectLink = helper::createLink('assetlib', $method, sprintf($vars, $action->objectID)) : helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID));
}
/**
* 获取文档库链接参数。
* Get doclib link params.
*
* @param object $action
* @access protected
* @return array|bool
*/
protected function getDocLibLinkParameters(object $action)
{
$libID = $action->objectID;
$type = 'custom';
if(!empty($action->project)) $type = 'project';
if(!empty($action->execution)) $type = 'execution';
if(!empty($action->product)) $type = 'product';
$libObjectID = $type != 'custom' ? $action->$type : '';
$libObjectID = trim($libObjectID, ',');
if(empty($libObjectID) && $type != 'custom') return false;
return array($type, $libID, $libObjectID);
}
/**
* 获取文档库类型参数。
* Get doclib type params.
*
* @param object $action
* @access protected
* @return array
*/
protected function getDoclibTypeParams(object $action): array
{
$params = '';
$docLib = $this->dao->select('type,product,project,execution,deleted')->from(TABLE_DOCLIB)->where('id')->eq($action->objectID)->fetch();
$docLib->objectID = in_array($docLib->type, array('product', 'project', 'execution')) ? $docLib->{$docLib->type} : 0;
$appendLib = $docLib->deleted == '1' ? $action->objectID : 0;
if($docLib->type == 'api')
{
$moduleName = 'api';
$methodName = 'index';
$params = "libID={$action->objectID}&moduleID=0&apiID=0&version=0&release=0&appendLib={$appendLib}";
if(!empty($docLib->project) || !empty($docLib->product))
{
$moduleName = 'doc';
if(!empty($docLib->product))
{
$objectID = $docLib->product;
$methodName = 'productspace';
}
if(!empty($docLib->project))
{
$objectID = $docLib->project;
$methodName = 'projectspace';
}
$params = "objectID={$objectID}&libID={$action->objectID}";
}
}
else
{
$moduleName = 'doc';
$methodName = zget($this->config->doc->spaceMethod, $docLib->type, 'tablecontents');
if($methodName == 'myspace') $params = "type=mine&libID={$action->objectID}";
if(!in_array($methodName, array('myspace', 'tablecontents'))) $params = "objectID={$docLib->objectID}&libID={$action->objectID}";
}
return array($moduleName, $methodName, $params);
}
/**
* 检查Action是否可点击。
* Check if action is clickable.
*
* @param object $action
* @param array $deptUsers
* @param string $moduleName
* @param string $methodName
* @access protected
* @return bool
*/
protected function checkActionClickable(object $action, array $deptUsers, string $moduleName, string $methodName): bool
{
if(empty($moduleName) || empty($methodName)) return false;
if(!common::hasPriv($moduleName, $methodName)) return false;
if($action->objectType == 'user' && !isset($deptUsers[$action->objectID]) && !$this->app->user->admin) return false;
if($action->objectType == 'user' && ($action->action == 'login' || $action->action == 'logout')) return false;
if($action->objectType == 'user')
{
$user = $this->dao->select('deleted')->from(TABLE_USER)->where('id')->eq($action->objectID)->fetch();
if($user->deleted == '1') return false;
}
if($action->objectType == 'todo')
{
$todo = $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($action->objectID)->fetch();
if($todo->private == 1 && $todo->account != $this->app->user->account) return false;
}
if($action->objectType == 'mr' && (empty($action->objectName) || $action->action == 'deleted')) return false;
if($action->objectType == 'stakeholder' && $action->project == 0) return false;
if($action->objectType == 'chartgroup') return false;
if($action->objectType == 'branch' && $action->action == 'mergedbranch') return false;
return true;
}
/**
* 获取对象链接参数。
* Get object link params.
*
* @param object $action
* @param string $vars
* @access protected
* @return string
*/
protected function getObjectLinkParams(object $action, string $vars): string
{
if($action->objectType == 'api')
{
$api = $this->dao->select('id,lib,module')->from(TABLE_API)->where('id')->eq($action->objectID)->fetch();
$params = sprintf($vars, $api->lib, $api->id, $api->module);
}
elseif($action->objectType == 'branch' || ($action->objectType == 'module' && $action->action == 'deleted'))
{
$params = sprintf($vars, trim($action->product, ','));
}
elseif($action->objectType == 'kanbanspace')
{
$kanbanSpace = $this->dao->select('type')->from(TABLE_KANBANSPACE)->where('id')->eq($action->objectID)->fetch();
$params = sprintf($vars, $kanbanSpace->type);
}
elseif($action->objectType == 'kanbancard')
{
$table = $this->config->objectTables[$action->objectType];
$kanbanID = $this->dao->select('kanban')->from($table)->where('id')->eq($action->objectID)->fetch('kanban');
$params = sprintf($vars, $kanbanID);
}
else
{
$params = sprintf($vars, $action->objectID);
}
return $params;
}
/**
* 根据对象类型获取恢复对象参数。
* Get object params by object type.
*
* @param string $objectType
* @access protected
* @return array
*/
protected function getUndeleteParamsByObjectType(string $objectType): array
{
$table = $this->config->objectTables[$objectType];
$orderby = '';
$field = '*';
switch($objectType)
{
case 'product':
$field = 'id, name, code, acl';
break;
case 'program':
case 'project':
$field = 'id, acl, name, hasProduct';
break;
case 'doc':
$table = TABLE_DOCCONTENT;
$orderby = 'version desc';
default:
break;
}
return array($table, $orderby, $field);
}
}