Zentao docking enterprise wechat work message notice.

This commit is contained in:
leiyong
2020-02-22 00:30:36 +08:00
parent a49b81b30c
commit f6a7fb114c
10 changed files with 288 additions and 29 deletions

View File

@@ -0,0 +1,168 @@
<?php
class wechatapi
{
public $apiUrl = 'https://qyapi.weixin.qq.com/cgi-bin/';
private $appKey;
private $appSecret;
private $token;
private $expires;
private $errors = array();
/**
* Construct
*
* @param string $appKey
* @param string $appSecret
* @param string $agentId
* @param string $apiUrl
* @access public
*/
public function __construct($appKey, $appSecret, $agentId, $apiUrl = '')
{
$this->appKey = $appKey;
$this->appSecret = $appSecret;
$this->agentId = $agentId;
if($apiUrl) $this->apiUrl = rtrim($apiUrl, '/') . '/';
if(!$this->getToken()) return array('result' => 'fail', 'message' => $this->errors);
}
/**
* Get token.
*
* @access public
* @return string
*/
public function getToken()
{
if($this->token and (time() - $this->expires) >= 0) return $this->token;
$response = $this->queryAPI($this->apiUrl . "gettoken?corpid={$this->appKey}&corpsecret={$this->appSecret}");
if($this->isError()) return false;
$this->token = $response->access_token;
$this->expires = time() + $response->expires_in;
return $this->token;
}
/**
* Get all users.
*
* @access public
* @return array
*/
public function getAllUsers()
{
$depts = $this->getAllDepts();
if($this->isError()) return array('result' => 'fail', 'message' => $this->errors);
$users = array();
foreach($depts as $deptID => $deptName)
{
$response = $this->queryAPI($this->apiUrl . "user/simplelist?access_token={$this->token}&department_id={$deptID}");
if($this->isError()) return array('result' => 'fail', 'message' => $this->errors);
foreach($response->userlist as $user) $users[$user->name] = $user->userid;
}
return array('result' => 'success', 'data' => $users);
}
/**
* Get all depts.
*
* @access public
* @return array
*/
public function getAllDepts()
{
$response = $this->queryAPI($this->apiUrl . "department/list?access_token={$this->token}");
if($this->isError()) return false;
$deptPairs = array();
foreach($response->department as $dept) $deptPairs[$dept->id] = $dept->name;
return $deptPairs;
}
/**
* Send message
*
* @param string $userList
* @param string $message
* @access public
* @return array
*/
public function send($userList, $message)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl, CURLOPT_HEADER, FALSE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/plain'));
curl_setopt($curl, CURLOPT_URL, $this->apiUrl . 'message/send?access_token=' . $this->token);
$message = json_decode($message);
$message->agentid = $this->agentId;
$message->touser = str_replace(',', '|', $userList);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($message));
$response = curl_exec($curl);
curl_close($curl);
$response = json_decode($response);
if(isset($response->errcode) and $response->errcode == 0) return array('result' => 'success');
$this->errors[$response->errcode] = "Errcode:{$response->errcode}, Errmsg:{$response->errmsg}";
return array('result' => 'fail', 'message' => $this->errors);
}
/**
* Query API.
*
* @param string $url
* @access public
* @return string
*/
public function queryAPI($url)
{
$response = json_decode(file_get_contents($url));
if(isset($response->errcode) and $response->errcode == 0) return $response;
$this->errors[$response->errcode] = "Errcode:{$response->errcode}, Errmsg:{$response->errmsg}";
return false;
}
/**
* Check for errors.
*
* @access public
* @return bool
*/
public function isError()
{
return !empty($this->errors);
}
/**
* Get errors.
*
* @access public
* @return array
*/
public function getErrors()
{
$errors = $this->errors;
$this->errors = array();
return $errors;
}
}

View File

@@ -6,6 +6,7 @@ $config->webhook->edit = new stdclass();
$config->webhook->edit->requiredFields = 'name, url';
$config->webhook->dingapiUrl = 'https://oapi.dingtalk.com/';
$config->webhook->wechatApiUrl = 'https://qyapi.weixin.qq.com/cgi-bin/';
/* Unset entry to hide actions. */
$config->webhook->objectTypes = array();

View File

@@ -166,16 +166,24 @@ class webhook extends control
}
$webhook = $this->webhook->getById($id);
if($webhook->type != 'dingapi')
if($webhook->type != 'dingapi' && $webhook->type != 'weixin')
{
echo js::alert($this->lang->webhook->note->bind);
die(js::locate($this->createLink('webhook', 'browse')));
}
$webhook->secret = json_decode($webhook->secret);
$this->app->loadClass('dingapi', true);
$dingapi = new dingapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$response = $dingapi->getAllUsers();
if($webhook->type == 'dingapi'){
$this->app->loadClass('dingapi', true);
$dingapi = new dingapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$response = $dingapi->getAllUsers();
}elseif ($webhook->type == 'weixin')
{
$this->app->loadClass('wechatapi', true);
$weichatapi = new wechatapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$response = $weichatapi->getAllUsers();
}
if($response['result'] == 'fail')
{
echo js::error($response['message']);
@@ -204,6 +212,7 @@ class webhook extends control
$this->view->position[] = html::a($this->createLink('webhook', 'browse'), $this->lang->webhook->common);
$this->view->position[] = $this->lang->webhook->bind;
$this->view->webhook = $webhook;
$this->view->dingUsers = $dingUsers;
$this->view->useridPairs = $useridPairs;
$this->view->users = $users;

View File

@@ -5,9 +5,10 @@ $(function()
var type = $(this).val();
$('#sendTypeTR').toggle(type != 'dingding' && type != 'dingapi');
$('#secretTR').toggle(type == 'dingding');
$('#urlTR').toggle(type != 'dingapi');
$('#urlTR').toggle(type != 'dingapi' && type != 'weixin');
$('.dingapiTR').toggle(type == 'dingapi');
$('#paramsTR').toggle(type != 'bearychat' && type != 'dingding' && type != 'dingapi' && type != 'weixin');
$('.wechatTR').toggle(type == 'weixin');
$('#paramsTR').toggle(type != 'bearychat' && type != 'dingding' && type != 'dingapi' && type != 'weixin' && type != 'wxRobot');
$('#urlNote').html(urlNote[type]);
});

View File

@@ -34,11 +34,12 @@ $lang->webhook->date = '发送时间';
$lang->webhook->data = '数据';
$lang->webhook->result = '结果';
$lang->webhook->typeList[''] = '';
$lang->webhook->typeList['dingding'] = '钉钉群通知机器人';
$lang->webhook->typeList['dingapi'] = '钉钉工作消息通知';
$lang->webhook->typeList['weixin'] = '企业微信';
$lang->webhook->typeList['default'] = '其他';
$lang->webhook->typeList[''] = '';
$lang->webhook->typeList['dingding'] = '钉钉群通知机器人';
$lang->webhook->typeList['dingapi'] = '钉钉工作消息通知';
$lang->webhook->typeList['weixin'] = '企业微信应用消息';
$lang->webhook->typeList['wxRobot'] = '企业微信机器人';
$lang->webhook->typeList['default'] = '其他';
$lang->webhook->sendTypeList['sync'] = '同步';
$lang->webhook->sendTypeList['async'] = '异步';
@@ -49,6 +50,12 @@ $lang->webhook->dingAppSecret = '钉钉AppSecret';
$lang->webhook->dingUserid = '钉钉Userid';
$lang->webhook->dingBindStatus = '钉钉绑定状态';
$lang->webhook->wechatCorpId = '企业ID';
$lang->webhook->wechatCorpSecret = '应用的凭证密钥';
$lang->webhook->wechatAgentId = '企业应用的ID';
$lang->webhook->wechatUserid = '微信Userid';
$lang->webhook->wechatBindStatus = '微信绑定状态';
$lang->webhook->dingBindStatusList['0'] = '未绑定';
$lang->webhook->dingBindStatusList['1'] = '已绑定';
@@ -67,16 +74,18 @@ $lang->webhook->confirmDelete = '您确认要删除该webhook吗';
$lang->webhook->trimWords = '了';
$lang->webhook->note = new stdClass();
$lang->webhook->note->async = '异步需要打开计划任务';
$lang->webhook->note->bind = '只有钉钉工作通知类型才需要绑定用户。';
$lang->webhook->note->async = '异步需要打开计划任务';
$lang->webhook->note->bind = '只有[钉钉/微信]工作通知类型才需要绑定用户。';
$lang->webhook->note->product = "此项为空时所有{$lang->productCommon}的动作都会触发钩子,否则只有关联{$lang->productCommon}的动作才会触发。";
$lang->webhook->note->project = "此项为空时所有{$lang->projectCommon}的动作都会触发钩子,否则只有关联{$lang->projectCommon}的动作才会触发。";
$lang->webhook->note->dingKey = " <a href='http://www.zentao.net/book/zentaopmshelp/358.html' target='_blank'><i class='icon-help'></i></a>";
$lang->webhook->note->wechatCorpid = " <a href='https://work.weixin.qq.com/api/doc/90000/90135/90665#corpid' target='_blank'><i class='icon-help'></i></a>";
$lang->webhook->note->wechatSecret = " <a href='https://work.weixin.qq.com/api/doc/90000/90135/90665#secret' target='_blank'><i class='icon-help'></i></a>";
$lang->webhook->note->typeList['bearychat'] = '请在倍洽中添加一个禅道机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['dingding'] = '请在钉钉中添加一个自定义机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['weixin'] = '请在企业微信中添加一个自定义机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['default'] = '从第三方系统获取webhook并填写到此处。';
$lang->webhook->note->typeList['bearychat'] = '请在倍洽中添加一个禅道机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['dingding'] = '请在钉钉中添加一个自定义机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['wechatRobot'] = '请在企业微信中添加一个自定义机器人并将其webhook填写到此处。';
$lang->webhook->note->typeList['default'] = '从第三方系统获取webhook并填写到此处。';
$lang->webhook->error = new stdclass();
$lang->webhook->error->curl = '需要加载php-curl扩展。';

View File

@@ -161,7 +161,23 @@ class webhookModel extends model
$webhook->secret = json_encode($webhook->secret);
$webhook->url = $this->config->webhook->dingapiUrl;
}elseif ($webhook->type == 'weixin')
{
$webhook->secret = array();
$webhook->secret['agentId'] = $webhook->wechatAppId;
$webhook->secret['appKey'] = $webhook->wechatCorpId;
$webhook->secret['appSecret'] = $webhook->wechatSecret;
if(empty($webhook->wechatCorpId)) dao::$errors['wechatCorpId'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatCorpId);
if(empty($webhook->wechatSecret)) dao::$errors['wechatSecret'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatCorpSecret);
if(empty($webhook->wechatAppId)) dao::$errors['wechatAppId'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatAgentId);
if(dao::isError()) return false;
$webhook->secret = json_encode($webhook->secret);
$webhook->url = $this->config->webhook->wechatApiUrl;
}
unset($webhook->wechatCorpId, $webhook->wechatSecret, $webhook->wechatAppId);
$this->dao->insert(TABLE_WEBHOOK)->data($webhook, 'agentId,appKey,appSecret')
->batchCheck($this->config->webhook->create->requiredFields, 'notempty')
@@ -202,9 +218,24 @@ class webhookModel extends model
if(empty($webhook->appSecret)) dao::$errors['appSecret'] = sprintf($this->lang->error->notempty, $this->lang->webhook->dingAppSecret);
if(dao::isError()) return false;
$webhook->secret = json_encode($webhook->secret);
}elseif ($webhook->type == 'weixin')
{
$webhook->secret = array();
$webhook->secret['agentId'] = $webhook->wechatCorpId;
$webhook->secret['appKey'] = $webhook->wechatSecret;
$webhook->secret['appSecret'] = $webhook->wechatAppId;
if(empty($webhook->wechatCorpId)) dao::$errors['wechatCorpId'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatCorpId);
if(empty($webhook->wechatSecret)) dao::$errors['wechatSecret'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatCorpSecret);
if(empty($webhook->wechatAppId)) dao::$errors['wechatAppId'] = sprintf($this->lang->error->notempty, $this->lang->webhook->wechatAgentId);
if(dao::isError()) return false;
$webhook->secret = json_encode($webhook->secret);
}
unset($webhook->wechatCorpId, $webhook->wechatSecret, $webhook->wechatAppId);
$this->dao->update(TABLE_WEBHOOK)->data($webhook, 'agentId,appKey,appSecret')
->batchCheck($this->config->webhook->edit->requiredFields, 'notempty')
->autoCheck()
@@ -347,7 +378,7 @@ class webhookModel extends model
{
$data = $this->getBearychatData($text, $mobile, $email, $objectType, $objectID);
}
elseif($webhook->type == 'weixin')
elseif($webhook->type == 'weixin' or $webhook->type == 'wxRobot')
{
$data = $this->getWeixinData($title, $text, $mobile);
}
@@ -515,17 +546,24 @@ class webhookModel extends model
{
if(!extension_loaded('curl')) die(helper::jsonEncode($this->lang->webhook->error->curl));
if($webhook->type == 'dingapi')
if($webhook->type == 'dingapi' || $webhook->type == 'weixin')
{
if(is_string($webhook->secret)) $webhook->secret = json_decode($webhook->secret);
$openIdList = $this->getOpenIdList($webhook->id, $actionID);
if(empty($openIdList)) return false;
$this->app->loadClass('dingapi', true);
$dingapi = new dingapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$result = $dingapi->send($openIdList, $sendData);
return json_encode($result);
if($webhook->type == 'dingapi'){
$this->app->loadClass('dingapi', true);
$dingapi = new dingapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$result = $dingapi->send($openIdList, $sendData);
return json_encode($result);
}elseif ($webhook->type == 'weixin')
{
$this->app->loadClass('wechatapi', true);
$wechatapi = new wechatapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
$result = $wechatapi->send($openIdList, $sendData);
return json_encode($result);
}
}
$contentType = "Content-Type: {$webhook->contentType};charset=utf-8";

View File

@@ -10,8 +10,8 @@
<tr class='text-center'>
<th class='text-left'><?php echo $lang->user->account?></th>
<th class='w-200px text-left'><?php echo $lang->user->realname?></th>
<th class='w-200px'><?php echo $lang->webhook->dingUserid?></th>
<th class='w-100px'><?php echo $lang->webhook->dingBindStatus?></th>
<th class='w-200px'><?php echo $webhook->type == 'dingapi' ? $lang->webhook->dingUserid : $lang->webhook->wechatUserid;?></th>
<th class='w-100px'><?php echo $webhook->type == 'dingapi' ? $lang->webhook->dingBindStatus : $lang->webhook->wechatBindStatus;?></th>
</tr>
</thead>
<tbody>

View File

@@ -34,7 +34,7 @@
<td class='text' title='<?php echo $webhook->url;?>'><?php echo $webhook->url;?></td>
<td class='c-actions text-right'>
<?php
if($webhook->type == 'dingapi') common::printIcon('webhook', 'bind', "webhookID=$id", '', 'list', 'link');
if($webhook->type == 'dingapi' or $webhook->type == 'weixin') common::printIcon('webhook', 'bind', "webhookID=$id", '', 'list', 'link');
common::printIcon('webhook', 'log', "webhookID=$id", '', 'list', 'file-text');
common::printIcon('webhook', 'edit', "webhookID=$id", '', 'list');
if(common::hasPriv('webhook', 'delete'))

View File

@@ -52,6 +52,21 @@
<th><?php echo $lang->webhook->dingAppSecret;?></th>
<td class='required'><?php echo html::input('appSecret', '', "class='form-control'");?></td>
</tr>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatCorpId;?></th>
<td class='required'><?php echo html::input('wechatCorpId', '', "class='form-control'")?></td>
<td><?php echo $lang->webhook->note->wechatCorpid;?></td>
</tr>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatCorpSecret;?></th>
<td class='required'><?php echo html::input('wechatSecret', '', "class='form-control'")?></td>
<td><?php echo $lang->webhook->note->wechatSecret;?></td>
</tr>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatAgentId;?></th>
<td class='required'><?php echo html::input('wechatAppId', '', "class='form-control'")?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->domain;?></th>
<td><?php echo html::input('domain', common::getSysURL(), "class='form-control'");?></td>

View File

@@ -29,7 +29,7 @@
<td><?php echo html::input('name', $webhook->name, "class='form-control'");?></td>
<td></td>
</tr>
<tr id='urlTR' class='<?php echo $webhook->type == 'dingapi' ? 'hidden' : '';?>'>
<tr id='urlTR' class='<?php echo in_array($webhook->type, array('dingapi', 'weixin')) ? 'hidden' : '';?>'>
<th><?php echo $lang->webhook->url;?></th>
<td><?php echo html::input('url', $webhook->url, "class='form-control'");?></td>
<td><?php echo zget($lang->webhook->note->typeList, $webhook->type, '');?></td>
@@ -55,6 +55,24 @@
<td class='required'><?php echo html::input('appSecret', $secret->appSecret, "class='form-control'");?></td>
</tr>
<?php endif;?>
<?php if($webhook->type == 'weixin'):?>
<?php $secret = json_decode($webhook->secret);?>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatCorpId;?></th>
<td class='required'><?php echo html::input('wechatCorpId', $secret->agentId, "class='form-control'")?></td>
<td><?php echo $lang->webhook->note->wechatCorpid;?></td>
</tr>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatCorpSecret;?></th>
<td class='required'><?php echo html::input('wechatSecret', $secret->appKey, "class='form-control'")?></td>
<td><?php echo $lang->webhook->note->wechatSecret;?></td>
</tr>
<tr class="wechatTR">
<th><?php echo $lang->webhook->wechatAgentId;?></th>
<td class='required'><?php echo html::input('wechatAppId', $secret->appSecret, "class='form-control'")?></td>
<td></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->webhook->domain;?></th>
<td><?php echo html::input('domain', $webhook->domain, "class='form-control'");?></td>
@@ -77,7 +95,7 @@
<td><?php echo html::select('projects[]', $projects, $webhook->projects, "class='form-control chosen' multiple");?></td>
<td><?php echo $lang->webhook->note->project;?></td>
</tr>
<?php if(strpos(',bearychat,dingding,dingapi,weixin,', ",$webhook->type,") === false):?>
<?php if(strpos(',bearychat,dingding,dingapi,weixin,wxRobot,', ",$webhook->type,") === false):?>
<tr id='paramsTR'>
<th>
<div class='checkbox-primary'>