From 45b736bb0161e4964e9e2c76a14b86e90a6469cc Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 6 Feb 2024 11:11:26 +0100 Subject: [PATCH 1/2] fix: stripe webhooks --- bootstrap/helpers/shared.php | 4 +--- config/sentry.php | 2 +- config/version.php | 2 +- routes/webhooks.php | 43 ++++++++++++++++++++++-------------- versions.json | 2 +- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index ad64b2550..a6d8a4ae5 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -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/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 @@ 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" } } } From b96807d34c5ca826120ae7ee10081c8f4dbcf2c9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 6 Feb 2024 11:36:20 +0100 Subject: [PATCH 2/2] fix: feedback from self-hosted envs to discord --- app/Livewire/Help.php | 23 +++++++++++++++---- bootstrap/helpers/shared.php | 2 +- config/coolify.php | 1 + docker-compose.prod.yml | 1 + .../components/navbar-subscription.blade.php | 5 ++-- resources/views/components/navbar.blade.php | 7 +++--- resources/views/layouts/boarding.blade.php | 5 ++-- resources/views/livewire/help.blade.php | 2 +- routes/api.php | 13 +++++++++++ 9 files changed, 42 insertions(+), 17 deletions(-) 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 a6d8a4ae5..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."; } 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/docker-compose.prod.yml b/docker-compose.prod.yml index 0961fad03..b4b81530c 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -46,6 +46,7 @@ services: - PUSHER_APP_SECRET - AUTOUPDATE - SELF_HOSTED + - FEEDBACK_DISCORD_WEBHOOK - WAITLIST - SUBSCRIPTION_PROVIDER - STRIPE_API_KEY diff --git a/resources/views/components/navbar-subscription.blade.php b/resources/views/components/navbar-subscription.blade.php index 8638430e5..084e778fb 100644 --- a/resources/views/components/navbar-subscription.blade.php +++ b/resources/views/components/navbar-subscription.blade.php @@ -26,11 +26,10 @@
  • - + + 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
  • 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 () {