fix(help): show an error when feedback cannot be delivered

Without SMTP or Resend configured, the Help form posts to the Cloud
feedback API but ignored the response, so it always reported success.
Check the response and show an error on failure. The Cloud endpoint now
returns 502 when the Discord webhook fails.
This commit is contained in:
Andras Bacsai committed 2026-09-29 10:19:57 +02:00
1 parent 639a07e4cb
commit 5ecc689135
4 files changed
+88 -7

No files matched your search

+12 -4
View File
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
@@ -281,10 +282,17 @@ class OtherController extends Controller
$webhook_url = config('constants.webhooks.feedback_discord_webhook');
if ($webhook_url) {
Http::timeout(5)->post($webhook_url, [
'content' => $data['content'],
'allowed_mentions' => ['parse' => []],
]);
try {
$response = Http::timeout(5)->post($webhook_url, [
'content' => $data['content'],
'allowed_mentions' => ['parse' => []],
]);
} catch (ConnectionException) {
$response = null;
}
if (! $response?->successful()) {
return response()->json(['message' => 'Feedback could not be delivered.'], 502);
}
}
return response()->json(['message' => 'Feedback sent.'], 200);
+13 -3
View File
@@ -3,6 +3,7 @@
namespace App\Livewire;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\Http;
use Livewire\Attributes\Validate;
@@ -38,9 +39,18 @@ class Help extends Component
// Sending feedback through Cloud API
if (blank($type)) {
$url = 'https://app.coolify.io/api/feedback';
Http::post($url, [
'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
]);
try {
$response = Http::timeout(10)->post($url, [
'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
]);
} catch (ConnectionException) {
$response = null;
}
if (! $response?->successful()) {
$this->dispatch('error', 'Feedback could not be sent.', 'Please try again later or contact us on Discord.');
return;
}
} else {
send_user_an_email($mail, auth()->user()?->email, 'feedback@coollabs.io');
}
+11
View File
@@ -94,3 +94,14 @@ it('disables discord mention parsing regardless of content', function () {
return $request['allowed_mentions'] === ['parse' => []];
});
});
it('returns an error when the discord webhook fails', function () {
config()->set('constants.webhooks.feedback_discord_webhook', 'https://webhook.example.com/failing');
Http::fake(['webhook.example.com/*' => Http::response([], 500)]);
$response = $this->postJson('/api/feedback', [
'content' => 'This is a valid feedback message for testing purposes.',
]);
$response->assertStatus(502);
});
+52
View File
@@ -0,0 +1,52 @@
<?php
use App\Livewire\Help;
use App\Models\InstanceSettings;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;
uses(RefreshDatabase::class);
beforeEach(function () {
InstanceSettings::forceCreate(['id' => 0]);
$this->actingAs(User::factory()->create());
});
it('shows success when the cloud api accepts feedback without email configured', function () {
Http::fake(['app.coolify.io/*' => Http::response(['message' => 'Feedback sent.'], 200)]);
Livewire::test(Help::class)
->set('subject', 'Test subject')
->set('description', 'This is a detailed feedback description.')
->call('submit')
->assertDispatched('success')
->assertNotDispatched('error');
Http::assertSent(fn ($request) => $request->url() === 'https://app.coolify.io/api/feedback');
});
it('shows an error when the cloud api rejects feedback without email configured', function (int $status) {
Http::fake(['app.coolify.io/*' => Http::response([], $status)]);
Livewire::test(Help::class)
->set('subject', 'Test subject')
->set('description', 'This is a detailed feedback description.')
->call('submit')
->assertDispatched('error')
->assertNotDispatched('success')
->assertSet('subject', 'Test subject');
})->with([422, 429, 500, 502]);
it('shows an error when the cloud api is unreachable', function () {
Http::fake(fn () => throw new ConnectionException('Connection refused'));
Livewire::test(Help::class)
->set('subject', 'Test subject')
->set('description', 'This is a detailed feedback description.')
->call('submit')
->assertDispatched('error')
->assertNotDispatched('success');
});