diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 7beaad19e..ef84b9abb 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -21,7 +21,7 @@ class Kernel extends HttpKernel \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, - // \App\Http\Middleware\LicenseValid::class, + \App\Http\Middleware\LicenseValid::class, ]; /** diff --git a/app/Http/Middleware/LicenseValid.php b/app/Http/Middleware/LicenseValid.php index 099092ff9..aeee9a5ac 100644 --- a/app/Http/Middleware/LicenseValid.php +++ b/app/Http/Middleware/LicenseValid.php @@ -16,7 +16,10 @@ class LicenseValid */ public function handle(Request $request, Closure $next): Response { - if (!config('coolify.self_hosted')) { + if (isCloud()) { + if (isDev()) { + return $next($request); + } $value = Cache::get('license_key'); if (!$value) { ray($request->path()); diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php new file mode 100644 index 000000000..380660b77 --- /dev/null +++ b/app/Models/Subscription.php @@ -0,0 +1,15 @@ +belongsTo(Team::class); + } +} diff --git a/app/Models/Team.php b/app/Models/Team.php index cf9a1f5cb..ad860dd72 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -66,7 +66,10 @@ class Team extends Model implements SendsDiscord, SendsEmail } - + public function subscription() + { + return $this->hasOne(Subscription::class); + } public function projects() { return $this->hasMany(Project::class); diff --git a/app/Models/Webhook.php b/app/Models/Webhook.php new file mode 100644 index 000000000..09afb9898 --- /dev/null +++ b/app/Models/Webhook.php @@ -0,0 +1,11 @@ +user()->id; + $email = auth()->user()->email ?? null; + $name = auth()->user()->name ?? null; + $url = "https://store.coollabs.io/checkout/buy/d0b28c6a-9b57-40bf-8b84-89fbafde6526?"; + if ($user_id) { + $url .= "checkout[custom][user_id]={$user_id}"; + } + if ($email) { + $url .= "?checkout[email]={$email}"; + } + if ($name) { + $url .= "&checkout[name]={$name}"; + } + $url = "?checkout[custom][user_id]={$user_id}&checkout[email]={$email}&checkout[name]={$name}"; + ray($url); + return $url; +} diff --git a/config/coolify.php b/config/coolify.php index 4e25c8745..044bb4563 100644 --- a/config/coolify.php +++ b/config/coolify.php @@ -2,6 +2,8 @@ return [ 'self_hosted' => env('SELF_HOSTED', true), + 'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET'), + 'lemon_squeezy_product_id' => env('LEMON_SQUEEZY_PRODUCT_ID'), 'mux_enabled' => env('MUX_ENABLED', true), 'dev_webhook' => env('SERVEO_URL'), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), diff --git a/database/migrations/2023_07_13_115117_create_subscriptions_table.php b/database/migrations/2023_07_13_115117_create_subscriptions_table.php new file mode 100644 index 000000000..e31fc1c3f --- /dev/null +++ b/database/migrations/2023_07_13_115117_create_subscriptions_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('lemon_order_id'); + $table->string('lemon_product_id'); + $table->string('lemon_variant_id'); + $table->string('lemon_customer_id'); + $table->string('lemon_status'); + $table->string('lemon_trial_ends_at'); + $table->string('lemon_renews_at'); + $table->string('lemon_ends_at'); + $table->string('lemon_update_payment_menthod_url'); + $table->foreignId('team_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('subscriptions'); + } +}; diff --git a/database/migrations/2023_07_13_120719_create_webhooks_table.php b/database/migrations/2023_07_13_120719_create_webhooks_table.php new file mode 100644 index 000000000..9376a10c9 --- /dev/null +++ b/database/migrations/2023_07_13_120719_create_webhooks_table.php @@ -0,0 +1,31 @@ +id(); + $table->enum('status', ['pending', 'success', 'failed'])->default('pending'); + $table->enum('type', ['github', 'gitlab', 'bitbucket', 'lemonsqueezy']); + $table->longText('payload'); + $table->longText('failure_reason')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('webhooks'); + } +}; diff --git a/database/seeders/SubscriptionSeeder.php b/database/seeders/SubscriptionSeeder.php new file mode 100644 index 000000000..e76d793a3 --- /dev/null +++ b/database/seeders/SubscriptionSeeder.php @@ -0,0 +1,17 @@ + @livewireStyles + diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index f9d5dd043..f194e4529 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -18,4 +18,6 @@
Applications, databases, etc...
+ {{-- Subscribe --}} + diff --git a/routes/webhooks.php b/routes/webhooks.php index f91f10656..5bfdbfde4 100644 --- a/routes/webhooks.php +++ b/routes/webhooks.php @@ -4,6 +4,7 @@ use App\Models\Application; use App\Models\ApplicationPreview; use App\Models\PrivateKey; use App\Models\GithubApp; +use App\Models\Webhook; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; @@ -170,3 +171,42 @@ Route::post('/source/github/events', function () { return general_error_handler(err: $e); } }); + +Route::post('/subscriptions/events', function () { + try { + $secret = config('coolify.lemon_squeezy_webhook_secret'); + $payload = request()->collect(); + $hash = hash_hmac('sha256', $payload, $secret); + $signature = ''; + + if (!hash_equals($hash, $signature)) { + return response('Invalid signature.', 400); + } + + $webhook = Webhook::create([ + 'type' => 'lemonsqueezy', + 'payload' => $payload + ]); + + $event = data_get($payload, 'meta.event_name'); + $email = data_get($payload, 'data.attributes.user_email'); + $update_payment_method = data_get($payload, 'data.attributes.urls.update_payment_method'); + switch ($event) { + case 'subscription_created': + + break; + } + + ray($payload); + $webhook->update([ + 'status' => 'success', + ]); + } catch (\Exception $e) { + $webhook->update([ + 'status' => 'failed', + 'failure_reason' => $e->getMessage() + ]); + } finally { + return response('OK'); + } +});