control.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <?php
  2. /**
  3. * The control file of release module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chunsheng Wang <chunsheng@cnezsoft.com>
  8. * @package release
  9. * @version $Id: control.php 4178 2013-01-20 09:32:11Z wwccss $
  10. * @link https://www.zentao.net
  11. */
  12. class projectrelease extends control
  13. {
  14. public $products = array();
  15. /**
  16. * 构造函数,自动加载模块。
  17. * Construct function, load module auto.
  18. *
  19. * @param string $moduleName
  20. * @param string $methodName
  21. * @access public
  22. * @return void
  23. */
  24. public function __construct($moduleName = '', $methodName = '')
  25. {
  26. parent::__construct($moduleName, $methodName);
  27. $this->loadModel('product');
  28. $this->loadModel('release');
  29. $this->loadModel('project');
  30. }
  31. /**
  32. * 项目发布列表。
  33. * Browse releases.
  34. *
  35. * @param int $projectID
  36. * @param int $executionID
  37. * @param string $type
  38. * @param string $orderBy
  39. * @param int $recTotal
  40. * @param int $recPerPage
  41. * @param int $pageID
  42. * @param string $from
  43. * @param int $blockID
  44. * @access public
  45. * @return void
  46. */
  47. public function browse($projectID = 0, $executionID = 0, $type = 'all', $orderBy = 't1.date_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1, $from = 'project', $blockID = 0)
  48. {
  49. /* 设置发布列表和版本列表 session。*/
  50. /* Set releaseList and buildList session. */
  51. $uri = $this->app->getURI(true);
  52. $this->session->set('releaseList', $uri, 'project');
  53. $this->session->set('buildList', $uri);
  54. if($from == 'doc' ||$from == 'ai')
  55. {
  56. $projects = $this->project->getPairs();
  57. if(empty($projects))
  58. {
  59. $this->app->loadLang('doc');
  60. return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->tips->noProject));
  61. }
  62. if(!$projectID) $projectID = key($projects);
  63. $this->view->projects = $projects;
  64. }
  65. /* 设置菜单。*/
  66. /* Set menu. */
  67. if($projectID) $this->project->setMenu($projectID);
  68. if($executionID) $this->loadModel('execution')->setMenu($executionID, $this->app->rawModule, $this->app->rawMethod);
  69. $this->app->loadClass('pager', true);
  70. $pager = new pager($recTotal, $recPerPage, $pageID);
  71. $releases = $this->projectrelease->getList($projectID, $type, $orderBy, $pager);
  72. $children = implode(',', array_column($releases, 'releases'));
  73. /* 判断是否展示分支。*/
  74. /* Judge whether to show branch. */
  75. $showBranch = false;
  76. foreach($releases as $release)
  77. {
  78. $release->desc = str_replace('&nbsp;', ' ', strip_tags($release->desc));
  79. if($release->productType != 'normal') $showBranch = true;
  80. }
  81. $project = $this->project->getByID($projectID);
  82. $execution = $this->loadModel('execution')->getByID($executionID);
  83. $this->view->title = (isset($project->name) ? $project->name : $execution->name) . $this->lang->hyphen . $this->lang->release->browse;
  84. $this->view->products = $this->product->getPairs('all', 0, '', 'all');
  85. $this->view->pageSummary = $this->release->getPageSummary($releases, $type);
  86. $this->view->projectID = $projectID;
  87. $this->view->executionID = $executionID;
  88. $this->view->type = $type;
  89. $this->view->from = $this->app->tab;
  90. $this->view->project = $project;
  91. $this->view->execution = $execution;
  92. $this->view->releases = $releases;
  93. $this->view->pager = $pager;
  94. $this->view->orderBy = $orderBy;
  95. $this->view->showBranch = $showBranch;
  96. $this->view->appList = $this->loadModel('system')->getPairs();
  97. $this->view->childReleases = $this->release->getListByCondition(toIntArray($children), 0, true);
  98. $this->view->from = $from;
  99. $this->view->blockID = $blockID;
  100. $this->view->idList = '';
  101. if($from == 'doc')
  102. {
  103. $content = $this->loadModel('doc')->getDocBlockContent($blockID);
  104. $this->view->idList = zget($content, 'idList', '');
  105. }
  106. $this->display();
  107. }
  108. /**
  109. * 创建一个发布。
  110. * Create a release.
  111. *
  112. * @param int $projectID
  113. * @param int $productID
  114. * @access public
  115. * @return void
  116. */
  117. public function create($projectID, $productID = 0)
  118. {
  119. /* Set create config. */
  120. $this->config->projectrelease->create = $this->config->release->create;
  121. if(!empty($_POST))
  122. {
  123. $release = $this->projectreleaseZen->buildReleaseForCreate($projectID);
  124. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  125. if(!empty($_FILES['releaseFiles'])) $_FILES['files'] = $_FILES['releaseFiles'];
  126. unset($_FILES['releaseFiles']);
  127. $releaseID = $this->release->create($release, $this->post->sync ? true : false);
  128. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  129. $this->loadModel('action')->create('release', $releaseID, 'opened');
  130. $message = $this->executeHooks($releaseID);
  131. if($message) $this->lang->saveSuccess = $message;
  132. if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $releaseID));
  133. if(isInModal()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true));
  134. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('view', "releaseID=$releaseID")));
  135. }
  136. /* Set menu. */
  137. $this->project->setMenu($projectID);
  138. $this->projectreleaseZen->commonAction($projectID, $productID);
  139. unset($this->lang->release->statusList['fail']);
  140. unset($this->lang->release->statusList['terminate']);
  141. /* Get the builds that can select. */
  142. $builds = $this->loadModel('build')->getBuildPairs(array($this->view->product->id), 'all', 'notrunk|withbranch|hasproject', $projectID, 'project', '', false);
  143. $releasedBuilds = $this->projectrelease->getReleasedBuilds($projectID);
  144. foreach($releasedBuilds as $build) unset($builds[$build]);
  145. $this->view->title = $this->view->project->name . $this->lang->hyphen . $this->lang->release->create;
  146. $this->view->projectID = $projectID;
  147. $this->view->builds = $builds;
  148. $this->view->lastRelease = $this->projectrelease->getLast($projectID);
  149. $this->view->users = $this->loadModel('user')->getPairs('noclosed');
  150. $this->view->status = 'wait';
  151. $this->display('release', 'create');
  152. }
  153. /**
  154. * 编辑一个发布。
  155. * Edit a release.
  156. *
  157. * @param int $releaseID
  158. * @access public
  159. * @return void
  160. */
  161. public function edit($releaseID)
  162. {
  163. /* Set edit config. */
  164. $this->config->projectrelease->edit = $this->config->release->edit;
  165. $release = $this->release->getByID($releaseID);
  166. $release->files = $this->loadModel('file')->getByObject('release', $releaseID);
  167. if(!empty($_POST))
  168. {
  169. if($this->post->status == 'wait')
  170. {
  171. $this->config->release->edit->requiredFields = str_replace(',releasedDate', '', $this->config->release->edit->requiredFields);
  172. }
  173. else
  174. {
  175. $this->config->release->edit->requiredFields = str_replace(',date', '', $this->config->release->edit->requiredFields);
  176. }
  177. $releaseData = form::data($this->config->release->form->edit, $releaseID)->setIF($this->post->build === false, 'build', 0)->get();
  178. $releaseData->releases = '';
  179. $system = $this->loadModel('system')->fetchByID($releaseData->system);
  180. if($system->integrated == '1')
  181. {
  182. $releases = (array)$this->post->releases;
  183. $releaseData->build = '';
  184. $releaseData->releases = trim(implode(',', array_filter($releases)), ',');
  185. if(!$releaseData->releases) dao::$errors['releases[' . key($releases) . ']'][] = sprintf($this->lang->error->notempty, $this->lang->release->name);
  186. }
  187. if(dao::isError()) return $this->sendError(dao::getError());
  188. $changes = $this->release->update($releaseData, $release);
  189. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  190. if($changes)
  191. {
  192. $actionID = $this->loadModel('action')->create('release', $releaseID, 'Edited');
  193. if(!empty($changes)) $this->action->logHistory($actionID, $changes);
  194. }
  195. $message = $this->executeHooks($releaseID);
  196. if($message) $this->lang->saveSuccess = $message;
  197. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('view', "releaseID={$releaseID}")));
  198. }
  199. /* Set menu. */
  200. if(!$this->session->project)
  201. {
  202. $releaseProject = explode(',', $release->project);
  203. $this->session->set('project', $releaseProject[0], 'project');
  204. }
  205. $this->project->setMenu($this->session->project);
  206. $this->projectreleaseZen->commonAction($this->session->project, $release->product, $release->branch);
  207. /* Get the builds that can select. */
  208. $builds = $this->loadModel('build')->getBuildPairs(array($release->product), $release->branch, 'notrunk|withbranch|hasproject', $this->session->project, 'project', $release->build, false);
  209. $bindBuilds = $this->build->getByList(explode(',', $release->build));
  210. $releasedBuilds = $this->projectrelease->getReleasedBuilds($this->session->project);
  211. foreach($releasedBuilds as $releasedBuild)
  212. {
  213. if(!isset($bindBuilds[$releasedBuild])) unset($builds[$releasedBuild]);
  214. }
  215. $appList = $this->view->appList;
  216. if($release->system && !isset($appList[$release->system])) $appList[$release->system] = $this->system->fetchByID($release->system);
  217. $this->view->title = $this->view->product->name . $this->lang->hyphen . $this->lang->release->edit;
  218. $this->view->release = $release;
  219. $this->view->builds = $builds;
  220. $this->view->users = $this->loadModel('user')->getPairs('noclosed');
  221. $this->view->appList = $appList;
  222. $this->display('release', 'edit');
  223. }
  224. /**
  225. * 查看一个发布。
  226. * View a release.
  227. *
  228. * @param int $releaseID
  229. * @param string $type
  230. * @param string $link
  231. * @param string $param
  232. * @param string $orderBy
  233. * @param int $recTotal
  234. * @param int $recPerPage
  235. * @param int $pageID
  236. * @access public
  237. * @return void
  238. */
  239. public function view($releaseID, $type = 'story', $link = 'false', $param = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1)
  240. {
  241. echo $this->fetch('release', 'view', "releaseID={$releaseID}&type={$type}&link={$link}&param={$param}&orderBy={$orderBy}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}");
  242. }
  243. /**
  244. * 提示发布。
  245. * Notify for release.
  246. *
  247. * @param int $releaseID
  248. * @access public
  249. * @return void
  250. */
  251. public function notify($releaseID)
  252. {
  253. echo $this->fetch('release', 'notify', "releaseID={$releaseID}&projectID={$this->session->project}");
  254. }
  255. /**
  256. * 删除一个发布。
  257. * Delete a release.
  258. *
  259. * @param int $releaseID
  260. * @access public
  261. * @return void
  262. */
  263. public function delete($releaseID)
  264. {
  265. return $this->fetch('release', 'delete', "releaseID={$releaseID}");
  266. }
  267. /**
  268. * 导出项目发布到 HTML。
  269. * Export the stories of release to HTML.
  270. *
  271. * @param int $releaseID
  272. * @access public
  273. * @return void
  274. */
  275. public function export($releaseID)
  276. {
  277. if(!empty($_POST)) return $this->fetch('release', 'export', "releaseID={$releaseID}");
  278. $this->display('release', 'export');
  279. }
  280. /**
  281. * 项目发布关联需求。
  282. * Link stories
  283. *
  284. * @param int $releaseID
  285. * @param string $browseType
  286. * @param int $param
  287. * @param int $recTotal
  288. * @param int $recPerPage
  289. * @param int $pageID
  290. * @access public
  291. * @return void
  292. */
  293. public function linkStory($releaseID = 0, $browseType = '', $param = 0, $recTotal = 0, $recPerPage = 100, $pageID = 1)
  294. {
  295. echo $this->fetch('release', 'linkStory', "releaseID={$releaseID}&browseType={$browseType}&param={$param}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}");
  296. }
  297. /**
  298. * 项目发布取消关联需求。
  299. * Unlink a story from a release.
  300. *
  301. * @param int $releaseID
  302. * @param int $storyID
  303. * @access public
  304. * @return void
  305. */
  306. public function unlinkStory($releaseID, $storyID)
  307. {
  308. echo $this->fetch('release', 'unlinkStory', "releaseID={$releaseID}&storyID={$storyID}");
  309. }
  310. /**
  311. * 项目发布批量取消关联需求。
  312. * Batch unlink story.
  313. *
  314. * @param int $releaseID
  315. * @access public
  316. * @return void
  317. */
  318. public function batchUnlinkStory($releaseID)
  319. {
  320. echo $this->fetch('release', 'batchUnlinkStory', "releaseID={$releaseID}");
  321. }
  322. /**
  323. * 项目发布关联 bug。
  324. * Link bugs.
  325. *
  326. * @param int $releaseID
  327. * @param string $browseType
  328. * @param int $param
  329. * @param string $type
  330. * @param int $recTotal
  331. * @param int $recPerPage
  332. * @param int $pageID
  333. * @access public
  334. * @return void
  335. */
  336. public function linkBug($releaseID = 0, $browseType = '', $param = 0, $type = 'bug', $recTotal = 0, $recPerPage = 100, $pageID = 1)
  337. {
  338. echo $this->fetch('release', 'linkBug', "releaseID={$releaseID}&browseType={$browseType}&param={$param}&type={$type}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}");
  339. }
  340. /**
  341. * 取消关联 bug。
  342. * Unlink bug.
  343. *
  344. * @param int $releaseID
  345. * @param int $bugID
  346. * @param string $type
  347. * @access public
  348. * @return void
  349. */
  350. public function unlinkBug($releaseID, $bugID, $type = 'bug')
  351. {
  352. echo $this->fetch('release', 'unlinkBug', "releaseID={$releaseID}&bugID={$bugID}&type={$type}");
  353. }
  354. /**
  355. * 项目发布批量取消关联 bug。
  356. * Batch unlink story.
  357. *
  358. * @param int $releaseID
  359. * @param string $type
  360. * @access public
  361. * @return void
  362. */
  363. public function batchUnlinkBug($releaseID, $type = 'bug')
  364. {
  365. echo $this->fetch('release', 'batchUnlinkBug', "releaseID={$releaseID}&type={$type}");
  366. }
  367. /**
  368. * 发布页面。
  369. * Publish page.
  370. *
  371. * @param int $releaseID
  372. * @access public
  373. * @return void
  374. */
  375. public function publish($releaseID)
  376. {
  377. echo $this->fetch('release', 'publish', "releaseID={$releaseID}");
  378. }
  379. /**
  380. * 停止维护或者激活发布。
  381. * Terminate or active the release.
  382. *
  383. * @param int $releaseID
  384. * @param string $status
  385. * @access public
  386. * @return void
  387. */
  388. public function changeStatus($releaseID, $status)
  389. {
  390. return $this->fetch('release', 'changeStatus', "releaseID={$releaseID}&status={$status}");
  391. }
  392. /**
  393. * 通过 ajax 加载版本。
  394. * Ajax load builds.
  395. *
  396. * @param int $projectID
  397. * @param int $productID
  398. * @access public
  399. * @return void
  400. */
  401. public function ajaxLoadBuilds($projectID, $productID)
  402. {
  403. $builds = $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'notrunk,withbranch,hasproject', $projectID, 'project', '', false);
  404. $releasedBuilds = $this->projectrelease->getReleasedBuilds($projectID);
  405. $buildList = array();
  406. foreach($builds as $buildID => $buildName)
  407. {
  408. if(in_array($buildID, $releasedBuilds)) continue;
  409. $buildList[] = array('text' => $buildName, 'value' => $buildID);
  410. }
  411. return print(json_encode($buildList));
  412. }
  413. }