飞书消息
This commit is contained in:
@@ -0,0 +1,186 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\controller;
|
||||||
|
|
||||||
|
use support\Request;
|
||||||
|
use support\exception\BusinessException;
|
||||||
|
|
||||||
|
class FeishuController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不需要登录的方法
|
||||||
|
*/
|
||||||
|
protected $noNeedLogin = ['auth', 'send', 'show'];
|
||||||
|
|
||||||
|
|
||||||
|
public function auth(Request $request)
|
||||||
|
{
|
||||||
|
$param = $request->all();
|
||||||
|
|
||||||
|
// 获取凭证
|
||||||
|
$certificate = config('feishu.mbaf');
|
||||||
|
|
||||||
|
// 飞书服务
|
||||||
|
$class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
|
||||||
|
|
||||||
|
if (isset($param['code']) && $param['code']) {
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
$userAccessToken = $class->userAccessToken($param['code'], $certificate['rUrl']);
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
$rst = $class->userInfo($userAccessToken['access_token']);
|
||||||
|
if ($rst['code'] != 0) {
|
||||||
|
throw new BusinessException('授权失败,请重试');
|
||||||
|
}
|
||||||
|
|
||||||
|
// var_dump($rst);
|
||||||
|
// array(3) {
|
||||||
|
// ["code"]=>
|
||||||
|
// int(0)
|
||||||
|
// ["data"]=>
|
||||||
|
// array(11) {
|
||||||
|
// ["avatar_big"]=>
|
||||||
|
// string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=640x640&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||||
|
// ["avatar_middle"]=>
|
||||||
|
// string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=240x240&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||||
|
// ["avatar_thumb"]=>
|
||||||
|
// string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||||
|
// ["avatar_url"]=>
|
||||||
|
// string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||||
|
// ["en_name"]=>
|
||||||
|
// string(9) "李佳博"
|
||||||
|
// ["mobile"]=>
|
||||||
|
// string(14) "+8615738985690"
|
||||||
|
// ["name"]=>
|
||||||
|
// string(9) "李佳博"
|
||||||
|
// ["open_id"]=>
|
||||||
|
// string(35) "ou_37bb7cfc4311c858ea32461700fa1a43"
|
||||||
|
// ["tenant_key"]=>
|
||||||
|
// string(16) "14e7bc0fe5985740"
|
||||||
|
// ["union_id"]=>
|
||||||
|
// string(35) "on_a3fdbca48cd9477a140c7f2167a63691"
|
||||||
|
// ["user_id"]=>
|
||||||
|
// string(8) "481g947d"
|
||||||
|
// }
|
||||||
|
// ["msg"]=>
|
||||||
|
// string(7) "success"
|
||||||
|
// }
|
||||||
|
|
||||||
|
return json($rst);
|
||||||
|
} else {
|
||||||
|
// 授权地址
|
||||||
|
$rst = $class->authorize($certificate);
|
||||||
|
// 拉起授权
|
||||||
|
return redirect($rst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function send()
|
||||||
|
{
|
||||||
|
// 获取凭证
|
||||||
|
$certificate = config('feishu.mbaf');
|
||||||
|
|
||||||
|
// 飞书服务
|
||||||
|
$class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
|
||||||
|
|
||||||
|
// $receiveId = 'ou_37bb7cfc4311c858ea32461700fa1a43';
|
||||||
|
$receiveId = 'ou_a3b97543acbf1b28d978356bb08f85dd';
|
||||||
|
|
||||||
|
// 富文本 类型
|
||||||
|
// $content = "{
|
||||||
|
// \"zh_cn\":{
|
||||||
|
// \"title\":\"演示-消息提醒\",
|
||||||
|
// \"content\":[
|
||||||
|
// [{
|
||||||
|
// \"tag\":\"text\",
|
||||||
|
// \"text\":\"示例内容 - demo\",
|
||||||
|
// \"style\":[\"bold\"]
|
||||||
|
// }],
|
||||||
|
// [{
|
||||||
|
// \"tag\":\"hr\"
|
||||||
|
// }],
|
||||||
|
// [{
|
||||||
|
// \"tag\":\"a\",
|
||||||
|
// \"href\":\"http://219.157.255.213:25321/feishu/show\",
|
||||||
|
// \"text\":\"查看详情\"
|
||||||
|
// }]
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }";
|
||||||
|
|
||||||
|
// 卡片 类型
|
||||||
|
$content = "{
|
||||||
|
\"config\":{
|
||||||
|
\"wide_screen_mode\":true
|
||||||
|
},
|
||||||
|
\"elements\":[{
|
||||||
|
\"tag\":\"div\",
|
||||||
|
\"text\":{
|
||||||
|
\"content\":\"**测试内容**,测试内容,测试内容。\\n 测试内容,测试内容,测试内容。\\n\\n 📬 示例1 示例1 示例1 \\n 😍 示例1 示例1 示例1 \\n 📝 示例1 示例1 示例1 \\n 🙌 示例1 示例1 示例1 \",
|
||||||
|
\"tag\":\"lark_md\"
|
||||||
|
}},{
|
||||||
|
\"actions\":[{
|
||||||
|
\"tag\":\"button\",
|
||||||
|
\"text\":{
|
||||||
|
\"content\":\"立即查看\",
|
||||||
|
\"tag\":\"plain_text\"
|
||||||
|
},
|
||||||
|
\"type\":\"primary\",
|
||||||
|
\"url\":\"http://219.157.255.213:25321/feishu/show\"
|
||||||
|
}],
|
||||||
|
\"tag\":\"action\"
|
||||||
|
}],
|
||||||
|
\"header\":{
|
||||||
|
\"template\":\"turquoise\",
|
||||||
|
\"title\":{
|
||||||
|
\"content\":\"📚标题\",
|
||||||
|
\"tag\":\"plain_text\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
$msgType = 'interactive';
|
||||||
|
$receiveIdtype = 'open_id';
|
||||||
|
|
||||||
|
$result = $class->sendMessages($receiveId, $content, $msgType, $receiveIdtype);
|
||||||
|
return json($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
return '<div>查看详情 - 示例页面</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 凭证
|
||||||
|
function certificate($gs = ''){
|
||||||
|
$data = [];
|
||||||
|
switch ($gs) {
|
||||||
|
case "xinyouhe":
|
||||||
|
$data = [
|
||||||
|
'appId' => "cli_a73e1e6406fa501c",
|
||||||
|
'appSecret' => "9cMfxujjGG9JPmNfNcOwUdCoIXqaM1wY",
|
||||||
|
'rUrl' => "https://server.xyh.hnzhwlkj.club",
|
||||||
|
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||||
|
'state' => "xinyouhe"
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "mbaf":
|
||||||
|
$data = [
|
||||||
|
'appId' => "cli_a75839fb4ff85028",
|
||||||
|
'appSecret' => "VsqLvwsRzpmisBVbrTIuKdNCvRCO447d",
|
||||||
|
'rUrl' => "https://server.xyh.hnzhwlkj.club",
|
||||||
|
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||||
|
'state' => "mbaf"
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new BusinessException('未授权应用');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\service;
|
||||||
|
|
||||||
|
use support\Cache;
|
||||||
|
use Webman\Exception\BusinessException;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
class FeishuService
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $appId = '';
|
||||||
|
protected $appSecret = '';
|
||||||
|
protected $baseUri = '';
|
||||||
|
protected $client = null;
|
||||||
|
protected $options = [];
|
||||||
|
protected $error = '';
|
||||||
|
protected $gs = 'hesu';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
public function __construct(string $appId = '', string $appSecret = '', string $gs = 'hesu')
|
||||||
|
{
|
||||||
|
if ($gs === 'mbaf') {
|
||||||
|
$this->baseUri = 'https://open.larksuite.com/open-apis/';
|
||||||
|
} else {
|
||||||
|
$this->baseUri = 'https://open.feishu.cn/open-apis/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->appId = $appId;
|
||||||
|
$this->appSecret = $appSecret;
|
||||||
|
$this->gs = $gs;
|
||||||
|
|
||||||
|
$this->client = new Client([
|
||||||
|
'base_uri' => $this->baseUri
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->options = [
|
||||||
|
'headers' => [
|
||||||
|
'Content-Type' => 'application/json; charset=utf-8'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常
|
||||||
|
*/
|
||||||
|
public function error()
|
||||||
|
{
|
||||||
|
return $this->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求
|
||||||
|
*/
|
||||||
|
public function requestResult($url = "", $method = "POST")
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$res = $this->client->request($method, $this->baseUri.$url, $this->options);
|
||||||
|
if ($res->getBody()) {
|
||||||
|
$result = json_decode($res->getBody(), true);
|
||||||
|
// var_dump($result);
|
||||||
|
if ($result["code"] === 0) {
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
$this->error = $result["msg"];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->error = "result error";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
if ($e->hasResponse()) {
|
||||||
|
var_dump('2 :'.$e->getResponse()->getBody());
|
||||||
|
throw new BusinessException($e->getResponse()->getBody());
|
||||||
|
} else {
|
||||||
|
var_dump('3 :'.$e->getMessage());
|
||||||
|
throw new BusinessException($e->getMessage());
|
||||||
|
}
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
var_dump('4 :'.$th->getFile()."|".$th->getLine()."|".$th->getMessage());
|
||||||
|
$this->error = $th->getFile()."|".$th->getLine()."|".$th->getMessage();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权
|
||||||
|
*/
|
||||||
|
public function authorize($certificate, $url = 'authen/v1/authorize')
|
||||||
|
{
|
||||||
|
$arr = [
|
||||||
|
'app_id' => $certificate['appId'],
|
||||||
|
'redirect_uri' => $certificate['rUrl'],
|
||||||
|
'scope' => $certificate['scope'],
|
||||||
|
'state' => $certificate['state']
|
||||||
|
];
|
||||||
|
$queryData = http_build_query($arr);
|
||||||
|
return $this->baseUri.$url.'?'.$queryData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自建应用获取 tenant_access_token
|
||||||
|
*/
|
||||||
|
public function tenantAccessToken()
|
||||||
|
{
|
||||||
|
$tenantAccessToken = Cache::get($this->gs.'-tenantAccessToken');
|
||||||
|
if (!$tenantAccessToken) {
|
||||||
|
$this->options["json"] = [
|
||||||
|
"app_id" => $this->appId,
|
||||||
|
"app_secret" => $this->appSecret
|
||||||
|
];
|
||||||
|
$rst = $this->requestResult('auth/v3/tenant_access_token/internal', 'POST');
|
||||||
|
// var_dump($rst);
|
||||||
|
if ($rst) {
|
||||||
|
$tenantAccessToken = $rst['tenant_access_token'];
|
||||||
|
Cache::set($this->gs.'-tenantAccessToken', $tenantAccessToken, $rst['expire']);
|
||||||
|
} else {
|
||||||
|
throw new BusinessException('tenant_access_token 获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $tenantAccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过手机号或邮箱获取用户 ID
|
||||||
|
*/
|
||||||
|
public function getUserIdByPhoneOrEmail($phone = '', $userIdType = 'open_id')
|
||||||
|
{
|
||||||
|
$this->options["headers"] = [
|
||||||
|
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||||
|
"Content-Type" => "application/json; charset=utf-8"
|
||||||
|
];
|
||||||
|
$this->options["json"] = [
|
||||||
|
"emails" => [],
|
||||||
|
"mobiles" => [$phone],
|
||||||
|
"include_resigned" => false
|
||||||
|
];
|
||||||
|
$rst = $this->requestResult('contact/v3/users/batch_get_id?user_id_type='.$userIdType, 'POST');
|
||||||
|
return $rst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*/
|
||||||
|
public function sendMessages($receiveId = '', $content = '', $msgType = 'text', $receiveIdtype = 'open_id')
|
||||||
|
{
|
||||||
|
$this->options["headers"] = [
|
||||||
|
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||||
|
"Content-Type" => "application/json; charset=utf-8"
|
||||||
|
];
|
||||||
|
$this->options["json"] = [
|
||||||
|
"receive_id" => $receiveId,
|
||||||
|
"msg_type" => $msgType,
|
||||||
|
"content" => $content
|
||||||
|
];
|
||||||
|
$rst = $this->requestResult('im/v1/messages?receive_id_type='.$receiveIdtype, 'POST');
|
||||||
|
return $rst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑消息
|
||||||
|
*/
|
||||||
|
public function updateSendMessages($messageId = '', $content = '', $msgType = 'text')
|
||||||
|
{
|
||||||
|
$this->options["headers"] = [
|
||||||
|
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||||
|
"Content-Type" => "application/json; charset=utf-8"
|
||||||
|
];
|
||||||
|
$this->options["json"] = [
|
||||||
|
"msg_type" => $msgType,
|
||||||
|
"content" => $content
|
||||||
|
];
|
||||||
|
$rst = $this->requestResult('im/v1/messages/'.$messageId, 'PUT');
|
||||||
|
return $rst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户 user_access_token
|
||||||
|
*/
|
||||||
|
public function userAccessToken($code = "", $redirect_uri = "")
|
||||||
|
{
|
||||||
|
$this->options["headers"] = [
|
||||||
|
"Content-Type" => "application/json; charset=utf-8"
|
||||||
|
];
|
||||||
|
$this->options["json"] = [
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"client_id" => $this->appId,
|
||||||
|
"client_secret" => $this->appSecret,
|
||||||
|
"code" => $code,
|
||||||
|
"redirect_uri" => $redirect_uri
|
||||||
|
];
|
||||||
|
return $this->requestResult('authen/v2/oauth/token');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
public function userInfo($userAccessToken = "")
|
||||||
|
{
|
||||||
|
$this->options["headers"] = [
|
||||||
|
"Authorization" => "Bearer " . $userAccessToken,
|
||||||
|
"Content-Type" => "application/json; charset=utf-8"
|
||||||
|
];
|
||||||
|
return $this->requestResult('authen/v1/user_info', "GET");
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -38,7 +38,9 @@
|
|||||||
"phpmailer/phpmailer": "^6.9",
|
"phpmailer/phpmailer": "^6.9",
|
||||||
"shopwwi/webman-filesystem": "^2.0",
|
"shopwwi/webman-filesystem": "^2.0",
|
||||||
"iidestiny/flysystem-oss": "4",
|
"iidestiny/flysystem-oss": "4",
|
||||||
"vlucas/phpdotenv": "^5.6"
|
"vlucas/phpdotenv": "^5.6",
|
||||||
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
|
"webman/cache": "^2.1"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-event": "For better performance. "
|
"ext-event": "For better performance. "
|
||||||
|
|||||||
Generated
+950
-8
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of webman.
|
||||||
|
*
|
||||||
|
* Licensed under The MIT License
|
||||||
|
* For full copyright and license information, please see the MIT-LICENSE.txt
|
||||||
|
* Redistributions of files must retain the above copyright notice.
|
||||||
|
*
|
||||||
|
* @author walkor<walkor@workerman.net>
|
||||||
|
* @copyright walkor<walkor@workerman.net>
|
||||||
|
* @link http://www.workerman.net/
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
return [
|
||||||
|
'default' => 'file',
|
||||||
|
'stores' => [
|
||||||
|
'file' => [
|
||||||
|
'driver' => 'file',
|
||||||
|
'path' => runtime_path('cache')
|
||||||
|
],
|
||||||
|
'redis' => [
|
||||||
|
'driver' => 'redis',
|
||||||
|
'connection' => 'default'
|
||||||
|
],
|
||||||
|
'array' => [
|
||||||
|
'driver' => 'array'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'xinyouhe' => [
|
||||||
|
'appId' => "cli_a73e1e6406fa501c",
|
||||||
|
'appSecret' => "9cMfxujjGG9JPmNfNcOwUdCoIXqaM1wY",
|
||||||
|
'rUrl' => "http://219.157.255.213:25321/feishu/auth",
|
||||||
|
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||||
|
'state' => "xinyouhe",
|
||||||
|
'baseUri' => "https://open.feishu.cn/open-apis/"
|
||||||
|
],
|
||||||
|
'mbaf' => [
|
||||||
|
'appId' => "cli_a75839fb4ff85028",
|
||||||
|
'appSecret' => "VsqLvwsRzpmisBVbrTIuKdNCvRCO447d",
|
||||||
|
'rUrl' => "http://219.157.255.213:25321/feishu/auth",
|
||||||
|
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||||
|
'state' => "mbaf",
|
||||||
|
'baseUri' => "https://open.larksuite.com/open-apis/"
|
||||||
|
]
|
||||||
|
];
|
||||||
+4
-3
@@ -28,6 +28,7 @@ Route::post('/upload', [app\controller\UploadController::class, 'uploadImage']);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 飞书
|
||||||
|
Route::post('/feishu/auth', [app\controller\FeishuController::class, 'auth']);
|
||||||
|
Route::post('/feishu/show', [app\controller\FeishuController::class, 'show']);
|
||||||
|
Route::post('/feishu/send', [app\controller\FeishuController::class, 'send']);
|
||||||
Reference in New Issue
Block a user