From e4279bf257865f56907a377405e7fcd2c573356f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 14 Aug 2023 15:22:29 +0200 Subject: [PATCH] feat: cloud --- app/Http/Controllers/ServerController.php | 24 ++++++++ app/Http/Livewire/Server/New/ByIp.php | 1 + app/Http/Middleware/SubscriptionValid.php | 50 +++++++++------- app/Models/Subscription.php | 18 ++++++ bootstrap/helpers/subscriptions.php | 37 ++++++++++-- config/constants.php | 7 +++ config/coolify.php | 13 +++- docker-compose.prod.yml | 11 +++- .../components/layout-subscription.blade.php | 2 +- .../views/components/limit-reached.blade.php | 6 ++ .../views/components/pricing-plans.blade.php | 6 +- .../views/livewire/server/new/by-ip.blade.php | 59 ++++++++++--------- resources/views/server/all.blade.php | 5 ++ resources/views/server/create.blade.php | 2 +- resources/views/team/show.blade.php | 12 +++- resources/views/team/storages/all.blade.php | 5 +- routes/web.php | 5 +- 17 files changed, 189 insertions(+), 74 deletions(-) create mode 100644 app/Http/Controllers/ServerController.php create mode 100644 resources/views/components/limit-reached.blade.php diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php new file mode 100644 index 000000000..1a5876c81 --- /dev/null +++ b/app/Http/Controllers/ServerController.php @@ -0,0 +1,24 @@ +user()->currentTeam()->servers->count(); + $subscription = auth()->user()->currentTeam()->subscription->type(); + $limits = config('constants.limits.server')[strtolower($subscription)]; + $limit_reached = true ?? $servers >= $limits[$subscription]; + return view('server.create', [ + 'limit_reached' => $limit_reached, + 'private_keys' => PrivateKey::ownedByCurrentTeam()->get(), + ]); + } +} diff --git a/app/Http/Livewire/Server/New/ByIp.php b/app/Http/Livewire/Server/New/ByIp.php index 233ea157d..c4f340413 100644 --- a/app/Http/Livewire/Server/New/ByIp.php +++ b/app/Http/Livewire/Server/New/ByIp.php @@ -8,6 +8,7 @@ class ByIp extends Component { public $private_keys; + public $limit_reached; public int|null $private_key_id = null; public $new_private_key_name; public $new_private_key_description; diff --git a/app/Http/Middleware/SubscriptionValid.php b/app/Http/Middleware/SubscriptionValid.php index c63c6d823..7d6cd5cfa 100644 --- a/app/Http/Middleware/SubscriptionValid.php +++ b/app/Http/Middleware/SubscriptionValid.php @@ -8,32 +8,38 @@ class SubscriptionValid { - public function handle(Request $request, Closure $next): Response { - if (auth()->user()) { - if (is_cloud() && !isSubscribed()) { - ray('SubscriptionValid Middleware'); + $is_instance_admin = auth()->user()?->isInstanceAdmin(); - $allowed_paths = [ - 'subscription', - 'login', - 'register', - 'logout', - 'livewire/message/check-license', - 'livewire/message/switch-team', - ]; - if (!in_array($request->path(), $allowed_paths)) { - return redirect('subscription'); - } else { - return $next($request); - } + if (!auth()->user() || !is_cloud()) { + if ($request->path() === 'subscription' && !$is_instance_admin) { + return redirect('/'); } else { - if ($request->path() === 'subscription' && !auth()->user()->isInstanceAdmin()) { - return redirect('/'); - } else { - return $next($request); - } + return $next($request); + } + } + if (is_subscription_active() && $request->path() === 'subscription' && !$is_instance_admin) { + return redirect('/'); + } + if (is_subscription_in_grace_period()) { + return $next($request); + } + if (!is_subscription_active() && !is_subscription_in_grace_period()) { + ray('SubscriptionValid Middleware'); + + $allowed_paths = [ + 'subscription', + 'login', + 'register', + 'logout', + 'livewire/message/check-license', + 'livewire/message/switch-team', + ]; + if (!in_array($request->path(), $allowed_paths)) { + return redirect('subscription'); + } else { + return $next($request); } } return $next($request); diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 89c4264cb..4b78c37a9 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -12,4 +12,22 @@ public function team() { return $this->belongsTo(Team::class); } + public function type() + { + $basic = explode(',', config('coolify.lemon_squeezy_basic_plan_ids')); + $pro = explode(',', config('coolify.lemon_squeezy_pro_plan_ids')); + $ultimate = explode(',', config('coolify.lemon_squeezy_ultimate_plan_ids')); + + $subscription = $this->lemon_variant_id; + if (in_array($subscription, $basic)) { + return 'basic'; + } + if (in_array($subscription, $pro)) { + return 'pro'; + } + if (in_array($subscription, $ultimate)) { + return 'ultimate'; + } + return 'unknown'; + } } diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php index 64cf9b24c..d362591b7 100644 --- a/bootstrap/helpers/subscriptions.php +++ b/bootstrap/helpers/subscriptions.php @@ -43,11 +43,36 @@ function getEndDate() return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s'); } -function isSubscribed() +function is_subscription_active() { - return - auth()->user()?->currentTeam()?->subscription?->lemon_status === 'active' || - (auth()->user()?->currentTeam()?->subscription?->lemon_ends_at && - Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_ends_at) > Carbon::now() - ) || auth()->user()->isInstanceAdmin(); + $team = auth()->user()?->currentTeam(); + if (!$team) { + return false; + } + $subscription = $team?->subscription; + if (!$subscription) { + return false; + } + + $is_active = $subscription->lemon_status === 'active'; + $is_instance_admin = auth()->user()->isInstanceAdmin(); + ray($is_instance_admin); + + return $is_active || $is_instance_admin; +} +function is_subscription_in_grace_period() +{ + $team = auth()->user()?->currentTeam(); + if (!$team) { + return false; + } + $subscription = $team?->subscription; + if (!$subscription) { + return false; + } + $is_instance_admin = auth()->user()->isInstanceAdmin(); + $is_still_grace_period = $subscription->lemon_ends_at && + Carbon::parse($subscription->lemon_ends_at) > Carbon::now(); + + return $is_still_grace_period || $is_instance_admin; } diff --git a/config/constants.php b/config/constants.php index a3c88c8e8..13097375e 100644 --- a/config/constants.php +++ b/config/constants.php @@ -6,4 +6,11 @@ 'expiration' => 10, ], ], + 'limits' => [ + 'server' => [ + 'basic' => 1, + 'pro' => 3, + 'ultimate' => 9999999999999999999, + ] + ] ]; diff --git a/config/coolify.php b/config/coolify.php index 51536284a..a933d12b4 100644 --- a/config/coolify.php +++ b/config/coolify.php @@ -3,9 +3,16 @@ return [ 'self_hosted' => env('SELF_HOSTED', true), 'license_url' => 'https://license.coolify.io', - 'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET'), - 'lemon_squeezy_checkout_id_monthly' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY'), - 'lemon_squeezy_checkout_id_yearly' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY'), + 'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET', null), + 'lemon_squeezy_checkout_id_monthly_basic' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_BASIC', null), + 'lemon_squeezy_checkout_id_monthly_pro' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_PRO', null), + 'lemon_squeezy_checkout_id_monthly_ultimate' => env('LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_ULTIMATE', null), + 'lemon_squeezy_checkout_id_yearly_basic' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_BASIC', null), + 'lemon_squeezy_checkout_id_yearly_pro' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_PRO', null), + 'lemon_squeezy_checkout_id_yearly_ultimate' => env('LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_ULTIMATE', null), + 'lemon_squeezy_basic_plan_ids' => env('LEMON_SQUEEZY_BASIC_PLAN_IDS', ""), + 'lemon_squeezy_pro_plan_ids' => env('LEMON_SQUEEZY_PRO_PLAN_IDS', ""), + 'lemon_squeezy_ultimate_plan_ids' => env('LEMON_SQUEEZY_ULTIMATE_PLAN_IDS', ""), 'mux_enabled' => env('MUX_ENABLED', true), 'dev_webhook' => env('SERVEO_URL'), 'base_config_path' => env('BASE_CONFIG_PATH', '/_data/coolify'), diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index ae6b74e19..063d1e257 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -34,8 +34,15 @@ services: - PHP_PM_MAX_SPARE_SERVERS=10 - SELF_HOSTED - LEMON_SQUEEZY_WEBHOOK_SECRET - - LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY - - LEMON_SQUEEZY_CHECKOUT_ID_YEARLY + - LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_BASIC + - LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_PRO + - LEMON_SQUEEZY_CHECKOUT_ID_MONTHLY_ULTIMATE + - LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_BASIC + - LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_PRO + - LEMON_SQUEEZY_CHECKOUT_ID_YEARLY_ULTIMATE + - LEMON_SQUEEZY_BASIC_PLAN_IDS + - LEMON_SQUEEZY_PRO_PLAN_IDS + - LEMON_SQUEEZY_ULTIMATE_PLAN_IDS ports: - "${APP_PORT:-8000}:80" expose: diff --git a/resources/views/components/layout-subscription.blade.php b/resources/views/components/layout-subscription.blade.php index d693b20cb..b2b8f67de 100644 --- a/resources/views/components/layout-subscription.blade.php +++ b/resources/views/components/layout-subscription.blade.php @@ -25,7 +25,7 @@ @livewireScripts - @if (auth()->user()->isInstanceAdmin()) + @if (auth()->user()->isInstanceAdmin() || is_subscription_in_grace_period())
diff --git a/resources/views/components/limit-reached.blade.php b/resources/views/components/limit-reached.blade.php new file mode 100644 index 000000000..c2c4b4b0e --- /dev/null +++ b/resources/views/components/limit-reached.blade.php @@ -0,0 +1,6 @@ +
+ You have reached the limit of {{ $name }} you can create. + Please upgrade your + subscription to create more + {{ $name }}. +
diff --git a/resources/views/components/pricing-plans.blade.php b/resources/views/components/pricing-plans.blade.php index 5ae2cacdd..5ccde5e23 100644 --- a/resources/views/components/pricing-plans.blade.php +++ b/resources/views/components/pricing-plans.blade.php @@ -111,7 +111,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap (save $6) Subscribe + href="{{ getSubscriptionLink('monthly_basic') }}">Subscribe Subscribe

Start self-hosting in @@ -185,7 +185,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap

(save $29) Subscribe + href="{{ getSubscriptionLink('monthly_pro') }}">Subscribe Subscribe

Scale your business or self-hosting environment. @@ -255,7 +255,7 @@ class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-coolgray-500 isolate gap

(save $69) Subscribe + href="{{ getSubscriptionLink('monthly_ultimate') }}">Subscribe Subscribe

Deploy complex infrastuctures and diff --git a/resources/views/livewire/server/new/by-ip.blade.php b/resources/views/livewire/server/new/by-ip.blade.php index 77ab1abb8..2c84e6cf3 100644 --- a/resources/views/livewire/server/new/by-ip.blade.php +++ b/resources/views/livewire/server/new/by-ip.blade.php @@ -1,29 +1,34 @@

-

Create a new Server

-
Servers are the main blocks of your infrastructure.
-
-
- - -
-
- - - -
- - - @foreach ($private_keys as $key) - @if ($loop->first) - - @else - - @endif - @endforeach - - - Save New Server - -
+ @if ($limit_reached) + + @else +

Create a new Server

+
Servers are the main blocks of your infrastructure.
+
+
+ + +
+
+ + + +
+ + + @foreach ($private_keys as $key) + @if ($loop->first) + + @else + + @endif + @endforeach + + + Save New Server + +
+ + @endif
diff --git a/resources/views/server/all.blade.php b/resources/views/server/all.blade.php index 0c3972b0f..afa223b91 100644 --- a/resources/views/server/all.blade.php +++ b/resources/views/server/all.blade.php @@ -35,6 +35,11 @@ @endforelse + @isset($error) +
+ {{ $error }} +
+ @endisset