model.php 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. <?php
  2. /**
  3. * The model file of group 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 group
  9. * @version $Id: model.php 4976 2013-07-02 08:15:31Z wyd621@gmail.com $
  10. * @link https://www.zentao.net
  11. */
  12. class groupModel extends model
  13. {
  14. /**
  15. * 创建一个分组。
  16. * Create a group.
  17. *
  18. * @access public
  19. * @return bool
  20. * @param object $group
  21. */
  22. public function create($group)
  23. {
  24. if(isset($group->limited))
  25. {
  26. unset($group->limited);
  27. $group->role = 'limited';
  28. }
  29. if(!isset($group->vision)) $group->vision = $this->config->vision;
  30. $this->lang->error->unique = $this->lang->group->repeat;
  31. $this->dao->insert(TABLE_GROUP)->data($group)
  32. ->check('name', 'unique', "vision = '{$this->config->vision}' and project='{$group->project}'")
  33. ->exec();
  34. if(dao::isError()) return false;
  35. $groupID = $this->dao->lastInsertId();
  36. $data = new stdclass();
  37. $data->group = $groupID;
  38. $data->module = 'index';
  39. $data->method = 'index';
  40. $this->dao->replace(TABLE_GROUPPRIV)->data($data)->exec();
  41. return $groupID;
  42. }
  43. /**
  44. * 更新权限分组。
  45. * Update a group.
  46. *
  47. * @param int $groupID
  48. * @param object $group
  49. * @access public
  50. * @return void
  51. */
  52. public function update($groupID, $group)
  53. {
  54. $this->lang->error->unique = $this->lang->group->repeat;
  55. $this->dao->update(TABLE_GROUP)->data($group)
  56. ->where('id')->eq($groupID)
  57. ->exec();
  58. return !dao::isError();
  59. }
  60. /**
  61. * 复制一个分组。
  62. * Copy a group.
  63. *
  64. * @param int $groupID
  65. * @param object $group
  66. * @param array $options
  67. * @access public
  68. * @return int|false
  69. */
  70. public function copy($groupID, $group, $options)
  71. {
  72. $this->lang->error->unique = $this->lang->group->repeat;
  73. $this->dao->insert(TABLE_GROUP)->data($group)
  74. ->check('name', 'unique', "vision = '{$this->config->vision}' and project = '{$group->project}'")
  75. ->exec();
  76. if(dao::isError()) return false;
  77. $newGroupID = $this->dao->lastInsertID();
  78. if(empty($options)) return $newGroupID;
  79. if(in_array('copyPriv', $options)) $this->copyPriv($groupID, $newGroupID);
  80. if(in_array('copyUser', $options)) $this->copyUser($groupID, $newGroupID);
  81. return $newGroupID;
  82. }
  83. /**
  84. * 复制分组的权限。
  85. * Copy privileges.
  86. *
  87. * @param int $fromGroup
  88. * @param int $toGroup
  89. * @access public
  90. * @return void
  91. * @param int $fromGroupID
  92. * @param int $toGroupID
  93. */
  94. public function copyPriv($fromGroupID, $toGroupID)
  95. {
  96. $privs = $this->dao->select('*')->from(TABLE_GROUPPRIV)->where('`group`')->eq($fromGroupID)->fetchAll();
  97. foreach($privs as $key => $priv)
  98. {
  99. $privs[$key]->group = $toGroupID;
  100. }
  101. $this->insertPrivs($privs);
  102. }
  103. /**
  104. * 复制分组的成员。
  105. * Copy user.
  106. *
  107. * @param int $fromGroup
  108. * @param int $toGroup
  109. * @access public
  110. * @return void
  111. */
  112. public function copyUser($fromGroupID, $toGroupID)
  113. {
  114. $users = $this->dao->select('*')->from(TABLE_USERGROUP)->where('`group`')->eq($fromGroupID)->fetchAll();
  115. foreach($users as $user)
  116. {
  117. $user->group = $toGroupID;
  118. $this->dao->insert(TABLE_USERGROUP)->data($user, 'id')->exec();
  119. }
  120. }
  121. /**
  122. * 获取分组列表。
  123. * Get group lists.
  124. *
  125. * @param int $projectID
  126. * @access public
  127. * @return array
  128. */
  129. public function getList($projectID = 0)
  130. {
  131. return $this->dao->select('*')->from(TABLE_GROUP)
  132. ->where('project')->eq($projectID)
  133. ->beginIF($this->config->vision)->andWhere('vision')->eq($this->config->vision)->fi()
  134. ->orderBy('id')
  135. ->fetchAll();
  136. }
  137. /**
  138. * 获取分组。
  139. * Get group pairs.
  140. *
  141. * @param int $projectID
  142. * @access public
  143. * @return array
  144. */
  145. public function getPairs($projectID = 0)
  146. {
  147. return $this->dao->select('id, name')->from(TABLE_GROUP)
  148. ->where('project')->eq($projectID)
  149. ->andWhere('vision')->eq($this->config->vision)
  150. ->orderBy('id')->fetchPairs();
  151. }
  152. /**
  153. * 获取一个分组。
  154. * Get group by id.
  155. *
  156. * @param int $groupID
  157. * @access public
  158. * @return object
  159. */
  160. public function getByID($groupID)
  161. {
  162. $group = $this->dao->findById($groupID)->from(TABLE_GROUP)->fetch();
  163. if(!$group) return null;
  164. if($group->acl) $group->acl = json_decode($group->acl, true);
  165. if(!isset($group->acl) || !is_array($group->acl)) $group->acl = array();
  166. return $group;
  167. }
  168. /**
  169. * 获取用户的所有分组。
  170. * Get group by account.
  171. *
  172. * @param string $account
  173. * @param bool $allVision
  174. * @access public
  175. * @return array
  176. */
  177. public function getByAccount($account, $allVision = false)
  178. {
  179. return $this->dao->select('t2.*')->from(TABLE_USERGROUP)->alias('t1')
  180. ->leftJoin(TABLE_GROUP)->alias('t2')
  181. ->on('t1.`group` = t2.id')
  182. ->where('t1.account')->eq($account)
  183. ->andWhere('t2.project')->eq(0)
  184. ->beginIF(!$allVision)->andWhere('t2.vision')->eq($this->config->vision)->fi()
  185. ->fetchAll('id');
  186. }
  187. /**
  188. * 获取多个分组包含的所有用户。
  189. * Get the accounts in the groups.
  190. *
  191. * @param array $groupIdList
  192. * @access public
  193. * @return array
  194. */
  195. public function getGroupAccounts($groupIdList = array())
  196. {
  197. $groupIdList = array_filter($groupIdList);
  198. if(empty($groupIdList)) return array();
  199. return $this->dao->select('account')->from(TABLE_USERGROUP)->where('`group`')->in($groupIdList)->fetchPairs('account');
  200. }
  201. /**
  202. * 获取一个分组的权限列表。
  203. * Get privileges of a groups.
  204. *
  205. * @param int $groupID
  206. * @access public
  207. * @return array
  208. */
  209. public function getPrivs($groupID)
  210. {
  211. $privs = array();
  212. $stmt = $this->dao->select('module, method')->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->orderBy('module')->query();
  213. while($priv = $stmt->fetch()) $privs[$priv->module][$priv->method] = $priv->method;
  214. return $privs;
  215. }
  216. /**
  217. * 获取一个分组下的用户Pairs。
  218. * Get user pairs of a group.
  219. *
  220. * @param int $groupID
  221. * @access public
  222. * @return array
  223. */
  224. public function getUserPairs($groupID)
  225. {
  226. return $this->dao->select('t2.account, t2.realname')
  227. ->from(TABLE_USERGROUP)->alias('t1')
  228. ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
  229. ->where('`group`')->eq((int)$groupID)
  230. ->beginIF($this->config->vision)->andWhere("CONCAT(',', visions, ',')")->like("%,{$this->config->vision},%")->fi()
  231. ->andWhere('t2.deleted')->eq(0)
  232. ->orderBy('t2.account')
  233. ->fetchPairs();
  234. }
  235. /**
  236. * 获取系统内权限分组的成员信息。
  237. * Get all group members.
  238. *
  239. * @access public
  240. * @return array
  241. */
  242. public function getAllGroupMembers()
  243. {
  244. /* Get normal group members. */
  245. $memberGroup = $this->dao->select('t1.`group` as `group`, t2.account, t2.realname')
  246. ->from(TABLE_USERGROUP)->alias('t1')
  247. ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
  248. ->where('t2.deleted')->eq(0)
  249. ->beginIF($this->config->vision)->andWhere("CONCAT(',', visions, ',')")->like("%,{$this->config->vision},%")->fi()
  250. ->orderBy('t2.account')
  251. ->fetchAll();
  252. $groupMembers = array();
  253. foreach($memberGroup as $member)
  254. {
  255. if(!isset($groupMembers[$member->group])) $groupMembers[$member->group] = array();
  256. $groupMembers[$member->group][$member->account] = $member->realname;
  257. }
  258. /* Get project admin memebers. */
  259. $projectAdmins = $this->dao->select('t1.account, t2.realname')->from(TABLE_PROJECTADMIN)->alias('t1')->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')->fetchPairs();
  260. $adminGroupID = $this->dao->select('id')->from(TABLE_GROUP)->where('role')->eq('projectAdmin')->fetch('id');
  261. $groupMembers[$adminGroupID] = $projectAdmins;
  262. return $groupMembers;
  263. }
  264. /**
  265. * 为项目管理员分组展示项目集、项目、产品、执行。
  266. * Get object for manage admin group.
  267. *
  268. * @access public
  269. * @return void
  270. */
  271. public function getObjectForAdminGroup()
  272. {
  273. $objects = $this->dao->select('id, name, path, type, project, grade, parent')->from(TABLE_PROJECT)
  274. ->where('vision')->eq($this->config->vision)
  275. ->andWhere('type')->ne('program')
  276. ->andWhere('deleted')->eq(0)
  277. ->fetchAll('id');
  278. $projects = array();
  279. $executions = array();
  280. foreach($objects as $object)
  281. {
  282. $type = $object->type;
  283. $path = explode(',', trim($object->path, ','));
  284. $topID = $path[0];
  285. if($type == 'project')
  286. {
  287. if($topID != $object->id) $object->name = isset($objects[$topID]) ? $objects[$topID]->name . '/' . $object->name : $object->name;
  288. $projects[$object->id] = $object->name;
  289. }
  290. else
  291. {
  292. if($object->grade == 2)
  293. {
  294. unset($objects[$object->parent]);
  295. unset($executions[$object->parent]);
  296. }
  297. $object->name = isset($objects[$object->project]) ? $objects[$object->project]->name . '/' . $object->name : $object->name;
  298. $executions[$object->id] = $object->name;
  299. }
  300. }
  301. $programs = $this->getProgramsForAdminGroup();
  302. $products = $this->getProductsForAdminGroup($programs);
  303. return array($programs, $projects, $products, $executions);
  304. }
  305. /**
  306. * 为项目管理员分组展示项目集。
  307. * Get programs for admin group.
  308. *
  309. * @access protected
  310. * @return array
  311. */
  312. protected function getProgramsForAdminGroup()
  313. {
  314. $isAdmin = $this->app->user->admin;
  315. /* Get the list of program sets under administrator permission. */
  316. if(!$this->app->user->admin) $this->app->user->admin = true;
  317. $programs = $this->loadModel('program')->getParentPairs('', '', false);
  318. if(!$isAdmin) $this->app->user->admin = false;
  319. return $programs;
  320. }
  321. /**
  322. * 为项目管理员分组展示产品列表。
  323. * Get products for admin group.
  324. *
  325. * @param array $programs
  326. * @access protected
  327. * @return array
  328. */
  329. protected function getProductsForAdminGroup($programs)
  330. {
  331. $products = array();
  332. $productList = $this->dao->select('id, name, program')->from(TABLE_PRODUCT)
  333. ->where('vision')->eq($this->config->vision)
  334. ->andWhere('deleted')->eq(0)
  335. ->andWhere('shadow')->eq(0)
  336. ->fetchAll('id');
  337. foreach($productList as $id => $product)
  338. {
  339. if(isset($programs[$product->program]) and $this->config->systemMode == 'ALM') $product->name = $programs[$product->program] . '/' . $product->name;
  340. $products[$product->id] = $product->name;
  341. }
  342. return $products;
  343. }
  344. /**
  345. * 获取项目管理员。
  346. * Get project admins for manage project admin.
  347. *
  348. * @access public
  349. * @return array
  350. */
  351. public function getProjectAdmins()
  352. {
  353. $admins = $this->dao->select('*')->from(TABLE_PROJECTADMIN)->fetchGroup('group', 'account');
  354. $projectAdmins = array();
  355. foreach($admins as $adminGroup)
  356. {
  357. if(!empty($adminGroup))
  358. {
  359. $accounts = implode(',', array_keys($adminGroup));
  360. if(isset($projectAdmins[$accounts]))
  361. {
  362. $adminGroup = current($adminGroup);
  363. $projectAdmins[$accounts]->programs .= ',' . $adminGroup->programs;
  364. $projectAdmins[$accounts]->projects .= ',' . $adminGroup->projects;
  365. $projectAdmins[$accounts]->products .= ',' . $adminGroup->products;
  366. $projectAdmins[$accounts]->executions .= ',' . $adminGroup->executions;
  367. }
  368. else
  369. {
  370. $projectAdmins[$accounts] = current($adminGroup);
  371. }
  372. }
  373. }
  374. return $projectAdmins;
  375. }
  376. /**
  377. * Get admins by object id list.
  378. *
  379. * @param array $idList
  380. * @param string $field
  381. * @access public
  382. * @return array
  383. */
  384. public function getAdmins($idList, $field = 'programs')
  385. {
  386. $objects = array();
  387. foreach($idList as $id)
  388. {
  389. $objects[$id] = $this->dao->select('DISTINCT account')->from(TABLE_PROJECTADMIN)
  390. ->where("CONCAT(',', $field, ',')")->like("%,$id,%")
  391. ->orWhere($field)->eq('all')
  392. ->fetchPairs();
  393. }
  394. return $objects;
  395. }
  396. /**
  397. * 删除分组。
  398. * Remove group.
  399. *
  400. * @param int $groupID
  401. * @access public
  402. * @return void
  403. */
  404. public function remove($groupID)
  405. {
  406. $this->dao->delete()->from(TABLE_GROUP)->where('id')->eq($groupID)->exec();
  407. $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->exec();
  408. $this->dao->delete()->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->exec();
  409. }
  410. /**
  411. * Insert privs.
  412. *
  413. * @param array $privs
  414. * @access protected
  415. * @return bool
  416. */
  417. public function insertPrivs($privs)
  418. {
  419. $groups = array();
  420. foreach($privs as $priv) $groups[$priv->group] = $priv->group;
  421. $privMap = array();
  422. $privList = $this->dao->select('`group`,module,method')->from(TABLE_GROUPPRIV)->where('group')->in($groups)->fetchAll();
  423. foreach($privList as $priv) $privMap[$priv->group . '-' . $priv->module . '-' . $priv->method] = true;
  424. foreach($privs as $priv)
  425. {
  426. if(!isset($privMap[$priv->group . '-' . $priv->module . '-' . $priv->method]))
  427. {
  428. $this->dao->insert(TABLE_GROUPPRIV)->data($priv, 'id')->exec();
  429. }
  430. }
  431. return true;
  432. }
  433. /**
  434. * 更新视野权限。
  435. * Update view priv.
  436. *
  437. * @param int $groupID
  438. * @param array $actions
  439. * @access public
  440. * @return bool
  441. */
  442. public function updateView($groupID, $actions)
  443. {
  444. /* 如果产品不为空,需要将影子产品追加上。Add shadow productID when select noProduct project or execution. */
  445. if(($actions['projects'] || $actions['sprints']) && isset($actions['products']))
  446. {
  447. /* Get all noProduct projects and executions . */
  448. $noProductList = $this->loadModel('project')->getNoProductList();
  449. $shadowProductIDList = $this->dao->select('id')->from(TABLE_PRODUCT)->where('shadow')->eq(1)->fetchPairs();
  450. $noProductObjects = array_merge($actions['projects'], $actions['sprints']);
  451. foreach($noProductObjects as $objectID)
  452. {
  453. if(isset($noProductList[$objectID])) $actions['products'][] = $noProductList[$objectID]->product;
  454. }
  455. }
  456. /* 设置views。 Set views. */
  457. if(!$actions['actionallchecker'])
  458. {
  459. $actions['views'] = empty($actions['views']) ? array() : array_keys($actions['views']);
  460. $actions['views'] = array_combine($actions['views'], $actions['views']);
  461. if(!isset($actions['actions'])) $actions['actions'] = array();
  462. if(isset($actions['actions']['project']['started'])) $actions['actions']['project']['syncproject'] = 'syncproject';
  463. if(isset($actions['actions']['execution']['started'])) $actions['actions']['execution']['syncexecution'] = 'syncexecution';
  464. $dynamic = array();
  465. foreach($actions['actions'] as $moduleName => $moduleActions)
  466. {
  467. $groupName = $moduleName;
  468. if(isset($this->lang->navGroup->$moduleName)) $groupName = $this->lang->navGroup->$moduleName;
  469. if($moduleName == 'case') $groupName = $this->lang->navGroup->testcase;
  470. if($groupName != 'my' and !isset($actions['views'][$groupName])) continue;
  471. $moduleActions = array_keys($moduleActions);
  472. $dynamic[$moduleName] = array_combine($moduleActions, $moduleActions);
  473. }
  474. $actions['actions'] = $dynamic;
  475. }
  476. $actions = empty($actions) ? '' : json_encode($actions);
  477. $this->dao->update(TABLE_GROUP)->set('acl')->eq($actions)->where('id')->eq($groupID)->exec();
  478. return !dao::isError();
  479. }
  480. /**
  481. * 按分组维护权限。
  482. * Update privilege of a group.
  483. *
  484. * @param int $groupID
  485. * @param string $nav
  486. * @param string $version
  487. * @access public
  488. * @return bool
  489. */
  490. public function updatePrivByGroup($groupID, $nav, $version = '')
  491. {
  492. /* Delete old. */
  493. $privs = array_keys($this->getPrivsByNav($nav, $version));
  494. $this->dao->delete()->from(TABLE_GROUPPRIV)
  495. ->where('`group`')->eq($groupID)
  496. ->beginIF(!empty($nav))->andWhere("CONCAT(module, '-', method)")->in($privs)->fi()
  497. ->exec();
  498. $data = new stdclass();
  499. $data->group = $groupID;
  500. $data->module = 'index';
  501. $data->method = 'index';
  502. $this->dao->replace(TABLE_GROUPPRIV)->data($data)->exec();
  503. /* Insert new. */
  504. if($this->post->actions)
  505. {
  506. $dependPrivs = array();
  507. foreach($this->config->group->package as $packageCode => $packageData)
  508. {
  509. if(!isset($packageData->privs)) continue;
  510. foreach($packageData->privs as $privCode => $priv)
  511. {
  512. if(isset($priv['depend'])) $dependPrivs[$privCode] = $priv['depend'];
  513. }
  514. }
  515. $insertPrivs = array();
  516. $insertPrivKeys = array();
  517. foreach($this->post->actions as $moduleName => $moduleActions)
  518. {
  519. if(empty($moduleName) or empty($moduleActions)) continue;
  520. foreach($moduleActions as $actionName)
  521. {
  522. $data = new stdclass();
  523. $data->group = $groupID;
  524. $data->module = $moduleName;
  525. $data->method = $actionName;
  526. $priKey = "{$moduleName}-{$actionName}";
  527. $insertPrivs[$priKey] = $data;
  528. $insertPrivKeys[$priKey] = $priKey;
  529. }
  530. }
  531. $insertDependPrivs = $this->processDepends($dependPrivs, $insertPrivKeys, $insertPrivKeys);
  532. foreach($insertDependPrivs as $priKey)
  533. {
  534. if(isset($insertPrivs[$priKey])) continue;
  535. list($moduleName, $actionName) = explode('-', $priKey);
  536. $data = new stdclass();
  537. $data->group = $groupID;
  538. $data->module = $moduleName;
  539. $data->method = $actionName;
  540. $insertPrivs[$priKey] = $data;
  541. }
  542. $this->insertPrivs($insertPrivs);
  543. return count($insertDependPrivs) != count($insertPrivKeys);
  544. }
  545. return true;
  546. }
  547. /**
  548. * 按模块维护权限。
  549. * Update privilege by module.
  550. *
  551. * @access public
  552. * @return void
  553. */
  554. public function updatePrivByModule()
  555. {
  556. if($this->post->module == false || array_filter($this->post->actions) == false || array_filter($this->post->groups) == false) return false;
  557. $privs = array();
  558. foreach($this->post->actions as $action)
  559. {
  560. if(!$action) continue;
  561. list($module, $method) = explode('-', $action);
  562. foreach($this->post->groups as $group)
  563. {
  564. $data = new stdclass();
  565. $data->group = $group;
  566. $data->module = $module;
  567. $data->method = $method;
  568. $privs[] = $data;
  569. }
  570. }
  571. return $this->insertPrivs($privs);
  572. }
  573. /**
  574. * 更新用户。
  575. * Update users.
  576. *
  577. * @param int $groupID
  578. * @access public
  579. * @return bool
  580. */
  581. public function updateUser($groupID)
  582. {
  583. $members = $this->post->members ? $this->post->members : array();
  584. $groupUsers = $this->dao->select('account')->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->fetchPairs('account');
  585. $newUsers = array_diff($members, $groupUsers);
  586. $delUsers = array_diff($groupUsers, $members);
  587. if(!empty($delUsers)) $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->andWhere('account')->in($delUsers)->exec();
  588. if(empty($newUsers)) return !dao::isError();
  589. $data = new stdclass();
  590. $data->group = $groupID;
  591. $data->project = '';
  592. foreach($newUsers as $account)
  593. {
  594. $data->account = $account;
  595. $this->dao->insert(TABLE_USERGROUP)->data($data)->exec();
  596. }
  597. return !dao::isError();
  598. }
  599. /**
  600. * 更新项目管理员。
  601. * Update project admins.
  602. *
  603. * @param array $formData
  604. * @access public
  605. * @return void
  606. */
  607. public function updateProjectAdmin($formData)
  608. {
  609. $allUsers = $this->dao->select('account')->from(TABLE_PROJECTADMIN)->fetchPairs();
  610. $this->dao->delete()->from(TABLE_PROJECTADMIN)->exec();
  611. $noProductList = $this->loadModel('project')->getNoProductList();
  612. $shadowProductIDList = $this->dao->select('id')->from(TABLE_PRODUCT)->where('shadow')->eq(1)->fetchPairs();
  613. foreach($formData as $lineID => $data)
  614. {
  615. if(!in_array('all', $data['product']))
  616. {
  617. /* 无产品项目的隐藏产品需要添加到product里。 Append products of 'No Product' project,execution. */
  618. if($data['project'] || $data['execution'])
  619. {
  620. $objects = array_merge($data['project'], $data['execution']);
  621. foreach($objects as $objectID)
  622. {
  623. if(isset($noProductList[$objectID])) $data['product'][] = $noProductList[$objectID]->product;
  624. }
  625. }
  626. if((in_array('all', $data['execution']) || in_array('all', $data['project']))) $data['product'] = array_merge($data['product'], $shadowProductIDList);
  627. }
  628. foreach($data['accounts'] as $account)
  629. {
  630. if(!$account) continue;
  631. $projectAdmin = new stdclass();
  632. $projectAdmin->group = $lineID;
  633. $projectAdmin->account = $account;
  634. $projectAdmin->programs = implode(',', $data['program']);
  635. $projectAdmin->projects = implode(',', $data['project']);
  636. $projectAdmin->products = implode(',', $data['product']);
  637. $projectAdmin->executions = implode(',', $data['execution']);
  638. $this->dao->replace(TABLE_PROJECTADMIN)->data($projectAdmin)->exec();
  639. $allUsers[$account] = $account;
  640. }
  641. }
  642. $this->loadModel('user');
  643. foreach($allUsers as $account)
  644. {
  645. if($account) $this->user->computeUserView($account, true);
  646. }
  647. return !dao::isError();
  648. }
  649. /**
  650. * resource排序。
  651. * Sort resource.
  652. *
  653. * @access public
  654. * @return void
  655. */
  656. public function sortResource()
  657. {
  658. $resources = $this->lang->resource;
  659. $this->lang->resource = new stdclass();
  660. /* sort moduleOrder. */
  661. ksort($this->lang->moduleOrder, SORT_ASC);
  662. foreach($this->lang->moduleOrder as $moduleName)
  663. {
  664. if(!isset($resources->$moduleName)) continue;
  665. $resource = $resources->$moduleName;
  666. unset($resources->$moduleName);
  667. $this->lang->resource->$moduleName = $resource;
  668. }
  669. foreach($resources as $key => $resource)
  670. {
  671. $this->lang->resource->$key = $resource;
  672. }
  673. /* sort methodOrder. */
  674. foreach($this->lang->resource as $moduleName => $resources)
  675. {
  676. $resources = (array)$resources;
  677. $tmpResources = new stdclass();
  678. if(isset($this->lang->$moduleName->methodOrder))
  679. {
  680. ksort($this->lang->$moduleName->methodOrder, SORT_ASC);
  681. foreach($this->lang->$moduleName->methodOrder as $key)
  682. {
  683. if(isset($resources[$key]))
  684. {
  685. $tmpResources->$key = $resources[$key];
  686. unset($resources[$key]);
  687. }
  688. }
  689. if($resources)
  690. {
  691. foreach($resources as $key => $resource)
  692. {
  693. $tmpResources->$key = $resource;
  694. }
  695. }
  696. $this->lang->resource->$moduleName = $tmpResources;
  697. unset($tmpResources);
  698. }
  699. }
  700. }
  701. /**
  702. * 判断分组操作是否可点击。
  703. * Judge an action is clickable or not.
  704. *
  705. * @param object $group
  706. * @param string $action
  707. * @static
  708. * @access public
  709. * @return bool
  710. */
  711. public static function isClickable($group, $action)
  712. {
  713. $action = strtolower($action);
  714. if($group->role == 'projectAdmin' && $action != 'manageprojectadmin') return false;
  715. if($action == 'manageprojectadmin' && $group->role != 'projectAdmin') return false;
  716. if($action == 'manageview' && $group->role == 'limited') return false;
  717. if($action == 'copy' && $group->role == 'limited') return false;
  718. return true;
  719. }
  720. /**
  721. * 加载resource的语言配置。
  722. * Load language of resource.
  723. *
  724. * @access public
  725. * @return void
  726. */
  727. public function loadResourceLang()
  728. {
  729. foreach($this->lang->resource as $moduleName => $action) $this->app->loadLang($moduleName);
  730. $this->app->loadLang('doc');
  731. $this->app->loadLang('api');
  732. $this->lang->custom->common = $this->lang->group->config;
  733. $this->lang->doc->common = $this->lang->doc->manage;
  734. $this->lang->api->common = $this->lang->api->manage;
  735. if(($this->config->edition == 'max' or $this->config->edition == 'ipd') and $this->config->vision == 'rnd' and isset($this->lang->baseline)) $this->lang->baseline->common = $this->lang->group->docTemplate;
  736. }
  737. /**
  738. * 处理权限依赖关系
  739. * Process circular dependency.
  740. *
  741. * @param array $depends
  742. * @param array $privs
  743. * @param array $excludes
  744. * @param array $processedPrivs
  745. * @access protected
  746. * @return array
  747. */
  748. protected function processDepends($depends, $privs, $excludes, $processedPrivs = array())
  749. {
  750. foreach($privs as $priv)
  751. {
  752. if(!isset($depends[$priv]) || isset($processedPrivs[$priv])) continue;
  753. /* 不重复处理权限,防止出现死循环。Avoid the infinite loop. */
  754. $processedPrivs[$priv] = true;
  755. foreach($depends[$priv] as $dependPriv)
  756. {
  757. if(isset($privs[$dependPriv]) || in_array($dependPriv, $excludes)) continue;
  758. $privs[$dependPriv] = $dependPriv;
  759. $dependPrivs = $this->processDepends($depends, zget($depends, $dependPriv, array()), $excludes, $processedPrivs);
  760. foreach($dependPrivs as $depend)
  761. {
  762. if(!in_array($depend, $excludes)) $privs[$depend] = $depend;
  763. }
  764. }
  765. }
  766. return $privs;
  767. }
  768. /**
  769. * 检查subset是否属于该nav。
  770. * Check nav have subset.
  771. *
  772. * @param string $nav
  773. * @param string $subset
  774. * @access protected
  775. * @return bool
  776. */
  777. protected function checkNavSubset($nav, $subset)
  778. {
  779. if(empty($nav)) return true;
  780. if($nav == 'general') return !isset($this->config->group->subset->$subset) || !isset($this->config->group->subset->$subset->nav) || $this->config->group->subset->$subset->nav == 'general';
  781. return isset($this->config->group->subset->$subset)
  782. && isset($this->config->group->subset->$subset->nav)
  783. && $this->config->group->subset->$subset->nav == $nav;
  784. }
  785. /**
  786. * Get priv list by nav.
  787. *
  788. * @param string $nav
  789. * @param string $version
  790. * @access public
  791. * @return array
  792. */
  793. public function getPrivsByNav($nav = '', $version = '')
  794. {
  795. $privList = array();
  796. $allPrivs = array();
  797. /* Filter privs equal or greater than this version.*/
  798. if($version) $versionPrivs = $this->getPrivsAfterVersion($version);
  799. $hiddenHost = $this->loadModel('zahost')->hiddenHost();
  800. /* Privs in package. */
  801. foreach($this->config->group->package as $packageCode => $packageData)
  802. {
  803. if(!isset($packageData->privs)) continue;
  804. $sortPriv = array();
  805. foreach($packageData->privs as $privCode => $priv)
  806. {
  807. list($moduleName, $methodName) = explode('-', $privCode);
  808. $allPrivs[$privCode] = $privCode;
  809. if($hiddenHost && $moduleName == 'zahost') continue;
  810. if($hiddenHost && $moduleName == 'zanode' && !in_array($methodName, $this->config->group->showNodePriv)) continue;
  811. if(!$this->config->inQuickon && !$this->config->inCompose && in_array("{$moduleName}-{$methodName}", $this->config->group->hiddenPriv)) continue;
  812. if(strpos(',' . $priv['edition'] . ',', ',' . $this->config->edition . ',') === false) continue;
  813. if(strpos(',' . $priv['vision'] . ',', ',' . $this->config->vision . ',') === false) continue;
  814. if(!$this->checkNavSubset($nav, $packageData->subset)) continue;
  815. /* If version is selected, only show privs before the version. */
  816. if(!empty($version) and strpos($versionPrivs, ",$privCode,") === false) continue;
  817. /* Add methods in workflow menus, remove privs unused in the edition. */
  818. if(isset($this->lang->$moduleName->menus) && isset($this->lang->$moduleName->menus[$methodName]))
  819. {
  820. $privName = $this->lang->$moduleName->menus[$methodName];
  821. }
  822. else
  823. {
  824. if(!isset($this->lang->resource->$moduleName) || !isset($this->lang->resource->$moduleName->$methodName)) continue;
  825. $methodLang = $this->lang->resource->$moduleName->$methodName;
  826. if(!isset($this->lang->$moduleName->$methodLang))
  827. {
  828. $this->app->loadLang($moduleName);
  829. if($moduleName == 'requirement') $this->app->loadLang('story');
  830. }
  831. $privName = isset($this->lang->$moduleName) && isset($this->lang->$moduleName->$methodLang) ? $this->lang->$moduleName->$methodLang : $privCode;
  832. }
  833. $privData = (object)array('code' => $privCode, 'subset' => $packageData->subset, 'package' => $packageCode, 'module' => $moduleName, 'method' => $methodName, 'selected' => false, 'name' => $privName);
  834. /* 将order作为键方便排序。 */
  835. if(!empty($priv['order']) && !isset($sortPriv[$priv['order']]))
  836. {
  837. $sortPriv[$priv['order']] = $privData;
  838. }
  839. else
  840. {
  841. $sortPriv[] = $privData;
  842. }
  843. }
  844. /* 以order排序后再放入privList数组。 */
  845. ksort($sortPriv);
  846. foreach($sortPriv as $priv) $privList[$priv->code] = $priv;
  847. }
  848. return $privList;
  849. }
  850. /**
  851. * Get privs list by group.
  852. *
  853. * @param int $groupID
  854. * @access public
  855. * @return array
  856. */
  857. public function getPrivsByGroup($groupID)
  858. {
  859. return $this->dao->select("CONCAT(module, '-', method) AS action")->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->fetchPairs();
  860. }
  861. /**
  862. * AJAX: Get privs by parents.
  863. *
  864. * @param string $selectedSubset
  865. * @param string $selectedPackages
  866. * @access public
  867. * @return array
  868. */
  869. public function getPrivsByParents($selectedSubset, $selectedPackages = '')
  870. {
  871. $allPrivs = array();
  872. $privs = array();
  873. /* Privs in package. */
  874. foreach($this->config->group->package as $packageCode => $packageData)
  875. {
  876. if(!isset($packageData->privs)) continue;
  877. foreach($packageData->privs as $privCode => $priv)
  878. {
  879. list($moduleName, $methodName) = explode('-', $privCode);
  880. /* Remove privs unused in the edition. */
  881. if(isset($this->lang->$moduleName->menus) && isset($this->lang->$moduleName->menus[$methodName]))
  882. {
  883. $privName = $this->lang->$moduleName->menus[$methodName];
  884. }
  885. else
  886. {
  887. if(!isset($this->lang->resource->$moduleName) || !isset($this->lang->resource->$moduleName->$methodName)) continue;
  888. $methodLang = $this->lang->resource->$moduleName->$methodName;
  889. if(!isset($this->lang->$moduleName->$methodLang))
  890. {
  891. $this->app->loadLang($moduleName);
  892. if($moduleName == 'requirement') $this->app->loadLang('story');
  893. }
  894. $privName = isset($this->lang->$moduleName) && isset($this->lang->$moduleName->$methodLang) ? $this->lang->$moduleName->$methodLang : "$moduleName-$methodName";
  895. }
  896. $allPrivs[$privCode] = $privCode;
  897. $subset = $packageData->subset;
  898. if($subset !== $selectedSubset) continue;
  899. if($selectedPackages && strpos($selectedPackages, "|$packageCode|") === false) continue;
  900. $privs[$privCode] = $privName;
  901. }
  902. }
  903. return $privs;
  904. }
  905. /**
  906. * Get privs after version
  907. *
  908. * @param string $version
  909. * @access public
  910. * @return string
  911. */
  912. public function getPrivsAfterVersion($version)
  913. {
  914. $realVersion = str_replace('_', '.', $version);
  915. $changelog = array();
  916. foreach($this->lang->changelog as $currentVersion => $currentChangeLog)
  917. {
  918. if(version_compare($currentVersion, $realVersion, '>=')) $changelog[] = join(',', $currentChangeLog);
  919. }
  920. $versionPrivs = ',' . join(',', $changelog) . ',';
  921. return $versionPrivs;
  922. }
  923. /**
  924. * Get related privs.
  925. *
  926. * @param array $allPrivList
  927. * @param array $selectedPrivList
  928. * @param array $recommendSelect
  929. * @access public
  930. * @return array
  931. */
  932. public function getRelatedPrivs($allPrivList, $selectedPrivList, $recommendSelect = array())
  933. {
  934. $this->loadResourceLang();
  935. $depends = array();
  936. $privSubsets = array();
  937. $relatedPrivs = array('depend' => array(), 'recommend' => array());
  938. foreach($this->config->group->package as $packagePage => $package)
  939. {
  940. if(!isset($package->privs)) continue;
  941. foreach($package->privs as $privCode => $priv)
  942. {
  943. $privSubsets[$privCode] = $package->subset;
  944. foreach(array('depend', 'recommend') as $type)
  945. {
  946. /* Show related privs when select. */
  947. if($type == 'recommend' && in_array($privCode, $recommendSelect)) $relatedPrivs[$type][$privCode] = $privCode;
  948. if(!in_array($privCode, $selectedPrivList) || !isset($priv[$type])) continue;
  949. foreach($priv[$type] as $code => $relatedPriv)
  950. {
  951. if(!in_array($relatedPriv, $selectedPrivList) && in_array($relatedPriv, $allPrivList))
  952. {
  953. $relatedPrivs[$type][$relatedPriv] = $relatedPriv;
  954. if($type == 'depend') $depends[$privCode][$code] = $relatedPriv;
  955. }
  956. }
  957. }
  958. }
  959. }
  960. /* Process circular dependency. */
  961. $relatedPrivs['depend'] = $this->processDepends($depends, $relatedPrivs['depend'], $selectedPrivList);
  962. $subsetPrivs = array('depend' => array(), 'recommend' => array());
  963. foreach(array('depend', 'recommend') as $type)
  964. {
  965. foreach($relatedPrivs[$type] as $relatedPriv)
  966. {
  967. if($type == 'recommend' && isset($relatedPrivs['depend'][$relatedPriv])) continue; // Don't show depend privs to recommend.
  968. $subsetName = $privSubsets[$relatedPriv];
  969. $subsetTitle = isset($this->lang->$subsetName) && isset($this->lang->$subsetName->common) ? $this->lang->$subsetName->common : $subsetName;
  970. if(!isset($subsetPrivs[$type][$subsetName])) $subsetPrivs[$type][$subsetName] = array('id' => $subsetName, 'text' => $subsetTitle, 'children' => array());
  971. list($moduleName, $methodName) = explode('-', $relatedPriv);
  972. if(!isset($this->lang->resource->$moduleName->$methodName)) continue;
  973. $method = $this->lang->resource->$moduleName->$methodName;
  974. if(!isset($this->lang->$moduleName->$method)) $this->app->loadLang($moduleName);
  975. $subsetPrivs[$type][$subsetName]['children'][] = array('id' => $relatedPriv, 'data-module' => $moduleName, 'data-method' => $methodName, 'subset' => $subsetName, 'text' => $this->lang->$moduleName->$method, 'data-id' => $relatedPriv, 'title' => $this->lang->$moduleName->$method);
  976. }
  977. }
  978. return array('depend' => array_values($subsetPrivs['depend']), 'recommend' => array_values($subsetPrivs['recommend']));
  979. }
  980. }