初始化
This commit is contained in:
commit
4bee43fc17
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
!.gitignore
|
||||
!.gitattributes
|
||||
*.DS_Store
|
||||
*.idea
|
||||
*.svn
|
||||
*.git
|
||||
composer.lock
|
||||
*.cache
|
||||
vendor
|
||||
config
|
85
.php-cs-fixer.php
Normal file
85
.php-cs-fixer.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
$header = '';
|
||||
|
||||
return (new \PhpCsFixer\Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'@Symfony' => true,
|
||||
'@DoctrineAnnotation' => true,
|
||||
'@PhpCsFixer' => true,
|
||||
'header_comment' => [
|
||||
'comment_type' => 'PHPDoc',
|
||||
'header' => $header,
|
||||
'separate' => 'none',
|
||||
'location' => 'after_declare_strict',
|
||||
],
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'list_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'concat_space' => [
|
||||
'spacing' => 'one',
|
||||
],
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'declare',
|
||||
],
|
||||
],
|
||||
'general_phpdoc_annotation_remove' => [
|
||||
'annotations' => [
|
||||
'author',
|
||||
],
|
||||
],
|
||||
'ordered_imports' => [
|
||||
'imports_order' => [
|
||||
'class', 'function', 'const',
|
||||
],
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'single_line_comment_style' => [
|
||||
'comment_types' => [
|
||||
],
|
||||
],
|
||||
'yoda_style' => [
|
||||
'always_move_variable' => false,
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'left',
|
||||
],
|
||||
'multiline_whitespace_before_semicolons' => [
|
||||
'strategy' => 'no_multi_line',
|
||||
],
|
||||
'constant_case' => [
|
||||
'case' => 'lower',
|
||||
],
|
||||
'class_attributes_separation' => true,
|
||||
'combine_consecutive_unsets' => true,
|
||||
'declare_strict_types' => true,
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'lowercase_static_reference' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_unused_imports' => true,
|
||||
'not_operator_with_successor_space' => true,
|
||||
'not_operator_with_space' => false,
|
||||
'ordered_class_elements' => true,
|
||||
'php_unit_strict' => false,
|
||||
'phpdoc_separation' => false,
|
||||
'single_quote' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'multiline_comment_opening_closing' => true,
|
||||
])
|
||||
->setFinder(
|
||||
\PhpCsFixer\Finder::create()
|
||||
->exclude('public')
|
||||
->exclude('runtime')
|
||||
->exclude('vendor')
|
||||
->in(__DIR__)
|
||||
)
|
||||
->setUsingCache(false)
|
||||
;
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Vinchan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
51
README.md
Normal file
51
README.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
## 三方平台消息通知组件
|
||||
|
||||
## 功能
|
||||
|
||||
* 支持钉钉群机器人、飞书群机器人、企业微信群机器人
|
||||
* 支持扩展自定义通道&消息模板
|
||||
|
||||
## 环境要求
|
||||
|
||||
* hyperf >= 2.2
|
||||
|
||||
## 安装
|
||||
|
||||
```sh
|
||||
composer require tm-wms/message-notify
|
||||
```
|
||||
|
||||
## 配置文件
|
||||
|
||||
发布配置文件`config/message_notify.php`
|
||||
|
||||
```sh
|
||||
php bin/hyperf.php vendor:publish tm-wms/message-notify
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use TmWms\MessageNotify\Notify;
|
||||
use TmWms\MessageNotify\Channel\DingTalkChannel;
|
||||
use TmWms\MessageNotify\Template\Text\DingTalk;
|
||||
|
||||
// 初始通道
|
||||
$channel = new DingTalkChannel();
|
||||
|
||||
// 初始消息模板
|
||||
$template = (new DingTalk())
|
||||
->setTitle('test')
|
||||
->setText('test')
|
||||
//@所有人
|
||||
->setAt([
|
||||
'all'
|
||||
]);
|
||||
|
||||
// 发送
|
||||
Notify::make($channel)->send($template);
|
||||
|
||||
```
|
||||
|
46
composer.json
Normal file
46
composer.json
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "tm-wms/message-notify",
|
||||
"description": "MIT",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "zyimm",
|
||||
"email": "zyimm.qq.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"TmWms\\MessageNotify\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"TmWms\\MessageNotifyTest\\": "test/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"ext-json": "*",
|
||||
"hyperf/guzzle": "^1.1|^2.1|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.0",
|
||||
"phpunit/phpunit": "^9.4",
|
||||
"hyperf/di": "^2.2|^3.0",
|
||||
"hyperf/utils": "^2.2|^3.0",
|
||||
"hyperf/config": "*",
|
||||
"hyperf/ide-helper": "v2.2.*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit -c phpunit.xml --colors=always",
|
||||
"cs-fix": "./vendor/bin/php-cs-fixer fix"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "TmWms\\MessageNotify\\ConfigProvider"
|
||||
}
|
||||
}
|
||||
}
|
21
phpunit.xml
Normal file
21
phpunit.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="./test/bootstrap.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="Tests">
|
||||
<directory suffix="Test.php">./test</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
56
publish/message_notify.php
Normal file
56
publish/message_notify.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use TmWms\MessageNotify\Channel\DingTalkChannel;
|
||||
use TmWms\MessageNotify\Channel\FeiShuChannel;
|
||||
use TmWms\MessageNotify\Channel\WechatChannel;
|
||||
use TmWms\MessageNotify\Notify;
|
||||
|
||||
return [
|
||||
'default' => env('NOTIFY_DEFAULT_CHANNEL', 'DingTalk'),
|
||||
'channels' => [
|
||||
// 钉钉群机器人
|
||||
'DingTalk' => [
|
||||
'default' => Notify::INFO,
|
||||
'channel' => DingTalkChannel::class,
|
||||
'pipeline' => [
|
||||
// 业务信息告警群
|
||||
Notify::INFO => [
|
||||
'token' => env('NOTIFY_DINGTALK_TOKEN', ''),
|
||||
'secret' => env('NOTIFY_DINGTALK_SECRET', ''),
|
||||
'keyword' => env('NOTIFY_DINGTALK_KEYWORD', ['test']),
|
||||
],
|
||||
// 错误信息告警群
|
||||
Notify::ERROR => [
|
||||
'token' => env('NOTIFY_DINGTALK_TOKEN', ''),
|
||||
'secret' => env('NOTIFY_DINGTALK_SECRET', ''),
|
||||
'keyword' => env('NOTIFY_DINGTALK_KEYWORD', []),
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
// 飞书群机器人
|
||||
'Feishu' => [
|
||||
'default' => Notify::INFO,
|
||||
'channel' => FeiShuChannel::class,
|
||||
'pipeline' => [
|
||||
'info' => [
|
||||
'token' => env('NOTIFY_FEISHU_TOKEN', ''),
|
||||
'secret' => env('NOTIFY_FEISHU_SECRET', ''),
|
||||
'keyword' => env('NOTIFY_FEISHU_KEYWORD'),
|
||||
]
|
||||
]
|
||||
],
|
||||
// 企业微信群机器人
|
||||
'Wechat' => [
|
||||
'default' => Notify::INFO,
|
||||
'channel' => WechatChannel::class,
|
||||
'pipeline' => [
|
||||
'info' => [
|
||||
'token' => env('NOTIFY_WECHAT_TOKEN'),
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
40
src/Channel/AbstractChannel.php
Normal file
40
src/Channel/AbstractChannel.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Channel;
|
||||
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
use TmWms\MessageNotify\Contracts\MessageChannelInterface;
|
||||
use TmWms\MessageNotify\Exceptions\MessageNotificationException;
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
abstract class AbstractChannel implements MessageChannelInterface
|
||||
{
|
||||
protected AbstractTemplate $template;
|
||||
|
||||
public string $channelUrl;
|
||||
|
||||
protected string $type;
|
||||
|
||||
public function setTemplate(AbstractTemplate $template): AbstractChannel
|
||||
{
|
||||
$this->template = $template;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* getConfig
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
if (class_exists(ApplicationContext::class)) {
|
||||
$configContext = make(ConfigInterface::class);
|
||||
return $configContext->get('message_notify.channels.'.$this->type);
|
||||
}
|
||||
throw new MessageNotificationException('ApplicationContext is not exist');
|
||||
}
|
||||
}
|
81
src/Channel/DingTalkChannel.php
Normal file
81
src/Channel/DingTalkChannel.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Channel;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use TmWms\MessageNotify\Exceptions\MessageNotificationException;
|
||||
|
||||
class DingTalkChannel extends AbstractChannel
|
||||
{
|
||||
public string $channelUrl = 'https://oapi.dingtalk.com';
|
||||
|
||||
protected string $type = 'DingTalk';
|
||||
|
||||
/**
|
||||
* send
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
|
||||
$client = $this->getClient();
|
||||
|
||||
$option = [
|
||||
RequestOptions::HEADERS => [],
|
||||
RequestOptions::JSON => $this->template->getBody(),
|
||||
];
|
||||
$request = $client->post('', $option);
|
||||
$result = json_decode($request->getBody()->getContents(), true);
|
||||
|
||||
if ($result['errcode'] !== 0) {
|
||||
throw new MessageNotificationException($result['errmsg']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* getClient
|
||||
*
|
||||
* @return Client|mixed
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
$query = $this->buildQuery($this->template->getPipeline());
|
||||
$config['base_uri'] = $this->channelUrl.'/robot/send?'.$query;
|
||||
return make(Client::class, [$config]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildQuery
|
||||
*
|
||||
* @param string $pipeline
|
||||
* @return string
|
||||
*/
|
||||
private function buildQuery(string $pipeline): string
|
||||
{
|
||||
$timestamp = time() * 1000;
|
||||
|
||||
$config = $this->getConfig();
|
||||
var_dump($config);
|
||||
$config = $config['pipeline'][$pipeline] ?? $config['pipeline'][$config['default']];
|
||||
$sign = '';
|
||||
if(isset($config['secret'])){
|
||||
$secret = hash_hmac('sha256', $timestamp."\n".$config['secret'], $config['secret'], true);
|
||||
$sign = urlencode(base64_encode($secret));
|
||||
}
|
||||
|
||||
$query = [
|
||||
'access_token' => $config['token'],
|
||||
'timestamp' => $timestamp,
|
||||
'sign' => $sign
|
||||
];
|
||||
return http_build_query($query);
|
||||
}
|
||||
}
|
86
src/Channel/FeiShuChannel.php
Normal file
86
src/Channel/FeiShuChannel.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Channel;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use TmWms\MessageNotify\Exceptions\MessageNotificationException;
|
||||
|
||||
class FeiShuChannel extends AbstractChannel
|
||||
{
|
||||
public string $channelUrl = 'https://open.feishu.cn';
|
||||
|
||||
protected string $type = 'Feishu';
|
||||
|
||||
/**
|
||||
* send
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
$client = $this->getClient($this->template->getPipeline());
|
||||
|
||||
$timestamp = time();
|
||||
$config = [
|
||||
'timestamp' => $timestamp,
|
||||
'sign' => $this->buildSign($timestamp, $this->template->getPipeline()),
|
||||
];
|
||||
|
||||
$option = [
|
||||
RequestOptions::HEADERS => [],
|
||||
RequestOptions::JSON => array_merge($config, $this->template->getBody()),
|
||||
];
|
||||
|
||||
$request = $client->post('', $option);
|
||||
$result = json_decode($request->getBody()->getContents(), true);
|
||||
|
||||
if (!isset($result['StatusCode']) || $result['StatusCode'] !== 0) {
|
||||
throw new MessageNotificationException($result['msg']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* getClient
|
||||
*
|
||||
* @param string $pipeline
|
||||
* @return Client
|
||||
*/
|
||||
public function getClient(string $pipeline): Client
|
||||
{
|
||||
$config = $this->config($pipeline);
|
||||
$config['base_uri'] = $this->channelUrl.'/open-apis/bot/v2/hook/'.$config['token'];
|
||||
return make(Client::class, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* buildSign
|
||||
*
|
||||
* @param int $timestamp
|
||||
* @param string $pipeline
|
||||
* @return string
|
||||
*/
|
||||
private function buildSign(int $timestamp, string $pipeline): string
|
||||
{
|
||||
$config = $this->config($pipeline);
|
||||
$secret = hash_hmac('sha256', '', $timestamp."\n".$config['secret'], true);
|
||||
return base64_encode($secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* config
|
||||
*
|
||||
* @param string $pipeline
|
||||
* @return mixed
|
||||
*/
|
||||
private function config(string $pipeline)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
return $config['pipeline'][$pipeline] ?? $config['pipeline'][$config['default']];
|
||||
}
|
||||
}
|
72
src/Channel/WechatChannel.php
Normal file
72
src/Channel/WechatChannel.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Channel;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use TmWms\MessageNotify\Exceptions\MessageNotificationException;
|
||||
|
||||
/**
|
||||
* 微信通知
|
||||
*/
|
||||
class WechatChannel extends AbstractChannel
|
||||
{
|
||||
public string $channelUrl = 'https://qyapi.weixin.qq.com';
|
||||
|
||||
protected string $type = 'Wechat';
|
||||
|
||||
/**
|
||||
* send
|
||||
*
|
||||
* @return bool
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
$client = $this->getClient($this->template->getPipeline());
|
||||
$option = [
|
||||
RequestOptions::HEADERS => [],
|
||||
RequestOptions::JSON => $this->template->getBody(),
|
||||
];
|
||||
$request = $client->post('', $option);
|
||||
$result = json_decode($request->getBody()->getContents(), true);
|
||||
|
||||
if ($result['errcode'] !== 0) {
|
||||
throw new MessageNotificationException($result['errmsg']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* getClient
|
||||
*
|
||||
* @param string $pipeline
|
||||
* @return Client|mixed
|
||||
*/
|
||||
private function getClient(string $pipeline)
|
||||
{
|
||||
$config = $this->config($pipeline);
|
||||
|
||||
$config['base_uri'] = $this->channelUrl.'/cgi-bin/webhook/send?key=' . $config['token'];
|
||||
|
||||
return make(Client::class, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* config
|
||||
*
|
||||
* @param string $pipeline
|
||||
* @return mixed
|
||||
*/
|
||||
public function config(string $pipeline)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
return $config['pipeline'][$pipeline] ?? $config['pipeline'][$config['default']];
|
||||
}
|
||||
|
||||
|
||||
}
|
31
src/ConfigProvider.php
Normal file
31
src/ConfigProvider.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify;
|
||||
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
return [
|
||||
'dependencies' => [],
|
||||
'annotations' => [
|
||||
'scan' => [
|
||||
'paths' => [
|
||||
__DIR__,
|
||||
],
|
||||
],
|
||||
],
|
||||
'publish' => [
|
||||
[
|
||||
'id' => 'config',
|
||||
'description' => 'The config of message client.',
|
||||
'source' => __DIR__.'/../publish/message_notify.php',
|
||||
'destination' => BASE_PATH.'/config/autoload/message_notify.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
24
src/Connection.php
Normal file
24
src/Connection.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify;
|
||||
|
||||
use TmWms\MessageNotify\Channel\AbstractChannel;
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class Connection
|
||||
{
|
||||
protected AbstractChannel $channel;
|
||||
|
||||
public function __construct(AbstractChannel $channel)
|
||||
{
|
||||
$this->channel = $channel;
|
||||
}
|
||||
|
||||
public function send(AbstractTemplate $template): bool
|
||||
{
|
||||
return $this->channel->setTemplate($template)->send();
|
||||
}
|
||||
|
||||
}
|
8
src/Contracts/MessageChannelInterface.php
Normal file
8
src/Contracts/MessageChannelInterface.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Contracts;
|
||||
|
||||
interface MessageChannelInterface
|
||||
{
|
||||
public function send();
|
||||
}
|
10
src/Contracts/MessageNotifyInterface.php
Normal file
10
src/Contracts/MessageNotifyInterface.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Contracts;
|
||||
|
||||
interface MessageNotifyInterface
|
||||
{
|
||||
|
||||
}
|
9
src/Exceptions/MessageNotificationException.php
Normal file
9
src/Exceptions/MessageNotificationException.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Exceptions;
|
||||
|
||||
class MessageNotificationException extends \RuntimeException
|
||||
{
|
||||
}
|
33
src/Notify.php
Normal file
33
src/Notify.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify;
|
||||
|
||||
use TmWms\MessageNotify\Channel\AbstractChannel;
|
||||
|
||||
class Notify
|
||||
{
|
||||
public const INFO = 'info';
|
||||
|
||||
public const ERROR = 'error';
|
||||
|
||||
public const EMERGENCY = 'emergency';
|
||||
|
||||
public const ALERT = 'alert';
|
||||
|
||||
public const CRITICAL = 'critical';
|
||||
|
||||
public const WARNING = 'warning';
|
||||
|
||||
public const NOTICE = 'notice';
|
||||
|
||||
public const DEBUG = 'debug';
|
||||
|
||||
public static function make(?AbstractChannel $channel = null): Connection
|
||||
{
|
||||
return make(Connection::class, [
|
||||
$channel
|
||||
]);
|
||||
}
|
||||
}
|
69
src/Template/AbstractTemplate.php
Normal file
69
src/Template/AbstractTemplate.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotify\Template;
|
||||
|
||||
use TmWms\MessageNotify\Notify;
|
||||
|
||||
abstract class AbstractTemplate
|
||||
{
|
||||
protected array $at = [];
|
||||
|
||||
protected string $pipeline = Notify::INFO;
|
||||
|
||||
protected string $text = '';
|
||||
|
||||
protected string $title = '';
|
||||
|
||||
abstract public function getBody();
|
||||
|
||||
public function getText(): string
|
||||
{
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
public function setText(string $text): AbstractTemplate
|
||||
{
|
||||
$this->text = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(string $title): AbstractTemplate
|
||||
{
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPipeline(): string
|
||||
{
|
||||
return $this->pipeline;
|
||||
}
|
||||
|
||||
public function setPipeline(string $pipeline): AbstractTemplate
|
||||
{
|
||||
$this->pipeline = $pipeline;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAt(array $at = []): AbstractTemplate
|
||||
{
|
||||
$this->at = $at;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAt(): array
|
||||
{
|
||||
return $this->at;
|
||||
}
|
||||
|
||||
public function isAtAll(): bool
|
||||
{
|
||||
return in_array('all', $this->at) || in_array('ALL', $this->at);
|
||||
}
|
||||
}
|
24
src/Template/MarkDown/DingTalk.php
Normal file
24
src/Template/MarkDown/DingTalk.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\MarkDown;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class DingTalk extends AbstractTemplate
|
||||
{
|
||||
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msgtype' => 'markdown',
|
||||
'markdown' => [
|
||||
'title' => $this->getTitle(),
|
||||
'text' => $this->getText(),
|
||||
],
|
||||
'at' => [
|
||||
'isAtAll' => $this->isAtAll(),
|
||||
'atMobiles' => $this->getAt(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
72
src/Template/MarkDown/FeiShu.php
Normal file
72
src/Template/MarkDown/FeiShu.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\MarkDown;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class FeiShu extends AbstractTemplate
|
||||
{
|
||||
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msg_type' => 'post',
|
||||
'content' => [
|
||||
'post' => [
|
||||
'zh_cn' => [
|
||||
'title' => $this->getTitle(),
|
||||
'content' => [$this->getFeiShuText()],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getFeiShuText(): array
|
||||
{
|
||||
$text = is_array($this->getText()) ? $this->getText() : json_decode($this->getText(), true) ?? [
|
||||
[
|
||||
'tag' => 'text',
|
||||
'text' => $this->getText(),
|
||||
],
|
||||
];
|
||||
|
||||
$at = $this->getFeiShuAt();
|
||||
|
||||
return array_merge($text, $at);
|
||||
}
|
||||
|
||||
private function getFeiShuAt(): array
|
||||
{
|
||||
$result = [];
|
||||
if ($this->isAtAll()) {
|
||||
$result[] = [
|
||||
'tag' => 'at',
|
||||
'user_id' => 'all',
|
||||
];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$at = $this->getAt();
|
||||
foreach ($at as $item) {
|
||||
// TODO::需要加入邮箱与收集@人
|
||||
if (strchr($item, '@') === false) {
|
||||
$result[] = [
|
||||
'tag' => 'at',
|
||||
'email' => $item,
|
||||
];
|
||||
} else {
|
||||
$result[] = [
|
||||
'tag' => 'at',
|
||||
'user_id' => $item,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
21
src/Template/MarkDown/Wechat.php
Normal file
21
src/Template/MarkDown/Wechat.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\MarkDown;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class Wechat extends AbstractTemplate
|
||||
{
|
||||
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msgtype' => 'markdown',
|
||||
'markdown' => [
|
||||
'content' => $this->getTitle().$this->getText(),
|
||||
'mentioned_list' => in_array('all', $this->getAt()) ? [] : [$this->getAt()],
|
||||
'mentioned_mobile_list' => in_array('all', $this->getAt()) ? ['@all'] : [$this->getAt()],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
22
src/Template/Text/DingTalk.php
Normal file
22
src/Template/Text/DingTalk.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\Text;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class DingTalk extends AbstractTemplate
|
||||
{
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msgtype' => 'text',
|
||||
'text' => [
|
||||
'content' => $this->getText(),
|
||||
],
|
||||
'at' => [
|
||||
'isAtAll' => $this->isAtAll(),
|
||||
'atMobiles' => $this->getAt(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
42
src/Template/Text/FeiShu.php
Normal file
42
src/Template/Text/FeiShu.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\Text;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class FeiShu extends AbstractTemplate
|
||||
{
|
||||
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msg_type' => 'text',
|
||||
'content' => [
|
||||
'text' => $this->getText() . $this->getFeiShuAt(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* getFeiShuAt
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getFeiShuAt(): string
|
||||
{
|
||||
if ($this->isAtAll()) {
|
||||
return '<at user_id="all">所有人</at>';
|
||||
}
|
||||
|
||||
$at = $this->getAt();
|
||||
$result = '';
|
||||
foreach ($at as $item) {
|
||||
if (strchr($item, '@') === false) {
|
||||
$result .= '<at phone="' . $item . '">' . $item . '</at>';
|
||||
} else {
|
||||
$result .= '<at email="' . $item . '">' . $item . '</at>';
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
21
src/Template/Text/Wechat.php
Normal file
21
src/Template/Text/Wechat.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace TmWms\MessageNotify\Template\Text;
|
||||
|
||||
use TmWms\MessageNotify\Template\AbstractTemplate;
|
||||
|
||||
class Wechat extends AbstractTemplate
|
||||
{
|
||||
|
||||
public function getBody(): array
|
||||
{
|
||||
return [
|
||||
'msgtype' => 'text',
|
||||
'text' => [
|
||||
'content' => $this->getText(),
|
||||
'mentioned_list' => in_array('all', $this->getAt()) ? [] : [$this->getAt()],
|
||||
'mentioned_mobile_list' => in_array('all', $this->getAt()) ? ['@all'] : [$this->getAt()],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
32
test/NotifyTest.php
Normal file
32
test/NotifyTest.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace TmWms\MessageNotifyTest;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use TmWms\MessageNotify\Channel\DingTalkChannel;
|
||||
use TmWms\MessageNotify\Notify;
|
||||
use TmWms\MessageNotify\Template\Text\DingTalk;
|
||||
|
||||
|
||||
class NotifyTest extends TestCase
|
||||
{
|
||||
public function testCase()
|
||||
{
|
||||
// 初始通道
|
||||
$channel = new DingTalkChannel();
|
||||
|
||||
// 初始消息模板
|
||||
$template = (new DingTalk())
|
||||
->setTitle('test')
|
||||
->setText('test')
|
||||
//@所有人
|
||||
->setAt([
|
||||
'all'
|
||||
]);
|
||||
// 发送
|
||||
Notify::make($channel)->send($template);
|
||||
|
||||
}
|
||||
}
|
12
test/bootstrap.php
Normal file
12
test/bootstrap.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
use Hyperf\Di\Container;
|
||||
use Hyperf\Di\Definition\DefinitionSourceFactory;
|
||||
use Hyperf\Utils\ApplicationContext;
|
||||
|
||||
! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
|
||||
|
||||
$container = new Container((new DefinitionSourceFactory(true))());
|
||||
|
||||
ApplicationContext::setContainer($container);
|
Loading…
Reference in New Issue
Block a user