Files
boursecu_server/app/Http/Controllers/Chat/SupportChatNotifyController.php
mohmdsdgandCursor 279e4bc881 Enable gated multi-level referral profit and harden chat/SMS notify paths.
Honor enable_customer_level_profit for order referral payouts, and tighten support-chat webhook/SMS plus SuperAdmin SMS panel sync settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 16:48:53 +03:30

152 lines
5.1 KiB
PHP

<?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');
$secret = app(ChatWebhookService::class)->sanitizeSecret($secret);
$incoming = app(ChatWebhookService::class)->sanitizeSecret(
(string) $request->header('X-Chat-Webhook-Secret', '')
);
if ($secret === '' || ! hash_equals($secret, $incoming)) {
Log::warning('support chat notify unauthorized', [
'has_secret' => $secret !== '',
'has_header' => $incoming !== '',
]);
return response()->json(['message' => 'unauthorized'], 401);
}
if (! self::isSmsNotifEnabled('sms_notif_support_admin')) {
Log::info('support chat notify skipped: sms_notif_support_admin disabled');
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)) {
Log::info('support chat notify skipped: admin focused', ['room_id' => $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 = 'مشتری';
}
$companyName = trim((string) self::Config('name_fa'));
if ($companyName === '') {
$companyName = trim((string) self::Config('name'));
}
if ($companyName === '') {
$companyName = 'پشتیبانی';
}
$message = 'شما از '.$name." پیام دارید\n".$companyName;
$admins = User::where('send_sms', 1)->get();
if ($admins->isEmpty()) {
Log::warning('support chat notify: no admins with send_sms=1', ['room_id' => $roomId]);
}
try {
$admins->each(function ($admin) use ($message) {
if (! empty($admin->mobile)) {
$this->send($admin->mobile, $message);
}
});
Log::info('support chat notify SMS sent', [
'room_id' => $roomId,
'name' => $name,
'company' => $companyName,
'admin_count' => $admins->count(),
]);
} 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 (از پنل ادمین).
* همیشه HTTP 200 — شکست ثبت best-effort است و نباید toast خطای 422 بسازد.
*/
public function ensureWebhook()
{
$result = app(ChatWebhookService::class)->ensureRegisteredDetailed();
return response()->json([
'ok' => (bool) ($result['ok'] ?? false),
'webhook_url' => (string) ($result['webhook_url'] ?? ''),
'reason' => (string) ($result['reason'] ?? ''),
'message' => (string) ($result['message'] ?? ''),
'attempts' => (int) ($result['attempts'] ?? 0),
]);
}
}