From 88b30055895a60669b3af1b9e5c1cc8884198116 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 15 Aug 2023 14:11:38 +0200 Subject: [PATCH] feat: force password reset + waitlist --- app/Console/Kernel.php | 3 + app/Http/Controllers/Controller.php | 10 ++++ app/Http/Kernel.php | 1 + app/Http/Livewire/ForcePasswordReset.php | 36 +++++++++++ app/Http/Livewire/Waitlist.php | 49 +++++++++++++++ .../Middleware/CheckForcePasswordReset.php | 29 +++++++++ .../Middleware/RedirectIfAuthenticated.php | 1 - app/Http/Middleware/SubscriptionValid.php | 4 +- app/Jobs/CleanupInstanceStuffsJob.php | 43 ++++++++++++++ app/Jobs/SendConfirmationForWaitlistJob.php | 59 +++++++++++++++++++ app/Models/User.php | 11 ++-- app/Models/Waitlist.php | 11 ++++ app/Providers/FortifyServiceProvider.php | 9 ++- bootstrap/helpers/shared.php | 6 +- config/constants.php | 7 ++- config/coolify.php | 1 + ...23_08_15_095902_create_waitlists_table.php | 31 ++++++++++ .../2023_08_15_111125_update_users_table.php | 28 +++++++++ database/seeders/WaitlistSeeder.php | 17 ++++++ .../views/auth/force-password-reset.blade.php | 3 + resources/views/auth/login.blade.php | 14 ++++- resources/views/auth/reset-password.blade.php | 9 ++- resources/views/auth/waitlist.blade.php | 3 + .../views/components/forms/input.blade.php | 5 +- .../views/components/layout-simple.blade.php | 15 +++++ .../application-deployment-failed.blade.php | 8 +++ .../emails/application-deployment-failed.php | 7 --- .../application-deployment-success.blade.php | 8 +++ .../emails/application-deployment-success.php | 7 --- .../views/emails/reset-password.blade.php | 4 +- .../emails/waitlist-confirmation.blade.php | 4 ++ .../livewire/force-password-reset.blade.php | 18 ++++++ resources/views/livewire/waitlist.blade.php | 23 ++++++++ routes/web.php | 3 + routes/webhooks.php | 39 +++++++++++- 35 files changed, 482 insertions(+), 44 deletions(-) create mode 100644 app/Http/Livewire/ForcePasswordReset.php create mode 100644 app/Http/Livewire/Waitlist.php create mode 100644 app/Http/Middleware/CheckForcePasswordReset.php create mode 100644 app/Jobs/CleanupInstanceStuffsJob.php create mode 100755 app/Jobs/SendConfirmationForWaitlistJob.php create mode 100644 app/Models/Waitlist.php create mode 100644 database/migrations/2023_08_15_095902_create_waitlists_table.php create mode 100644 database/migrations/2023_08_15_111125_update_users_table.php create mode 100644 database/seeders/WaitlistSeeder.php create mode 100644 resources/views/auth/force-password-reset.blade.php create mode 100644 resources/views/auth/waitlist.blade.php create mode 100644 resources/views/emails/application-deployment-failed.blade.php delete mode 100644 resources/views/emails/application-deployment-failed.php create mode 100644 resources/views/emails/application-deployment-success.blade.php delete mode 100644 resources/views/emails/application-deployment-success.php create mode 100644 resources/views/emails/waitlist-confirmation.blade.php create mode 100644 resources/views/livewire/force-password-reset.blade.php create mode 100644 resources/views/livewire/waitlist.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index f26b2ef4d..21c4de1d0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -4,6 +4,7 @@ use App\Jobs\CheckResaleLicenseJob; use App\Jobs\CheckResaleLicenseKeys; +use App\Jobs\CleanupInstanceStuffsJob; use App\Jobs\DatabaseBackupJob; use App\Jobs\DockerCleanupJob; use App\Jobs\InstanceApplicationsStatusJob; @@ -22,12 +23,14 @@ protected function schedule(Schedule $schedule): void $schedule->command('horizon:snapshot')->everyMinute(); $schedule->job(new InstanceApplicationsStatusJob)->everyMinute(); $schedule->job(new ProxyCheckJob)->everyFiveMinutes(); + $schedule->job(new CleanupInstanceStuffsJob)->everyMinute(); // $schedule->job(new CheckResaleLicenseJob)->hourly(); // $schedule->job(new DockerCleanupJob)->everyOddHour(); // $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute(); } else { $schedule->command('horizon:snapshot')->everyFiveMinutes(); + $schedule->job(new CleanupInstanceStuffsJob)->everyMinute(); $schedule->job(new InstanceApplicationsStatusJob)->everyMinute(); $schedule->job(new CheckResaleLicenseJob)->hourly(); $schedule->job(new ProxyCheckJob)->everyFiveMinutes(); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 9c39b3a03..84da5de2e 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -9,6 +9,7 @@ use App\Models\StandalonePostgresql; use App\Models\TeamInvitation; use App\Models\User; +use App\Models\Waitlist; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; @@ -18,6 +19,12 @@ class Controller extends BaseController { use AuthorizesRequests, ValidatesRequests; + public function waitlist() { + $waiting_in_line = Waitlist::whereVerified(true)->count(); + return view('auth.waitlist', [ + 'waiting_in_line' => $waiting_in_line, + ]); + } public function subscription() { if (!is_cloud()) { @@ -38,6 +45,9 @@ public function license() ]); } + public function force_passoword_reset() { + return view('auth.force-password-reset'); + } public function dashboard() { $projects = Project::ownedByCurrentTeam()->get(); diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 06777812f..57b5edfec 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -37,6 +37,7 @@ class Kernel extends HttpKernel \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, + \App\Http\Middleware\CheckForcePasswordReset::class, \App\Http\Middleware\SubscriptionValid::class, ], diff --git a/app/Http/Livewire/ForcePasswordReset.php b/app/Http/Livewire/ForcePasswordReset.php new file mode 100644 index 000000000..effceaa0f --- /dev/null +++ b/app/Http/Livewire/ForcePasswordReset.php @@ -0,0 +1,36 @@ + 'required|email', + 'password' => 'required|min:8', + 'password_confirmation' => 'required|same:password', + ]; + public function mount() { + $this->email = auth()->user()->email; + } + public function submit() { + try { + $this->validate(); + auth()->user()->forceFill([ + 'password' => Hash::make($this->password), + 'force_password_reset' => false, + ])->save(); + auth()->logout(); + return redirect()->route('login')->with('status', 'Your initial password has been set.'); + } catch(\Exception $e) { + return general_error_handler(err:$e, that:$this); + } + } + +} diff --git a/app/Http/Livewire/Waitlist.php b/app/Http/Livewire/Waitlist.php new file mode 100644 index 000000000..7f26351e1 --- /dev/null +++ b/app/Http/Livewire/Waitlist.php @@ -0,0 +1,49 @@ + 'required|email', + ]; + public function mount() + { + if (is_dev()) { + $this->email = 'test@example.com'; + } + } + public function submit() + { + $this->validate(); + try { + $found = ModelsWaitlist::where('email', $this->email)->first(); + ray($found); + if ($found) { + if (!$found->verified) { + $this->emit('error', 'You are already on the waitlist.
Please check your email to verify your email address.'); + return; + } + $this->emit('error', 'You are already on the waitlist.'); + return; + } + $waitlist = ModelsWaitlist::create([ + 'email' => $this->email, + 'type' => 'registration', + ]); + + $this->emit('success', 'You have been added to the waitlist.'); + dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid)); + } catch (\Exception $e) { + return general_error_handler(err: $e, that: $this); + } + + } +} diff --git a/app/Http/Middleware/CheckForcePasswordReset.php b/app/Http/Middleware/CheckForcePasswordReset.php new file mode 100644 index 000000000..8d1670de5 --- /dev/null +++ b/app/Http/Middleware/CheckForcePasswordReset.php @@ -0,0 +1,29 @@ +user()) { + $force_password_reset = auth()->user()->force_password_reset; + if ($force_password_reset) { + if ($request->routeIs('auth.force-password-reset') || $request->path() === 'livewire/message/force-password-reset') { + return $next($request); + } + return redirect()->route('auth.force-password-reset'); + } + } + return $next($request); + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index dae8398b7..3f17e6def 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -24,7 +24,6 @@ public function handle(Request $request, Closure $next, string ...$guards): Resp return redirect(RouteServiceProvider::HOME); } } - return $next($request); } } diff --git a/app/Http/Middleware/SubscriptionValid.php b/app/Http/Middleware/SubscriptionValid.php index 4c9d7b940..f84e6eede 100644 --- a/app/Http/Middleware/SubscriptionValid.php +++ b/app/Http/Middleware/SubscriptionValid.php @@ -10,7 +10,6 @@ class SubscriptionValid { public function handle(Request $request, Closure $next): Response { - if (!auth()->user() || !is_cloud()) { if ($request->path() === 'subscription') { return redirect('/'); @@ -36,7 +35,10 @@ public function handle(Request $request, Closure $next): Response 'subscription', 'login', 'register', + 'waitlist', + 'force-password-reset', 'logout', + 'livewire/message/force-password-reset', 'livewire/message/check-license', 'livewire/message/switch-team', ]; diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php new file mode 100644 index 000000000..7b3be1a44 --- /dev/null +++ b/app/Jobs/CleanupInstanceStuffsJob.php @@ -0,0 +1,43 @@ +container_name; + // } + + public function handle(): void + { + try { + $this->cleanup_waitlist(); + } catch (\Exception $e) { + ray($e->getMessage()); + } + } + + private function cleanup_waitlist() + { + $waitlist = Waitlist::whereVerified(false)->where('created_at', '<', now()->subMinutes(config('constants.waitlist.confirmation_valid_for_minutes')))->get(); + foreach ($waitlist as $item) { + $item->delete(); + } + } +} diff --git a/app/Jobs/SendConfirmationForWaitlistJob.php b/app/Jobs/SendConfirmationForWaitlistJob.php new file mode 100755 index 000000000..31098e180 --- /dev/null +++ b/app/Jobs/SendConfirmationForWaitlistJob.php @@ -0,0 +1,59 @@ +email . '&confirmation_code=' . $this->uuid; + $cancel_url = base_url() . '/webhooks/waitlist/cancel?email=' . $this->email . '&confirmation_code=' . $this->uuid; + + $mail->view('emails.waitlist-confirmation', + [ + 'confirmation_url' => $confirmation_url, + 'cancel_url' => $cancel_url, + ]); + $mail->subject('You are on the waitlist!'); + Mail::send( + [], + [], + fn(Message $message) => $message + ->from( + data_get($settings, 'smtp_from_address'), + data_get($settings, 'smtp_from_name') + ) + ->to($this->email) + ->subject($mail->subject) + ->html((string) $mail->render()) + ); + } catch (\Throwable $th) { + ray($th->getMessage()); + throw $th; + } + } +} diff --git a/app/Models/User.php b/app/Models/User.php index b37a070c3..f0a85d182 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Notifications\Channels\SendsEmail; +use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword; use App\Notifications\TrnsactionalEmails\ResetPassword; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -14,18 +15,14 @@ class User extends Authenticatable implements SendsEmail { use HasApiTokens, HasFactory, Notifiable, TwoFactorAuthenticatable; - protected $fillable = [ - 'id', - 'name', - 'email', - 'password', - ]; + protected $guarded = []; protected $hidden = [ 'password', 'remember_token', ]; protected $casts = [ 'email_verified_at' => 'datetime', + 'force_password_reset' => 'boolean', ]; protected static function boot() @@ -57,7 +54,7 @@ public function getRecepients($notification) public function sendPasswordResetNotification($token): void { - $this->notify(new ResetPassword($token)); + $this->notify(new TransactionalEmailsResetPassword($token)); } public function isAdmin() diff --git a/app/Models/Waitlist.php b/app/Models/Waitlist.php new file mode 100644 index 000000000..552c25eb3 --- /dev/null +++ b/app/Models/Waitlist.php @@ -0,0 +1,11 @@ +is_registration_enabled) { return redirect()->route('login'); } - return view('auth.register'); + if (config('coolify.waitlist')) { + return view('auth.waitlist'); + } else { + return view('auth.register'); + } }); Fortify::loginView(function () { diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 14b6ed75a..b2d279bac 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -101,9 +101,11 @@ function is_transactional_emails_active(): bool return data_get(InstanceSettings::get(), 'smtp_enabled'); } -function set_transanctional_email_settings(): void +function set_transanctional_email_settings(InstanceSettings|null $settings = null): void { - $settings = InstanceSettings::get(); + if (!$settings) { + $settings = InstanceSettings::get(); + } $password = data_get($settings, 'smtp_password'); if (isset($password)) { $password = decrypt($password); diff --git a/config/constants.php b/config/constants.php index 13097375e..6cb455265 100644 --- a/config/constants.php +++ b/config/constants.php @@ -1,5 +1,8 @@ [ + 'confirmation_valid_for_minutes' => 10, + ], 'invitation' => [ 'link' => [ 'base_url' => '/invitations/', @@ -11,6 +14,6 @@ 'basic' => 1, 'pro' => 3, 'ultimate' => 9999999999999999999, - ] - ] + ], + ], ]; diff --git a/config/coolify.php b/config/coolify.php index a933d12b4..0d4c50cb1 100644 --- a/config/coolify.php +++ b/config/coolify.php @@ -2,6 +2,7 @@ return [ 'self_hosted' => env('SELF_HOSTED', true), + 'waitlist' => env('WAITLIST', false), 'license_url' => 'https://license.coolify.io', 'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null), 'lemon_squeezy_checkout_id_monthly_basic' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_BASIC', null), diff --git a/database/migrations/2023_08_15_095902_create_waitlists_table.php b/database/migrations/2023_08_15_095902_create_waitlists_table.php new file mode 100644 index 000000000..641d152d1 --- /dev/null +++ b/database/migrations/2023_08_15_095902_create_waitlists_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('uuid'); + $table->string('type'); + $table->string('email')->unique(); + $table->boolean('verified')->default(false); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('waitlists'); + } +}; diff --git a/database/migrations/2023_08_15_111125_update_users_table.php b/database/migrations/2023_08_15_111125_update_users_table.php new file mode 100644 index 000000000..4453d39d4 --- /dev/null +++ b/database/migrations/2023_08_15_111125_update_users_table.php @@ -0,0 +1,28 @@ +boolean('force_password_reset')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('force_password_reset'); + }); + } +}; diff --git a/database/seeders/WaitlistSeeder.php b/database/seeders/WaitlistSeeder.php new file mode 100644 index 000000000..ce259253e --- /dev/null +++ b/database/seeders/WaitlistSeeder.php @@ -0,0 +1,17 @@ + + + diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 0a66be609..69204571c 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -8,9 +8,17 @@

{{ __('auth.login') }}

@if ($is_registration_enabled) - - {{ __('auth.register_now') }} - + @if (config('coolify.waitlist')) + + Join the waitlist + + @else + + {{ __('auth.register_now') }} + + @endif @endif
diff --git a/resources/views/auth/reset-password.blade.php b/resources/views/auth/reset-password.blade.php index dd58d4956..e1afe3443 100644 --- a/resources/views/auth/reset-password.blade.php +++ b/resources/views/auth/reset-password.blade.php @@ -1,14 +1,13 @@ -
+
-
-

{{ __('auth.reset_password') }}

+
+

{{ __('auth.reset_password') }}

@@ -16,7 +15,7 @@ -
+
+ + diff --git a/resources/views/components/forms/input.blade.php b/resources/views/components/forms/input.blade.php index 9f4bca9fb..a12366238 100644 --- a/resources/views/components/forms/input.blade.php +++ b/resources/views/components/forms/input.blade.php @@ -25,14 +25,15 @@ class="absolute inset-y-0 left-0 flex items-center pl-2 cursor-pointer hover:tex merge(['class' => $defaultClass . ' pl-10']) }} @required($required) wire:model.defer={{ $id }} wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled" type="{{ $type }}" - @readonly($readonly) @disabled($disabled) id="{{ $id }}" name="{{ $name }}"> + @readonly($readonly) @disabled($disabled) id="{{ $id }}" name="{{ $name }}" + placeholder="{{ $attributes->get('placeholder') }}">
@else merge(['class' => $defaultClass]) }} @required($required) @readonly($readonly) wire:model.defer={{ $id }} wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" wire:loading.attr="disabled" type="{{ $type }}" @disabled($disabled) - id="{{ $id }}" name="{{ $name }}"> + id="{{ $id }}" name="{{ $name }}" placeholder="{{ $attributes->get('placeholder') }}"> @endif @if (!$label && $helper) diff --git a/resources/views/components/layout-simple.blade.php b/resources/views/components/layout-simple.blade.php index e4481af85..cda1667a3 100644 --- a/resources/views/components/layout-simple.blade.php +++ b/resources/views/components/layout-simple.blade.php @@ -24,11 +24,25 @@ @livewireScripts +
{{ $slot }}
+ diff --git a/resources/views/emails/application-deployment-failed.blade.php b/resources/views/emails/application-deployment-failed.blade.php new file mode 100644 index 000000000..c9a35860d --- /dev/null +++ b/resources/views/emails/application-deployment-failed.blade.php @@ -0,0 +1,8 @@ +@if ($pull_request_id !== 0) + Pull Request #{{ $pull_request_id }} of {{ $name }} ({{ $fqdn }}) deployment failed: +@else + Deployment failed of {{ $name }} ({{ $fqdn }}): +@endif + +View Deployment Logs

diff --git a/resources/views/emails/application-deployment-failed.php b/resources/views/emails/application-deployment-failed.php deleted file mode 100644 index e201d9e11..000000000 --- a/resources/views/emails/application-deployment-failed.php +++ /dev/null @@ -1,7 +0,0 @@ -@if ($pull_request_id !== 0) -Pull Request #{{ $pull_request_id }} of {{ $name }} ({{ $fqdn }}) deployment failed: -@else -Deployment failed of {{ $name }} ({{ $fqdn }}): -@endif - -View Deployment Logs

\ No newline at end of file diff --git a/resources/views/emails/application-deployment-success.blade.php b/resources/views/emails/application-deployment-success.blade.php new file mode 100644 index 000000000..ae52aa913 --- /dev/null +++ b/resources/views/emails/application-deployment-success.blade.php @@ -0,0 +1,8 @@ +@if ($pull_request_id === 0) + A new version of {{ $fqdn }} is available: +@else + Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully: Application Link | +@endif +View + Deployment Logs

diff --git a/resources/views/emails/application-deployment-success.php b/resources/views/emails/application-deployment-success.php deleted file mode 100644 index 2fc84995e..000000000 --- a/resources/views/emails/application-deployment-success.php +++ /dev/null @@ -1,7 +0,0 @@ -@if ($pull_request_id === 0) -A new version of {{ $fqdn }} is available: -@else -Pull request #{{ $pull_request_id }} of {{ $name }} deployed successfully: Application Link | -@endif -View - Deployment Logs

\ No newline at end of file diff --git a/resources/views/emails/reset-password.blade.php b/resources/views/emails/reset-password.blade.php index 7a0c9788c..30c7b9429 100644 --- a/resources/views/emails/reset-password.blade.php +++ b/resources/views/emails/reset-password.blade.php @@ -1,8 +1,6 @@ -Hello,

- A password reset requested for your email address on "{{ config('app.name') }}".

Please click the following link to reset your password: Password Reset

-This password reset link will expire in "{{ $count }}" minutes. +This password reset link will expire in {{ $count }} minutes. diff --git a/resources/views/emails/waitlist-confirmation.blade.php b/resources/views/emails/waitlist-confirmation.blade.php new file mode 100644 index 000000000..44aac5f74 --- /dev/null +++ b/resources/views/emails/waitlist-confirmation.blade.php @@ -0,0 +1,4 @@ +Someone added this email to the Coolify Cloud's waitlist. +
+Click here to confirm! The link will expire in {{config('constants.waitlist.confirmation_valid_for_minutes')}} minutes.

+You have no idea what Coolify Cloud is or this waitlist? Click here to remove you from the waitlist. diff --git a/resources/views/livewire/force-password-reset.blade.php b/resources/views/livewire/force-password-reset.blade.php new file mode 100644 index 000000000..c2ecbf098 --- /dev/null +++ b/resources/views/livewire/force-password-reset.blade.php @@ -0,0 +1,18 @@ +
+
+ +
+

Set your initial password

+
+ + + + + Reset Password + +
+
diff --git a/resources/views/livewire/waitlist.blade.php b/resources/views/livewire/waitlist.blade.php new file mode 100644 index 000000000..64eff5def --- /dev/null +++ b/resources/views/livewire/waitlist.blade.php @@ -0,0 +1,23 @@ +
+
+
+

Start self-hosting in the + + + + + + +

+
+
+ + Join Waitlist + + Waiting: {{$waiting_in_line}} +
+
diff --git a/routes/web.php b/routes/web.php index 91acfa7db..dfe98f0d6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -38,6 +38,8 @@ } return response()->json(['message' => 'Transactional emails are not active'], 400); })->name('password.forgot'); +Route::get('/waitlist', [Controller::class, 'waitlist'])->name('auth.waitlist'); + Route::prefix('magic')->middleware(['auth'])->group(function () { Route::get('/servers', [MagicController::class, 'servers']); Route::get('/destinations', [MagicController::class, 'destinations']); @@ -91,6 +93,7 @@ Route::middleware(['auth'])->group(function () { Route::get('/', [Controller::class, 'dashboard'])->name('dashboard'); + Route::get('/force-password-reset', [Controller::class, 'force_passoword_reset'])->name('auth.force-password-reset'); Route::get('/subscription', [Controller::class, 'subscription'])->name('subscription'); Route::get('/settings', [Controller::class, 'settings'])->name('settings.configuration'); Route::get('/settings/license', [Controller::class, 'license'])->name('settings.license'); diff --git a/routes/webhooks.php b/routes/webhooks.php index eff2cb639..0739c1c38 100644 --- a/routes/webhooks.php +++ b/routes/webhooks.php @@ -6,6 +6,7 @@ use App\Models\PrivateKey; use App\Models\Subscription; use App\Models\Team; +use App\Models\Waitlist; use App\Models\Webhook; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Route; @@ -139,7 +140,7 @@ ApplicationPreview::create([ 'application_id' => $application->id, 'pull_request_id' => $pull_request_id, - 'pull_request_html_url' => $pull_request_html_url + 'pull_request_html_url' => $pull_request_html_url, ]); } queue_application_deployment( @@ -175,6 +176,38 @@ }); if (is_cloud()) { + Route::get('/waitlist/confirm', function () { + $email = request()->get('email'); + $confirmation_code = request()->get('confirmation_code'); + ray($email, $confirmation_code); + try { + $found = Waitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); + if ($found && !$found->verified && $found->created_at > now()->subMinutes(config('constants.waitlist.confirmation_valid_for_minutes'))) { + $found->verified = true; + $found->save(); + return 'Thank you for confirming your email address. We will notify you when you are next in line.'; + } + return redirect()->route('dashboard'); + } catch (error) { + return redirect()->route('dashboard'); + } + + })->name('webhooks.waitlist.confirm'); + Route::get('/waitlist/cancel', function () { + $email = request()->get('email'); + $confirmation_code = request()->get('confirmation_code'); + try { + $found = Waitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); + if ($found && !$found->verified) { + $found->delete(); + return 'Your email address has been removed from the waitlist.'; + } + return redirect()->route('dashboard'); + } catch (error) { + return redirect()->route('dashboard'); + } + + })->name('webhooks.waitlist.cancel'); Route::post('/payments/events', function () { try { $secret = config('coolify.lemon_squeezy_webhook_secret'); @@ -188,7 +221,7 @@ $webhook = Webhook::create([ 'type' => 'lemonsqueezy', - 'payload' => $payload + 'payload' => $payload, ]); $event = data_get($payload, 'meta.event_name'); ray('Subscription event: ' . $event); @@ -256,7 +289,7 @@ ray($e->getMessage()); $webhook->update([ 'status' => 'failed', - 'failure_reason' => $e->getMessage() + 'failure_reason' => $e->getMessage(), ]); } finally { return response('OK');