@@ -556,7 +556,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
 | 
				
			|||||||
                "hidden" => true,
 | 
					                "hidden" => true,
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
                "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
 | 
					                "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ return [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // The release version of your application
 | 
					    // The release version of your application
 | 
				
			||||||
    // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
 | 
					    // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
 | 
				
			||||||
    'release' => '4.0.0-beta.120',
 | 
					    'release' => '4.0.0-beta.121',
 | 
				
			||||||
    // When left empty or `null` the Laravel environment will be used
 | 
					    // When left empty or `null` the Laravel environment will be used
 | 
				
			||||||
    'environment' => config('app.env'),
 | 
					    'environment' => config('app.env'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ return [
 | 
				
			|||||||
    'stripe_price_id_pro_yearly' => env('STRIPE_PRICE_ID_PRO_YEARLY', null),
 | 
					    'stripe_price_id_pro_yearly' => env('STRIPE_PRICE_ID_PRO_YEARLY', null),
 | 
				
			||||||
    'stripe_price_id_ultimate_monthly' => env('STRIPE_PRICE_ID_ULTIMATE_MONTHLY', null),
 | 
					    'stripe_price_id_ultimate_monthly' => env('STRIPE_PRICE_ID_ULTIMATE_MONTHLY', null),
 | 
				
			||||||
    'stripe_price_id_ultimate_yearly' => env('STRIPE_PRICE_ID_ULTIMATE_YEARLY', null),
 | 
					    'stripe_price_id_ultimate_yearly' => env('STRIPE_PRICE_ID_ULTIMATE_YEARLY', null),
 | 
				
			||||||
 | 
					    'stripe_excluded_plans' => env('STRIPE_EXCLUDED_PLANS', null),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Paddle
 | 
					    // Paddle
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,3 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return '4.0.0-beta.120';
 | 
					return '4.0.0-beta.121';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
    @endif
 | 
					    @endif
 | 
				
			||||||
    <div id="screen" :class="fullscreen ? 'fullscreen' : ''">
 | 
					    <div id="screen" :class="fullscreen ? 'fullscreen' : ''">
 | 
				
			||||||
        <div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
 | 
					        <div @if ($isKeepAliveOn) wire:poll.2000ms="polling" @endif
 | 
				
			||||||
            class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto scrollbar border-coolgray-400"
 | 
					            class="relative flex flex-col-reverse w-full p-2 px-4 mt-4 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
 | 
				
			||||||
            :class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
 | 
					            :class="fullscreen ? '' : 'max-h-[40rem] border border-dotted rounded'">
 | 
				
			||||||
            <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
 | 
					            <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
 | 
				
			||||||
                    class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 | 
					                    class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 | 
				
			||||||
@@ -48,7 +48,7 @@
 | 
				
			|||||||
                    @foreach (decode_remote_command_output($application_deployment_queue) as $line)
 | 
					                    @foreach (decode_remote_command_output($application_deployment_queue) as $line)
 | 
				
			||||||
                        <div @class([
 | 
					                        <div @class([
 | 
				
			||||||
                            'font-mono whitespace-pre-line',
 | 
					                            'font-mono whitespace-pre-line',
 | 
				
			||||||
                            'text-neutral-400' => $line['type'] == 'stdout',
 | 
					                            'text-white' => $line['type'] == 'stdout',
 | 
				
			||||||
                            'text-error' => $line['type'] == 'stderr',
 | 
					                            'text-error' => $line['type'] == 'stderr',
 | 
				
			||||||
                            'text-warning' => $line['hidden'],
 | 
					                            'text-warning' => $line['hidden'],
 | 
				
			||||||
                        ])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
 | 
					                        ])>[{{ $line['timestamp'] }}] @if ($line['hidden'])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,14 +12,14 @@
 | 
				
			|||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
    @forelse ($deployments as $deployment)
 | 
					    @forelse ($deployments as $deployment)
 | 
				
			||||||
        <a @class([
 | 
					        <a @class([
 | 
				
			||||||
            'bg-coolgray-200 p-2 border-l border-dashed transition-colors hover:no-underline',
 | 
					            'bg-coolgray-100 p-2 border-l border-dashed transition-colors hover:no-underline',
 | 
				
			||||||
            'hover:bg-coolgray-200' =>
 | 
					            'hover:bg-coolgray-200' =>
 | 
				
			||||||
                data_get($deployment, 'status') === 'queued' ||
 | 
					                data_get($deployment, 'status') === 'queued',
 | 
				
			||||||
                data_get($deployment, 'status') === 'cancelled by system',
 | 
					 | 
				
			||||||
            'border-warning hover:bg-warning hover:text-black' =>
 | 
					            'border-warning hover:bg-warning hover:text-black' =>
 | 
				
			||||||
                data_get($deployment, 'status') === 'in_progress',
 | 
					                data_get($deployment, 'status') === 'in_progress'  ||
 | 
				
			||||||
 | 
					                data_get($deployment, 'status') === 'cancelled-by-user',
 | 
				
			||||||
            'border-error hover:bg-error' =>
 | 
					            'border-error hover:bg-error' =>
 | 
				
			||||||
                data_get($deployment, 'status') === 'error',
 | 
					                data_get($deployment, 'status') === 'failed',
 | 
				
			||||||
            'border-success hover:bg-success' =>
 | 
					            'border-success hover:bg-success' =>
 | 
				
			||||||
                data_get($deployment, 'status') === 'finished',
 | 
					                data_get($deployment, 'status') === 'finished',
 | 
				
			||||||
        ]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
 | 
					        ]) href="{{ $current_url . '/' . data_get($deployment, 'deployment_uuid') }}"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@
 | 
				
			|||||||
                @if ($application->could_set_build_commands())
 | 
					                @if ($application->could_set_build_commands())
 | 
				
			||||||
                    @if ($application->build_pack === 'nixpacks')
 | 
					                    @if ($application->build_pack === 'nixpacks')
 | 
				
			||||||
                        <div>Nixpacks will detect the required configuration automatically.
 | 
					                        <div>Nixpacks will detect the required configuration automatically.
 | 
				
			||||||
                            <a class="underline" href="https://coolify.io/docs/frameworks">Framework Specific Docs</a>
 | 
					                            <a class="underline" href="https://coolify.io/docs/frameworks/">Framework Specific Docs</a>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <div class="flex flex-col gap-2 xl:flex-row">
 | 
					                        <div class="flex flex-col gap-2 xl:flex-row">
 | 
				
			||||||
                            <x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
 | 
					                            <x-forms.input placeholder="If you modify this, you probably need to have a nixpacks.toml"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@
 | 
				
			|||||||
        <x-forms.button type="submit">Refresh</x-forms.button>
 | 
					        <x-forms.button type="submit">Refresh</x-forms.button>
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
    <div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'container w-full pt-4 mx-auto'">
 | 
					    <div id="screen" x-data="{ fullscreen: false, alwaysScroll: false, intervalId: null }" :class="fullscreen ? 'fullscreen' : 'container w-full pt-4 mx-auto'">
 | 
				
			||||||
        <div class="relative flex flex-col-reverse w-full p-4 pt-6 overflow-y-auto text-white scrollbar border-coolgray-300"
 | 
					        <div class="relative flex flex-col-reverse w-full p-4 pt-6 overflow-y-auto text-white bg-coolgray-100 scrollbar border-coolgray-300"
 | 
				
			||||||
            :class="fullscreen ? '' : 'max-h-[40rem] border border-solid rounded'">
 | 
					            :class="fullscreen ? '' : 'max-h-[40rem] border border-solid rounded'">
 | 
				
			||||||
            <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
 | 
					            <button title="Minimize" x-show="fullscreen" class="fixed top-4 right-4" x-on:click="makeFullscreen"><svg
 | 
				
			||||||
                    class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 | 
					                    class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,12 @@
 | 
				
			|||||||
        <div class="flex flex-col gap-4 min-w-fit">
 | 
					        <div class="flex flex-col gap-4 min-w-fit">
 | 
				
			||||||
            <a :class="activeTab === 'general' && 'text-white'"
 | 
					            <a :class="activeTab === 'general' && 'text-white'"
 | 
				
			||||||
                @click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
 | 
					                @click.prevent="activeTab = 'general'; window.location.hash = 'general'" href="#">General</a>
 | 
				
			||||||
            <a :class="activeTab === 'environment-variables' && 'text-white'"
 | 
					            @if ($application->build_pack !== 'static')
 | 
				
			||||||
                @click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
 | 
					                <a :class="activeTab === 'environment-variables' && 'text-white'"
 | 
				
			||||||
                href="#">Environment
 | 
					                    @click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
 | 
				
			||||||
                Variables</a>
 | 
					                    href="#">Environment
 | 
				
			||||||
 | 
					                    Variables</a>
 | 
				
			||||||
 | 
					            @endif
 | 
				
			||||||
            @if ($application->git_based())
 | 
					            @if ($application->git_based())
 | 
				
			||||||
                <a :class="activeTab === 'source' && 'text-white'"
 | 
					                <a :class="activeTab === 'source' && 'text-white'"
 | 
				
			||||||
                    @click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
 | 
					                    @click.prevent="activeTab = 'source'; window.location.hash = 'source'" href="#">Source</a>
 | 
				
			||||||
@@ -16,21 +18,25 @@
 | 
				
			|||||||
            <a :class="activeTab === 'server' && 'text-white'"
 | 
					            <a :class="activeTab === 'server' && 'text-white'"
 | 
				
			||||||
                @click.prevent="activeTab = 'server'; window.location.hash = 'server'" href="#">Server
 | 
					                @click.prevent="activeTab = 'server'; window.location.hash = 'server'" href="#">Server
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
            <a :class="activeTab === 'storages' && 'text-white'"
 | 
					            @if ($application->build_pack !== 'static')
 | 
				
			||||||
                @click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
 | 
					                <a :class="activeTab === 'storages' && 'text-white'"
 | 
				
			||||||
            </a>
 | 
					                    @click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            @endif
 | 
				
			||||||
            <a :class="activeTab === 'webhooks' && 'text-white'"
 | 
					            <a :class="activeTab === 'webhooks' && 'text-white'"
 | 
				
			||||||
                @click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
 | 
					                @click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
            @if ($application->git_based())
 | 
					            @if ($application->git_based() && $application->build_pack !== 'static')
 | 
				
			||||||
                <a :class="activeTab === 'previews' && 'text-white'"
 | 
					                <a :class="activeTab === 'previews' && 'text-white'"
 | 
				
			||||||
                    @click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
 | 
					                    @click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
 | 
				
			||||||
                    Deployments
 | 
					                    Deployments
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
            @endif
 | 
					            @endif
 | 
				
			||||||
            <a :class="activeTab === 'health' && 'text-white'"
 | 
					            @if ($application->build_pack !== 'static')
 | 
				
			||||||
                @click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Health Checks
 | 
					                <a :class="activeTab === 'health' && 'text-white'"
 | 
				
			||||||
            </a>
 | 
					                    @click.prevent="activeTab = 'health'; window.location.hash = 'health'" href="#">Health Checks
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            @endif
 | 
				
			||||||
            <a :class="activeTab === 'rollback' && 'text-white'"
 | 
					            <a :class="activeTab === 'rollback' && 'text-white'"
 | 
				
			||||||
                @click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
 | 
					                @click.prevent="activeTab = 'rollback'; window.location.hash = 'rollback'" href="#">Rollback
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -237,7 +237,7 @@ Route::post('/payments/stripe/events', function () {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
        $webhookSecret = config('subscription.stripe_webhook_secret');
 | 
					        $webhookSecret = config('subscription.stripe_webhook_secret');
 | 
				
			||||||
        $signature = request()->header('Stripe-Signature');
 | 
					        $signature = request()->header('Stripe-Signature');
 | 
				
			||||||
 | 
					        $excludedPlans = config('subscription.stripe_excluded_plans');
 | 
				
			||||||
        $event = \Stripe\Webhook::constructEvent(
 | 
					        $event = \Stripe\Webhook::constructEvent(
 | 
				
			||||||
            request()->getContent(),
 | 
					            request()->getContent(),
 | 
				
			||||||
            $signature,
 | 
					            $signature,
 | 
				
			||||||
@@ -253,6 +253,10 @@ Route::post('/payments/stripe/events', function () {
 | 
				
			|||||||
        switch ($type) {
 | 
					        switch ($type) {
 | 
				
			||||||
            case 'checkout.session.completed':
 | 
					            case 'checkout.session.completed':
 | 
				
			||||||
                $clientReferenceId = data_get($data, 'client_reference_id');
 | 
					                $clientReferenceId = data_get($data, 'client_reference_id');
 | 
				
			||||||
 | 
					                if (is_null($clientReferenceId)) {
 | 
				
			||||||
 | 
					                    send_internal_notification('Checkout session completed without client reference id.');
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                $userId = Str::before($clientReferenceId, ':');
 | 
					                $userId = Str::before($clientReferenceId, ':');
 | 
				
			||||||
                $teamId = Str::after($clientReferenceId, ':');
 | 
					                $teamId = Str::after($clientReferenceId, ':');
 | 
				
			||||||
                $subscriptionId = data_get($data, 'subscription');
 | 
					                $subscriptionId = data_get($data, 'subscription');
 | 
				
			||||||
@@ -282,12 +286,17 @@ Route::post('/payments/stripe/events', function () {
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'invoice.paid':
 | 
					            case 'invoice.paid':
 | 
				
			||||||
                $customerId = data_get($data, 'customer');
 | 
					                $customerId = data_get($data, 'customer');
 | 
				
			||||||
 | 
					                $planId = data_get($data, 'lines.data.0.plan.id');
 | 
				
			||||||
 | 
					                if (Str::contains($excludedPlans, $planId)) {
 | 
				
			||||||
 | 
					                    send_internal_notification('Subscription excluded.');
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
					                $subscription = Subscription::where('stripe_customer_id', $customerId)->first();
 | 
				
			||||||
                if (!$subscription) {
 | 
					                if (!$subscription) {
 | 
				
			||||||
                    Sleep::for(5)->seconds();
 | 
					                    Sleep::for(5)->seconds();
 | 
				
			||||||
                    $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
 | 
					                    $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                $planId = data_get($data, 'lines.data.0.plan.id');
 | 
					
 | 
				
			||||||
                $subscription->update([
 | 
					                $subscription->update([
 | 
				
			||||||
                    'stripe_plan_id' => $planId,
 | 
					                    'stripe_plan_id' => $planId,
 | 
				
			||||||
                    'stripe_invoice_paid' => true,
 | 
					                    'stripe_invoice_paid' => true,
 | 
				
			||||||
@@ -303,11 +312,15 @@ Route::post('/payments/stripe/events', function () {
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'customer.subscription.updated':
 | 
					            case 'customer.subscription.updated':
 | 
				
			||||||
                $customerId = data_get($data, 'customer');
 | 
					                $customerId = data_get($data, 'customer');
 | 
				
			||||||
                $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
 | 
					 | 
				
			||||||
                $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
 | 
					 | 
				
			||||||
                $status = data_get($data, 'status');
 | 
					                $status = data_get($data, 'status');
 | 
				
			||||||
                $subscriptionId = data_get($data, 'items.data.0.subscription');
 | 
					                $subscriptionId = data_get($data, 'items.data.0.subscription');
 | 
				
			||||||
                $planId = data_get($data, 'items.data.0.plan.id');
 | 
					                $planId = data_get($data, 'items.data.0.plan.id');
 | 
				
			||||||
 | 
					                if (Str::contains($excludedPlans, $planId)) {
 | 
				
			||||||
 | 
					                    send_internal_notification('Subscription excluded.');
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
 | 
				
			||||||
 | 
					                $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
 | 
				
			||||||
                $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
 | 
					                $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
 | 
				
			||||||
                $alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
 | 
					                $alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
 | 
				
			||||||
                $feedback = data_get($data, 'cancellation_details.feedback');
 | 
					                $feedback = data_get($data, 'cancellation_details.feedback');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
            "version": "3.12.36"
 | 
					            "version": "3.12.36"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "v4": {
 | 
					        "v4": {
 | 
				
			||||||
            "version": "4.0.0-beta.120"
 | 
					            "version": "4.0.0-beta.121"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user