tao.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. <?php
  2. class actionTao extends actionModel
  3. {
  4. /**
  5. * 获取一个action的基础数据。
  6. * Fetch base info of a action.
  7. *
  8. * @param int $actionID
  9. * @access public
  10. * @return object|bool
  11. */
  12. public function fetchBaseInfo($actionID)
  13. {
  14. return $this->dao->select('*')->from(TABLE_ACTION)->where('id')->eq($actionID)->fetch();
  15. }
  16. /**
  17. * 获取一个基础对象的信息。
  18. * Get object base info.
  19. *
  20. * @param string $table
  21. * @param array $queryParam
  22. * @param string $field
  23. * @param string $orderby
  24. * @access public
  25. * @return object|bool
  26. */
  27. public function getObjectBaseInfo($table, $queryParam, $field = '*', $orderby = '')
  28. {
  29. $querys = array_map(function($key, $query){return "`{$key}` = '{$query}'";}, array_keys($queryParam), $queryParam);
  30. return $this->dao->select($field)->from($table)->where(implode(' and ', $querys))->orderby($orderby)->fetch();
  31. }
  32. /**
  33. * 获取无需过滤的关联关系。
  34. * Get no filter required relation.
  35. *
  36. * @param string $objectType
  37. * @param int $objectID
  38. * @access public
  39. * @return array
  40. */
  41. public function getNoFilterRequiredRelation($objectType, $objectID)
  42. {
  43. $product = array(0);
  44. $project = $execution = 0;
  45. switch($objectType)
  46. {
  47. case 'product':
  48. $product = array($objectID);
  49. break;
  50. case 'project':
  51. case 'execution':
  52. $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($objectID)->fetchPairs();
  53. if($products) $product = $products;
  54. ${$objectType} = $objectID;
  55. if($objectType == 'execution')
  56. {
  57. $project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($objectID)->fetch('project');
  58. if(!$project) $project = 0;
  59. }
  60. break;
  61. case 'marketresearch':
  62. $project = $objectID;
  63. break;
  64. }
  65. return array($product, $project, $execution);
  66. }
  67. /**
  68. * 获取对象的产品项目以及执行。
  69. * Get product, project, execution of the object.
  70. *
  71. * @param string $objectType
  72. * @param int $objectID
  73. * @param string $actionType
  74. * @param string $extra
  75. * @access public
  76. * @return array
  77. */
  78. public function getNeedRelatedFields($objectType, $objectID, $actionType = '', $extra = '')
  79. {
  80. $product = array(0);
  81. $project = $execution = 0;
  82. switch($objectType)
  83. {
  84. case 'story':
  85. list($product, $project, $execution) = $this->getStoryActionRelated($objectType, $actionType, $objectID, (int)$extra);
  86. break;
  87. case 'productplan':
  88. case 'branch':
  89. $product = $objectID == 0 ? $extra : $this->dao->select('product')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch('product');
  90. break;
  91. case 'testcase':
  92. case 'case':
  93. list($product, $project, $execution) = $this->getCaseRelated($objectType, $actionType, $objectID, (int)$extra);
  94. break;
  95. case 'repo':
  96. case 'nc':
  97. case 'kanbanlane':
  98. $execution = $this->dao->select('execution')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch('execution');
  99. break;
  100. case 'release':
  101. list($product, $project) = $this->getReleaseRelated($objectType, $objectID);
  102. break;
  103. case 'task':
  104. list($product, $project, $execution) = $this->getTaskRelated($objectType, $objectID);
  105. break;
  106. case 'kanbancolumn':
  107. $execution = $extra;
  108. break;
  109. case 'team':
  110. $type = $this->dao->select('type')->from(TABLE_PROJECT)->where('id')->eq($objectID)->fetch('type');
  111. if($type != 'project') $type = 'execution';
  112. ${$type} = $objectID;
  113. break;
  114. case 'whitelist':
  115. if($extra == 'product' || $extra == 'project') ${$extra} = $objectID;
  116. if($extra == 'sprint' || $extra == 'stage') $execution = $objectID;
  117. break;
  118. case 'module':
  119. $moduleID = $actionType != 'deleted' ? (int)$extra : (int)$objectID;
  120. $module = $this->dao->select('type,root')->from(TABLE_MODULE)->where('id')->eq($moduleID)->fetch();
  121. if(!empty($module) && $module->type == 'story') $product = array($module->root);
  122. break;
  123. case 'review':
  124. case 'cm':
  125. case 'projectchange':
  126. list($product, $project) = $this->getReviewRelated($objectType, $objectID);
  127. break;
  128. default:
  129. list($product, $project, $execution) = $this->getGenerateRelated($objectType, $objectID);
  130. break;
  131. }
  132. return array($product, $project, $execution);
  133. }
  134. /**
  135. * 获取用户故事相关的产品、项目、阶段。
  136. * Get story related product, project, stage.
  137. *
  138. * @param string $objectType
  139. * @param string $actionType
  140. * @param int $objectID
  141. * @param int $extra
  142. * @access public
  143. * @return array
  144. */
  145. public function getStoryActionRelated($objectType, $actionType, $objectID, $extra)
  146. {
  147. list($product, $project, $execution) = $this->getGenerateRelated($objectType, $objectID);
  148. switch($actionType)
  149. {
  150. case 'linked2build':
  151. case 'unlinkedfrombuild':
  152. $build = $this->dao->select('project,execution')->from(TABLE_BUILD)->where('id')->eq($extra)->fetch();
  153. if($build)
  154. {
  155. $project = $build->project;
  156. $execution = $build->execution;
  157. }
  158. break;
  159. case 'estimated':
  160. $project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($extra)->fetch('project');
  161. $execution = (int)$extra;
  162. break;
  163. default:
  164. $projectList = $this->dao->select('t2.id,t2.project,t2.type')->from(TABLE_PROJECTSTORY)->alias('t1')
  165. ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
  166. ->where('t1.story')->eq($objectID)
  167. ->fetchAll();
  168. foreach($projectList as $projectInfo)
  169. {
  170. if($projectInfo->type == 'project')
  171. {
  172. $project = $projectInfo->id;
  173. continue;
  174. }
  175. $project = $projectInfo->project;
  176. $execution = $projectInfo->id;
  177. }
  178. break;
  179. }
  180. return array($product, $project, $execution);
  181. }
  182. /**
  183. * 获取用例相关的产品、项目、阶段。
  184. * Get case related product, project, stage.
  185. *
  186. * @param string $objectType
  187. * @param string $actionType
  188. * @param string $table
  189. * @param int $objectID
  190. * @param int $extra
  191. * @access public
  192. * @return array
  193. */
  194. public function getCaseRelated($objectType, $actionType, $objectID, $extra)
  195. {
  196. list($product, $project, $execution) = $this->getGenerateRelated($objectType, $objectID);
  197. if(in_array($actionType, array('linked2testtask', 'unlinkedfromtesttask', 'run')) && $extra)
  198. {
  199. $testtask = $this->dao->select('project,execution')->from(TABLE_TESTTASK)->where('id')->eq($extra)->fetch();
  200. $project = $testtask->project;
  201. $execution = $testtask->execution;
  202. }
  203. return array($product, $project, $execution);
  204. }
  205. /**
  206. * 常规获取相关的产品、项目、执行。
  207. * Get general related product, project, execution.
  208. *
  209. * @param string $objectType
  210. * @param int $objectID
  211. * @access public
  212. * @return array
  213. */
  214. public function getGenerateRelated($objectType, $objectID)
  215. {
  216. $product = $project = $execution = 0;
  217. if(!isset($this->config->objectTables[$objectType])) return array(array($product), $project, $execution);
  218. $result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
  219. if($result)
  220. {
  221. $product = zget($result, 'product', 0);
  222. $project = zget($result, 'project', 0);
  223. $execution = zget($result, 'execution', 0);
  224. }
  225. return array(array($product), $project, $execution);
  226. }
  227. /**
  228. * 获取分支相关的产品、项目、执行。
  229. * Get case related product, project, execution.
  230. *
  231. * @param string $objectType
  232. * @param int $objectID
  233. * @access public
  234. * @return array
  235. */
  236. public function getReleaseRelated($objectType, $objectID)
  237. {
  238. $product = 0;
  239. $project = 0;
  240. $result = $this->dao->select('product, build')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
  241. if($result)
  242. {
  243. $product = $result->product;
  244. $project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->in($result->build)->fetch('project');
  245. }
  246. return array(array($product), $project);
  247. }
  248. /**
  249. * 获取任务相关的产品、项目、执行。
  250. * Get task related product, project, execution.
  251. *
  252. * @param string $objectType
  253. * @param int $objectID
  254. * @access public
  255. * @return array
  256. */
  257. public function getTaskRelated($objectType, $objectID)
  258. {
  259. $product = array(0);
  260. $project = $execution = 0;
  261. $result = $this->dao->select('project,execution,story')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
  262. if($result)
  263. {
  264. $table = $result->story != 0 ? TABLE_STORY : TABLE_PROJECTPRODUCT;
  265. $field = $result->story != 0 ? 'id' : 'project';
  266. $value = $result->story != 0 ? $result->story : $result->execution;
  267. $products = $this->dao->select('product')->from($table)->where($field)->eq($value)->fetchPairs();
  268. if($products) $product = array_values($products);
  269. $project = $result->project;
  270. $execution = $result->execution;
  271. }
  272. return array($product, $project, $execution);
  273. }
  274. /**
  275. * 获取需求相关的产品、项目、执行。
  276. * Get story related product, project, execution.
  277. *
  278. * @param string $objectType
  279. * @param int $objectID
  280. * @access public
  281. * @return array
  282. */
  283. public function getReviewRelated($objectType, $objectID)
  284. {
  285. $product = array(0);
  286. $project = 0;
  287. $result = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
  288. if($result)
  289. {
  290. $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($result->project)->fetchPairs();
  291. if($products) $product = $products;
  292. $project = zget($result, 'project', 0);
  293. }
  294. return array($product, $project);
  295. }
  296. /**
  297. * 根据类型和ID获取操作记录列表。
  298. * Get action list by type and ID.
  299. *
  300. * @param string $objectType
  301. * @param int $objectID
  302. * @param array $modules
  303. * @access public
  304. * @return array
  305. */
  306. public function getActionListByTypeAndID($objectType, $objectID, $modules)
  307. {
  308. $subTables = array();
  309. if($this->config->edition != 'open')
  310. {
  311. $subTables = $this->dao->select('module')->from(TABLE_WORKFLOW)
  312. ->where('parent')->eq($objectType)
  313. ->andWhere('type')->eq('table')
  314. ->fetchPairs();
  315. }
  316. return $this->dao->select('*')->from(TABLE_ACTION)
  317. ->beginIF($objectType == 'project')
  318. ->where("objectType IN('project', 'testtask', 'build')")
  319. ->andWhere('project')->in($objectID)
  320. ->fi()
  321. ->beginIF($objectType == 'story')
  322. ->where('objectType')->in('story,requirement')
  323. ->andWhere('objectID')->in($objectID)
  324. ->fi()
  325. ->beginIF($objectType == 'case' || $objectType == 'testcase')
  326. ->where('objectType')->in('case,testcase')
  327. ->andWhere('objectID')->in($objectID)
  328. ->fi()
  329. ->beginIF($objectType == 'module')
  330. ->where('objectType')->eq($objectType)
  331. ->andWhere('((action')->ne('deleted')->andWhere('objectID')->in($objectID)->markRight(1)
  332. ->orWhere('(action')->eq('deleted')->andWhere('objectID')->in($modules)->markRight(1)->markRight(1)
  333. ->fi()
  334. ->beginIF(!empty($subTables))
  335. ->where('(objectType')->eq($objectType)
  336. ->andWhere('objectID')->in($objectID)
  337. ->markRight(1)
  338. ->orWhere('(objectType')->in($subTables)
  339. ->andWhere('extra')->in($objectID)
  340. ->markRight(1)
  341. ->fi()
  342. ->beginIF(empty($subTables) && !in_array($objectType, array('project', 'case', 'testcase', 'story', 'module')))
  343. ->where('objectType')->eq($objectType)
  344. ->andWhere('objectID')->in($objectID)
  345. ->fi()
  346. ->orderBy('date, id')
  347. ->fetchAll('id', false);
  348. }
  349. /**
  350. * 获取 linked 和 unlinked 操作记录的附加信息。
  351. * Get action extra info.
  352. *
  353. * @param object $action
  354. * @param string $type
  355. * @access public
  356. * @return bool
  357. */
  358. public function getLinkedExtra($action, $type)
  359. {
  360. if($type == 'plan') $type = 'productplan';
  361. if($type == 'revision') $type = 'repohistory';
  362. if($type == 'bug') $type = 'build';
  363. if($type == 'roadmap' && $action->objectType == 'story') $type = 'roadmap';
  364. $table = zget($this->config->objectTables, $type, '');
  365. if(empty($table)) return false;
  366. $method = 'view';
  367. if(in_array($type, array('execution', 'kanban')))
  368. {
  369. $execution = $this->fetchObjectInfoByID(TABLE_EXECUTION, (int)$action->extra, 'name, type, multiple');
  370. if(!$execution) return false;
  371. if($execution->type != 'project' && empty($execution->multiple)) return false;
  372. $name = $execution->name;
  373. if($execution->type == 'kanban') $method = 'kanban';
  374. if($name)
  375. {
  376. $isModalKanban = $method == 'kanban' && isonlybody();
  377. $canShowLink = common::hasPriv('execution', $method) && !$isModalKanban && $this->config->vision != 'or';
  378. $action->extra = $canShowLink ? html::a(helper::createLink('execution', $method, "executionID={$action->execution}"), $name, '', "data-app='execution'") : $name;
  379. }
  380. }
  381. elseif($type == 'project')
  382. {
  383. $project = $this->fetchObjectInfoByID($table, (int)$action->extra, 'name, model, multiple');
  384. if(!$project) return false;
  385. $name = $project->name;
  386. if($project->model == 'kanban') $method = $project->multiple ? 'kanban' : 'index';
  387. if($name) $action->extra = (common::hasPriv('project', $method) and $this->config->vision != 'or') ? html::a(helper::createLink('project', $method, "projectID=$action->project"), $name, '_self', in_array($method, array('view', 'index')) ? 'data-app="project"' : '') : $name;
  388. }
  389. elseif($type == 'plan' || $type == 'productplan')
  390. {
  391. $plan = $this->fetchObjectInfoByID($table, (int)$action->extra, 'title');
  392. if($plan && $plan->title) $action->extra = common::hasPriv('productplan', 'view') && $this->config->vision != 'or' ? html::a(helper::createLink('productplan', $method, "planID={$action->extra}"), $plan->title) : $plan->title;
  393. }
  394. elseif(in_array($type, array('build', 'bug', 'release', 'testtask', 'roadmap')))
  395. {
  396. $field = $type == 'build' ? 'name, execution' : 'name';
  397. $object = $this->fetchObjectInfoByID($table, (int)$action->extra, $field);
  398. $buildTab = $type == 'build' && (in_array($this->app->tab, array('product', 'qa')) || empty($action->execution)) ? 'project' : $this->app->tab;
  399. if($this->app->tab == 'system') $buildTab = 'project';
  400. if($object && $object->name) $action->extra = common::hasPriv($type, $method) ? html::a(helper::createLink($type, $method, $this->processParamString($action, $type)), $object->name, '', $type == 'build' ? "data-app='{$buildTab}'" : '') : $object->name;
  401. }
  402. elseif($type == 'revision')
  403. {
  404. $commit = $this->fetchObjectInfoByID($table, $action->extra, 'repo, revision');
  405. if($commit)
  406. {
  407. $revision = substr($commit->revision, 0, 10);
  408. $action->extra = common::hasPriv('repo', 'revision') ? html::a(helper::createLink('repo', 'revision', "repoID={$commit->repo}&objectID=0&revision={$commit->revision}"), $revision) : $revision;
  409. }
  410. }
  411. return true;
  412. }
  413. /**
  414. * 通过ID获取对象信息。
  415. * Get object info by ID.
  416. *
  417. * @param string $table
  418. * @param int $objectID
  419. * @access public
  420. * @return object|bool
  421. * @param string $field
  422. */
  423. public function fetchObjectInfoByID($table, $objectID, $field = '*')
  424. {
  425. return $this->dao->select($field)->from($table)->where('id')->eq($objectID)->fetch();
  426. }
  427. /**
  428. * 组建Action的extra信息。
  429. * Build action extra info.
  430. *
  431. * @param string $table
  432. * @param object $action
  433. * @param string $fields
  434. * @param string $type
  435. * @param string $method
  436. * @param bool $onlyBody
  437. * @param bool $addlink
  438. * @access public
  439. * @return void
  440. * @param bool $addLink
  441. */
  442. public function processActionExtra($table, $action, $fields, $type, $method = 'view', $onlyBody = false, $addLink = true)
  443. {
  444. $object = $this->fetchObjectInfoByID($table, (int)$action->extra, $fields);
  445. $condition = common::hasPriv($type, $method);
  446. if($onlyBody) $condition = $condition && !isonlybody();
  447. if($object && $object->{$fields})
  448. {
  449. $misc = '';
  450. if($action->objectType == 'bug' && $action->action == 'converttotask' && $type == 'task' && $method == 'view')
  451. {
  452. $misc = "data-app='execution'";
  453. $isMultipleProject = $this->dao->select('multiple')->from(TABLE_PROJECT)->where('id')->eq($action->project)->fetch('multiple');
  454. if(!$isMultipleProject) $misc = "data-app='project'";
  455. }
  456. $action->extra = $condition && $addLink ? html::a(helper::createLink($type, $method, $this->processParamString($action, $type)), "#{$action->extra} " . $object->{$fields}, '', $misc) : "#{$action->extra} " . $object->{$fields};
  457. }
  458. }
  459. /**
  460. * 处理需求层级。
  461. * Process story grade.
  462. *
  463. * @param object $action
  464. * @access public
  465. * @return object
  466. */
  467. public function processStoryGradeActionExtra($action)
  468. {
  469. $action->extra = $this->dao->select('t1.name')->from(TABLE_STORYGRADE)->alias('t1')
  470. ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.grade = t2.grade AND t1.type = t2.type')
  471. ->where('t2.id')->eq($action->objectID)
  472. ->fetch('name');
  473. return $action;
  474. }
  475. /**
  476. * 处理属性。
  477. * Process attribute.
  478. *
  479. * @param string $type
  480. * @access public
  481. * @return string
  482. */
  483. public function processAttribute($type)
  484. {
  485. if($type == 'testtask') $type = 'task';
  486. return $type;
  487. }
  488. /**
  489. * 处理参数字符串。
  490. * Process param string.
  491. *
  492. * @param object $action
  493. * @param string $type
  494. * @access public
  495. * @return string
  496. */
  497. public function processParamString($action, $type)
  498. {
  499. $paramString = '';
  500. switch($type)
  501. {
  502. case 'build':
  503. case 'bug':
  504. case 'release':
  505. $attribute = $this->processAttribute($type);
  506. $paramString = "{$attribute}ID={$action->extra}&type={$action->objectType}";
  507. break;
  508. case 'testtask':
  509. $paramString = "taskID={$action->extra}";
  510. break;
  511. case 'execution':
  512. case 'kanban':
  513. case 'story':
  514. $paramString = "{$type}ID={$action->extra}";
  515. break;
  516. case 'task':
  517. case 'story':
  518. case 'charter':
  519. $paramString = "{$type}ID={$action->extra}";
  520. break;
  521. case 'project':
  522. $productID = trim($action->product, ',');
  523. $paramString = "{$type}ID={$action->execution}&productID={$productID}";
  524. break;
  525. case 'productplan':
  526. $paramString = "planID={$action->extra}";
  527. break;
  528. case 'caselib':
  529. $paramString = "libID={$action->extra}";
  530. break;
  531. case 'roadmap':
  532. $paramString = "roadmapID={$action->extra}";
  533. break;
  534. case 'assetlib':
  535. $paramString = "libID={$action->extra}";
  536. break;
  537. case 'demand':
  538. $paramString = "demandID={$action->extra}";
  539. break;
  540. case 'epic':
  541. $paramString = "storyID={$action->extra}";
  542. break;
  543. }
  544. return $paramString;
  545. }
  546. /**
  547. * 搭建创建子任务的Action的extra信息。
  548. * Build create children action extra info.
  549. *
  550. * @param object $action
  551. * @access public
  552. * @return void
  553. */
  554. public function processCreateChildrenActionExtra($action)
  555. {
  556. $names = $this->dao->select('id,name')->from(TABLE_TASK)->where('id')->in($action->extra)->fetchPairs();
  557. $action->extra = '';
  558. if($names)
  559. {
  560. foreach($names as $id => $name) $action->extra .= common::hasPriv('task', 'view') ? html::a(helper::createLink('task', 'view', "taskID={$id}"), "#{$id} " . $name) . ', ' : "#{$id} " . $name . ', ';
  561. }
  562. $action->extra = trim(trim($action->extra), ',');
  563. }
  564. /**
  565. * 搭建创建需求的Action的extra信息。
  566. * Build create requirement action extra info.
  567. *
  568. * @param object $action
  569. * @access public
  570. * @return void
  571. */
  572. public function processCreateRequirementsActionExtra($action)
  573. {
  574. $names = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($action->extra)->fetchPairs();
  575. $action->extra = '';
  576. if($names)
  577. {
  578. foreach($names as $id => $name) $action->extra .= common::hasPriv('requriement', 'view') ? html::a(helper::createLink('story', 'view', "storyID={$id}"), "#{$id} " . $name) . ', ' : "#{$id} " . $name . ', ';
  579. }
  580. $action->extra = trim(trim($action->extra), ',');
  581. }
  582. /**
  583. * 通过 extra 获取对象的 appendLink。
  584. * Get object appendLink by extra.
  585. *
  586. * @param object $action
  587. * @access public
  588. * @return void
  589. */
  590. public function processAppendLinkByExtra($action)
  591. {
  592. $action->appendLink = '';
  593. if(strpos($action->extra, '|') !== false) $action->extra = substr($action->extra, 0, strpos($action->extra, '|'));
  594. if(strpos($action->extra, ':') !== false)
  595. {
  596. list($extra, $id) = explode(':', $action->extra);
  597. if($id)
  598. {
  599. $extra = strtolower($extra);
  600. $module = $action->objectType == 'todo' ? $extra : $action->objectType;
  601. $table = $this->config->objectTables[$module];
  602. $field = $this->config->action->objectNameFields[$module];
  603. $name = $this->dao->select($field)->from($table)->where('id')->eq($id)->fetch($field);
  604. $method = $module == 'story' ? 'storyView' : 'view';
  605. if($name) $action->appendLink = html::a(helper::createLink($module, $method, "id={$id}"), "#{$id} " . $name);
  606. }
  607. $action->extra = $extra;
  608. }
  609. }
  610. /**
  611. * 搭建关联用户故事和bug的Action的extra信息。
  612. * Build link story and bug action extra info.
  613. *
  614. * @param object $action
  615. * @param string $module
  616. * @param string $method
  617. * @access public
  618. * @return void
  619. */
  620. public function processLinkStoryAndBugActionExtra($action, $module, $method)
  621. {
  622. $extra = '';
  623. foreach(explode(',', $action->extra) as $id) $extra .= common::hasPriv($module, $method) ? html::a(helper::createLink($module, $method, "{$module}ID={$id}"), "#{$id} ", '', "data-size='lg' data-toggle='modal'") . ', ' : "#{$id}, ";
  624. $action->extra = trim(trim($extra), ',');
  625. }
  626. /**
  627. * 搭建与用户故事相关的Action的extra信息。
  628. * Build story related action extra info.
  629. *
  630. * @param object $action
  631. * @access public
  632. * @return void
  633. */
  634. public function processToStoryActionExtra($action)
  635. {
  636. $productShadow = $this->dao->select('shadow')->from(TABLE_PRODUCT)->where('id')->in(trim($action->product, ','))->fetch('shadow');
  637. $title = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($action->extra)->fetch('title');
  638. $defaultExtra = "#{$action->extra} {$title}";
  639. if($productShadow)
  640. {
  641. $projectID = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($action->extra)->fetch('project');
  642. if($title) $action->extra = common::hasPriv('projectstory', 'view') && $projectID ? html::a(helper::createLink('projectstory', 'view', "storyID={$action->extra}&projectID={$projectID}"), $defaultExtra) : $defaultExtra;
  643. }
  644. else
  645. {
  646. if($title) $action->extra = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID={$action->extra}"), $defaultExtra) : $defaultExtra;
  647. }
  648. }
  649. /**
  650. * 通过条件获取操作记录列表。
  651. * Get action list by condition.
  652. *
  653. * @param string $condition
  654. * @param string $begin
  655. * @param string $end
  656. * @param string $account
  657. * @param string|int $productID
  658. * @param string|int $projectID
  659. * @param string|int $executionID
  660. * @param string $actionCondition
  661. * @param string $orderBy
  662. * @param int $limit
  663. * @access public
  664. * @return array|bool
  665. */
  666. public function getActionListByCondition($condition, $begin, $end, $account, $productID, $projectID, $executionID, $actionCondition, $orderBy, $limit = 50)
  667. {
  668. /* 获取最近一个月的动态用actionrecent表。 */
  669. $lastMonth = date('Y-m-d', strtotime('-1 month'));
  670. $actionTable = ($begin >= $lastMonth && $end >= $lastMonth) ? TABLE_ACTIONRECENT : TABLE_ACTION;
  671. $actionCondition = str_replace(' `action`', ' action.`action`', $actionCondition);
  672. $hasProduct = preg_match('/t2\.(`?)product/', $condition);
  673. if(is_numeric($productID) && $productID) $hasProduct = true;
  674. if($productID === 'notzero') $hasProduct = true;
  675. return $this->dao->select('action.*')->from($actionTable)->alias('action')
  676. ->beginIF($hasProduct)->leftJoin(TABLE_ACTIONPRODUCT)->alias('t2')->on('action.id=t2.action')->fi()
  677. ->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
  678. ->andWhere('action.action')->notIN($this->config->action->ignoreActions4Dynamic)
  679. ->andWhere('vision')->eq($this->config->vision)
  680. ->beginIF($begin != EPOCH_DATE)->andWhere('date')->ge($begin)->fi()
  681. ->beginIF($end != FUTURE_DATE)->andWhere('date')->le($end)->fi()
  682. ->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi()
  683. ->beginIF(is_numeric($productID) && $productID)->andWhere('t2.product')->eq($productID)->fi()
  684. ->beginIF(is_numeric($projectID) && $projectID)->andWhere('project')->eq($projectID)->fi()
  685. ->beginIF(is_numeric($executionID) && $executionID)->andWhere('execution')->eq($executionID)->fi()
  686. /* lite模式下需要排除的一些类型。 */
  687. /* Types excluded from Lite. */
  688. ->beginIF($this->config->vision == 'lite')->andWhere('objectType')->notin('product')->fi()
  689. ->beginIF($this->config->systemMode == 'light')->andWhere('objectType')->notin('program')->fi()
  690. ->beginIF($productID === 'notzero')->andWhere('t2.product')->gt(0)->fi()
  691. ->beginIF($projectID === 'notzero')->andWhere('project')->gt(0)->fi()
  692. ->beginIF($executionID === 'notzero')->andWhere('execution')->gt(0)->fi()
  693. ->beginIF($condition && $condition != '1=1')->andWhere($condition)->fi()
  694. ->beginIF($actionCondition)->andWhere("($actionCondition)")->fi()
  695. ->orderBy($orderBy)
  696. ->limit($limit)
  697. ->fetchAll('', false);
  698. }
  699. /**
  700. * 根据条件获取动态表。
  701. * Get action table by condition.
  702. *
  703. * @param string $period
  704. * @access public
  705. * @return string
  706. */
  707. public function getActionTable($period)
  708. {
  709. return in_array($period, $this->config->action->latestDateList) ? TABLE_ACTIONRECENT : TABLE_ACTION;
  710. }
  711. /**
  712. * 检查Action是否合法。
  713. * Check if action is legal.
  714. *
  715. * @param object $action
  716. * @param array $shadowProducts
  717. * @param array $docList
  718. * @param array $apiList
  719. * @param array $docLibList
  720. * @access public
  721. * @return bool
  722. */
  723. public function checkIsActionLegal($action, $shadowProducts, $docList, $apiList, $docLibList)
  724. {
  725. if(($action->objectType == 'doc' || $action->objectType == 'doctemplate') && !isset($docList[$action->objectID])) return false;
  726. if($action->objectType == 'api' && !isset($apiList[$action->objectID])) return false;
  727. if($action->objectType == 'doclib' && !isset($docLibList[$action->objectID])) return false;
  728. if($action->objectType == 'product' && isset($shadowProducts[$action->objectID])) return false;
  729. return true;
  730. }
  731. /**
  732. * 为Action添加对象名称。
  733. * Add object name for action.
  734. *
  735. * @param object $action
  736. * @param array $objectNames
  737. * @param string $objectType
  738. * @access public
  739. * @return void
  740. */
  741. public function addObjectNameForAction($action, $objectNames, $objectType)
  742. {
  743. $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : '';
  744. if($action->objectType == 'program' && strpos('syncexecution,syncproject,syncprogram', $action->action) !== false)
  745. {
  746. $action->objectName .= $this->lang->action->label->startProgram;
  747. }
  748. elseif($action->objectType == 'branch' && $action->action == 'mergedbranch')
  749. {
  750. if($action->objectID == 0) $action->objectName = $this->lang->branch->main;
  751. $action->objectName = '"' . $action->extra . ' "' . $this->lang->action->to . ' "' . $action->objectName . '"';
  752. }
  753. elseif($action->objectType == 'user')
  754. {
  755. $user = $this->dao->select('id,realname')->from(TABLE_USER)->where('id')->eq($action->objectID)->fetch();
  756. if($user) $action->objectName = $user->realname;
  757. }
  758. elseif($action->objectType == 'kanbancard' && strpos($action->action, 'imported') !== false && $action->action != 'importedcard')
  759. {
  760. $objectType = str_replace('imported', '', $action->action);
  761. $objectTable = zget($this->config->objectTables, $objectType, '');
  762. $objectName = ($objectType == 'productplan' || $objectType == 'ticket') ? 'title' : 'name';
  763. if($objectTable) $action->objectName = $this->dao->select($objectName)->from($objectTable)->where('id')->eq($action->extra)->fetch($objectName);
  764. }
  765. elseif(strpos(',module,chartgroup,', ",$action->objectType,") !== false && !empty($action->extra) && $action->action != 'deleted')
  766. {
  767. $modules = $this->dao->select('id,name')->from(TABLE_MODULE)->where('id')->in(explode(',', $action->extra))->fetchPairs('id');
  768. $action->objectName = implode(',', $modules);
  769. }
  770. elseif($action->objectType == 'mr' && $action->action == 'deleted')
  771. {
  772. $action->objectName = $action->extra;
  773. }
  774. elseif($action->objectType == 'pivot')
  775. {
  776. $pivotNames = json_decode($action->objectName, true);
  777. $action->objectName = zget($pivotNames, $this->app->getClientLang(), '');
  778. if(empty($action->objectName))
  779. {
  780. $pivotNames = array_filter($pivotNames);
  781. $action->objectName = reset($pivotNames);
  782. }
  783. }
  784. elseif($action->objectType == 'aiassistant')
  785. {
  786. $action->objectName = $this->dao->select('name')->from(TABLE_AI_ASSISTANT)->where('id')->eq($action->objectID)->fetch('name');
  787. }
  788. if (empty($action->objectName) && preg_match('/^(gitlab|gitea|gogs|mr)/', $objectType)) $action->objectName = $action->extra;
  789. }
  790. /**
  791. * 旗舰版处理资产库的链接。
  792. * Process doc link for max.
  793. *
  794. * @param object $action
  795. * @param string $moduleName
  796. * @param string $methodName
  797. * @param string $vars
  798. * @access public
  799. * @return void
  800. */
  801. public function processMaxDocObjectLink($action, $moduleName, $methodName, $vars)
  802. {
  803. if($action->objectType == 'doc')
  804. {
  805. $assetLibType = $this->dao->select('assetLibType')->from(TABLE_DOC)->where('id')->eq($action->objectID)->fetch('assetLibType');
  806. if($assetLibType) $method = $assetLibType == 'practice' ? 'practiceView' : 'componentView';
  807. }
  808. else
  809. {
  810. $method = $this->config->action->assetViewMethod[$action->objectType];
  811. }
  812. if(isset($method))
  813. {
  814. $moduleName = 'assetlib';
  815. $methodName = $method;
  816. }
  817. $action->objectLink = common::hasPriv($moduleName, $methodName) ? helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID)) : '';
  818. $action->hasLink = true;
  819. }
  820. /**
  821. * 获取文档库链接参数。
  822. * Get doclib link params.
  823. *
  824. * @param object $action
  825. * @access public
  826. * @return array|bool
  827. */
  828. public function getDocLibLinkParameters($action)
  829. {
  830. $libID = $action->objectID;
  831. $type = 'custom';
  832. if(!empty($action->project)) $type = 'project';
  833. if(!empty($action->execution)) $type = 'execution';
  834. if(!empty($action->product)) $type = 'product';
  835. $libObjectID = $type != 'custom' ? $action->{$type} : '';
  836. $libObjectID = trim($libObjectID, ',');
  837. if(empty($libObjectID) && $type != 'custom') return false;
  838. return array($type, $libID, $libObjectID);
  839. }
  840. /**
  841. * 获取文档库类型参数。
  842. * Get doclib type params.
  843. *
  844. * @param object $action
  845. * @access public
  846. * @return array
  847. */
  848. public function getDoclibTypeParams($action)
  849. {
  850. $params = '';
  851. $docLib = $this->dao->select('type,product,project,execution,deleted')->from(TABLE_DOCLIB)->where('id')->eq($action->objectID)->fetch();
  852. $docLib->objectID = in_array($docLib->type, array('product', 'project', 'execution')) ? $docLib->{$docLib->type} : 0;
  853. $appendLib = $docLib->deleted == '1' ? $action->objectID : 0;
  854. if($docLib->type == 'api')
  855. {
  856. $moduleName = 'api';
  857. $methodName = 'index';
  858. $params = "libID={$action->objectID}&moduleID=0&apiID=0&version=0&release=0&appendLib={$appendLib}";
  859. if(!empty($docLib->project) || !empty($docLib->product))
  860. {
  861. $moduleName = 'doc';
  862. if(!empty($docLib->product))
  863. {
  864. $objectID = $docLib->product;
  865. $methodName = 'productspace';
  866. }
  867. if(!empty($docLib->project))
  868. {
  869. $objectID = $docLib->project;
  870. $methodName = 'projectspace';
  871. }
  872. $params = "objectID={$objectID}&libID={$action->objectID}";
  873. }
  874. }
  875. else
  876. {
  877. $moduleName = 'doc';
  878. $methodName = zget($this->config->doc->spaceMethod, $docLib->type, 'tablecontents');
  879. if($methodName == 'myspace') $params = "type=mine&libID={$action->objectID}";
  880. if(!in_array($methodName, array('myspace', 'tablecontents'))) $params = "objectID={$docLib->objectID}&libID={$action->objectID}";
  881. }
  882. return array($moduleName, $methodName, $params);
  883. }
  884. /**
  885. * 检查Action是否可点击。
  886. * Check if action is clickable.
  887. *
  888. * @param object $action
  889. * @param array $deptUsers
  890. * @param string $moduleName
  891. * @param string $methodName
  892. * @access public
  893. * @return bool
  894. */
  895. public function checkActionClickable($action, $deptUsers, $moduleName, $methodName)
  896. {
  897. if(empty($moduleName) || empty($methodName)) return false;
  898. if(!common::hasPriv($moduleName, $methodName)) return false;
  899. if(!helper::hasFeature($moduleName)) return false;
  900. if($action->objectType == 'user' && !isset($deptUsers[$action->objectID]) && !$this->app->user->admin) return false;
  901. if($action->objectType == 'user' && ($action->action == 'login' || $action->action == 'logout')) return false;
  902. if($action->objectType == 'user')
  903. {
  904. $user = $this->dao->select('deleted')->from(TABLE_USER)->where('id')->eq($action->objectID)->fetch();
  905. if($user && $user->deleted == '1') return false;
  906. }
  907. if($action->objectType == 'todo')
  908. {
  909. $todo = $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($action->objectID)->fetch();
  910. if($todo && $todo->private == 1 && $todo->account != $this->app->user->account) return false;
  911. }
  912. if($action->objectType == 'docTemplate' && !common::hasPriv('docTempalte', 'view')) return false;
  913. if($action->objectType == 'mr' && (empty($action->objectName) || $action->action == 'deleted')) return false;
  914. if($action->objectType == 'stakeholder' && $action->project == 0) return false;
  915. if($action->objectType == 'chartgroup') return false;
  916. if($action->objectType == 'branch' && $action->action == 'mergedbranch') return false;
  917. if($action->objectType == 'case')
  918. {
  919. $case = $this->dao->select('lib')->from(TABLE_CASE)->where('id')->eq($action->objectID)->fetch();
  920. if($action->action == 'tolib' || !empty($case->lib)) return helper::hasFeature('caselib');
  921. }
  922. return true;
  923. }
  924. /**
  925. * 获取对象链接参数。
  926. * Get object link params.
  927. *
  928. * @param object $action
  929. * @param string $vars
  930. * @access public
  931. * @return string
  932. */
  933. public function getObjectLinkParams($action, $vars)
  934. {
  935. if($action->objectType == 'api')
  936. {
  937. $api = $this->dao->select('id,lib,module')->from(TABLE_API)->where('id')->eq($action->objectID)->fetch();
  938. $params = sprintf($vars, $api->lib, $api->id, $api->module);
  939. }
  940. elseif($action->objectType == 'branch' || ($action->objectType == 'module' && $action->action == 'deleted'))
  941. {
  942. $params = sprintf($vars, trim($action->product, ','));
  943. }
  944. elseif($action->objectType == 'kanbanspace')
  945. {
  946. $kanbanSpace = $this->dao->select('type')->from(TABLE_KANBANSPACE)->where('id')->eq($action->objectID)->fetch();
  947. $params = sprintf($vars, $kanbanSpace->type);
  948. }
  949. elseif($action->objectType == 'kanbancard')
  950. {
  951. $table = $this->config->objectTables[$action->objectType];
  952. $kanbanID = $this->dao->select('kanban')->from($table)->where('id')->eq($action->objectID)->fetch('kanban');
  953. $params = sprintf($vars, $kanbanID);
  954. }
  955. elseif($action->objectType == 'module' && $action->action == 'undeleted')
  956. {
  957. $table = $this->config->objectTables[$action->objectType];
  958. $moduleID = $this->dao->select('root')->from($table)->where('id')->eq($action->objectID)->fetch('root');
  959. $params = sprintf($vars, $moduleID);
  960. }
  961. else
  962. {
  963. $params = sprintf($vars, $action->objectID);
  964. }
  965. return $params;
  966. }
  967. /**
  968. * 根据对象类型获取恢复对象参数。
  969. * Get object params by object type.
  970. *
  971. * @param string $objectType
  972. * @access public
  973. * @return array
  974. */
  975. public function getUndeleteParamsByObjectType($objectType)
  976. {
  977. $table = $this->config->objectTables[$objectType];
  978. $orderby = '';
  979. $field = '*';
  980. $queryKey = 'id';
  981. switch($objectType)
  982. {
  983. case 'product':
  984. $field = 'id, name, code, acl';
  985. break;
  986. case 'program':
  987. case 'project':
  988. $field = 'id, acl, name, hasProduct, multiple';
  989. break;
  990. case 'doc':
  991. $table = TABLE_DOCCONTENT;
  992. $orderby = 'version desc';
  993. $queryKey = 'doc';
  994. default:
  995. break;
  996. }
  997. return array($table, $orderby, $field, $queryKey);
  998. }
  999. }