| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- <?php
- /**
- * The model file of message module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Yidong Wang <yidong@cnezsoft.com>
- * @package message
- * @version $Id$
- * @link https://www.zentao.net
- */
- class messageModel extends model
- {
- /**
- * 获取消息。
- * Get messages.
- *
- * @param string $status all|wait|sended
- * @param string $orderBy
- * @access public
- * @return array
- */
- public function getMessages($status = 'all', $orderBy = 'createdDate')
- {
- $now = helper::now();
- return $this->dao->select('t1.*')->from(TABLE_NOTIFY)->alias('t1')
- ->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.objectType = 'message' AND t1.action = t2.id")
- ->where('t1.objectType')->eq('message')
- ->andWhere('t1.toList')->eq(",{$this->app->user->account},")
- ->beginIF(!empty($status) && $status != 'all')->andWhere('t1.status')->eq($status)->fi()
- ->andWhere('(t1.sendTime IS NULL OR t1.sendTime <= "' . $now . '")')
- ->orderBy($orderBy)
- ->fetchAll('id', false);
- }
- /**
- * 获取对象类型。
- * Get object types.
- *
- * @access public
- * @return array
- */
- public function getObjectTypes()
- {
- $this->loadModel('action');
- $objectTypes = array();
- foreach($this->config->message->objectTypes as $objectType => $actions)
- {
- if(!isset($this->lang->action->objectTypes[$objectType])) continue;
- $objectTypes[$objectType] = $this->lang->action->objectTypes[$objectType];
- }
- return $objectTypes;
- }
- /**
- * 获取对象操作。
- * Get object actions.
- *
- * @access public
- * @return array
- */
- public function getObjectActions()
- {
- $objectActions = array();
- foreach($this->config->message->objectTypes as $objectType => $actions)
- {
- foreach($actions as $action)
- {
- if(isset($this->lang->message->label->{$action})) $objectActions[$objectType][$action] = $this->lang->message->label->{$action};
- if(isset($this->lang->message->label->{$objectType}) && isset($this->lang->message->label->{$objectType}->{$action})) $objectActions[$objectType][$action] = $this->lang->message->label->{$objectType}->{$action};
- }
- }
- return $objectActions;
- }
- /**
- * 发送消息。
- * Send messages.
- *
- * @param string $objectType
- * @param int $objectID
- * @param string $actionType
- * @param int $actionID
- * @param string $actor
- * @param string $extra
- * @access public
- * @return void
- */
- public function send($objectType, $objectID, $actionType, $actionID, $actor = '', $extra = '')
- {
- if(commonModel::isTutorialMode()) return;
- $objectType = strtolower($objectType);
- $messageSetting = $this->config->message->setting;
- if(is_string($messageSetting)) $messageSetting = json_decode($messageSetting, true);
- /* 如果是业需和用需,则使用它们的发信配置。*/
- if($objectType == 'story')
- {
- $story = $this->loadModel('story')->fetchByID($objectID);
- if($story) $objectType = $story->type;
- if($story && $story->status == 'draft') return;
- }
- if(isset($messageSetting['mail']))
- {
- $actions = $messageSetting['mail']['setting'];
- if(isset($actions[$objectType]) && in_array($actionType, $actions[$objectType]))
- {
- /* If it is an api call, get the request method set by the user. */
- global $config;
- $requestType = $config->requestType;
- if(defined('RUN_MODE') && RUN_MODE == 'api')
- {
- $configRoot = $this->app->getConfigRoot();
- include file_exists($configRoot . 'my.php') ? $configRoot . 'my.php' : $configRoot . 'config.php';
- }
- if($objectType == 'feedback' || $objectType == 'ticket')
- {
- $this->loadModel($objectType)->sendmail($objectID, $actionID);
- }
- else
- {
- $this->loadModel('mail')->sendmail($objectID, $actionID);
- }
- if(defined('RUN_MODE') && RUN_MODE == 'api') $config->requestType = $requestType;
- }
- }
- if(isset($messageSetting['webhook']))
- {
- $actions = $messageSetting['webhook']['setting'];
- if(isset($actions[$objectType]) && in_array($actionType, $actions[$objectType])) $this->loadModel('webhook')->send($objectType, $objectID, $actionType, $actionID, $actor);
- }
- if(isset($messageSetting['message']))
- {
- $isBuiltinMethod = true;
- if($this->config->edition != 'open')
- {
- $groupID = $this->loadModel('workflowgroup')->getGroupIDByDataID($objectType, $objectID);
- $method = $this->loadModel('workflowaction')->getByModuleAndAction($objectType, $this->app->rawMethod, $groupID);
- if($method && !$method->buildin) $isBuiltinMethod = false;
- }
- $actions = $messageSetting['message']['setting'];
- if($isBuiltinMethod && isset($actions[$objectType]) && in_array($actionType, $actions[$objectType])) $this->saveNotice($objectType, $objectID, $actionType, $actionID, $actor);
- }
- }
- /**
- * 批量保存待办消息。
- * Batch save todo notice.
- *
- * @access public
- * @return array
- */
- public function batchSaveTodoNotice()
- {
- $todos = $this->getNoticeTodos();
- if(empty($todos)) return array();
- $account = $this->app->user->account;
- $newTodos = array();
- foreach($todos as $todo)
- {
- $notice = new stdclass();
- $notice->objectType = 'message';
- $notice->action = 0;
- $notice->toList = ",{$account},";
- $notice->data = $todo->data;
- $notice->status = 'wait';
- $notice->createdBy = $account;
- $notice->createdDate = helper::now();
- $this->dao->insert(TABLE_NOTIFY)->data($notice)->exec();
- $noticeID = $this->dao->lastInsertID();
- $todo->id = $noticeID;
- $newTodos[$noticeID] = $todo;
- }
- return $newTodos;
- }
- /**
- * 存储提示消息。
- * Save notice.
- *
- * @param string $objectType
- * @param int $objectID
- * @param string $actionType
- * @param int $actionID
- * @param string $actor
- * @access public
- * @return bool
- */
- public function saveNotice($objectType, $objectID, $actionType, $actionID, $actor = '')
- {
- if(empty($actor)) $actor = $this->app->user->account;
- if(empty($actor) || !$objectID) return false;
- /* 如果对象类型是瀑布,动作是提交审计或者审计,那么对象类型就是审批。*/
- if($objectType == 'waterfall' && strpos(',toaudit,audited,', ",{$actionType},") !== false) $objectType = 'review';
- $this->loadModel('action');
- $user = $this->loadModel('user')->getById($actor);
- $table = $this->config->objectTables[$objectType];
- $field = $this->config->action->objectNameFields[$objectType];
- $object = $this->dao->select('*')->from($table)->where('id')->eq($objectID)->fetch();
- $toList = $this->getToList($object, $objectType, $actionID);
- if(empty($toList) || $toList == $actor) return false;
- $this->app->loadConfig('mail');
- $sysURL = zget($this->config->mail, 'domain', common::getSysURL());
- $isonlybody = isInModal();
- if($isonlybody) unset($_GET['onlybody']);
- $methodNmae = 'view';
- $moduleName = $objectType == 'case' ? 'testcase' : $objectType;
- if($objectType == 'kanbancard') $moduleName = 'kanban';
- if($objectType == 'feedback' && $this->config->vision == 'rnd') $methodNmae = 'adminView';
- if($objectType == 'auditplan') $object->title = $this->lang->auditplan->common . ' #' . $object->id;
- $space = common::checkNotCN() ? ' ' : '';
- $data = ($actor == 'guest' ? 'guest' : $user->realname) . $space . $this->lang->action->label->{$actionType} . $space . $this->lang->action->objectTypes[$objectType];
- $dataID = $objectType == 'kanbancard' ? $object->kanban : $objectID;
- $url = helper::createLink($moduleName, $methodNmae, "id={$dataID}") . "#app={$this->app->tab}";
- $data .= ' ' . html::a((strpos($url, $sysURL) === 0 ? '' : $sysURL) . $url, "[#{$objectID}::{$object->$field}]");
- if($objectType == 'aitask' && in_array($actionType, array('finished', 'failed')))
- {
- $url = helper::createLink('aitask', 'view', "taskID={$objectID}");
- $linkUrl = (strpos($url, $sysURL) === 0 ? '' : $sysURL) . $url;
- $data = $this->loadModel('aitask')->getNotificationText($object, $objectID, $actionType, 'html', $linkUrl);
- }
- else
- {
- $methodNmae = 'view';
- $moduleName = $objectType == 'case' ? 'testcase' : $objectType;
- if($objectType == 'kanbancard') $moduleName = 'kanban';
- if($objectType == 'feedback' && $this->config->vision == 'rnd') $methodNmae = 'adminView';
- $space = common::checkNotCN() ? ' ' : '';
- $data = ($actor == 'guest' ? 'guest' : $user->realname) . $space . $this->lang->action->label->{$actionType} . $space . $this->lang->action->objectTypes[$objectType];
- $dataID = $objectType == 'kanbancard' ? $object->kanban : $objectID;
- $url = helper::createLink($moduleName, $methodNmae, "id={$dataID}");
- $data .= ' ' . html::a((strpos($url, $sysURL) === 0 ? '' : $sysURL) . $url, "[#{$objectID}::{$object->$field}]");
- }
- $sendTime = null;
- if($objectType == 'aitask' && in_array($actionType, array('finished', 'failed')))
- {
- $sendTime = helper::now();
- if($object && !empty($object->noticeTime) && $object->noticeTime != '1')
- {
- $today = date('Y-m-d');
- $targetTime = $today . ' ' . $object->noticeTime . ':00';
- $targetTimestamp = strtotime($targetTime);
- $nowTimestamp = time();
- $sendTime = $targetTimestamp < $nowTimestamp ? helper::now() : $targetTime;
- }
- }
- if($isonlybody) $_GET['onlybody'] = 'yes';
- foreach(explode(',', trim($toList, ',')) as $to)
- {
- if($to == $actor || empty($to)) continue;
- $notify = new stdclass();
- $notify->objectType = 'message';
- $notify->action = $actionID;
- $notify->toList = ",{$to},";
- $notify->data = $data;
- $notify->status = 'wait';
- $notify->createdBy = $actor;
- $notify->createdDate = helper::now();
- $notify->sendTime = $sendTime;
- $this->dao->insert(TABLE_NOTIFY)->data($notify)->exec();
- }
- return true;
- }
- /**
- * 获取抄送给的人员。
- * Get toList.
- *
- * @param object $object
- * @param string $objectType
- * @param int $actionID
- * @access public
- * @return string
- */
- public function getToList($object, $objectType, $actionID = 0)
- {
- $toList = '';
- $ccList = '';
- if($objectType == 'aitask')
- {
- $toList = !empty($object->assignedTo) ? $object->assignedTo : ($object->createdBy ?? '');
- return trim($toList, ',');
- }
- if(!empty($object->assignedTo)) $toList = $object->assignedTo;
- if(empty($toList) && $objectType == 'todo') $toList = $object->account;
- if(empty($toList) && $objectType == 'testtask') $toList = $object->owner;
- if(empty($toList) && $objectType == 'meeting') $toList = $object->host . $object->participant;
- if(empty($toList) && $objectType == 'mr') $toList = $object->createdBy . ',' . $object->assignee;
- if(empty($toList) and $objectType == 'demandpool') $toList = trim($object->owner, ',') . ',' . trim($object->reviewer, ',');
- if(empty($toList) && in_array($objectType, array('release', 'doc', 'execution')))
- {
- list($toList, $ccList) = $this->loadModel($objectType)->getToAndCcList($object);
- $toList = $toList . ',' . $ccList;
- }
- if(empty($toList) && $objectType == 'rule' && $actionID)
- {
- $action = $this->loadModel('action')->getById($actionID);
- list($toList, $ccList) = $this->loadModel('rule')->getToAndCcList($object, $action);
- $toList = $toList . ',' . $ccList;
- }
- if($toList == 'closed') $toList = '';
- if($objectType == 'feedback' && $object->status == 'replied') $toList = ',' . $object->openedBy . ',';
- if(in_array($objectType, array('story', 'epic', 'requirement', 'ticket', 'review', 'deploy', 'task', 'feedback', 'reviewissue', 'bug')) && $actionID)
- {
- $action = $this->loadModel('action')->getById($actionID);
- $toAndCcList = $this->loadModel($objectType)->getToAndCcList($object, $action->action);
- if(!empty($toAndCcList)) list($toList, $ccList) = $toAndCcList;
- $toList = $toList . ',' . $ccList;
- }
- if($objectType == 'testtask')
- {
- $toList = array_merge(explode(',', $toList), explode(',', $object->members));
- $toList = array_filter(array_unique($toList));
- $toList = implode(',', $toList);
- }
- if(empty($toList) and $objectType == 'demand' and $this->config->edition == 'ipd')
- {
- $toList = $object->assignedTo;
- $toList .= ',' . str_replace(' ', '', trim($object->mailto, ','));
- $toList .= ",$object->createdBy";
- $reviewers = $this->loadModel('demand')->getReviewerPairs($object->id, $object->version);
- $reviewers = array_keys($reviewers);
- if($reviewers) $toList .= ',' . implode(',', $reviewers);
- $toList = trim($toList, ',');
- }
- if(strpos(',opportunity,risk,issue,', ",{$objectType},") !== false) $toList = "{$object->assignedTo},{$object->createdBy}";
- /* 非内置工作流使用工作流的toList。 */
- if($this->config->edition != 'open')
- {
- $flow = $this->loadModel('workflow')->getByModule($objectType);
- $groupID = $this->loadModel('workflowgroup')->getGroupIDByDataID($objectType, $object->id);
- $method = $this->loadModel('workflowaction')->getByModuleAndAction($objectType, $this->app->rawMethod, $groupID);
- if(($flow && !$flow->buildin) || ($method && !$method->buildin)) $toList = $this->loadModel('flow')->getToList($flow, $object->id, $method);
- }
- if($objectType == 'product') $toList = $object->createdBy . ',' . $object->PO;
- if($objectType == 'project') $toList = $object->openedBy . ',' . $object->PM;
- return trim($toList, ',');
- }
- /**
- * 获取提示待办。
- * Get notice todos.
- *
- * @access public
- * @return array
- */
- public function getNoticeTodos()
- {
- $todos = $this->loadModel('todo')->getList('today', $this->app->user->account, 'wait');
- $notices = array();
- $now = helper::now();
- $interval = 60;
- if($todos)
- {
- /* Set date array. */
- $begins[1] = (int)date('Hi', strtotime($now));
- $begins[10] = (int)date('Hi', strtotime("+10 minute {$now}"));
- $begins[30] = (int)date('Hi', strtotime("+30 minute {$now}"));
- $ends[1] = (int)date('Hi', strtotime("+{$interval} seconds {$now}"));
- $ends[10] = (int)date('Hi', strtotime("+10 minute {$interval} seconds {$now}"));
- $ends[30] = (int)date('Hi', strtotime("+30 minute {$interval} seconds {$now}"));
- foreach($todos as $todo)
- {
- if(empty($todo->begin)) continue;
- $time = (int)str_replace(':', '', $todo->begin);
- $lastTime = 0;
- if($time > $begins[1] && $time <= $ends[1]) $lastTime = 1;
- if($time > $begins[10] && $time <= $ends[10]) $lastTime = 10;
- if($time > $begins[30] && $time <= $ends[30]) $lastTime = 30;
- /* If the todo needs to be reminded, add it to notices array. */
- if($lastTime)
- {
- $notice = new stdclass();
- $notice->id = 'todo' . $todo->id;
- $notice->data = $this->lang->todo->common . ' ' . html::a(helper::createLink('todo', 'view', "id={$todo->id}"), "{$todo->begin} {$todo->name}");
- $notices[$notice->id] = $notice;
- }
- }
- }
- return $notices;
- }
- /**
- * 获取浏览器通知的相关配置信息。
- * Get browser message config.
- *
- * @access public
- * @return array
- */
- public function getBrowserMessageConfig()
- {
- return array('turnon' => $this->config->message->browser->turnon, 'pollTime' => $this->config->message->browser->pollTime);
- }
- /**
- * 获取未读消息数量。
- * Get unread count.
- *
- * @access public
- * @return int
- */
- public function getUnreadCount()
- {
- $account = $this->app->user->account;
- return $this->dao->select('COUNT(1) as count')->from(TABLE_NOTIFY)->where('toList')->eq(",{$account},")->andWhere('objectType')->eq('message')->andWhere('status')->ne('read')->fetch('count');
- }
- /**
- * 删除过期消息。
- * Delete expire messages.
- *
- * @access public
- * @return void
- */
- public function deleteExpired()
- {
- $days = (int)$this->config->message->browser->maxDays;
- $account = $this->app->user->account;
- $expiryDate = date('Y-m-d 00:00:00', time() - 86400 * ($days + 1));
- $this->dao->delete()->from(TABLE_NOTIFY)->where('toList')->eq(",{$account},")->andWhere('objectType')->eq('message')->andWhere('createdDate')->lt($expiryDate)->exec();
- }
- }
|