diff --git a/db/update9.5.1.sql b/db/update9.5.1.sql index 50c22de4a3..7223eb3bf6 100644 --- a/db/update9.5.1.sql +++ b/db/update9.5.1.sql @@ -94,4 +94,4 @@ CREATE TABLE `zt_score` ( KEY `method` (`method`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`, `lastTime`) VALUES ('*/5', '*', '*', '*', '*', 'moduleName=webhook&methodName=asyncSend', '异步发送Webhook', 'zentao', 0, 'normal', '0000-00-00 00:00:00'); +INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type`, `buildin`, `status`, `lastTime`) VALUES ('*/5', '*', '*', '*', '*', 'moduleName=webhook&methodName=asyncSend', '异步发送Webhook', 'zentao', 1, 'normal', '0000-00-00 00:00:00'); diff --git a/lib/base/dao/dao.class.php b/lib/base/dao/dao.class.php index 24592083f8..c772e56f42 100644 --- a/lib/base/dao/dao.class.php +++ b/lib/base/dao/dao.class.php @@ -172,6 +172,15 @@ class baseDAO */ static public $cache = array(); + /** + * 缓存过期时间 + * The cache timeout. + * + * @var float + * @access public + */ + public $cacheTimeout = 60; + /** * 构造方法。 * The construct method. @@ -757,6 +766,7 @@ class baseDAO try { + if($this->table) unset(dao::$cache[$this->table]); $this->reset(); return $this->dbh->exec($sql); } @@ -779,26 +789,29 @@ class baseDAO */ public function fetch($field = '') { - $sql = $this->processSQL(); - $key = md5($sql); - if(isset(dao::$cache['fetch'][$key])) + $sql = $this->processSQL(); + $table = $this->table; + $key = md5($sql); + if(isset(dao::$cache[$table]['fetch'][$key]) and dao::$cache[$table]['fetch'][$key]['time'] <= time() - $this->cacheTimeout) { - if(empty($field)) return $this->getRow(dao::$cache['fetch'][$key]); + if(empty($field)) return $this->getRow(dao::$cache[$table]['fetch'][$key]['data']); - $result = dao::$cache['fetch'][$key]; + $result = dao::$cache[$table]['fetch'][$key]['data']; return $result ? $result->$field : ''; } if(empty($field)) { $data = $this->query()->fetch(); - dao::$cache['fetch'][$key] = $data; + dao::$cache[$table]['fetch'][$key]['data'] = $data; + dao::$cache[$table]['fetch'][$key]['time'] = time(); return $this->getRow($data); } $this->setFields($field); $result = $this->query()->fetch(PDO::FETCH_OBJ); - dao::$cache['fetch'][$key] = $result; + dao::$cache[$table]['fetch'][$key]['data'] = $result; + dao::$cache[$table]['fetch'][$key]['time'] = time(); return $result ? $result->$field : ''; } @@ -813,11 +826,12 @@ class baseDAO */ public function fetchAll($keyField = '') { - $sql = $this->processSQL(); - $key = md5($sql . $keyField); - if(isset(dao::$cache['fetchAll'][$key])) + $sql = $this->processSQL(); + $table = $this->table; + $key = md5($sql . $keyField); + if(isset(dao::$cache[$table]['fetchAll'][$key]) and dao::$cache[$table]['fetchAll'][$key]['time'] <= time() - $this->cacheTimeout) { - $rows = dao::$cache['fetchAll'][$key]; + $rows = dao::$cache[$table]['fetchAll'][$key]['data']; $result = array(); foreach($rows as $i => $row) $result[$i] = $this->getRow($row); return $result; @@ -828,14 +842,19 @@ class baseDAO { $rows = $stmt->fetchAll(); $result = array(); - dao::$cache['fetchAll'][$key] = $rows; + dao::$cache[$table]['fetchAll'][$key]['data'] = $rows; + dao::$cache[$table]['fetchAll'][$key]['time'] = time(); foreach($rows as $i => $row) $result[$i] = $this->getRow($row); return $result; } $rows = array(); - while($row = $stmt->fetch()) $rows[$row->$keyField] = $this->getRow($row); - dao::$cache['fetchAll'][$key] = $rows; + dao::$cache[$table]['fetchAll'][$key]['time'] = time(); + while($row = $stmt->fetch()) + { + dao::$cache[$table]['fetchAll'][$key]['data'][$row->$keyField] = $row; + $rows[$row->$keyField] = $this->getRow($row); + } return $rows; } @@ -850,12 +869,13 @@ class baseDAO */ public function fetchGroup($groupField, $keyField = '') { - $sql = $this->processSQL(); - $key = md5($sql . $groupField . $keyField); - if(isset(dao::$cache['fetchGroup'][$key])) + $sql = $this->processSQL(); + $table = $this->table; + $key = md5($sql . $groupField . $keyField); + if(isset(dao::$cache[$table]['fetchGroup'][$key]) and dao::$cache[$table]['fetchGroup'][$key]['time'] <= time() - $this->cacheTimeout) { $result = array(); - $groupRows = dao::$cache['fetchGroup'][$key]; + $groupRows = dao::$cache[$table]['fetchGroup'][$key]['data']; foreach($groupRows as $groupField => $rows) { foreach($rows as $keyField => $row) $result[$groupField][$keyField] = $this->getRow($row); @@ -869,7 +889,8 @@ class baseDAO { empty($keyField) ? $rows[$row->$groupField][] = $row : $rows[$row->$groupField][$row->$keyField] = $this->getRow($row); } - dao::$cache['fetchGroup'][$key] = $rows; + dao::$cache[$table]['fetchGroup'][$key]['data'] = $rows; + dao::$cache[$table]['fetchGroup'][$key]['time'] = time(); return $rows; } @@ -890,9 +911,10 @@ class baseDAO $keyField = trim($keyField, '`'); $valueField = trim($valueField, '`'); - $sql = $this->processSQL(); - $key = md5($sql . $keyField . $valueField); - if(isset(dao::$cache["fetchPairs"][$key])) return dao::$cache['fetchPairs'][$key]; + $sql = $this->processSQL(); + $table = $this->table; + $key = md5($sql . $keyField . $valueField); + if(isset(dao::$cache[$table]["fetchPairs"][$key]) and dao::$cache[$table]["fetchPairs"][$key]['time'] <= time() - $this->cacheTimeout) return dao::$cache[$table]['fetchPairs'][$key]['data']; $pairs = array(); $ready = false; @@ -913,7 +935,8 @@ class baseDAO $pairs[$row[$keyField]] = $row[$valueField]; } - dao::$cache['fetchPairs'][$key] = $pairs; + dao::$cache[$table]['fetchPairs'][$key]['data'] = $pairs; + dao::$cache[$table]['fetchPairs'][$key]['time'] = time(); return $pairs; } diff --git a/module/project/control.php b/module/project/control.php index 47eff3bad5..eee780130c 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1247,7 +1247,7 @@ class project extends control * @access public * @return void */ - public function kanban($projectID, $orderBy = 'pri_asc') + public function kanban($projectID, $type = 'story', $orderBy = 'pri_asc') { /* Save to session. */ $uri = $this->app->getURI(true); @@ -1260,19 +1260,22 @@ class project extends control $this->project->setMenu($this->projects, $projectID); $project = $this->loadModel('project')->getById($projectID); - $stories = $this->loadModel('story')->getProjectStories($projectID, $orderBy); $tasks = $this->project->getKanbanTasks($projectID, "id"); $bugs = $this->loadModel('bug')->getProjectBugs($projectID); - $stories = $this->project->getKanbanGroupData($stories, $tasks, $bugs); + $stories = $this->loadModel('story')->getProjectStories($projectID, $orderBy); - $this->view->title = $this->lang->project->kanban; - $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $this->view->position[] = $this->lang->project->kanban; - $this->view->stories = $stories; - $this->view->realnames = $this->loadModel('user')->getPairs('noletter'); - $this->view->orderBy = $orderBy; - $this->view->projectID = $projectID; - $this->view->project = $project; + $kanbanGroup = $this->project->getKanbanGroupData($stories, $tasks, $bugs, $type); + + $this->view->title = $this->lang->project->kanban; + $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->project->kanban; + $this->view->stories = $stories; + $this->view->realnames = $this->loadModel('user')->getPairs('noletter'); + $this->view->orderBy = $orderBy; + $this->view->projectID = $projectID; + $this->view->project = $project; + $this->view->type = $type; + $this->view->kanbanGroup = $kanbanGroup; $kanbanSetting = $this->project->getKanbanSetting($projectID); diff --git a/module/project/css/kanban.css b/module/project/css/kanban.css index cae429cd04..1d9ebc48cf 100644 --- a/module/project/css/kanban.css +++ b/module/project/css/kanban.css @@ -63,12 +63,12 @@ table th.col-closed {width:14%} .board {background: #333; color: #f1f1f1; outline: 1px solid rgba(0,0,0,.1); outline-offset: -1px;} .board:hover {outline: 1px solid rgba(0,0,0,.3); color:#fff} -.board-bug-cancel, .board-task-cancel {background: #333; opacity: 0.7;} -.board-bug-wait, .board-task-wait {background: #2b529c;opacity: 0.7;} -.board-task-pause {background: #E48600;opacity: 0.7;} -.board-bug-doing, .board-task-doing {background: #D2322D;opacity: 0.7;} -.board-bug-done, .board-task-done {background: #229F24;opacity: 0.7;} -.board-bug-closed, .board-task-closed {background: #777; opacity: 0.7;} +.board-bug-cancel, .board-task-cancel {background: #333; opacity: 1;} +.board-bug-wait, .board-task-wait {background: #2b529c;opacity: 1;} +.board-task-pause {background: #E48600;opacity: 1;} +.board-bug-doing, .board-task-doing {background: #D2322D;opacity: 1;} +.board-bug-done, .board-task-done {background: #229F24;opacity: 1;} +.board-bug-closed, .board-task-closed {background: #777; opacity: 1;} .board-bug-cancel.inverse, .board-task-cancel.inverse {opacity: 1;} .board-bug-wait.inverse, .board-task-wait.inverse {opacity: 1} diff --git a/module/project/model.php b/module/project/model.php index cb89ef9044..5ceb134028 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -2103,41 +2103,49 @@ class projectModel extends model * @access public * @return array */ - public function getKanbanGroupData($stories, $tasks, $bugs) + public function getKanbanGroupData($stories, $tasks, $bugs, $type = 'story') { - $stories['nostory'] = new stdclass(); + $kanbanGroup = array(); + if($type == 'story') $kanbanGroup = $stories; + foreach($tasks as $task) { - $storyID = $task->storyID; - $status = $task->status; - if(!empty($storyID) and isset($stories[$storyID])) + $groupKey = $type == 'story' ? $task->storyID : $task->$type; + + $status = $task->status; + if(!empty($groupKey) and (($type == 'story' and isset($stories[$groupKey])) or $type != 'story')) { - $stories[$storyID]->tasks[$status][] = $task; + if(!isset($kanbanGroup[$groupKey])) $kanbanGroup[$groupKey] = new stdclass(); + $kanbanGroup[$groupKey]->tasks[$status][] = $task; } else { - $noStoryTasks[$status][] = $task; + $noKeyTasks[$status][] = $task; } } - if(isset($noStoryTasks)) $stories['nostory']->tasks = $noStoryTasks; foreach($bugs as $bug) { - $storyID = $bug->story; + $groupKey = $type == 'finishedBy' ? $bug->resolvedBy : $bug->$type; + $status = $bug->status; $status = $status == 'active' ? 'wait' : ($status == 'resolved' ? ($bug->resolution == 'postponed' ? 'cancel' : 'done') : $status); - if(!empty($storyID) and isset($stories[$storyID])) + if(!empty($groupKey) and (($type == 'story' and isset($stories[$groupKey])) or $type != 'story')) { - $stories[$storyID]->bugs[$status][] = $bug; + if(!isset($kanbanGroup[$groupKey])) $kanbanGroup[$groupKey] = new stdclass(); + $kanbanGroup[$groupKey]->bugs[$status][] = $bug; } else { - $noStoryBugs[$status][] = $bug; + $noKeyBugs[$status][] = $bug; } } - if(isset($noStoryBugs)) $stories['nostory']->bugs = $noStoryBugs; - return $stories; + $kanbanGroup['nokey'] = new stdclass(); + if(isset($noKeyTasks)) $kanbanGroup['nokey']->tasks = $noKeyTasks; + if(isset($noKeyBugs)) $kanbanGroup['nokey']->bugs = $noKeyBugs; + + return $kanbanGroup; } /** diff --git a/module/project/view/kanban.html.php b/module/project/view/kanban.html.php index a8e56ac739..457de5ea64 100644 --- a/module/project/view/kanban.html.php +++ b/module/project/view/kanban.html.php @@ -24,17 +24,21 @@ $account = $this->app->user->account - = 2;?> - + 0) or $type != 'story');?> + @@ -48,6 +52,15 @@ $account = $this->app->user->account @@ -61,7 +74,7 @@ $account = $this->app->user->account
+ + + task->$type;?> +
- + @@ -69,12 +82,14 @@ $account = $this->app->user->account - - + $group):?> + - + - + diff --git a/module/webhook/view/log.html.php b/module/webhook/view/log.html.php index 8d2add7770..755aef4c62 100644 --- a/module/webhook/view/log.html.php +++ b/module/webhook/view/log.html.php @@ -23,6 +23,7 @@ id}&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?> + @@ -33,6 +34,7 @@ $log):?> +
- id)):?> + + +
assignedTo == $account) echo ' inverse';?>' data-id='id?>'>
createLink('story', 'view', "storyID=$story->id", '', true), $story->title, '', 'class="kanbanFrame" title="' . $story->title . '"');?> @@ -103,13 +118,20 @@ $account = $this->app->user->account
estimate . 'h ';?>
+ +
+
+ +
+
+
- tasks[$col])):?> - tasks[$col] as $task):?> + tasks[$col])):?> + tasks[$col] as $task):?>
assignedTo == $account) echo ' inverse';?>' data-id='id?>' id='task-id?>'>
app->user->account $labelClass = $task->status == 'doing' ? 'label-delay-doing' : 'label-delay-wait'; echo "{$lang->task->delayed}"; } - echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), $task->name, '', 'class="kanbanFrame" title="' . $task->name . '"'); + $childrenAB = empty($task->parent) ? '' : "" . $lang->task->childrenAB . ' '; + echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), $childrenAB . $task->name, '', 'class="kanbanFrame" title="' . $task->name . '"'); ?>
@@ -126,7 +149,7 @@ $account = $this->app->user->account -
"; + $title = ''; + if($id == 'name') $title = " title='{$task->name}'"; + if($id == 'story') $title = " title='{$task->storyTitle}'"; + + echo ""; switch($id) { case 'id': diff --git a/module/webhook/control.php b/module/webhook/control.php index bab999ee9e..9f768555d6 100644 --- a/module/webhook/control.php +++ b/module/webhook/control.php @@ -136,12 +136,20 @@ class webhook extends control */ public function asyncSend() { - $webhooks = $this->webhook->getList(); - if(empty($hooks)) return false; + $webhooks = $this->webhook->getList($type = '', $orderBy = 'id_desc', $pager = null, $decode = false); + if(empty($webhooks)) + { + echo "NO WEBHOOK EXIST.\n"; + return false; + } + $dataList = $this->webhook->getDataList(); - if(empty($dataList)) return true; + if(empty($dataList)) + { + echo "OK\n"; + return true; + } - $snoopy = $this->app->loadClass('snoopy'); foreach($dataList as $data) { $webhook = zget($webhooks, $data->webhook, ''); @@ -149,13 +157,15 @@ class webhook extends control { $contentType = zget($this->config->webhook->contentTypes, $webhook->contentType, 'application/json'); $result = $this->webhook->fetchHook($contentType, $webhook->url, $data->data); - $this->saveLog($data->webhook, $data->action, $webhook->url, $contentType, $data->data, $result); + $this->webhook->saveLog($data->webhook, $data->action, $webhook->url, $contentType, $data->data, $result); } - $this->dao->update(TABLE_WEBHOOKDATA)->set('status')->eq('sended')->where('id')->eq($data->id)->exec(); + $this->dao->update(TABLE_WEBHOOKDATAS)->set('status')->eq('sended')->where('id')->eq($data->id)->exec(); } - $this->dao->delete()->from(TABLE_WEBHOOKDATA)->where('status')->eq('sended')->exec(); + $this->dao->delete()->from(TABLE_WEBHOOKDATAS)->where('status')->eq('sended')->exec(); + + echo "OK\n"; return true; } } diff --git a/module/webhook/js/create.js b/module/webhook/js/create.js index 3acb71ac46..9fed36bc05 100644 --- a/module/webhook/js/create.js +++ b/module/webhook/js/create.js @@ -13,5 +13,5 @@ $(function() }); $('#name').focus(); - $('#paramsmessage').attr('disabled', 'disabled'); + $('#paramstext').attr('disabled', 'disabled'); }); diff --git a/module/webhook/js/edit.js b/module/webhook/js/edit.js index 3acb71ac46..9fed36bc05 100644 --- a/module/webhook/js/edit.js +++ b/module/webhook/js/edit.js @@ -13,5 +13,5 @@ $(function() }); $('#name').focus(); - $('#paramsmessage').attr('disabled', 'disabled'); + $('#paramstext').attr('disabled', 'disabled'); }); diff --git a/module/webhook/lang/zh-cn.php b/module/webhook/lang/zh-cn.php index 2e95a320d8..f7f0c744fe 100644 --- a/module/webhook/lang/zh-cn.php +++ b/module/webhook/lang/zh-cn.php @@ -26,6 +26,7 @@ $lang->webhook->createdBy = '由谁创建'; $lang->webhook->createdDate = '创建时间'; $lang->webhook->editedby = '最后编辑'; $lang->webhook->editedDate = '编辑时间'; +$lang->webhook->date = '发送时间'; $lang->webhook->data = '数据'; $lang->webhook->result = '结果'; @@ -40,7 +41,7 @@ $lang->webhook->paramsList['action'] = '动作'; $lang->webhook->paramsList['actor'] = '操作者'; $lang->webhook->paramsList['date'] = '操作日期'; $lang->webhook->paramsList['comment'] = '备注'; -$lang->webhook->paramsList['message'] = '操作内容'; +$lang->webhook->paramsList['text'] = '操作内容'; $lang->webhook->saveSuccess = '保存成功'; $lang->webhook->confirmDelete = '您确认要删除该webhook吗?'; diff --git a/module/webhook/model.php b/module/webhook/model.php index 211dd1b870..16699baf5d 100644 --- a/module/webhook/model.php +++ b/module/webhook/model.php @@ -31,10 +31,11 @@ class webhookModel extends model * @param string $type * @param string $orderBy * @param object $pager + * @param bool $decode * @access public * @return array */ - public function getList($type = '', $orderBy = 'id_desc', $pager = null) + public function getList($type = '', $orderBy = 'id_desc', $pager = null, $decode = true) { $webhooks = $this->dao->select('*')->from(TABLE_WEBHOOK) ->where('deleted')->eq('0') @@ -42,7 +43,7 @@ class webhookModel extends model ->orderBy($orderBy) ->page($pager) ->fetchAll('id'); - foreach($webhooks as $webhook) $webhook->actions = json_decode($webhook->actions); + if($decode) foreach($webhooks as $webhook) $webhook->actions = json_decode($webhook->actions); return $webhooks; } @@ -208,7 +209,6 @@ class webhookModel extends model if(!$webhooks) $webhooks = $this->getList(); if(!$webhooks) return true; - $snoopy = $this->app->loadClass('snoopy'); foreach($webhooks as $id => $webhook) { if(!isset($webhook->actions->$objectType) or !in_array($actionType, $webhook->actions->$objectType)) continue; @@ -258,7 +258,7 @@ class webhookModel extends model } static $users = array(); - if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter'); + if(empty($users)) $users = $this->loadModel('user')->getList(); $object = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch(); $field = $this->config->action->objectNameFields[$objectType]; @@ -269,17 +269,45 @@ class webhookModel extends model $data = new stdclass(); if($webhook->type == 'dingding') { - $title = $this->app->user->realname . $this->lang->action->label->$actionType . $this->lang->action->objectTypes[$objectType]; - if($actionType == 'assigned') $title .= ' ' . $this->lang->webhook->assigned . ' ' . zget($users, $object->assignedTo); + $title = $this->app->user->realname . $this->lang->action->label->$actionType . $this->lang->action->objectTypes[$objectType]; + $mobile = ''; + if($actionType == 'assigned') + { + $assignedTo = $object->assignedTo; + foreach($users as $user) + { + if($user->account == $object->assignedTo) + { + $assignedTo = $user->realname; + $mobile = $user->mobile; + break; + } + } + if($mobile) $title .= ' ' . "[#{$objectID}::{$title}](" . $host . $viewLink . ")"; + $title .= ' ' . $this->lang->webhook->assigned . ' ' . $assignedTo; + } - $link = new stdclass(); - $link->text = "[#{$objectID}::{$text}]"; - $link->title = $title; - $link->picUrl = ''; - $link->messageUrl = $host . $viewLink; + if($mobile) + { + $at = new stdclass(); + $at->atMobiles = array($mobile); + $at->isAtAll = false; - $data->msgtype = 'link'; - $data->link = $link; + $data->msgtype = 'text'; + $data->text = array('content' => $title); + $data->at = $at; + } + else + { + $link = new stdclass(); + $link->text = "[#{$objectID}::{$text}]"; + $link->title = $title; + $link->picUrl = ''; + $link->messageUrl = $host . $viewLink; + + $data->msgtype = 'link'; + $data->link = $link; + } return helper::jsonEncode($data); } diff --git a/module/webhook/view/create.html.php b/module/webhook/view/create.html.php index ddd74bacf0..6b59be8c1f 100644 --- a/module/webhook/view/create.html.php +++ b/module/webhook/view/create.html.php @@ -56,7 +56,7 @@
webhook->params;?>webhook->paramsList, 'message');?>webhook->paramsList, 'text');?>
webhook->id);?>webhook->date);?> webhook->url);?> webhook->action);?> webhook->contentType);?>
date;?> url;?> actionURL, $log->action);?> contentType;?>