zaloBotService = $zaloBotService; $this->settingService = $settingService; } /** * Handle webhook request from Zalo Bot Platform. */ public function handle(Request $request): JsonResponse { $configuredSecret = $this->settingService->get('zalo_webhook_secret'); if (!empty($configuredSecret)) { $incomingSecret = $request->header('X-Bot-Api-Secret-Token') ?? $request->header('x-bot-api-secret-token'); if ($incomingSecret !== $configuredSecret) { return response()->json([ 'ok' => false, 'error' => 'Unauthorized. Secret token mismatch.' ], 401); } } $payload = $request->all(); // Pass payload to ZaloBotService $this->zaloBotService->handleWebhook($payload); return response()->json([ 'ok' => true, ]); } /** * Process a Shopee link for the Zalo user-bot (self-bot) and return the formatted reply. */ public function processLink(Request $request): JsonResponse { $request->validate([ 'url' => 'required|string', 'sender_name' => 'nullable|string', 'thread_id' => 'nullable|string', 'chat_name' => 'nullable|string' ]); $url = $request->input('url'); $fromName = $request->input('sender_name') ?? 'Bạn'; $threadId = $request->input('thread_id'); $chatName = $request->input('chat_name'); // 1. Add/Update this thread into discovered groups pool so Admin can whitelist it if ($threadId) { \App\Models\ZaloDiscoveredGroup::updateOrCreate( ['group_id' => $threadId], ['name' => $chatName ?: ($fromName ? "Chat với {$fromName}" : "Trò chuyện cá nhân")] ); } // 2. Whitelist Filtering: Bot is ONLY allowed to respond to whitelisted threads (Default Deny) $isAllowed = \App\Models\ZaloChannel::where('thread_id', $threadId) ->where('is_allowed', true) ->exists(); $productTitle = $request->input('product_title'); $productImage = $request->input('product_image'); if (!$isAllowed) { return response()->json([ 'success' => false, 'error' => 'Thread is not whitelisted. Bot response restricted.' ], 403); } try { // 1. Resolve redirect if short link $resolvedUrl = $this->zaloBotService->resolveShortUrl($url); // 2. Convert link to short redirect affiliate link and log details $convertResult = app(\App\Services\LinkConverterService::class)->process( $resolvedUrl, $threadId, $chatName, 'zalo_bot', null, null, $productTitle, $productImage ); if ($convertResult && $convertResult->isSuccess) { $shortLink = $convertResult->affiliateUrl; // Fetch the logged history to extract cào details $history = \App\Models\ConversionHistory::where('original_url', $resolvedUrl) ->where('zalo_thread_id', $threadId) ->latest() ->first(); $productName = $history && $history->product_title ? $history->product_title : ($productTitle ?: ($this->zaloBotService->extractProductName($resolvedUrl) ?? 'Sản phẩm Shopee')); // 3. Construct the message template $replyText = "Hi @{$fromName}, Link của bạn đây ạ:\n\n" . "📦 Tên sản phẩm Shopee:\n{$productName}\n\n" . "🔗 Link: {$shortLink}\n\n" . "⚠️ Lưu ý: Để đơn hàng được ghi nhận, KHÔNG mua qua Livestream, KHÔNG xem video/live bất kỳ sau khi click & XÓA sản phẩm ra khỏi giỏ hàng TRƯỚC KHI bấm link!"; return response()->json([ 'success' => true, 'reply_text' => $replyText, 'short_link' => $shortLink ]); } return response()->json([ 'success' => false, 'error' => $convertResult->errorMessage ?? 'Conversion failed' ], 400); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Update Zalo user-bot (self-bot) status in settings table. */ public function updateStatus(Request $request): JsonResponse { $request->validate([ 'status' => 'required|string', 'user_name' => 'nullable|string' ]); $this->settingService->set('zalo_bot_status', $request->input('status')); if ($request->has('user_name')) { $this->settingService->set('zalo_bot_user', $request->input('user_name') ?? ''); } else if ($request->input('status') === 'disconnected') { $this->settingService->set('zalo_bot_user', ''); } return response()->json(['ok' => true]); } /** * Sync Zalo groups from userbot into discovered pool. */ public function syncGroups(Request $request): JsonResponse { $request->validate([ 'groups' => 'required|array', 'groups.*.id' => 'required|string', 'groups.*.name' => 'nullable|string' ]); $groups = $request->input('groups'); $fetchedIds = array_column($groups, 'id'); // Delete groups no longer joined \App\Models\ZaloDiscoveredGroup::whereNotIn('group_id', $fetchedIds)->delete(); // Update or insert current groups foreach ($groups as $group) { \App\Models\ZaloDiscoveredGroup::updateOrCreate( ['group_id' => $group['id']], ['name' => $group['name'] ?? 'Nhóm Zalo'] ); } return response()->json(['ok' => true]); } }