RESAZIP-PC\resaz

add daitogooglechat

......@@ -113,6 +113,88 @@ DaitoString::convertToUtf8('/tmp/source.csv');
DaitoString::convertToUtf8('/tmp/source.csv', '/tmp/out', 'source_utf8.csv', 1);
```
## DaitoGoogleChat (Laravel webhook utility)
### 1) Publish config
```bash
php artisan vendor:publish --tag=daito-google-chat-config
```
This creates `config/daito-google-chat.php`.
### 2) Minimal `.env` setup
```dotenv
DAITO_GOOGLE_CHAT_ENABLED=true
DAITO_GOOGLE_CHAT_WEBHOOK_URL=https://chat.googleapis.com/v1/spaces/.../messages?key=...&token=...
```
### 3) Send immediately
```php
use Daito\Lib\DaitoGoogleChat;
DaitoGoogleChat::sendText('Deploy success', array(
'service' => 'billing-api',
'env' => 'production',
));
```
### 4) Send via queue
```php
use Daito\Lib\DaitoGoogleChat;
DaitoGoogleChat::queueText('Large import finished', array(
'job_id' => 12345,
'duration' => '02:31',
));
```
### 5) Advanced payload
```php
DaitoGoogleChat::sendPayload(array(
'text' => 'Custom payload from daito/lib',
));
```
### 6) cardV2 (send immediately)
```php
use Daito\Lib\DaitoGoogleChat;
$arrCardV2 = array(
'cardId' => 'deploy-status',
'card' => array(
'header' => array(
'title' => 'Deploy Success',
'subtitle' => 'billing-api / production',
),
'sections' => array(
array(
'widgets' => array(
array(
'decoratedText' => array(
'topLabel' => 'Version',
'text' => 'v2.3.1',
),
),
array(
'decoratedText' => array(
'topLabel' => 'Duration',
'text' => '01:45',
),
),
),
),
),
),
);
DaitoGoogleChat::sendCardV2($arrCardV2);
```
### 7) cardV2 (send via queue)
```php
DaitoGoogleChat::queueCardV2($arrCardV2);
```
## QueryLog (Laravel shared package)
> **Provider registration note**
......
......@@ -20,7 +20,8 @@
"extra": {
"laravel": {
"providers": [
"Daito\\Lib\\DaitoQueryLog\\Providers\\DaitoQueryLogProvider"
"Daito\\Lib\\DaitoQueryLog\\Providers\\DaitoQueryLogProvider",
"Daito\\Lib\\DaitoGoogleChat\\Providers\\DaitoGoogleChatProvider"
]
}
}
......
<?php
namespace Daito\Lib;
use Daito\Lib\DaitoGoogleChat\DaitoGoogleChatManager;
use RuntimeException;
class DaitoGoogleChat
{
public static function sendText($text, array $arrContext = array(), $webhookUrl = null): array
{
return self::manager()->sendText($text, $arrContext, $webhookUrl);
}
public static function sendPayload(array $arrPayload, $webhookUrl = null): array
{
return self::manager()->sendPayload($arrPayload, $webhookUrl);
}
public static function sendCardV2(array $arrCardV2, $webhookUrl = null): array
{
return self::manager()->sendCardV2($arrCardV2, $webhookUrl);
}
public static function sendCardsV2(array $arrCardsV2, $webhookUrl = null): array
{
return self::manager()->sendCardsV2($arrCardsV2, $webhookUrl);
}
public static function queueText($text, array $arrContext = array(), $webhookUrl = null): void
{
self::manager()->queueText($text, $arrContext, $webhookUrl);
}
public static function queuePayload(array $arrPayload, $webhookUrl = null): void
{
self::manager()->queuePayload($arrPayload, $webhookUrl);
}
public static function queueCardV2(array $arrCardV2, $webhookUrl = null): void
{
self::manager()->queueCardV2($arrCardV2, $webhookUrl);
}
public static function queueCardsV2(array $arrCardsV2, $webhookUrl = null): void
{
self::manager()->queueCardsV2($arrCardsV2, $webhookUrl);
}
private static function manager(): DaitoGoogleChatManager
{
if (!function_exists('app')) {
throw new RuntimeException('Laravel app container is required for DaitoGoogleChat.');
}
$manager = app(DaitoGoogleChatManager::class);
if (!$manager instanceof DaitoGoogleChatManager) {
throw new RuntimeException('Can not resolve DaitoGoogleChatManager from container.');
}
return $manager;
}
}
<?php
namespace Daito\Lib\DaitoGoogleChat;
use Daito\Lib\DaitoGoogleChat\Jobs\DaitoGoogleChatWebhookJob;
use Daito\Lib\DaitoGoogleChat\Services\DaitoGoogleChatWebhookClient;
class DaitoGoogleChatManager
{
/**
* @var \Daito\Lib\DaitoGoogleChat\Services\DaitoGoogleChatWebhookClient
*/
private $client;
public function __construct(DaitoGoogleChatWebhookClient $client)
{
$this->client = $client;
}
public function sendText($text, array $arrContext = array(), $webhookUrl = null): array
{
return $this->sendPayload(
array(
'text' => $this->buildTextContent((string) $text, $arrContext),
),
$webhookUrl
);
}
public function sendPayload(array $arrPayload, $webhookUrl = null): array
{
return $this->client->send($arrPayload, $webhookUrl);
}
public function sendCardV2(array $arrCardV2, $webhookUrl = null): array
{
return $this->sendCardsV2(array($arrCardV2), $webhookUrl);
}
public function sendCardsV2(array $arrCardsV2, $webhookUrl = null): array
{
return $this->sendPayload(
array(
'cardsV2' => array_values($arrCardsV2),
),
$webhookUrl
);
}
public function queueText($text, array $arrContext = array(), $webhookUrl = null): void
{
$this->queuePayload(
array(
'text' => $this->buildTextContent((string) $text, $arrContext),
),
$webhookUrl
);
}
public function queuePayload(array $arrPayload, $webhookUrl = null): void
{
$job = new DaitoGoogleChatWebhookJob($arrPayload, $webhookUrl);
if (config('daito-google-chat.queue_connection') !== null) {
$job->onConnection(config('daito-google-chat.queue_connection'));
}
if (config('daito-google-chat.queue_name') !== null) {
$job->onQueue(config('daito-google-chat.queue_name'));
}
dispatch($job);
}
public function queueCardV2(array $arrCardV2, $webhookUrl = null): void
{
$this->queueCardsV2(array($arrCardV2), $webhookUrl);
}
public function queueCardsV2(array $arrCardsV2, $webhookUrl = null): void
{
$this->queuePayload(
array(
'cardsV2' => array_values($arrCardsV2),
),
$webhookUrl
);
}
private function buildTextContent(string $text, array $arrContext = array()): string
{
$textContent = trim($text);
if ($arrContext === array()) {
return $textContent;
}
$arrContextLines = array();
foreach ($arrContext as $key => $value) {
$arrContextLines[] = sprintf('%s: %s', (string) $key, $this->normalizeContextValue($value));
}
return $textContent . "\n" . implode("\n", $arrContextLines);
}
private function normalizeContextValue($value): string
{
if (is_scalar($value) || $value === null) {
return (string) $value;
}
$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return $json !== false ? $json : '[unserializable]';
}
}
<?php
namespace Daito\Lib\DaitoGoogleChat\Jobs;
use Daito\Lib\DaitoGoogleChat\Services\DaitoGoogleChatWebhookClient;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class DaitoGoogleChatWebhookJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $arrPayload;
protected $webhookUrl;
public $tries;
public $backoff;
public function __construct(array $arrPayload, $webhookUrl = null)
{
$this->arrPayload = $arrPayload;
$this->webhookUrl = $webhookUrl !== null ? (string) $webhookUrl : null;
$this->tries = max(1, (int) config('daito-google-chat.queue_tries', 3));
$this->backoff = max(1, (int) config('daito-google-chat.queue_backoff_seconds', 10));
}
public function handle(DaitoGoogleChatWebhookClient $client): void
{
$client->send($this->arrPayload, $this->webhookUrl);
}
}
<?php
namespace Daito\Lib\DaitoGoogleChat\Providers;
use Daito\Lib\DaitoGoogleChat\DaitoGoogleChatManager;
use Daito\Lib\DaitoGoogleChat\Services\DaitoGoogleChatWebhookClient;
use Illuminate\Support\ServiceProvider;
class DaitoGoogleChatProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(
__DIR__ . '/../config/daito-google-chat.php',
'daito-google-chat'
);
$this->app->singleton(DaitoGoogleChatWebhookClient::class, function () {
return new DaitoGoogleChatWebhookClient();
});
$this->app->singleton(DaitoGoogleChatManager::class, function ($app) {
return new DaitoGoogleChatManager(
$app->make(DaitoGoogleChatWebhookClient::class)
);
});
}
public function boot(): void
{
$this->publishes(
array(
__DIR__ . '/../config/daito-google-chat.php' => config_path('daito-google-chat.php'),
),
'daito-google-chat-config'
);
}
}
<?php
namespace Daito\Lib\DaitoGoogleChat\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use RuntimeException;
class DaitoGoogleChatWebhookClient
{
public function send(array $arrPayload, $webhookUrl = null): array
{
if (!(bool) config('daito-google-chat.enabled', false)) {
return array(
'success' => 0,
'status' => 'disabled',
'message' => 'Daito Google Chat notification is disabled.',
);
}
$resolvedWebhookUrl = $this->resolveWebhookUrl($webhookUrl);
$this->assertWebhookUrlIsAllowed($resolvedWebhookUrl);
$response = Http::acceptJson()
->asJson()
->timeout((int) config('daito-google-chat.timeout_seconds', 5))
->connectTimeout((int) config('daito-google-chat.connect_timeout_seconds', 3))
->retry(
(int) config('daito-google-chat.retry_times', 1),
(int) config('daito-google-chat.retry_sleep_ms', 200)
)
->post($resolvedWebhookUrl, $arrPayload);
if ($response->successful()) {
return array(
'success' => 1,
'status' => 'sent',
'http_code' => $response->status(),
);
}
$arrError = array(
'success' => 0,
'status' => 'failed',
'http_code' => $response->status(),
'message' => trim((string) $response->body()),
);
Log::warning('DaitoGoogleChat send failed.', $arrError);
if ((bool) config('daito-google-chat.throw_on_error', false)) {
throw new RuntimeException('DaitoGoogleChat send failed: HTTP ' . (string) $response->status());
}
return $arrError;
}
private function resolveWebhookUrl($webhookUrl): string
{
$resolvedWebhookUrl = trim((string) ($webhookUrl ?: config('daito-google-chat.default_webhook_url', '')));
if ($resolvedWebhookUrl === '') {
throw new RuntimeException('Google Chat webhook URL is empty.');
}
return $resolvedWebhookUrl;
}
private function assertWebhookUrlIsAllowed(string $webhookUrl): void
{
if (!(bool) config('daito-google-chat.validate_webhook_host', true)) {
return;
}
$host = strtolower((string) parse_url($webhookUrl, PHP_URL_HOST));
if ($host === '') {
throw new RuntimeException('Google Chat webhook URL is invalid.');
}
$arrAllowedWebhookHosts = array_map('strtolower', (array) config('daito-google-chat.allowed_webhook_hosts', array()));
if (!in_array($host, $arrAllowedWebhookHosts, true)) {
throw new RuntimeException('Google Chat webhook host is not allowed: ' . $host);
}
}
}
<?php
return array(
'enabled' => env('DAITO_GOOGLE_CHAT_ENABLED', false),
'default_webhook_url' => env('DAITO_GOOGLE_CHAT_WEBHOOK_URL', ''),
'validate_webhook_host' => env('DAITO_GOOGLE_CHAT_VALIDATE_WEBHOOK_HOST', true),
'allowed_webhook_hosts' => array(
'chat.googleapis.com',
),
'timeout_seconds' => env('DAITO_GOOGLE_CHAT_TIMEOUT', 5),
'connect_timeout_seconds' => env('DAITO_GOOGLE_CHAT_CONNECT_TIMEOUT', 3),
'retry_times' => env('DAITO_GOOGLE_CHAT_RETRY_TIMES', 1),
'retry_sleep_ms' => env('DAITO_GOOGLE_CHAT_RETRY_SLEEP_MS', 200),
'queue_connection' => env('DAITO_GOOGLE_CHAT_QUEUE_CONNECTION', null),
'queue_name' => env('DAITO_GOOGLE_CHAT_QUEUE_NAME', null),
'queue_tries' => env('DAITO_GOOGLE_CHAT_QUEUE_TRIES', 3),
'queue_backoff_seconds' => env('DAITO_GOOGLE_CHAT_QUEUE_BACKOFF', 10),
'throw_on_error' => env('DAITO_GOOGLE_CHAT_THROW_ON_ERROR', false),
);