trangshopeeaffiliate/app/Http/Controllers/Api/ZaloWebhookController.php
2026-07-11 22:56:22 +07:00

195 lines
6.7 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\ZaloBotService;
use App\Services\SettingService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ZaloWebhookController extends Controller
{
protected ZaloBotService $zaloBotService;
protected SettingService $settingService;
public function __construct(
ZaloBotService $zaloBotService,
SettingService $settingService
) {
$this->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]);
}
}