added trigger for chat sms

This commit is contained in:
2026-08-04 18:59:38 +03:30
parent fab3c2270a
commit bfb8b91133
8 changed files with 245 additions and 5 deletions
@@ -0,0 +1,119 @@
<?php
namespace App\Http\Controllers\Chat;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\User;
use App\Services\ChatWebhookService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class SupportChatNotifyController extends Controller
{
public const FOCUS_CACHE_PREFIX = 'admin_support_focus:';
public const FOCUS_TTL_SECONDS = 45;
/**
* Webhook از ah_chat وقتی اولین پیام خوانده‌نشدهٔ مشتری در اتاق SUPPORT ذخیره شود.
*/
public function notify(Request $request)
{
$secret = (string) self::Config('chat_webhook_secret');
$incoming = (string) $request->header('X-Chat-Webhook-Secret', '');
if ($secret === '' || ! hash_equals($secret, $incoming)) {
return response()->json(['message' => 'unauthorized'], 401);
}
if (! self::isSmsNotifEnabled('sms_notif_support_admin')) {
return response()->json(['ok' => true, 'skipped' => 'disabled']);
}
$roomId = trim((string) $request->input('room_id', ''));
if ($roomId === '') {
return response()->json(['message' => 'room_id required'], 422);
}
if (Cache::has(self::FOCUS_CACHE_PREFIX.$roomId)) {
return response()->json(['ok' => true, 'skipped' => 'admin_focused']);
}
$customer = Customer::query()
->where('chat_room_id', $roomId)
->first();
$name = $customer
? trim((string) ($customer->name ?: $customer->username ?: 'مشتری'))
: 'مشتری';
if ($name === '') {
$name = 'مشتری';
}
$message = 'شما از '.$name.' پیام دارید';
try {
User::where('send_sms', 1)->get()->each(function ($admin) use ($message) {
if (! empty($admin->mobile)) {
$this->send($admin->mobile, $message);
}
});
} catch (\Throwable $e) {
Log::warning('support chat SMS notify failed', [
'room_id' => $roomId,
'error' => $e->getMessage(),
]);
}
return response()->json(['ok' => true]);
}
/**
* Heartbeat تمرکز ادمین روی یک اتاق پشتیبانی (یا ترک تمرکز).
*/
public function focus(Request $request)
{
$roomId = trim((string) $request->input('room_id', ''));
$previousRoomId = trim((string) $request->input('previous_room_id', ''));
if ($previousRoomId !== '' && $previousRoomId !== $roomId) {
Cache::forget(self::FOCUS_CACHE_PREFIX.$previousRoomId);
}
if ($roomId === '') {
return response()->json(['ok' => true]);
}
Cache::put(self::FOCUS_CACHE_PREFIX.$roomId, true, self::FOCUS_TTL_SECONDS);
return response()->json(['ok' => true, 'room_id' => $roomId]);
}
/**
* ترک تمرکز روی یک اتاق مشخص.
*/
public function unfocus(Request $request)
{
$roomId = trim((string) $request->input('room_id', ''));
if ($roomId !== '') {
Cache::forget(self::FOCUS_CACHE_PREFIX.$roomId);
}
return response()->json(['ok' => true]);
}
/**
* ثبت/تازه‌سازی وب‌هوک روی ah_chat (از پنل ادمین).
*/
public function ensureWebhook()
{
$ok = app(ChatWebhookService::class)->ensureRegistered();
return response()->json([
'ok' => $ok,
'message' => $ok ? 'webhook registered' : 'webhook register skipped or failed',
], $ok ? 200 : 422);
}
}
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Customer;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Services\ChatWebhookService;
use Illuminate\Support\Facades\Http;
class ChatController extends Controller
@@ -26,6 +27,8 @@ class ChatController extends Controller
? (string) $user->chat_user_id
: 'user_'.$user->id;
app(ChatWebhookService::class)->ensureRegistered();
if (!empty($user->chat_room_id)) {
if ($this->chatRoomIsAccessible($host, (string) $chatApiKey, (string) $user->chat_room_id, $userChatId)) {
if (empty($user->chat_user_id) || $user->chat_user_id !== $userChatId) {
+1
View File
@@ -109,6 +109,7 @@ class Setting extends Model
'value',
'value_json',
'type',
'can_edit',
];
protected $casts = [
'value_json'=>'array',
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace App\Services;
use App\Http\Controllers\Controller;
use App\Models\Setting;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class ChatWebhookService
{
public function ensureRegistered(): bool
{
$chatApi = Controller::Config('chat_api');
$chatApiKey = Controller::Config('chat_api_key');
if (!$chatApi || !$chatApiKey) {
return false;
}
$host = preg_replace('#^https?://#', '', rtrim((string) $chatApi, '/'));
$secret = $this->ensureSecret();
if ($host === '' || $secret === '') {
return false;
}
$webhookUrl = rtrim((string) config('app.url'), '/').'/api/chat/support-message-notify';
try {
$response = Http::timeout(8)->post('https://'.$host.'/api/projects/set-webhook', [
'api_key' => $chatApiKey,
'webhook_url' => $webhookUrl,
'webhook_secret' => $secret,
]);
return $response->successful();
} catch (\Throwable $e) {
Log::warning('chat webhook register failed', [
'host' => $host,
'error' => $e->getMessage(),
]);
return false;
}
}
public function ensureSecret(): string
{
$existing = trim((string) Controller::Config('chat_webhook_secret'));
if ($existing !== '') {
return $existing;
}
$secret = Str::random(48);
$row = Setting::where('key', 'chat_webhook_secret')->first();
if ($row) {
if (trim((string) $row->value) === '') {
$row->value = $secret;
$row->save();
} else {
return (string) $row->value;
}
} else {
Setting::create([
'key' => 'chat_webhook_secret',
'value' => $secret,
'title_fa' => 'رمز وب‌هوک چت',
'is_active' => true,
'can_edit' => 0,
'description' => 'رمز مشترک بین لاراول و سرور چت برای اعلان پیام پشتیبانی. فقط سرور؛ در صورت خالی بودن به‌صورت خودکار ساخته می‌شود.',
'type' => 'text',
]);
}
return $secret;
}
}