model.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <?php
  2. /**
  3. * The model file of score module of ZenTaoPMS.
  4. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  5. * @author Memory <lvtao@cnezsoft.com>
  6. * @package score
  7. * @version $Id: model.php $
  8. * @link https://www.zentao.net
  9. */
  10. class scoreModel extends model
  11. {
  12. /**
  13. * 获取用户的积分记录。
  14. * Get user score list.
  15. *
  16. * @param string $account
  17. * @param object $pager
  18. * @access public
  19. * @return array
  20. */
  21. public function getListByAccount($account, $pager = null)
  22. {
  23. return $this->dao->select('*')->from(TABLE_SCORE)->where('account')->eq($account)->orderBy('time_desc, id_desc')->page($pager)->fetchAll();
  24. }
  25. /**
  26. * 创建积分日志。
  27. * Add score logs.
  28. *
  29. * @param string $module
  30. * @param string $method
  31. * @param int|string|object $param
  32. * @param string $account
  33. * @param string $time
  34. * @access public
  35. * @return bool|object
  36. */
  37. public function create($module = '', $method = '', $param = '', $account = '', $time = '')
  38. {
  39. if(empty($this->config->score->rule->{$module}->{$method}) || empty($this->config->global->scoreStatus)) return true;
  40. $rule = $this->config->score->rule->{$module}->{$method};
  41. $desc = $this->lang->score->modules[$module];
  42. $user = empty($account) ? $this->app->user->account : $account;
  43. $time = empty($time) ? helper::now() : $time;
  44. $extended = isset($this->config->score->ruleExtended[$module][$method]) ? $this->config->score->ruleExtended[$module][$method] : array();
  45. if(is_numeric($param)) $desc .= 'ID:' . $param;
  46. $object = '';
  47. switch($module)
  48. {
  49. case 'user':
  50. if($method == 'login') $desc = $this->lang->score->methods[$module][$method];
  51. if($method == 'changePassword')
  52. {
  53. if(!empty($extended['strength'][$param])) $rule['score'] = $rule['score'] + $extended['strength'][$param];
  54. $desc = $this->lang->score->methods[$module][$method];
  55. }
  56. break;
  57. case 'story':
  58. if($method == 'close')
  59. {
  60. $openedBy = $this->dao->findById($param)->from(TABLE_STORY)->fetch('openedBy');
  61. $object = true;
  62. if(!empty($openedBy))
  63. {
  64. $newRule = $rule;
  65. $newRule['score'] = $extended['createID'];
  66. $object = $this->saveScore($openedBy, $newRule, $module, $method, $desc, $time);
  67. unset($newRule);
  68. }
  69. }
  70. break;
  71. case 'task':
  72. if($method == 'finish')
  73. {
  74. $data = $this->computeTaskScore($module, $method, $param, $rule, $extended);
  75. if(!$data) return true;
  76. list($desc, $rule) = $data;
  77. }
  78. break;
  79. case 'bug':
  80. list($rule, $desc, $user) = $this->computeBugScore($module, $method, $param, $rule, $desc, $user, $extended);
  81. break;
  82. case 'testTask':
  83. if($method == 'runCase') $desc = $this->lang->score->methods[$module][$method] . 'ID:' . $param;
  84. break;
  85. case 'execution':
  86. if($method == 'close') list($rule, $desc, $object) = $this->computeExecutionScore($module, $method, $param, $user, $time, $rule, $desc, $extended);
  87. break;
  88. case 'search':
  89. if($method == 'saveQueryAdvanced') $desc = $this->lang->score->methods[$module][$method];
  90. break;
  91. case 'ajax':
  92. $desc = $this->lang->score->methods[$module][$method];
  93. break;
  94. }
  95. return $object === '' ? $this->saveScore($user, $rule, $module, $method, $desc, $time) : $object;
  96. }
  97. /**
  98. * 计算任务积分。
  99. * Compute task score.
  100. *
  101. * @param string $module
  102. * @param string $method
  103. * @param int $param
  104. * @param array $rule
  105. * @param array $extended
  106. * @access public
  107. * @return array|bool
  108. */
  109. public function computeTaskScore($module, $method, $param, $rule, $extended)
  110. {
  111. if($method != 'finish') return true;
  112. $desc = $this->lang->score->methods[$module][$method] . 'ID:' . $param;
  113. /* Check child task. */
  114. $parentTask = $this->dao->select('id')->from(TABLE_TASK)->where('parent')->eq($param)->fetch('id');
  115. if(!empty($parentTask)) return false;
  116. $task = $this->loadModel('task')->getByID($param);
  117. if(!$task) return false;
  118. if(!empty($extended['pri'][$task->pri]))
  119. {
  120. $rule['score'] = $rule['score'] + $extended['pri'][$task->pri];
  121. }
  122. if($task->estimate > 0)
  123. {
  124. $rule['score'] = $rule['score'] + ($task->consumed > 0 ? round($task->consumed / 10.0 * $task->estimate / $task->consumed) : 0);
  125. }
  126. return array($desc, $rule);
  127. }
  128. /**
  129. * 计算Bug积分。
  130. * Compute bug score.
  131. *
  132. * @param string $module
  133. * @param string $method
  134. * @param string|object|int $param
  135. * @param array $rule
  136. * @param string $desc
  137. * @param string $user
  138. * @param array $extended
  139. * @access public
  140. * @return array
  141. */
  142. public function computeBugScore($module, $method, $param, $rule, $desc, $user, $extended)
  143. {
  144. if($method == 'createFormCase')
  145. {
  146. $desc = $this->lang->score->modules['testcase'] . 'ID:' . $param;
  147. $openedBy = $this->dao->findById($param)->from(TABLE_CASE)->fetch('openedBy');
  148. if(!empty($openedBy)) $user = $openedBy;
  149. }
  150. if($method == 'saveTplModal') $desc = $this->lang->score->methods[$module][$method] . 'ID:' . $param;
  151. if($method == 'confirm')
  152. {
  153. $user = $param->openedBy;
  154. $desc .= 'ID:' . $param->id;
  155. if(!empty($extended['severity'][$param->severity]))
  156. {
  157. $rule['score'] = $rule['score'] + $extended['severity'][$param->severity];
  158. }
  159. }
  160. if($method == 'resolve' && !empty($extended['severity'][$param->severity]))
  161. {
  162. $rule['score'] = $rule['score'] + $extended['severity'][$param->severity];
  163. }
  164. return array($rule, $desc, $user);
  165. }
  166. /**
  167. * 计算执行积分。
  168. * Compute execution score.
  169. *
  170. * @param string $module
  171. * @param string $method
  172. * @param object $param
  173. * @param string $user
  174. * @param string $time
  175. * @param array $rule
  176. * @param string $desc
  177. * @param array $extended
  178. * @access public
  179. * @return array
  180. */
  181. public function computeExecutionScore($module, $method, $param, $user, $time, $rule, $desc, $extended)
  182. {
  183. if($method != 'close') return array();
  184. $desc = $this->lang->score->methods[$module][$method] . ',' . $desc . 'ID:' . $param->id;
  185. $timestamp = empty($time) ? time() : strtotime($time);
  186. $object = true;
  187. /* Project PM. */
  188. if(!empty($param->PM))
  189. {
  190. $rule['score'] = $extended['manager']['close'];
  191. if($param->end > date('Y-m-d', $timestamp))
  192. {
  193. $rule['score'] += $extended['manager']['onTime'];
  194. }
  195. $object = $this->saveScore($param->PM, $rule, $module, $method, $desc, $time);
  196. }
  197. /* Project team user. */
  198. $teams = $this->dao->select('account')->from(TABLE_TEAM)->where('root')->eq($param->id)->andWhere('type')->eq('execution')->fetchPairs();
  199. if(!empty($teams))
  200. {
  201. $rule['score'] = $extended['member']['close'];
  202. if($param->end > date('Y-m-d', $timestamp))
  203. {
  204. $rule['score'] += $extended['member']['onTime'];
  205. }
  206. foreach($teams as $user)
  207. {
  208. if($user != $param->PM) $object = $this->saveScore($user, $rule, $module, $method, $desc, $time);
  209. }
  210. }
  211. return array($rule, $desc, $object);
  212. }
  213. /**
  214. * 保存用户积分。
  215. * Save user score.
  216. *
  217. * @param string $account
  218. * @param array $rule
  219. * @param string $module
  220. * @param string $method
  221. * @param string $desc
  222. * @param string $time
  223. * @access public
  224. * @return object|bool
  225. */
  226. public function saveScore($account = '', $rule = array(), $module = '', $method = '', $desc = '', $time = '')
  227. {
  228. if($rule['score'] == 0) return true;
  229. if(!empty($rule['times']) || !empty($rule['hour']))
  230. {
  231. if(empty($rule['hour']))
  232. {
  233. $count = $this->dao->select('id')->from(TABLE_SCORE)->where('account')->eq($account)->andWhere('module')->eq($module)->andWhere('method')->eq($method)->count();
  234. }
  235. else
  236. {
  237. $timestamp = empty($time) ? time() : strtotime($time);
  238. $count = $this->dao->select('id')->from(TABLE_SCORE)->where('account')->eq($account)
  239. ->andWhere('time')->between(date('Y-m-d 00:00:00', $timestamp), date('Y-m-d 23:59:59', $timestamp))
  240. ->andWhere('module')->eq($module)
  241. ->andWhere('method')->eq($method)
  242. ->count();
  243. }
  244. if($count >= $rule['times']) return true;
  245. }
  246. $user = $this->loadModel('user')->getById($account);
  247. if(empty($user)) return false;
  248. $data = new stdClass();
  249. $data->account = $account;
  250. $data->module = $module;
  251. $data->method = $method;
  252. $data->desc = $desc;
  253. $data->before = $user->score;
  254. $data->score = (int)$rule['score'];
  255. $data->after = $user->score + $rule['score'];
  256. $data->time = empty($time) ? helper::now() : $time;
  257. $this->dao->insert(TABLE_SCORE)->data($data)->exec();
  258. $this->dao->update(TABLE_USER)->set("`score`=`score` + " . $data->score)->set("`scoreLevel`=`scoreLevel` + " . $data->score)->where('account')->eq($account)->exec();
  259. if(dao::isError()) return false;
  260. return $data;
  261. }
  262. /**
  263. * 构建积分规则列表。
  264. * Build rules for list.
  265. *
  266. * @access public
  267. * @return array
  268. */
  269. public function buildRules()
  270. {
  271. $allRules = array();
  272. foreach($this->config->score->rule as $module => $moduleRule)
  273. {
  274. foreach($moduleRule as $method => $rule)
  275. {
  276. $rules['module'] = $this->lang->score->modules[$module];
  277. $rules['method'] = $this->lang->score->methods[$module][$method];
  278. $rules['times'] = empty($rule['times']) ? $this->lang->score->noLimit : $rule['times'];
  279. $rules['hour'] = empty($rule['hour']) ? $this->lang->score->noLimit : $rule['hour'];
  280. $rules['score'] = $rule['score'];
  281. $rules['desc'] = '';
  282. if(!isset($this->lang->score->extended[$module][$method]))
  283. {
  284. $allRules[] = $rules;
  285. continue;
  286. }
  287. $desc = $this->lang->score->extended[$module][$method];
  288. $descRule = explode('##', $desc);
  289. if(!empty($descRule))
  290. {
  291. foreach($descRule as $key => $value)
  292. {
  293. if($key % 2 != 1) continue;
  294. $match = explode(',', $value);
  295. if(count($match) == 2) $score = $this->config->score->ruleExtended[$module][$method][$match[0]][$match[1]];
  296. if(count($match) != 2) $score = $this->config->score->ruleExtended[$module][$method][$match[0]];
  297. $desc = str_replace('##' . $value . '##', (string)$score, $desc);
  298. }
  299. }
  300. $rules['desc'] = $desc;
  301. $allRules[] = $rules;
  302. }
  303. }
  304. return $allRules;
  305. }
  306. /**
  307. * 修复积分动作类型。
  308. * Fix action type for score.
  309. *
  310. * @param string $action
  311. * @access public
  312. * @return string
  313. */
  314. public function fixKey($action)
  315. {
  316. $actionList = array('created' => 'create', 'opened' => 'create', 'closed' => 'close', 'finished' => 'finish', 'bugconfirmed' => 'confirm', 'resolved' => 'resolve');
  317. return isset($actionList[$action]) ? $actionList[$action] : $action;
  318. }
  319. /**
  320. * 获取当前用户昨日的积分总数。
  321. * Get yesterday's score for user.
  322. *
  323. * @access public
  324. * @return string
  325. */
  326. public function getNotice()
  327. {
  328. if(empty($this->config->global->scoreStatus) || empty($this->app->user->lastTime)) return '';
  329. if(date('Y-m-d', (int)$this->app->user->lastTime) == helper::today()) return '';
  330. $this->app->user->lastTime = time();
  331. $score = $this->dao->select("SUM(score) AS score")->from(TABLE_SCORE)
  332. ->where('time')->between(date('Y-m-d 00:00:00', strtotime('-1 day')), date('Y-m-d 23:59:59', strtotime('-1 day')))
  333. ->andWhere('account')->eq($this->app->user->account)
  334. ->fetch('score');
  335. if(!$score) return '';
  336. return sprintf($this->lang->score->tips, $score, $this->app->user->score);
  337. }
  338. }