diff --git a/app/Livewire/Help.php b/app/Livewire/Help.php
index 5e0876f89..657670526 100644
--- a/app/Livewire/Help.php
+++ b/app/Livewire/Help.php
@@ -2,8 +2,10 @@
namespace App\Livewire;
+use App\Models\InstanceSettings;
use DanHarrin\LivewireRateLimiting\WithRateLimiting;
use Illuminate\Notifications\Messages\MailMessage;
+use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
@@ -28,9 +30,8 @@ class Help extends Component
public function submit()
{
try {
- $this->rateLimit(3, 60);
+ $this->rateLimit(3, 30);
$this->validate();
- $subscriptionType = auth()->user()?->subscription?->type() ?? 'Free';
$debug = "Route: {$this->path}";
$mail = new MailMessage();
$mail->view(
@@ -40,9 +41,21 @@ class Help extends Component
'debug' => $debug
]
);
- $mail->subject("[HELP - {$subscriptionType}]: {$this->subject}");
- send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
- $this->dispatch('success', 'Your message has been sent successfully.
We will get in touch with you as soon as possible.');
+ $mail->subject("[HELP]: {$this->subject}");
+ $settings = InstanceSettings::get();
+ $type = set_transanctional_email_settings($settings);
+ if (!$type) {
+ $url = "https://app.coolify.io/api/feedback";
+ if (isDev()) {
+ $url = "http://localhost:80/api/feedback";
+ }
+ Http::post($url, [
+ 'content' => "User: `" . auth()->user()?->email . "` with subject: `" . $this->subject . "` has the following problem: `" . $this->description . "`"
+ ]);
+ } else {
+ send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
+ }
+ $this->dispatch('success', 'Feedback sent.', 'We will get in touch with you as soon as possible.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index ad64b2550..23ee3fa06 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -104,7 +104,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n
ray($error);
if ($error instanceof TooManyRequestsException) {
if (isset($livewire)) {
- return $livewire->dispatch('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
+ return $livewire->dispatch('error', "Too many requests.","Please try again in {$error->secondsUntilAvailable} seconds.");
}
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
}
@@ -298,10 +298,8 @@ function validate_cron_expression($expression_to_validate): bool
function send_internal_notification(string $message): void
{
try {
- $baseUrl = config('app.name');
$team = Team::find(0);
- $team?->notify(new GeneralNotification("👀 {$baseUrl}: " . $message));
- ray("👀 {$baseUrl}: " . $message);
+ $team?->notify(new GeneralNotification($message));
} catch (\Throwable $e) {
ray($e->getMessage());
}
diff --git a/config/coolify.php b/config/coolify.php
index 2e15c8618..69ec23146 100644
--- a/config/coolify.php
+++ b/config/coolify.php
@@ -3,6 +3,7 @@
return [
'docs' => 'https://coolify.io/docs/',
'contact' => 'https://coolify.io/docs/contact',
+ 'feedback_discord_webhook' => env('FEEDBACK_DISCORD_WEBHOOK'),
'self_hosted' => env('SELF_HOSTED', true),
'waitlist' => env('WAITLIST', false),
'license_url' => 'https://licenses.coollabs.io',
diff --git a/config/sentry.php b/config/sentry.php
index 2d8f7c7f3..18b1b1fc0 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.209',
+ 'release' => '4.0.0-beta.210',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index ff1387709..6dde1069a 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
-
diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php
index 9256dc502..881ad1bd8 100644
--- a/resources/views/components/navbar.blade.php
+++ b/resources/views/components/navbar.blade.php
@@ -142,13 +142,12 @@
@endif
@if (isSubscriptionActive() || isDev())
-
+
-
+
+ d="M144 180a16 16 0 1 1-16-16a16 16 0 0 1 16 16m92-52A108 108 0 1 1 128 20a108.12 108.12 0 0 1 108 108m-24 0a84 84 0 1 0-84 84a84.09 84.09 0 0 0 84-84m-84-64c-24.26 0-44 17.94-44 40v4a12 12 0 0 0 24 0v-4c0-8.82 9-16 20-16s20 7.18 20 16s-9 16-20 16a12 12 0 0 0-12 12v8a12 12 0 0 0 23.73 2.56C158.31 137.88 172 122.37 172 104c0-22.06-19.74-40-44-40" />
- Feedback
@endif
diff --git a/resources/views/layouts/boarding.blade.php b/resources/views/layouts/boarding.blade.php
index d108c2e38..e11067938 100644
--- a/resources/views/layouts/boarding.blade.php
+++ b/resources/views/layouts/boarding.blade.php
@@ -3,11 +3,10 @@
@if (isSubscriptionActive() || isDev())
@endif
diff --git a/resources/views/livewire/help.blade.php b/resources/views/livewire/help.blade.php
index 84a4f99bd..66e80e428 100644
--- a/resources/views/livewire/help.blade.php
+++ b/resources/views/livewire/help.blade.php
@@ -6,6 +6,6 @@
- Send Email
+ Send
diff --git a/routes/api.php b/routes/api.php
index ee44e390e..30dddd2d4 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -12,6 +12,7 @@ use App\Models\Tag;
use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Visus\Cuid2\Cuid2;
@@ -34,6 +35,16 @@ if (isDev()) {
Route::get('/health', function () {
return 'OK';
});
+Route::post('/feedback', function (Request $request) {
+ $content = $request->input('content');
+ $webhook_url = config('coolify.feedback_discord_webhook');
+ if ($webhook_url) {
+ Http::post($webhook_url, [
+ 'content' => $content
+ ]);
+ }
+ return response()->json(['message' => 'Feedback sent.'], 200);
+});
// Route::group([
// 'middleware' => $middlewares,
// 'prefix' => 'v1'
@@ -53,6 +64,8 @@ Route::group([
'prefix' => 'v1'
], function () {
Route::get('/deploy', [Deploy::class, 'deploy']);
+
+
});
Route::middleware(['throttle:5'])->group(function () {
diff --git a/routes/webhooks.php b/routes/webhooks.php
index 6af79ab63..25d438123 100644
--- a/routes/webhooks.php
+++ b/routes/webhooks.php
@@ -764,7 +764,6 @@ Route::post('/payments/stripe/events', function () {
]);
$type = data_get($event, 'type');
$data = data_get($event, 'data.object');
- ray('Event: ' . $type);
switch ($type) {
case 'checkout.session.completed':
$clientReferenceId = data_get($data, 'client_reference_id');
@@ -779,7 +778,8 @@ Route::post('/payments/stripe/events', function () {
$team = Team::find($teamId);
$found = $team->members->where('id', $userId)->first();
if (!$found->isAdmin()) {
- throw new Exception("User {$userId} is not an admin or owner of team {$team->id}.");
+ send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
+ throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
}
$subscription = Subscription::where('team_id', $teamId)->first();
if ($subscription) {
@@ -819,25 +819,35 @@ Route::post('/payments/stripe/events', function () {
break;
case 'invoice.payment_failed':
$customerId = data_get($data, 'customer');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
+ $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
+ if (!$subscription) {
+ send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: ' . $customerId);
+ return response('No subscription found in Coolify.');
+ }
$team = data_get($subscription, 'team');
if (!$team) {
- throw new Exception('No team found for subscription: ' . $subscription->id);
+ send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: ' . $customerId);
+ return response('No team found in Coolify.');
}
if (!$subscription->stripe_invoice_paid) {
SubscriptionInvoiceFailedJob::dispatch($team);
- send_internal_notification('Invoice payment failed: ' . $subscription->team->id);
+ send_internal_notification('Invoice payment failed: ' . $customerId);
} else {
- send_internal_notification('Invoice payment failed but already paid: ' . $subscription->team->id);
+ send_internal_notification('Invoice payment failed but already paid: ' . $customerId);
}
break;
case 'payment_intent.payment_failed':
$customerId = data_get($data, 'customer');
- $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
- $subscription->update([
- 'stripe_invoice_paid' => false,
- ]);
- send_internal_notification('Subscription payment failed: ' . $subscription->team->id);
+ $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
+ if (!$subscription) {
+ send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: ' . $customerId);
+ return response('No subscription found in Coolify.');
+ }
+ if ($subscription->stripe_invoice_paid) {
+ send_internal_notification('payment_intent.payment_failed but invoice is active for customer: ' . $customerId);
+ return;
+ }
+ send_internal_notification('Subscription payment failed for customer: ' . $customerId);
break;
case 'customer.subscription.updated':
$customerId = data_get($data, 'customer');
@@ -868,7 +878,7 @@ Route::post('/payments/stripe/events', function () {
$subscription->update([
'stripe_invoice_paid' => false,
]);
- send_internal_notification('Subscription paused or incomplete for team: ' . $subscription->team->id);
+ send_internal_notification('Subscription paused or incomplete for customer: ' . $customerId);
}
// Trial ended but subscribed, reactive servers
@@ -878,7 +888,7 @@ Route::post('/payments/stripe/events', function () {
}
if ($feedback) {
- $reason = "Cancellation feedback for {$subscription->team->id}: '" . $feedback . "'";
+ $reason = "Cancellation feedback for {$customerId}: '" . $feedback . "'";
if ($comment) {
$reason .= ' with comment: \'' . $comment . "'";
}
@@ -888,7 +898,7 @@ Route::post('/payments/stripe/events', function () {
if ($cancelAtPeriodEnd) {
// send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
} else {
- send_internal_notification('Subscription resumed for team: ' . $subscription->team->id);
+ send_internal_notification('customer.subscription.updated for customer: ' . $customerId);
}
}
break;
@@ -905,9 +915,10 @@ Route::post('/payments/stripe/events', function () {
'stripe_invoice_paid' => false,
'stripe_trial_already_ended' => true,
]);
- // send_internal_notification('Subscription cancelled: ' . $subscription->team->id);
+ send_internal_notification('customer.subscription.deleted for customer: ' . $customerId);
break;
case 'customer.subscription.trial_will_end':
+ // Not used for now
$customerId = data_get($data, 'customer');
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
$team = data_get($subscription, 'team');
@@ -929,7 +940,7 @@ Route::post('/payments/stripe/events', function () {
'stripe_invoice_paid' => false,
]);
SubscriptionTrialEndedJob::dispatch($team);
- send_internal_notification('Subscription paused for team: ' . $subscription->team->id);
+ send_internal_notification('Subscription paused for customer: ' . $customerId);
break;
default:
// Unhandled event type
diff --git a/versions.json b/versions.json
index c074128e2..bb86e0435 100644
--- a/versions.json
+++ b/versions.json
@@ -4,7 +4,7 @@
"version": "3.12.36"
},
"v4": {
- "version": "4.0.0-beta.209"
+ "version": "4.0.0-beta.210"
}
}
}