fix(telegram): send button links as text when Telegram rejects the button URL

Closes #8269

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-03 22:34:39 +01:00
co-authored by Claude Opus 5.5
parent c3e5b4ba73
commit a7b7aa350a
2 changed files with 40 additions and 7 deletions
+16 -7
View File
@@ -81,12 +81,6 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue
}
}
$payload = [
// 'parse_mode' => 'markdown',
'reply_markup' => json_encode([
'inline_keyboard' => [
[...$inlineButtons],
],
]),
'chat_id' => trim($this->chatId),
'text' => $this->text,
];
@@ -94,6 +88,21 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue
$payload['message_thread_id'] = $this->threadId;
}
return $this->sendNotificationRequest('Telegram', $url, fn () => Http::post($url, $payload));
$response = $this->sendNotificationRequest('Telegram', $url, fn () => Http::post($url, [
...$payload,
'reply_markup' => json_encode(['inline_keyboard' => [$inlineButtons]]),
]));
// Telegram rejects the whole message when it cannot open a button URL (for example localhost or an IP address without a domain).
if ($inlineButtons !== [] && $response->status() === 400
&& Str::contains((string) $response->json('description'), ['button url', 'button_url'], true)) {
$links = collect($inlineButtons)->map(fn (array $button) => "{$button['text']}: {$button['url']}")->implode("\n");
$response = $this->sendNotificationRequest('Telegram', $url, fn () => Http::post($url, [
...$payload,
'text' => "{$this->text}\n\n{$links}",
]));
}
return $response;
}
}
@@ -74,3 +74,27 @@ it('tells the user to check the bot token when Telegram does not find the bot',
->assertDispatched('error', 'Telegram rejected the test notification.', 'The Bot API token is not valid. Copy it again from @BotFather.')
->assertNotDispatched('success');
});
it('sends the dashboard link as text when Telegram rejects the button URL', function () {
Http::fakeSequence('api.telegram.org/*')
->push(['ok' => false, 'error_code' => 400, 'description' => 'Bad Request: BUTTON_URL_INVALID'], 400)
->push(['ok' => true, 'result' => []]);
Livewire::test(TelegramNotification::class)
->call('sendTestNotification')
->assertDispatched('success', 'Test notification sent.');
$requests = Http::recorded();
expect($requests)->toHaveCount(2)
->and($requests[0][0]->data())->toHaveKey('reply_markup')
->and($requests[1][0]->data())->not->toHaveKey('reply_markup')
->and($requests[1][0]['text'])->toBe("Coolify: This is a test Telegram notification from Coolify.\n\nGo to your dashboard: ".base_url());
});
it('does not resend a notification that Telegram rejects for another reason', function () {
Http::fake(['api.telegram.org/*' => Http::response(['ok' => false, 'description' => 'Bad Request: chat not found'], 400)]);
Livewire::test(TelegramNotification::class)->call('sendTestNotification');
Http::assertSentCount(1);
});