diff --git a/app/Jobs/SendMessageToTelegramJob.php b/app/Jobs/SendMessageToTelegramJob.php index 0cb1a7124d..babebad956 100644 --- a/app/Jobs/SendMessageToTelegramJob.php +++ b/app/Jobs/SendMessageToTelegramJob.php @@ -8,6 +8,7 @@ use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeEncrypted; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Http\Client\Response; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Http; @@ -49,6 +50,19 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue * Execute the job. */ public function handle(): void + { + $response = $this->sendMessage(); + + // 401: invalid bot token, 403: the bot was blocked or removed from the chat, 400 "chat not found": wrong chat ID. + $isConfigurationError = in_array($response->status(), [401, 403], true) + || ($response->status() === 400 && Str::contains((string) $response->json('description'), 'chat not found', true)); + $this->handleNotificationResponse($response, 'Telegram', $isConfigurationError); + } + + /** + * Call the Telegram sendMessage API and return its response without handling errors. + */ + public function sendMessage(): Response { $url = 'https://api.telegram.org/bot'.$this->token.'/sendMessage'; $inlineButtons = []; @@ -78,11 +92,7 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue if ($this->threadId) { $payload['message_thread_id'] = $this->threadId; } - $response = Http::post($url, $payload); - // 401: invalid bot token, 403: the bot was blocked or removed from the chat, 400 "chat not found": wrong chat ID. - $isConfigurationError = in_array($response->status(), [401, 403], true) - || ($response->status() === 400 && Str::contains((string) $response->json('description'), 'chat not found', true)); - $this->handleNotificationResponse($response, 'Telegram', $isConfigurationError); + return Http::post($url, $payload); } } diff --git a/app/Livewire/Notifications/Telegram.php b/app/Livewire/Notifications/Telegram.php index cd7bea60cd..f6edb89d3e 100644 --- a/app/Livewire/Notifications/Telegram.php +++ b/app/Livewire/Notifications/Telegram.php @@ -2,6 +2,7 @@ namespace App\Livewire\Notifications; +use App\Jobs\SendMessageToTelegramJob; use App\Livewire\Notifications\Concerns\TogglesNotificationEvents; use App\Models\Team; use App\Models\TelegramNotificationSettings; @@ -306,7 +307,23 @@ class Telegram extends Component { try { $this->authorize('sendTest', $this->settings); - $this->team->notify(new Test(channel: 'telegram')); + + // Send synchronously so that the user sees the error from Telegram (a queued test always "succeeds"). + $message = (new Test(channel: 'telegram'))->toTelegram(); + $response = (new SendMessageToTelegramJob( + text: $message['message'], + buttons: $message['buttons'], + token: (string) $this->settings->telegram_token, + chatId: (string) $this->settings->telegram_chat_id, + ))->sendMessage(); + + if ($response->failed()) { + $reason = $response->json('description') ?? "HTTP {$response->status()}"; + $this->dispatch('error', 'Telegram rejected the test notification.', e($reason)); + + return; + } + $this->dispatch('success', 'Test notification sent.'); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/tests/Feature/TelegramTestNotificationTest.php b/tests/Feature/TelegramTestNotificationTest.php new file mode 100644 index 0000000000..ce9640406a --- /dev/null +++ b/tests/Feature/TelegramTestNotificationTest.php @@ -0,0 +1,52 @@ + InstanceSettings::updateOrCreate(['id' => 0], ['id' => 0])); + + $this->team = Team::factory()->create(); + $this->team->telegramNotificationSettings->update([ + 'telegram_enabled' => true, + 'telegram_token' => 'bot-token', + 'telegram_chat_id' => '123456', + ]); + + $admin = User::factory()->create(); + $admin->teams()->attach($this->team, ['role' => 'admin']); + $this->actingAs($admin); + session(['currentTeam' => $this->team]); + Queue::fake(); +}); + +it('shows the error from Telegram when the test notification is rejected', function () { + Http::fake(['api.telegram.org/*' => Http::response(['ok' => false, 'description' => 'Bad Request: chat not found'], 400)]); + + Livewire::test(TelegramNotification::class) + ->call('sendTestNotification') + ->assertDispatched('error', 'Telegram rejected the test notification.', 'Bad Request: chat not found') + ->assertNotDispatched('success'); + + Queue::assertNothingPushed(); +}); + +it('sends the test notification synchronously and reports success', function () { + Http::fake(['api.telegram.org/*' => Http::response(['ok' => true, 'result' => []])]); + + Livewire::test(TelegramNotification::class) + ->call('sendTestNotification') + ->assertDispatched('success', 'Test notification sent.'); + + Http::assertSent(fn ($request) => $request->url() === 'https://api.telegram.org/botbot-token/sendMessage' + && $request['chat_id'] === '123456'); + Queue::assertNothingPushed(); +});