wip
This commit is contained in:
64
app/Actions/License/CheckResaleLicense.php
Normal file
64
app/Actions/License/CheckResaleLicense.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\License;
|
||||||
|
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
|
class CheckResaleLicense
|
||||||
|
{
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$settings = InstanceSettings::get();
|
||||||
|
$instance_id = config('app.id');
|
||||||
|
if (!$settings->resale_license) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ray('Checking license key');
|
||||||
|
$data = Http::withHeaders([
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
])->post('https://api.lemonsqueezy.com/v1/licenses/validate', [
|
||||||
|
'license_key' => $settings->resale_license,
|
||||||
|
'instance_name' => $instance_id,
|
||||||
|
])->throw()->json();
|
||||||
|
$product_id = data_get($data, 'meta.product_id');
|
||||||
|
|
||||||
|
if (isDev()) {
|
||||||
|
$valid_product_id = 93221;
|
||||||
|
} else {
|
||||||
|
$valid_product_id = 93222;
|
||||||
|
}
|
||||||
|
if ($product_id !== $valid_product_id) {
|
||||||
|
throw new \Exception('Invalid product id');
|
||||||
|
}
|
||||||
|
ray('Valid Product Id');
|
||||||
|
|
||||||
|
['valid' => $valid, 'license_key' => $license_key] = $data;
|
||||||
|
|
||||||
|
if ($valid) {
|
||||||
|
if (data_get($license_key, 'status') === 'inactive') {
|
||||||
|
Http::withHeaders([
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
])->post('https://api.lemonsqueezy.com/v1/licenses/activate', [
|
||||||
|
'license_key' => $settings->resale_license,
|
||||||
|
'instance_name' => $instance_id,
|
||||||
|
])->throw()->json();
|
||||||
|
}
|
||||||
|
$settings->update([
|
||||||
|
'is_resale_license_active' => true,
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new \Exception('Invalid license key');
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
ray($th);
|
||||||
|
$settings->update([
|
||||||
|
'resale_license' => null,
|
||||||
|
'is_resale_license_active' => false,
|
||||||
|
]);
|
||||||
|
throw $th;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
|
use App\Jobs\CheckResaleLicenseJob;
|
||||||
use App\Jobs\InstanceAutoUpdateJob;
|
use App\Jobs\InstanceAutoUpdateJob;
|
||||||
use App\Jobs\ProxyCheckJob;
|
use App\Jobs\ProxyCheckJob;
|
||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
|
use App\Jobs\CheckResaleLicenseKeys;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ class Kernel extends ConsoleKernel
|
|||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$schedule->command('horizon:snapshot')->everyMinute();
|
$schedule->command('horizon:snapshot')->everyMinute();
|
||||||
|
$schedule->job(new CheckResaleLicenseJob)->everyMinute();
|
||||||
$schedule->job(new DockerCleanupJob)->everyOddHour();
|
$schedule->job(new DockerCleanupJob)->everyOddHour();
|
||||||
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
|
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
|
||||||
} else {
|
} else {
|
||||||
@@ -29,4 +32,4 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
require base_path('routes/console.php');
|
require base_path('routes/console.php');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,9 +17,11 @@ class Controller extends BaseController
|
|||||||
{
|
{
|
||||||
use AuthorizesRequests, ValidatesRequests;
|
use AuthorizesRequests, ValidatesRequests;
|
||||||
|
|
||||||
public function license()
|
public function subscription()
|
||||||
{
|
{
|
||||||
return view('license');
|
return view('subscription', [
|
||||||
|
'settings' => InstanceSettings::get()
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
public function dashboard()
|
public function dashboard()
|
||||||
{
|
{
|
||||||
|
@@ -21,7 +21,6 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
\App\Http\Middleware\LicenseValid::class,
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
42
app/Http/Livewire/CheckLicense.php
Normal file
42
app/Http/Livewire/CheckLicense.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use App\Actions\License\CheckResaleLicense;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class CheckLicense extends Component
|
||||||
|
{
|
||||||
|
public InstanceSettings|null $settings = null;
|
||||||
|
public string|null $instance_id = null;
|
||||||
|
protected $rules = [
|
||||||
|
'settings.resale_license' => 'nullable',
|
||||||
|
'settings.is_resale_license_active' => 'nullable',
|
||||||
|
];
|
||||||
|
protected $validationAttributes = [
|
||||||
|
'settings.resale_license' => 'License',
|
||||||
|
'instance_id' => 'Instance Id (Do not change this)',
|
||||||
|
'settings.is_resale_license_active' => 'Is License Active',
|
||||||
|
];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->instance_id = config('app.id');
|
||||||
|
$this->settings = InstanceSettings::get();
|
||||||
|
}
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
$this->settings->save();
|
||||||
|
if ($this->settings->resale_license) {
|
||||||
|
try {
|
||||||
|
resolve(CheckResaleLicense::class)();
|
||||||
|
$this->emit('reloadWindow');
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
session()->flash('error', 'License is not valid. Please contact support.');
|
||||||
|
ray($th->getMessage());
|
||||||
|
return redirect()->to('/subscription');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -5,6 +5,7 @@ namespace App\Http\Livewire\Settings;
|
|||||||
use App\Jobs\ProxyCheckJob;
|
use App\Jobs\ProxyCheckJob;
|
||||||
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
use App\Models\InstanceSettings as ModelsInstanceSettings;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
@@ -21,11 +22,13 @@ class Configuration extends Component
|
|||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'settings.fqdn' => 'nullable',
|
'settings.fqdn' => 'nullable',
|
||||||
|
'settings.resale_license' => 'nullable',
|
||||||
'settings.public_port_min' => 'required',
|
'settings.public_port_min' => 'required',
|
||||||
'settings.public_port_max' => 'required',
|
'settings.public_port_max' => 'required',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'settings.fqdn' => 'FQDN',
|
'settings.fqdn' => 'FQDN',
|
||||||
|
'settings.resale_license' => 'Resale License',
|
||||||
'settings.public_port_min' => 'Public port min',
|
'settings.public_port_min' => 'Public port min',
|
||||||
'settings.public_port_max' => 'Public port max',
|
'settings.public_port_max' => 'Public port max',
|
||||||
];
|
];
|
||||||
|
@@ -16,15 +16,21 @@ class LicenseValid
|
|||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if (isCloud() && !isDev()) {
|
if (isCloud()) {
|
||||||
$value = Cache::get('license_key');
|
$value = Cache::get('license_key');
|
||||||
|
if (isDev()) {
|
||||||
|
$value = true;
|
||||||
|
}
|
||||||
if (!$value) {
|
if (!$value) {
|
||||||
ray($request->path());
|
|
||||||
if ($request->path() !== 'license' && $request->path() !== 'livewire/message/license') {
|
if ($request->path() !== 'license' && $request->path() !== 'livewire/message/license') {
|
||||||
return redirect('license');
|
return redirect('license');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ($request->path() === 'license' || $request->path() === 'livewire/message/license') {
|
||||||
|
return redirect('home');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,33 +4,34 @@ namespace App\Http\Middleware;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class SubscriptionValid
|
class SubscriptionValid
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
$allowed_paths = [
|
$allowed_paths = [
|
||||||
'team',
|
'subscription',
|
||||||
'livewire/message/team',
|
|
||||||
'login',
|
'login',
|
||||||
'register',
|
'register',
|
||||||
'livewire/message/switch-team',
|
|
||||||
'logout',
|
'logout',
|
||||||
|
'livewire/message/check-license',
|
||||||
|
'livewire/message/switch-team',
|
||||||
];
|
];
|
||||||
if (isCloud()) {
|
if (isCloud() && !isSubscribed()) {
|
||||||
if (!$request->user()?->currentTeam()?->subscription && $request->user()?->currentTeam()->subscription?->lemon_status !== 'active') {
|
ray('SubscriptionValid Middleware');
|
||||||
if (!in_array($request->path(), $allowed_paths)) {
|
if (!in_array($request->path(), $allowed_paths)) {
|
||||||
return redirect('team');
|
return redirect('subscription');
|
||||||
|
} else {
|
||||||
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ($request->path() === 'subscription') {
|
||||||
|
return redirect('/');
|
||||||
|
} else {
|
||||||
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $next($request);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
app/Jobs/CheckResaleLicenseJob.php
Normal file
32
app/Jobs/CheckResaleLicenseJob.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\License\CheckResaleLicense;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
|
class CheckResaleLicenseJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
resolve(CheckResaleLicense::class)();
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
ray($th);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,7 @@ use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
|||||||
class InstanceSettings extends Model implements SendsEmail
|
class InstanceSettings extends Model implements SendsEmail
|
||||||
{
|
{
|
||||||
use Notifiable, SchemalessAttributesTrait;
|
use Notifiable, SchemalessAttributesTrait;
|
||||||
|
protected $guarded = [];
|
||||||
protected $schemalessAttributes = [
|
protected $schemalessAttributes = [
|
||||||
'smtp',
|
'smtp',
|
||||||
];
|
];
|
||||||
|
@@ -61,7 +61,8 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
{
|
{
|
||||||
return $this->email;
|
return $this->email;
|
||||||
}
|
}
|
||||||
public function isAdmin() {
|
public function isAdmin()
|
||||||
|
{
|
||||||
return $this->pivot->role === 'admin' || $this->pivot->role === 'owner';
|
return $this->pivot->role === 'admin' || $this->pivot->role === 'owner';
|
||||||
}
|
}
|
||||||
public function isAdminFromSession()
|
public function isAdminFromSession()
|
||||||
@@ -91,7 +92,8 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
});
|
});
|
||||||
return $found_root_team->count() > 0;
|
return $found_root_team->count() > 0;
|
||||||
}
|
}
|
||||||
public function personalTeam() {
|
public function personalTeam()
|
||||||
|
{
|
||||||
return $this->teams()->where('personal_team', true)->first();
|
return $this->teams()->where('personal_team', true)->first();
|
||||||
}
|
}
|
||||||
public function teams()
|
public function teams()
|
||||||
|
@@ -130,5 +130,5 @@ function isDev()
|
|||||||
}
|
}
|
||||||
function isCloud()
|
function isCloud()
|
||||||
{
|
{
|
||||||
return !config('coolify.self_hosted');
|
return (bool)config('coolify.self_hosted') === false;
|
||||||
}
|
}
|
||||||
|
@@ -23,12 +23,21 @@ function getSubscriptionLink()
|
|||||||
}
|
}
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
function getPaymentLink() {
|
function getPaymentLink()
|
||||||
|
{
|
||||||
return auth()->user()->currentTeam()->subscription->lemon_update_payment_menthod_url;
|
return auth()->user()->currentTeam()->subscription->lemon_update_payment_menthod_url;
|
||||||
}
|
}
|
||||||
function getRenewDate() {
|
function getRenewDate()
|
||||||
|
{
|
||||||
return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_renews_at)->format('Y-M-d H:i:s');
|
||||||
}
|
}
|
||||||
function isSubscribed() {
|
function getEndDate()
|
||||||
return isCloud() && auth()->user()->currentTeam()->subscription?->lemon_status === 'active';
|
{
|
||||||
}
|
return Carbon::parse(auth()->user()->currentTeam()->subscription->lemon_ends_at)->format('Y-M-d H:i:s');
|
||||||
|
}
|
||||||
|
function isSubscribed()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
@@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Facade;
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
'id' => env('APP_ID'),
|
||||||
'port' => env('APP_PORT', 8000),
|
'port' => env('APP_PORT', 8000),
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@@ -3,9 +3,8 @@
|
|||||||
return [
|
return [
|
||||||
'self_hosted' => env('SELF_HOSTED', true),
|
'self_hosted' => env('SELF_HOSTED', true),
|
||||||
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET'),
|
'lemon_squeezy_webhook_secret' => env('LEMON_SQUEEZY_WEBHOOK_SECRET'),
|
||||||
'lemon_squeezy_product_id' => env('LEMON_SQUEEZY_PRODUCT_ID'),
|
|
||||||
'mux_enabled' => env('MUX_ENABLED', true),
|
'mux_enabled' => env('MUX_ENABLED', true),
|
||||||
'dev_webhook' => env('SERVEO_URL'),
|
'dev_webhook' => env('SERVEO_URL'),
|
||||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||||
'proxy_config_path' => env('BASE_CONFIG_PATH', '/data/coolify') . "/proxy",
|
'proxy_config_path' => env('BASE_CONFIG_PATH', '/data/coolify') . "/proxy",
|
||||||
];
|
];
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('instance_settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_resale_license_active')->default(false);
|
||||||
|
$table->string('resale_license')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('instance_settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_resale_license_active');
|
||||||
|
$table->dropColumn('resale_license');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -16,7 +16,6 @@ class TeamSeeder extends Seeder
|
|||||||
$root_user_personal_team->save();
|
$root_user_personal_team->save();
|
||||||
|
|
||||||
$normal_user_in_root_team->teams()->attach($root_user_personal_team);
|
$normal_user_in_root_team->teams()->attach($root_user_personal_team);
|
||||||
|
|
||||||
$normal_user_not_in_root_team = User::find(2);
|
$normal_user_not_in_root_team = User::find(2);
|
||||||
$normal_user_in_root_team_personal_team = Team::find(1);
|
$normal_user_in_root_team_personal_team = Team::find(1);
|
||||||
$normal_user_not_in_root_team->teams()->attach($normal_user_in_root_team_personal_team, ['role' => 'admin']);
|
$normal_user_not_in_root_team->teams()->attach($normal_user_in_root_team_personal_team, ['role' => 'admin']);
|
||||||
|
40
resources/views/components/layout-subscription.blade.php
Normal file
40
resources/views/components/layout-subscription.blade.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="preconnect" href="https://api.fonts.coollabs.io" crossorigin>
|
||||||
|
<link href="https://api.fonts.coollabs.io/css2?family=Inter&display=swap" rel="stylesheet">
|
||||||
|
@env('local')
|
||||||
|
<title>Coolify - localhost</title>
|
||||||
|
@endenv
|
||||||
|
@env('production')
|
||||||
|
<title>{{ $title ?? 'Coolify' }}</title>
|
||||||
|
@endenv
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
||||||
|
<style>
|
||||||
|
[x-cloak] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@livewireStyles
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
@livewireScripts
|
||||||
|
<x-toaster-hub />
|
||||||
|
<x-navbar-subscription />
|
||||||
|
<main class="main">
|
||||||
|
{{ $slot }}
|
||||||
|
</main>
|
||||||
|
<x-version class="fixed left-2 bottom-1" />
|
||||||
|
<script>
|
||||||
|
Livewire.on('reloadWindow', () => {
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@@ -30,11 +30,9 @@
|
|||||||
@auth
|
@auth
|
||||||
<x-toaster-hub />
|
<x-toaster-hub />
|
||||||
<x-navbar />
|
<x-navbar />
|
||||||
@if (isSubscribed())
|
<div class="fixed top-3 left-4" id="vue">
|
||||||
<div class="fixed top-3 left-4" id="vue">
|
<magic-bar></magic-bar>
|
||||||
<magic-bar></magic-bar>
|
</div>
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
<main class="main">
|
<main class="main">
|
||||||
{{ $slot }}
|
{{ $slot }}
|
||||||
</main>
|
</main>
|
||||||
|
20
resources/views/components/navbar-subscription.blade.php
Normal file
20
resources/views/components/navbar-subscription.blade.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@auth
|
||||||
|
<nav class="fixed h-full overflow-hidden overflow-y-auto scrollbar">
|
||||||
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
|
<li class="pb-6" title="Logout">
|
||||||
|
<form action="/logout" method="POST" class=" hover:bg-transparent">
|
||||||
|
@csrf
|
||||||
|
<button class="flex items-center gap-2 rounded-none hover:text-white hover:bg-transparent"> <svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M13 12v.01" />
|
||||||
|
<path d="M3 21h18" />
|
||||||
|
<path d="M5 21v-16a2 2 0 0 1 2 -2h7.5m2.5 10.5v7.5" />
|
||||||
|
<path d="M14 7h7m-3 -3l3 3l-3 3" />
|
||||||
|
</svg> Logout</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
@endauth
|
@@ -1,5 +1,5 @@
|
|||||||
@auth
|
@auth
|
||||||
<nav class="fixed h-full overflow-hidden overflow-y-auto scrollbar" :class="{ isSubscribed() ? 'pt-14' : '' }">
|
<nav class="fixed h-full overflow-hidden overflow-y-auto pt-14 scrollbar">
|
||||||
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
<ul class="flex flex-col h-full gap-4 menu flex-nowrap">
|
||||||
<li title="Dashboard">
|
<li title="Dashboard">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('/')) href="/" @endif>
|
||||||
@@ -10,90 +10,88 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (isSubscribed())
|
<li title="Projects">
|
||||||
<li title="Projects">
|
<a class="hover:bg-transparent" @if (!request()->is('projects')) href="/projects" @endif>
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('projects')) href="/projects" @endif>
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="{{ request()->is('project/*') || request()->is('projects') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M12 4l-8 4l8 4l8 -4l-8 -4" />
|
||||||
|
<path d="M4 12l8 4l8 -4" />
|
||||||
|
<path d="M4 16l8 4l8 -4" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li title="Servers">
|
||||||
|
<a class="hover:bg-transparent" @if (!request()->is('servers')) href="/servers" @endif>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="{{ request()->is('server/*') || request()->is('servers') ? 'text-warning icon' : 'icon' }}"
|
||||||
|
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
||||||
|
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
||||||
|
<path d="M7 8v.01" />
|
||||||
|
<path d="M7 16v.01" />
|
||||||
|
<path d="M20 15l-2 3h3l-2 3" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@if (auth()->user()->isInstanceAdmin())
|
||||||
|
<li title="Command Center">
|
||||||
|
<a class="hover:bg-transparent" @if (!request()->is('command-center')) href="/command-center" @endif>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
class="{{ request()->is('project/*') || request()->is('projects') ? 'text-warning icon' : 'icon' }}"
|
class="{{ request()->is('command-center') ? 'text-warning icon' : 'icon' }}" viewBox="0 0 24 24"
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
stroke-linejoin="round">
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
<path d="M12 4l-8 4l8 4l8 -4l-8 -4" />
|
<path d="M5 7l5 5l-5 5" />
|
||||||
<path d="M4 12l8 4l8 -4" />
|
<path d="M12 19l7 0" />
|
||||||
<path d="M4 16l8 4l8 -4" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li title="Servers">
|
<li title="Profile">
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('servers')) href="/servers" @endif>
|
<a class="hover:bg-transparent" @if (!request()->is('profile')) href="/profile" @endif>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
class="{{ request()->is('server/*') || request()->is('servers') ? 'text-warning icon' : 'icon' }}"
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z" />
|
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||||
<path d="M15 20h-9a3 3 0 0 1 -3 -3v-2a3 3 0 0 1 3 -3h12" />
|
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
||||||
<path d="M7 8v.01" />
|
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
||||||
<path d="M7 16v.01" />
|
</svg>
|
||||||
<path d="M20 15l-2 3h3l-2 3" />
|
</a>
|
||||||
|
</li>
|
||||||
|
<li title="Teams">
|
||||||
|
<a class="hover:bg-transparent" href="{{ route('team.show') }}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
||||||
|
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
||||||
|
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||||
|
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<livewire:upgrade />
|
||||||
|
<li title="Settings" class="mt-auto">
|
||||||
|
<a class="hover:bg-transparent" @if (!request()->is('settings')) href="/settings" @endif>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="{{ request()->is('settings*') ? 'text-warning icon' : 'icon' }}" viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
||||||
|
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if (auth()->user()->isInstanceAdmin())
|
|
||||||
<li title="Command Center">
|
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('command-center')) href="/command-center" @endif>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="{{ request()->is('command-center') ? 'text-warning icon' : 'icon' }}"
|
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M5 7l5 5l-5 5" />
|
|
||||||
<path d="M12 19l7 0" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li title="Profile">
|
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('profile')) href="/profile" @endif>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
|
||||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
|
||||||
<path d="M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" />
|
|
||||||
<path d="M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li title="Teams">
|
|
||||||
<a class="hover:bg-transparent" href="{{ route('team.show') }}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24" stroke-width="1.5"
|
|
||||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path d="M10 13a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M8 21v-1a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v1" />
|
|
||||||
<path d="M15 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M17 10h2a2 2 0 0 1 2 2v1" />
|
|
||||||
<path d="M5 5a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
|
||||||
<path d="M3 13v-1a2 2 0 0 1 2 -2h2" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<livewire:upgrade />
|
|
||||||
<li title="Settings" class="mt-auto">
|
|
||||||
<a class="hover:bg-transparent" @if (!request()->is('settings')) href="/settings" @endif>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="{{ request()->is('settings*') ? 'text-warning icon' : 'icon' }}"
|
|
||||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
|
||||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
||||||
<path
|
|
||||||
d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" />
|
|
||||||
<path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@endif
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<li class="pb-6" title="Logout">
|
<li class="pb-6" title="Logout">
|
||||||
|
@@ -20,22 +20,20 @@
|
|||||||
@endif
|
@endif
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
@if (isSubscribed())
|
<nav class="flex items-end gap-4 py-2 border-b-2 border-solid border-coolgray-200">
|
||||||
<nav class="flex items-end gap-4 py-2 border-b-2 border-solid border-coolgray-200">
|
<a class="{{ request()->routeIs('team.show') ? 'text-white' : '' }}" href="{{ route('team.show') }}">
|
||||||
<a class="{{ request()->routeIs('team.show') ? 'text-white' : '' }}" href="{{ route('team.show') }}">
|
<button>General</button>
|
||||||
<button>General</button>
|
</a>
|
||||||
</a>
|
<a class="{{ request()->routeIs('team.members') ? 'text-white' : '' }}" href="{{ route('team.members') }}">
|
||||||
<a class="{{ request()->routeIs('team.members') ? 'text-white' : '' }}" href="{{ route('team.members') }}">
|
<button>Members</button>
|
||||||
<button>Members</button>
|
</a>
|
||||||
</a>
|
<a class="{{ request()->routeIs('team.notifications') ? 'text-white' : '' }}"
|
||||||
<a class="{{ request()->routeIs('team.notifications') ? 'text-white' : '' }}"
|
href="{{ route('team.notifications') }}">
|
||||||
href="{{ route('team.notifications') }}">
|
<button>Notifications</button>
|
||||||
<button>Notifications</button>
|
</a>
|
||||||
</a>
|
<div class="flex-1"></div>
|
||||||
<div class="flex-1"></div>
|
<div class="-mt-9">
|
||||||
<livewire:switch-team />
|
<livewire:switch-team />
|
||||||
@else
|
</div>
|
||||||
<livewire:switch-team />
|
|
||||||
@endif
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
17
resources/views/livewire/check-license.blade.php
Normal file
17
resources/views/livewire/check-license.blade.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<form wire:submit.prevent='submit' class="flex flex-col gap-2">
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox id="settings.is_resale_license_active" label="Is license active?" disabled />
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input id="settings.resale_license" label="License" />
|
||||||
|
<x-forms.input id="instance_id" label="Instance Id (do not change this)" disabled />
|
||||||
|
</div>
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Check License
|
||||||
|
</x-forms.button>
|
||||||
|
@if (session()->has('error'))
|
||||||
|
<div class="text-error">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</form>
|
@@ -10,6 +10,7 @@
|
|||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input id="settings.fqdn" label="Coolify's Domain" />
|
<x-forms.input id="settings.fqdn" label="Coolify's Domain" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- <div class="flex gap-2 ">
|
{{-- <div class="flex gap-2 ">
|
||||||
<x-forms.input type="number" id="settings.public_port_min" label="Public Port Min" />
|
<x-forms.input type="number" id="settings.public_port_min" label="Public Port Min" />
|
||||||
<x-forms.input type="number" id="settings.public_port_max" label="Public Port Max" />
|
<x-forms.input type="number" id="settings.public_port_max" label="Public Port Max" />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="w-64 -mt-9">
|
<div class="w-64">
|
||||||
<x-forms.select wire:model="selectedTeamId">
|
<x-forms.select wire:model="selectedTeamId">
|
||||||
<option value="default" disabled selected>Switch team</option>
|
<option value="default" disabled selected>Switch team</option>
|
||||||
@foreach (auth()->user()->teams as $team)
|
@foreach (auth()->user()->teams as $team)
|
||||||
|
41
resources/views/subscription.blade.php
Normal file
41
resources/views/subscription.blade.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<x-layout-subscription>
|
||||||
|
@if (auth()->user()->isInstanceAdmin())
|
||||||
|
<div class="pb-10">
|
||||||
|
<h3>Resale License</h3>
|
||||||
|
<livewire:check-license />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if (!auth()->user()->isInstanceAdmin() && !$settings->is_resale_license_active)
|
||||||
|
<div>Resale license is not active. Please contact your instance admin.</div>
|
||||||
|
@endif
|
||||||
|
@if ($settings->is_resale_license_active)
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<h3>Subscription</h3>
|
||||||
|
<livewire:switch-team />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center pb-8">
|
||||||
|
<span>Currently active team: {{ session('currentTeam.name') }}</span>
|
||||||
|
</div>
|
||||||
|
@if (data_get(auth()->user()->currentTeam(),
|
||||||
|
'subscription'))
|
||||||
|
<div>Status: {{ auth()->user()->currentTeam()->subscription->lemon_status }}</div>
|
||||||
|
<div>Type: {{ auth()->user()->currentTeam()->subscription->lemon_variant_name }}</div>
|
||||||
|
@if (auth()->user()->currentTeam()->subscription->lemon_status === 'cancelled')
|
||||||
|
<div class="pb-4">Subscriptions ends at: {{ getEndDate() }}</div>
|
||||||
|
<x-forms.button><a class="text-white" href="{{ getSubscriptionLink() }}">Subscribe
|
||||||
|
Again</a>
|
||||||
|
</x-forms.button>
|
||||||
|
@else
|
||||||
|
<div class="pb-4">Renews at: {{ getRenewDate() }}</div>
|
||||||
|
@endif
|
||||||
|
<x-forms.button><a class="text-white" href="{{ getPaymentLink() }}">Update Payment Details</a>
|
||||||
|
</x-forms.button>
|
||||||
|
@else
|
||||||
|
<x-forms.button class="mt-4"><a class="text-white" href="{{ getSubscriptionLink() }}">Subscribe Now</a>
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
|
<x-forms.button><a class="text-white" href="https://app.lemonsqueezy.com/my-orders">Manage My
|
||||||
|
Subscription</a>
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
|
</x-layout-subscription>
|
@@ -1,8 +1,6 @@
|
|||||||
<x-layout>
|
<x-layout>
|
||||||
<x-team.navbar :team="session('currentTeam')" />
|
<x-team.navbar :team="session('currentTeam')" />
|
||||||
@if (isSubscribed())
|
<livewire:team.form />
|
||||||
<livewire:team.form />
|
|
||||||
@endif
|
|
||||||
@if (isCloud())
|
@if (isCloud())
|
||||||
<div class="pb-8">
|
<div class="pb-8">
|
||||||
<h3>Subscription</h3>
|
<h3>Subscription</h3>
|
||||||
@@ -29,7 +27,5 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (isSubscribed())
|
<livewire:team.delete />
|
||||||
<livewire:team.delete />
|
|
||||||
@endif
|
|
||||||
</x-layout>
|
</x-layout>
|
||||||
|
@@ -84,7 +84,7 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
Route::get('/', [Controller::class, 'dashboard'])->name('dashboard');
|
Route::get('/', [Controller::class, 'dashboard'])->name('dashboard');
|
||||||
Route::get('/license', [Controller::class, 'license'])->name('license');
|
Route::get('/subscription', [Controller::class, 'subscription'])->name('subscription');
|
||||||
Route::get('/settings', [Controller::class, 'settings'])->name('settings.configuration');
|
Route::get('/settings', [Controller::class, 'settings'])->name('settings.configuration');
|
||||||
Route::get('/settings/emails', [Controller::class, 'emails'])->name('settings.emails');
|
Route::get('/settings/emails', [Controller::class, 'emails'])->name('settings.emails');
|
||||||
Route::get('/profile', fn () => view('profile', ['request' => request()]))->name('profile');
|
Route::get('/profile', fn () => view('profile', ['request' => request()]))->name('profile');
|
||||||
|
@@ -176,8 +176,9 @@ Route::post('/source/github/events', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
Route::post('/subscriptions/events', function () {
|
Route::post('/payments/events', function () {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$secret = config('coolify.lemon_squeezy_webhook_secret');
|
$secret = config('coolify.lemon_squeezy_webhook_secret');
|
||||||
$payload = request()->collect();
|
$payload = request()->collect();
|
||||||
$hash = hash_hmac('sha256', $payload, $secret);
|
$hash = hash_hmac('sha256', $payload, $secret);
|
||||||
@@ -192,8 +193,12 @@ if (isCloud()) {
|
|||||||
'payload' => $payload
|
'payload' => $payload
|
||||||
]);
|
]);
|
||||||
$event = data_get($payload, 'meta.event_name');
|
$event = data_get($payload, 'meta.event_name');
|
||||||
|
ray('Subscription event: ' . $event);
|
||||||
$email = data_get($payload, 'data.attributes.user_email');
|
$email = data_get($payload, 'data.attributes.user_email');
|
||||||
$team_id = data_get($payload, 'meta.custom_data.team_id');
|
$team_id = data_get($payload, 'meta.custom_data.team_id');
|
||||||
|
if (is_null($team_id) || empty($team_id)) {
|
||||||
|
throw new \Exception('No team_id found in webhook payload.');
|
||||||
|
}
|
||||||
$subscription_id = data_get($payload, 'data.id');
|
$subscription_id = data_get($payload, 'data.id');
|
||||||
$order_id = data_get($payload, 'data.attributes.order_id');
|
$order_id = data_get($payload, 'data.attributes.order_id');
|
||||||
$product_id = data_get($payload, 'data.attributes.product_id');
|
$product_id = data_get($payload, 'data.attributes.product_id');
|
||||||
@@ -218,7 +223,7 @@ if (isCloud()) {
|
|||||||
$subscription = Subscription::updateOrCreate([
|
$subscription = Subscription::updateOrCreate([
|
||||||
'team_id' => $team_id,
|
'team_id' => $team_id,
|
||||||
], [
|
], [
|
||||||
'lemon_subscription_id'=> $subscription_id,
|
'lemon_subscription_id' => $subscription_id,
|
||||||
'lemon_customer_id' => $customer_id,
|
'lemon_customer_id' => $customer_id,
|
||||||
'lemon_order_id' => $order_id,
|
'lemon_order_id' => $order_id,
|
||||||
'lemon_product_id' => $product_id,
|
'lemon_product_id' => $product_id,
|
||||||
@@ -246,7 +251,6 @@ if (isCloud()) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ray('Subscription event: ' . $event);
|
|
||||||
$webhook->update([
|
$webhook->update([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
]);
|
]);
|
||||||
@@ -260,4 +264,4 @@ if (isCloud()) {
|
|||||||
return response('OK');
|
return response('OK');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user