model.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <?php
  2. /**
  3. * The model file of admin 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 admin
  9. * @version $Id: model.php 5148 2013-07-16 01:31:08Z chencongzhi520@gmail.com $
  10. * @link https://www.zentao.net
  11. */
  12. ?>
  13. <?php
  14. class adminModel extends model
  15. {
  16. /**
  17. * 获取密钥。
  18. * Get secret key.
  19. *
  20. * @access public
  21. * @return object
  22. */
  23. public function getSecretKey()
  24. {
  25. $apiConfig = $this->getApiConfig();
  26. $apiURL = $this->config->admin->apiRoot . "/user-secretKey.json";
  27. $params['u'] = $this->config->global->community;
  28. $params['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
  29. $params[$apiConfig->sessionVar] = $apiConfig->sessionID;
  30. $params['k'] = $this->getSignature($params);
  31. $result = common::http($apiURL . '?' . http_build_query($params));
  32. $result = json_decode($result);
  33. return $result;
  34. }
  35. /**
  36. * 获取签名。
  37. * Get signature.
  38. *
  39. * @param array $params
  40. * @access public
  41. * @return string
  42. */
  43. public function getSignature($params)
  44. {
  45. unset($params['u']);
  46. $privateKey = $this->config->global->ztPrivateKey;
  47. return md5(http_build_query($params) . md5($privateKey));
  48. }
  49. /**
  50. * 获取禅道官网配置信息。
  51. * Get api config.
  52. *
  53. * @access public
  54. * @return object
  55. */
  56. public function getApiConfig()
  57. {
  58. if(!$this->session->apiConfig || time() - $this->session->apiConfig->serverTime > $this->session->apiConfig->expiredTime)
  59. {
  60. $config = file_get_contents($this->config->admin->apiRoot . "?mode=getconfig");
  61. if(empty($config)) return null;
  62. $config = json_decode($config);
  63. if(empty($config->sessionID)) return null;
  64. $this->session->set('apiConfig', $config);
  65. }
  66. return $this->session->apiConfig;
  67. }
  68. /**
  69. * 弱口令扫描。
  70. * Check weak.
  71. *
  72. * @param object $user
  73. * @access public
  74. * @return bool
  75. */
  76. public function checkWeak($user)
  77. {
  78. $weaks = array();
  79. foreach(explode(',', $this->config->safe->weak) as $weak)
  80. {
  81. $weaks[$weak] = md5(trim($weak));
  82. }
  83. if(isset($weaks[$user->password])) return true;
  84. if(in_array($user->password, $weaks)) return true;
  85. if($user->password == md5($user->account)) return true;
  86. if($user->phone && $user->password == md5($user->phone)) return true;
  87. if($user->mobile && $user->password == md5($user->mobile)) return true;
  88. if($user->birthday && $user->password == md5($user->birthday)) return true;
  89. return false;
  90. }
  91. /**
  92. * 设置后台二级导航。
  93. * Set admin menu.
  94. *
  95. * @param int $groupID
  96. * @access public
  97. * @return void
  98. */
  99. public function setMenu($groupID = 0)
  100. {
  101. $this->checkPrivMenu();
  102. $menuKey = $this->getMenuKey();
  103. if(empty($menuKey)) return;
  104. $customKey = "admin-$menuKey";
  105. $customMenu = isset($this->config->customMenu->{$customKey}) ? json_decode($this->config->customMenu->{$customKey}) : array();
  106. $this->setSwitcher($menuKey);
  107. if(isset($this->lang->admin->menuList->$menuKey))
  108. {
  109. if(in_array($menuKey, array('projectflow', 'productflow')) && $groupID) $this->lang->admin->menuList->{$menuKey}['subMenu'] = $this->lang->admin->menuList->{$menuKey}['childMenu'];
  110. if(isset($this->lang->admin->menuList->{$menuKey}['subMenu']))
  111. {
  112. $moduleName = $this->app->rawModule;
  113. $methodName = $this->app->rawMethod;
  114. $firstParam = $this->app->rawParams ? reset($this->app->rawParams) : '';
  115. foreach($this->lang->admin->menuList->{$menuKey}['subMenu'] as $subMenuKey => $subMenu)
  116. {
  117. $subModule = '';
  118. if($moduleName == 'custom' && strpos(',required,set,', $methodName) !== false)
  119. {
  120. if(isset($this->config->admin->navsGroup[$menuKey][$subMenuKey]) && strpos($this->config->admin->navsGroup[$menuKey][$subMenuKey], ",$firstParam,") !== false) $subModule = 'custom';
  121. if($firstParam == $subMenuKey) $subModule = 'custom';
  122. }
  123. /* 针对项目流程和产品流程菜单做特殊处理。 */
  124. if(in_array($menuKey, array('projectflow', 'productflow')) && $groupID)
  125. {
  126. $workflowGroup = $this->fetchByID($groupID, 'workflowgroup');
  127. if($subMenuKey == 'review' && $workflowGroup->projectModel == 'kanban') continue;
  128. if($subMenuKey == 'stage' && in_array($workflowGroup->projectModel, array('kanban', 'scrum', 'agileplus'))) continue;
  129. $subMenu['link'] = sprintf($subMenu['link'], $groupID);
  130. if(isset($subMenu['subMenu']))
  131. {
  132. foreach($subMenu['subMenu'] as $subSubMenuKey => $subSubMenu)
  133. {
  134. $subMenu['subMenu'][$subSubMenuKey]['link'] = sprintf($subSubMenu['link'], $groupID);
  135. }
  136. }
  137. }
  138. if(!empty($subModule)) $subMenu['subModule'] = $subModule;
  139. if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey]))
  140. {
  141. if(!empty($subModule))
  142. {
  143. $this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey][$firstParam]['subModule'] = $subModule;
  144. unset($this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey][$firstParam]['exclude']);
  145. }
  146. $subMenu['subMenu'] = $this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey];
  147. }
  148. if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu']['menuOrder'][$subMenuKey])) $subMenu['menuOrder'] = $this->lang->admin->menuList->{$menuKey}['tabMenu']['menuOrder'][$subMenuKey];
  149. if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu']['dividerMenu'][$subMenuKey])) $subMenu['dividerMenu'] = $this->lang->admin->menuList->{$menuKey}['tabMenu']['dividerMenu'][$subMenuKey];
  150. $this->lang->admin->menu->$subMenuKey = $subMenu;
  151. }
  152. }
  153. if($customMenu)
  154. {
  155. $this->lang->admin->menuList->{$menuKey}['menuOrder'] = array();
  156. $this->lang->admin->menuList->{$menuKey}['dividerMenu'] = '';
  157. $prev = '';
  158. foreach($customMenu as $item)
  159. {
  160. $this->lang->admin->menuList->{$menuKey}['menuOrder'][$item->order] = $item->name;
  161. if($prev == 'divider') $this->lang->admin->menuList->{$menuKey}['dividerMenu'] .= ',' . $item->name;
  162. $prev = $item->name;
  163. }
  164. if($this->lang->admin->menuList->{$menuKey}['dividerMenu']) $this->lang->admin->menuList->{$menuKey}['dividerMenu'] = ',' . trim($this->lang->admin->menuList->{$menuKey}['dividerMenu']) . ',';
  165. ksort($this->lang->admin->menuList->{$menuKey}['menuOrder']);
  166. }
  167. if(isset($this->lang->admin->menuList->{$menuKey}['menuOrder'])) $this->lang->admin->menuOrder = $this->lang->admin->menuList->{$menuKey}['menuOrder'];
  168. if(isset($this->lang->admin->menuList->{$menuKey}['dividerMenu'])) $this->lang->admin->dividerMenu = $this->lang->admin->menuList->{$menuKey}['dividerMenu'];
  169. if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu'])) $this->lang->admin->tabMenu = $this->lang->admin->menuList->{$menuKey}['tabMenu'];
  170. }
  171. }
  172. /**
  173. * 检查导航权限并设置导航链接。
  174. * Check priv menu.
  175. *
  176. * @access public
  177. * @return void
  178. */
  179. public function checkPrivMenu()
  180. {
  181. $orders = array();
  182. foreach($this->lang->admin->menuList as $menuKey => $menu)
  183. {
  184. $menu['disabled'] = true;
  185. if(!isset($menu['link'])) $menu['link'] = '';
  186. if($menuKey == 'company' && $this->app->rawModule != 'convert')
  187. {
  188. $dept = $this->dao->select('id')->from(TABLE_DEPT)->limit(1)->fetch();
  189. if($dept && common::hasPriv('company', 'browse')) $menu['link'] = helper::createLink('company', 'browse');
  190. }
  191. if(!empty($menu['link']) && strpos($menu['link'], '|') !== false)
  192. {
  193. list($module, $method, $params) = explode('|', $menu['link'] . '|');
  194. $menu['link'] = helper::createLink($module, $method, $params);
  195. if(($this->app->user->admin || $module . $method != 'adminregister') && common::hasPriv($module, $method)) $menu['disabled'] = false;
  196. }
  197. /* Set links to authorized navigation. */
  198. if(!in_array($menuKey, array('productflow', 'projectflow')) && isset($menu['subMenu']))
  199. {
  200. $menu = $this->setSubMenu($menuKey, $menu);
  201. }
  202. $order = $menu['order'];
  203. $orders[$order] = $menuKey;
  204. $this->lang->admin->menuList->$menuKey = $menu;
  205. }
  206. ksort($orders);
  207. $menuList = new stdclass();
  208. foreach($orders as $index => $menuKey)
  209. {
  210. $menuList->$menuKey = $this->lang->admin->menuList->$menuKey;
  211. $menuList->{$menuKey}['order'] = $index;
  212. }
  213. $this->lang->admin->menuList = $menuList;
  214. }
  215. /**
  216. * 设置二级导航。
  217. * Set sub menu.
  218. *
  219. * @param string $menuKey
  220. * @param array $menu
  221. * @access public
  222. * @return array
  223. */
  224. public function setSubMenu($menuKey, $menu)
  225. {
  226. /* Reorder secondary navigation. */
  227. $subMenuList = array();
  228. $subMenuOrders = !empty($menu['menuOrder']) ? $menu['menuOrder'] : array();
  229. if(empty($subMenuOrders)) return array();
  230. ksort($subMenuOrders);
  231. foreach($subMenuOrders as $value)
  232. {
  233. if(!isset($menu['subMenu'][$value])) continue;
  234. $subMenuList[$value] = $menu['subMenu'][$value];
  235. }
  236. foreach($subMenuList as $subMenuKey => $subMenu)
  237. {
  238. /* Set links by special config. */
  239. if($menuKey == 'message' && $subMenuKey == 'mail')
  240. {
  241. $this->loadModel('mail');
  242. if(!$this->config->mail->turnon && !$this->session->mailConfig) $subMenu['link'] = $this->lang->mail->common . '|mail|detect|';
  243. }
  244. if($menuKey == 'dev' && $subMenuKey == 'editor')
  245. {
  246. if(!empty($this->config->global->editor)) $subMenu['link'] = $this->lang->editor->common . '|editor|index|';
  247. if(empty($this->config->global->editor) && !$this->app->user->admin)
  248. {
  249. unset($menu['subMenu']['editor']);
  250. continue;
  251. }
  252. }
  253. /* Get authorized links and change parent navigation links. */
  254. $link = array();
  255. if(isset($menu['tabMenu'][$subMenuKey]))
  256. {
  257. list($menu, $link) = $this->setTabMenu($subMenuKey, $menu);
  258. }
  259. else
  260. {
  261. $link = $this->getHasPrivLink($subMenu);
  262. }
  263. if(!empty($link))
  264. {
  265. /* Updated secondary navigation link. */
  266. list($module, $method, $params) = $link;
  267. $menu['subMenu'][$subMenuKey]['link'] = substr($subMenu['link'], 0, strpos($subMenu['link'], '|') + 1) . $module . '|' . $method . '|' . $params;
  268. /* Update the level 1 navigation link. */
  269. if(!empty($menu['disabled']))
  270. {
  271. $menu['link'] = helper::createLink($module, $method, $params);
  272. $menu['disabled'] = false;
  273. }
  274. }
  275. }
  276. return $menu;
  277. }
  278. /**
  279. * 设置三级导航。
  280. * Set tab menu.
  281. *
  282. * @param string $subMenuKey
  283. * @param array $menu
  284. * @access public
  285. * @return array
  286. */
  287. public function setTabMenu($subMenuKey, $menu)
  288. {
  289. /* Reorder tertiary navigation. */
  290. $tabMenuList = $menu['tabMenu'][$subMenuKey];
  291. if(isset($menu['tabMenu']['menuOrder'][$subMenuKey]))
  292. {
  293. $tabMenuOrders = $menu['tabMenu']['menuOrder'][$subMenuKey];
  294. ksort($tabMenuOrders);
  295. foreach($tabMenuOrders as $value) $tabMenuList[$value] = $menu['tabMenu'][$subMenuKey][$value];
  296. }
  297. /* Check tab menu priv. */
  298. $link = array();
  299. foreach($tabMenuList as $tabMenuKey => $tabMenu)
  300. {
  301. $tabMenuLink = $this->getHasPrivLink($tabMenu);
  302. if(!empty($tabMenuLink))
  303. {
  304. /* Updated tertiary navigation links. */
  305. list($module, $method, $params) = $tabMenuLink;
  306. $menu['tabMenu'][$subMenuKey][$tabMenuKey]['link'] = substr($tabMenu['link'], 0, strpos($tabMenu['link'], '|') + 1) . $module . '|' . $method . '|' . $params;
  307. }
  308. if(empty($link)) $link = $tabMenuLink;
  309. }
  310. return array($menu, $link);
  311. }
  312. /**
  313. * 获取有权限的链接。
  314. * Get the authorized link.
  315. *
  316. * @param array $menu
  317. * @access public
  318. * @return array
  319. */
  320. public function getHasPrivLink($menu)
  321. {
  322. $link = array();
  323. if(!empty($menu['link']))
  324. {
  325. list($label, $module, $method, $params) = explode('|', $menu['link']);
  326. if(common::hasPriv($module, $method))
  327. {
  328. $link = array($module, $method, $params);
  329. }
  330. elseif(!empty($menu['links']))
  331. {
  332. foreach($menu['links'] as $menuLink)
  333. {
  334. list($module, $method, $params) = explode('|', $menuLink);
  335. if(common::hasPriv($module, $method))
  336. {
  337. $link = array($module, $method, $params);
  338. break;
  339. }
  340. }
  341. }
  342. }
  343. return $link;
  344. }
  345. /**
  346. * 获取页面所在的导航索引。
  347. * Get menu key
  348. *
  349. * @access public
  350. * @return string
  351. */
  352. public function getMenuKey()
  353. {
  354. $moduleName = $this->app->rawModule;
  355. $methodName = $this->app->rawMethod;
  356. $firstParam = $this->app->rawParams ? reset($this->app->rawParams) : '';
  357. if($this->config->edition == 'open')
  358. {
  359. $this->config->admin->menuGroup['feature'][] = 'stage|browse';
  360. $this->config->admin->menuGroup['feature'][] = 'stage|batchcreate';
  361. }
  362. foreach($this->config->admin->menuGroup as $menuKey => $menuGroup)
  363. {
  364. if(in_array($moduleName, $menuGroup))
  365. {
  366. return $menuKey;
  367. }
  368. elseif(in_array("$moduleName|$methodName", $menuGroup))
  369. {
  370. if($moduleName == 'custom' && ($methodName == 'required' || $methodName == 'set'))
  371. {
  372. if(in_array($firstParam, $this->config->admin->menuModuleGroup[$menuKey]["custom|$methodName"])) return $menuKey;
  373. }
  374. elseif($moduleName == 'workflowgroup' && $firstParam && !in_array($methodName, array('project', 'product')))
  375. {
  376. $workflowgroup = $this->loadModel('workflowgroup')->fetchByID($firstParam);
  377. return $workflowgroup->type == 'project' ? 'projectflow' : 'productflow';
  378. }
  379. else
  380. {
  381. return $menuKey;
  382. }
  383. }
  384. }
  385. return '';
  386. }
  387. /**
  388. * 检查网络。
  389. * Check internet.
  390. *
  391. * @param string $url
  392. * @param int $timeout
  393. * @access public
  394. * @return bool
  395. */
  396. public function checkInternet($url = '', $timeout = 1)
  397. {
  398. if(empty($url)) $url = $this->config->admin->apiSite;
  399. $curl = curl_init();
  400. curl_setopt($curl, CURLOPT_URL, $url);
  401. curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
  402. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
  403. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  404. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  405. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  406. $connected = curl_exec($curl);
  407. curl_close($curl);
  408. return (bool)$connected;
  409. }
  410. /**
  411. * 获取禅道使用时长。
  412. * Get date used object.
  413. *
  414. * @param string $end
  415. * @access public
  416. * @return object
  417. */
  418. public function genDateUsed($end = '')
  419. {
  420. $firstUseDate = $this->dao->select('min(`date`) as `date`')->from(TABLE_ACTION)
  421. ->where('`date`')->ge(FIRST_RELEASE_DATE)
  422. ->andWhere('actor')->eq($this->app->user->account)
  423. ->fetch('date');
  424. if($firstUseDate) $firstUseDate = substr($firstUseDate, 0, 10);
  425. return helper::getDateInterval($firstUseDate, $end);
  426. }
  427. /**
  428. * 获取1.5级下拉菜单。
  429. * Set switcher.
  430. *
  431. * @param string $currentMenuKey
  432. * @access public
  433. * @return void
  434. */
  435. public function setSwitcher($currentMenuKey = 'system')
  436. {
  437. if(empty($currentMenuKey)) return null;
  438. $currentMenu = $this->lang->admin->menuList->$currentMenuKey;
  439. $output = "<div class='btn-group header-btn'>";
  440. $output .= "<button class='btn pull-right btn-link' data-toggle='dropdown'>";
  441. $output .= "<span class='text'>{$currentMenu['name']}</span> ";
  442. $output .= "<span class='caret'></span></button>";
  443. $output .= "<ul class='dropdown-menu' id='adminMenu'>";
  444. foreach($this->lang->admin->menuList as $menuKey => $menuGroup)
  445. {
  446. if($this->config->vision == 'lite' and !in_array($menuKey, $this->config->admin->liteMenuList)) continue;
  447. $class = $menuKey == $currentMenuKey ? "active" : '';
  448. if(!empty($menuGroup['disabled'])) $class .= ' disabled not-clear-menu';
  449. $output .= "<li class='$class'>" . html::a(!empty($menuGroup['disabled']) ? '###' : (!empty($menuGroup['link']) ? $menuGroup['link'] : ''), (!empty($menuGroup['icon']) ? "<i class='icon icon-{$menuGroup['icon']} svg-icon bg-{$menuGroup['bg']}' style='height:24px;width:24px;text-align:center;border-radius:0.375rem;color:#fff;align-content:center;margin-left:6px;opacity:1;transform: scale(1);'></i>" : "<img src='{$this->config->webRoot}static/svg/admin-{$menuKey}.svg'/>") . $menuGroup['name']) . "</li>";
  450. }
  451. $output .= "</ul></div>";
  452. $this->lang->switcherMenu = $output;
  453. }
  454. /**
  455. * 获取交付物评审信息。
  456. * Get deliverable review info.
  457. *
  458. * @param int $groupID
  459. * @access public
  460. * @return array
  461. */
  462. public function getDeliverableReviewPairs($groupID = 0)
  463. {
  464. return $this->dao->select('t1.id, t1.review')->from(TABLE_PROJECTDELIVERABLE)->alias('t1')
  465. ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
  466. ->where('1=1')
  467. ->beginIF($groupID)->andWhere('t2.workflowGroup')->eq($groupID)->fi()
  468. ->fetchPairs('id');
  469. }
  470. }