From f3b04c1ef987395f29132da52bfdda5930e09d8b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 09:23:27 +0100 Subject: [PATCH 01/19] refactor: custom labels --- app/Jobs/ApplicationDeploymentJob.php | 15 +-------------- app/Livewire/Project/Application/General.php | 19 +------------------ app/Models/Application.php | 20 ++++++++++++++++++++ config/sentry.php | 2 +- config/version.php | 2 +- versions.json | 2 +- 6 files changed, 25 insertions(+), 35 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 7bb0df489..9e9725bd1 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -874,20 +874,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $environment_variables = $this->generate_environment_variables($ports); if (data_get($this->application, 'custom_labels')) { - if (base64_encode(base64_decode(data_get($this->application, 'custom_labels'), true)) === data_get($this->application, 'custom_labels')) { - ray('custom_labels is base64 encoded'); - } else { - ray('custom_labels is not base64 encoded'); - $this->application->custom_labels = str($this->application->custom_labels)->replace(',', "\n"); - $this->application->custom_labels = base64_encode(data_get($this->application, 'custom_labels')); - $this->application->save(); - } - - if (mb_detect_encoding(base64_decode($this->application->custom_labels), 'ASCII', true) === false) { - ray('custom_labels contains non-ascii characters'); - $this->application->custom_labels = base64_encode(str(implode(",", generateLabelsApplication($this->application, $this->preview)))->replace(',', "\n")); - $this->application->save(); - } + $this->application->parseContainerLabels(); $labels = collect(preg_split("/\r\n|\n|\r/", base64_decode($this->application->custom_labels))); $labels = $labels->filter(function ($value, $key) { return !Str::startsWith($value, 'coolify.'); diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php index 279e55651..d27fcff54 100644 --- a/app/Livewire/Project/Application/General.php +++ b/app/Livewire/Project/Application/General.php @@ -109,24 +109,7 @@ class General extends Component $this->application->isConfigurationChanged(true); } $this->isConfigurationChanged = $this->application->isConfigurationChanged(); - - if (data_get($this->application, 'custom_labels')) { - if (base64_encode(base64_decode(data_get($this->application, 'custom_labels'), true)) === data_get($this->application, 'custom_labels')) { - ray('custom_labels is base64 encoded'); - } else { - ray('custom_labels is not base64 encoded'); - $this->application->custom_labels = str($this->application->custom_labels)->replace(',', "\n"); - $this->application->custom_labels = base64_encode(data_get($this->application, 'custom_labels')); - $this->application->save(); - } - $this->customLabels = base64_decode(data_get($this->application, 'custom_labels')); - // // Fix for non-ascii characters - if (mb_detect_encoding($this->customLabels, 'ASCII', true) === false) { - ray('custom_labels contains non-ascii characters'); - $this->resetDefaultLabels(false); - } - } - + $this->customLabels = $this->application->parseContainerLabels(); $this->initialDockerComposeLocation = $this->application->docker_compose_location; $this->checkLabelUpdates(); } diff --git a/app/Models/Application.php b/app/Models/Application.php index 10f27e207..d56be8f0a 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1024,4 +1024,24 @@ class Application extends BaseModel ]; } } + function parseContainerLabels(?ApplicationPreview $preview = null) + { + $customLabels = data_get($this, 'custom_labels'); + if (!$customLabels) { + return; + } + if (base64_encode(base64_decode($customLabels, true)) !== $customLabels) { + ray('custom_labels is not base64 encoded'); + $this->custom_labels = str($customLabels)->replace(',', "\n"); + $this->custom_labels = base64_encode($customLabels); + } + $customLabels = base64_decode($this->custom_labels); + if (mb_detect_encoding($customLabels, 'ASCII', true) === false) { + ray('custom_labels contains non-ascii characters'); + $customLabels = str(implode(",", generateLabelsApplication($this, $preview)))->replace(',', "\n"); + } + $this->custom_labels = base64_encode($customLabels); + $this->save(); + return $customLabels; + } } diff --git a/config/sentry.php b/config/sentry.php index 076edb85e..ca9e80d7c 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.161', + 'release' => '4.0.0-beta.162', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 8f7d7b0d4..bf223006f 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Date: Wed, 13 Dec 2023 11:12:53 +0100 Subject: [PATCH 02/19] improve local dev + contribution guide --- CONTRIBUTION.md | 6 +++-- docker-compose.dev.yml | 8 +++++- docker/dev-ssu/Dockerfile | 2 +- .../s6-rc.d/horizon/dependencies.d/init-setup | 0 .../etc/s6-overlay/s6-rc.d/init-setup/type | 1 + .../etc/s6-overlay/s6-rc.d/init-setup/up | 4 +++ .../dependencies.d/init-setup | 0 .../s6-rc.d/user/contents.d/init-setup | 0 .../s6-rc.d/user/contents.d/scheduler-worker | 0 docker/prod-ssu/Dockerfile | 2 +- resources/views/auth/login.blade.php | 26 +++++++++---------- .../views/components/forms/input.blade.php | 11 ++++---- scripts/run | 13 ++++++---- 13 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-setup create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/type create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup create mode 100644 docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index c11930538..8744da671 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -22,7 +22,10 @@ You can ask for guidance anytime on our - Run `spin up` - You can notice that errors will be thrown. Don't worry. - If you see weird permission errors, especially on Mac, run `sudo spin up` instead. -- Run `./scripts/run setup:dev` - This will generate a secret key for you, delete any existing database layouts, migrate database to the new layout, and seed your database. +If you are running Coolify for the first time: +- Run `./scripts/run dev:init` - This will delete any existing database layouts, migrate database to the new layout, and seed your database. + +> If you see the login page with a 404 error, you forgot to run `./scripts/run dev:init`. ### 4) Start development You can login your Coolify instance at `localhost:8000` with `test@example.com` and `password`. @@ -31,7 +34,6 @@ Your horizon (Laravel scheduler): `localhost:8000/horizon` - Only reachable if y Mails are caught by Mailpit: `localhost:8025` - ## New Service Contribution Check out the docs [here](https://coolify.io/docs/how-to-add-a-service). diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 87b4bb6b5..e789c3ba7 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -56,7 +56,7 @@ services: ports: - "${FORWARD_SOKETI_PORT:-6001}:6001" environment: - SOKETI_DEBUG: "true" + SOKETI_DEBUG: "false" SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}" SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}" SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}" @@ -115,3 +115,9 @@ volumes: coolify-pg-data-dev: coolify-redis-data-dev: coolify-minio-data-dev: + +networks: + coolify: + name: coolify + driver: bridge + external: false diff --git a/docker/dev-ssu/Dockerfile b/docker/dev-ssu/Dockerfile index 58941b73f..df98985f4 100644 --- a/docker/dev-ssu/Dockerfile +++ b/docker/dev-ssu/Dockerfile @@ -2,7 +2,7 @@ FROM serversideup/php:8.2-fpm-nginx ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases -ARG CLOUDFLARED_VERSION=2023.8.2 +ARG CLOUDFLARED_VERSION=2023.10.0 ARG POSTGRES_VERSION=15 RUN apt-get update diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-setup b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/horizon/dependencies.d/init-setup new file mode 100644 index 000000000..e69de29bb diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/type b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/type new file mode 100644 index 000000000..3d92b15f2 --- /dev/null +++ b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/type @@ -0,0 +1 @@ +oneshot \ No newline at end of file diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up new file mode 100644 index 000000000..e5d89d959 --- /dev/null +++ b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up @@ -0,0 +1,4 @@ +#!/command/execlineb -P +foreground { composer -d /var/www/html/ install } +foreground { php /var/www/html/artisan key:generate } +foreground { php /var/www/html/artisan migrate --step } diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/scheduler-worker/dependencies.d/init-setup new file mode 100644 index 000000000..e69de29bb diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/init-setup new file mode 100644 index 000000000..e69de29bb diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/user/contents.d/scheduler-worker new file mode 100644 index 000000000..e69de29bb diff --git a/docker/prod-ssu/Dockerfile b/docker/prod-ssu/Dockerfile index dac8c56a9..79c0a839c 100644 --- a/docker/prod-ssu/Dockerfile +++ b/docker/prod-ssu/Dockerfile @@ -15,7 +15,7 @@ FROM serversideup/php:8.2-fpm-nginx ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases -ARG CLOUDFLARED_VERSION=2023.8.2 +ARG CLOUDFLARED_VERSION=2023.10.0 ARG POSTGRES_VERSION=15 WORKDIR /var/www/html diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index b2111d561..ed288f9ee 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -24,20 +24,20 @@
@csrf @env('local') - + - - - {{ __('auth.forgot_password') }}? - - @else - - - - {{ __('auth.forgot_password') }}? - + + + {{ __('auth.forgot_password') }}? + + @else + + + + {{ __('auth.forgot_password') }}? + @endenv {{ __('auth.login') }} @if (!$is_registration_enabled) diff --git a/resources/views/components/forms/input.blade.php b/resources/views/components/forms/input.blade.php index 4e9fffef5..3e9c3a35d 100644 --- a/resources/views/components/forms/input.blade.php +++ b/resources/views/components/forms/input.blade.php @@ -22,7 +22,7 @@ @endif - merge(['class' => $defaultClass . ' pl-10']) }} @required($required) + merge(['class' => $defaultClass . ' pl-10']) }} @required($required) wire:model={{ $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 }}" placeholder="{{ $attributes->get('placeholder') }}" @@ -30,10 +30,11 @@ @else - merge(['class' => $defaultClass]) }} @required($required) @readonly($readonly) - wire:model={{ $id }} wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" - wire:loading.attr="disabled" type="{{ $type }}" @disabled($disabled) - id="{{ $id }}" name="{{ $name }}" placeholder="{{ $attributes->get('placeholder') }}"> + merge(['class' => $defaultClass]) }} @required($required) + @readonly($readonly) wire:model={{ $id }} wire:dirty.class.remove='text-white' + wire:dirty.class="input-warning" wire:loading.attr="disabled" type="{{ $type }}" + @disabled($disabled) id="{{ $id }}" name="{{ $name }}" + placeholder="{{ $attributes->get('placeholder') }}"> @endif @if (!$label && $helper) diff --git a/scripts/run b/scripts/run index 7362b1e5a..80ff17a16 100755 --- a/scripts/run +++ b/scripts/run @@ -20,12 +20,12 @@ function help { compgen -A function | cat -n } -function setup:dev { - docker exec coolify bash -c "composer install" - docker exec coolify bash -c "php artisan key:generate" - docker exec coolify bash -c "php artisan migrate:fresh --seed" +function dev:init { + docker exec coolify bash -c "php artisan migrate --seed" + echo "Need to update privileges on a few files. I need your password for that." sudo chmod -R o+rwx . } + function sync:v3 { if [ -z "$1" ]; then echo -e "Please provide a version.\n\nExample: run sync:v3 3.12.32" @@ -57,9 +57,12 @@ function schedule:run { function db { bash spin exec -u webuser coolify php artisan db } +function db:seed { + bash spin exec -u webuser coolify php artisan migrate --seed +} function db:migrate { - bash spin exec -u webuser coolify php artisan migrate + bash spin exec -u webuser coolify php artisan migrate --step } function db:reset { From 3c54e01d87871ea9b5ab28767fd03bd96e5da3d3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 11:35:53 +0100 Subject: [PATCH 03/19] improve more --- CONTRIBUTION.md | 5 -- app/Console/Commands/Dev.php | 33 +++++++++ app/Http/Middleware/NOTUSEDIsBoardingFlow.php | 28 -------- .../Middleware/NOTUSEDIsSubscriptionValid.php | 45 ------------ .../factories/StandaloneMongoDBFactory.php | 23 ------ docker-compose.dev.yml | 21 +++--- .../etc/s6-overlay/s6-rc.d/init-setup/up | 3 +- scripts/run | 72 +++++++++---------- 8 files changed, 79 insertions(+), 151 deletions(-) create mode 100644 app/Console/Commands/Dev.php delete mode 100644 app/Http/Middleware/NOTUSEDIsBoardingFlow.php delete mode 100644 app/Http/Middleware/NOTUSEDIsSubscriptionValid.php delete mode 100644 database/factories/StandaloneMongoDBFactory.php diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 8744da671..c6a5b3273 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -22,11 +22,6 @@ You can ask for guidance anytime on our - Run `spin up` - You can notice that errors will be thrown. Don't worry. - If you see weird permission errors, especially on Mac, run `sudo spin up` instead. -If you are running Coolify for the first time: -- Run `./scripts/run dev:init` - This will delete any existing database layouts, migrate database to the new layout, and seed your database. - -> If you see the login page with a 404 error, you forgot to run `./scripts/run dev:init`. - ### 4) Start development You can login your Coolify instance at `localhost:8000` with `test@example.com` and `password`. diff --git a/app/Console/Commands/Dev.php b/app/Console/Commands/Dev.php new file mode 100644 index 000000000..ba60826d1 --- /dev/null +++ b/app/Console/Commands/Dev.php @@ -0,0 +1,33 @@ +showQueries()->color('orange'); - if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) { - if (Str::startsWith($request->path(), 'invitations')) { - return $next($request); - } - return redirect('boarding'); - } - return $next($request); - } -} diff --git a/app/Http/Middleware/NOTUSEDIsSubscriptionValid.php b/app/Http/Middleware/NOTUSEDIsSubscriptionValid.php deleted file mode 100644 index 5774e5190..000000000 --- a/app/Http/Middleware/NOTUSEDIsSubscriptionValid.php +++ /dev/null @@ -1,45 +0,0 @@ -user() || !isCloud()) { - if ($request->path() === 'subscription') { - return redirect('/'); - } else { - return $next($request); - } - } - if (isSubscriptionActive() && $request->path() === 'subscription') { - // ray('active subscription Middleware'); - return redirect('/'); - } - if (isSubscriptionOnGracePeriod()) { - // ray('is_subscription_in_grace_period Middleware'); - return $next($request); - } - if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) { - // ray('SubscriptionValid Middleware'); - if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) { - if (Str::startsWith($request->path(), 'invitations')) { - return $next($request); - } - return redirect('subscription'); - } else { - return $next($request); - } - } - return $next($request); - } -} diff --git a/database/factories/StandaloneMongoDBFactory.php b/database/factories/StandaloneMongoDBFactory.php deleted file mode 100644 index 8ec395e49..000000000 --- a/database/factories/StandaloneMongoDBFactory.php +++ /dev/null @@ -1,23 +0,0 @@ - - */ -class StandaloneMongodbFactory extends Factory -{ - /** - * Define the model's default state. - * - * @return array - */ - public function definition(): array - { - return [ - // - ]; - } -} diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e789c3ba7..a9f09efa3 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -70,6 +70,8 @@ services: volumes: - .:/var/www/html:cached command: sh -c "npm install && npm run dev" + networks: + - coolify testing-host: <<: *testing-host-base container_name: coolify-testing-host @@ -77,15 +79,8 @@ services: - /:/host - /var/run/docker.sock:/var/run/docker.sock - /data/coolify/:/data/coolify - # - coolify-data-dev:/data/coolify - # remote-host: - # <<: *testing-host-base - # container_name: coolify-remote-host - # volumes: - # - /:/host - # - /var/run/docker.sock:/var/run/docker.sock - # - /data/coolify/:/data/coolify - # # - coolify-data-dev:/data/coolify + networks: + - coolify mailpit: image: "axllent/mailpit:latest" container_name: coolify-mail @@ -116,8 +111,8 @@ volumes: coolify-redis-data-dev: coolify-minio-data-dev: + networks: - coolify: - name: coolify - driver: bridge - external: false + coolify: + name: coolify + external: false diff --git a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up index e5d89d959..e974e54cc 100644 --- a/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up +++ b/docker/dev-ssu/etc/s6-overlay/s6-rc.d/init-setup/up @@ -1,4 +1,5 @@ #!/command/execlineb -P foreground { composer -d /var/www/html/ install } -foreground { php /var/www/html/artisan key:generate } foreground { php /var/www/html/artisan migrate --step } +foreground { php /var/www/html/artisan dev:init } + diff --git a/scripts/run b/scripts/run index 80ff17a16..dfb011c39 100755 --- a/scripts/run +++ b/scripts/run @@ -20,50 +20,50 @@ function help { compgen -A function | cat -n } -function dev:init { - docker exec coolify bash -c "php artisan migrate --seed" - echo "Need to update privileges on a few files. I need your password for that." - sudo chmod -R o+rwx . -} +# function dev:init { +# docker exec coolify bash -c "php artisan migrate --seed" +# echo "Need to update privileges on a few files. I need your password for that." +# sudo chmod -R o+rwx . +# } -function sync:v3 { - if [ -z "$1" ]; then - echo -e "Please provide a version.\n\nExample: run sync:v3 3.12.32" - exit 1 - fi - skopeo copy --all docker://ghcr.io/coollabsio/coolify:$1 docker://coollabsio/coolify:$1 -} +# function sync:v3 { +# if [ -z "$1" ]; then +# echo -e "Please provide a version.\n\nExample: run sync:v3 3.12.32" +# exit 1 +# fi +# skopeo copy --all docker://ghcr.io/coollabsio/coolify:$1 docker://coollabsio/coolify:$1 +# } function sync:bunny { php artisan sync:bunny --env=secrets } -function queue { - bash spin exec -u webuser coolify php artisan queue:listen -} +# function queue { +# bash spin exec -u webuser coolify php artisan queue:listen +# } -function horizon { - bash spin exec -u webuser coolify php artisan horizon -vvv -} +# function horizon { +# bash spin exec -u webuser coolify php artisan horizon -vvv +# } -function schedule { - bash spin exec -u webuser coolify php artisan schedule:work -} +# function schedule { +# bash spin exec -u webuser coolify php artisan schedule:work +# } -function schedule:run { - bash spin exec -u webuser coolify php artisan schedule:run -} +# function schedule:run { +# bash spin exec -u webuser coolify php artisan schedule:run +# } -function db { - bash spin exec -u webuser coolify php artisan db -} -function db:seed { - bash spin exec -u webuser coolify php artisan migrate --seed -} +# function db { +# bash spin exec -u webuser coolify php artisan db +# } +# function db:seed { +# bash spin exec -u webuser coolify php artisan migrate --seed +# } -function db:migrate { - bash spin exec -u webuser coolify php artisan migrate --step -} +# function db:migrate { +# bash spin exec -u webuser coolify php artisan migrate --step +# } function db:reset { bash spin exec -u webuser coolify php artisan migrate:fresh --seed @@ -101,9 +101,9 @@ function tinker { } -function build:helper { - act -W .github/workflows/coolify-helper.yml --secret-file .env.secrets -} +# function build:helper { +# act -W .github/workflows/coolify-helper.yml --secret-file .env.secrets +# } function default { help } From f954ee15c3c4bac9d45da1db51ccb32292d90fb1 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 11:53:01 +0100 Subject: [PATCH 04/19] fix: init script echos --- app/Console/Commands/Init.php | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 6ff7e90db..96b843876 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -115,15 +115,15 @@ class Init extends Command $applications = Application::all(); foreach ($applications as $application) { if (!data_get($application, 'environment')) { - echo 'Application without environment' . $application->name . 'deleting\n'; + echo 'Application without environment: ' . $application->name . ' deleting\n'; $application->delete(); } if (!$application->destination()) { - echo 'Application without destination' . $application->name . 'deleting\n'; + echo 'Application without destination: ' . $application->name . ' deleting\n'; $application->delete(); } if (!data_get($application, 'destination.server')) { - echo 'Application without server' . $application->name . 'deleting\n'; + echo 'Application without server: ' . $application->name . ' deleting\n'; $application->delete(); } } @@ -134,15 +134,15 @@ class Init extends Command $postgresqls = StandalonePostgresql::all(); foreach ($postgresqls as $postgresql) { if (!data_get($postgresql, 'environment')) { - echo 'Postgresql without environment' . $postgresql->name . 'deleting\n'; + echo 'Postgresql without environment: ' . $postgresql->name . ' deleting\n'; $postgresql->delete(); } if (!$postgresql->destination()) { - echo 'Postgresql without destination' . $postgresql->name . 'deleting\n'; + echo 'Postgresql without destination: ' . $postgresql->name . ' deleting\n'; $postgresql->delete(); } if (!data_get($postgresql, 'destination.server')) { - echo 'Postgresql without server' . $postgresql->name . 'deleting\n'; + echo 'Postgresql without server: ' . $postgresql->name . ' deleting\n'; $postgresql->delete(); } } @@ -153,15 +153,15 @@ class Init extends Command $redis = StandaloneRedis::all(); foreach ($redis as $redis) { if (!data_get($redis, 'environment')) { - echo 'Redis without environment' . $redis->name . 'deleting\n'; + echo 'Redis without environment: ' . $redis->name . ' deleting\n'; $redis->delete(); } if (!$redis->destination()) { - echo 'Redis without destination' . $redis->name . 'deleting\n'; + echo 'Redis without destination: ' . $redis->name . ' deleting\n'; $redis->delete(); } if (!data_get($redis, 'destination.server')) { - echo 'Redis without server' . $redis->name . 'deleting\n'; + echo 'Redis without server: ' . $redis->name . ' deleting\n'; $redis->delete(); } } @@ -173,15 +173,15 @@ class Init extends Command $mongodbs = StandaloneMongodb::all(); foreach ($mongodbs as $mongodb) { if (!data_get($mongodb, 'environment')) { - echo 'Mongodb without environment' . $mongodb->name . 'deleting\n'; + echo 'Mongodb without environment: ' . $mongodb->name . ' deleting\n'; $mongodb->delete(); } if (!$mongodb->destination()) { - echo 'Mongodb without destination' . $mongodb->name . 'deleting\n'; + echo 'Mongodb without destination: ' . $mongodb->name . ' deleting\n'; $mongodb->delete(); } if (!data_get($mongodb, 'destination.server')) { - echo 'Mongodb without server' . $mongodb->name . 'deleting\n'; + echo 'Mongodb without server: ' . $mongodb->name . ' deleting\n'; $mongodb->delete(); } } @@ -193,15 +193,15 @@ class Init extends Command $mysqls = StandaloneMysql::all(); foreach ($mysqls as $mysql) { if (!data_get($mysql, 'environment')) { - echo 'Mysql without environment' . $mysql->name . 'deleting\n'; + echo 'Mysql without environment: ' . $mysql->name . ' deleting\n'; $mysql->delete(); } if (!$mysql->destination()) { - echo 'Mysql without destination' . $mysql->name . 'deleting\n'; + echo 'Mysql without destination: ' . $mysql->name . ' deleting\n'; $mysql->delete(); } if (!data_get($mysql, 'destination.server')) { - echo 'Mysql without server' . $mysql->name . 'deleting\n'; + echo 'Mysql without server: ' . $mysql->name . ' deleting\n'; $mysql->delete(); } } @@ -213,15 +213,15 @@ class Init extends Command $mariadbs = StandaloneMariadb::all(); foreach ($mariadbs as $mariadb) { if (!data_get($mariadb, 'environment')) { - echo 'Mariadb without environment' . $mariadb->name . 'deleting\n'; + echo 'Mariadb without environment: ' . $mariadb->name . ' deleting\n'; $mariadb->delete(); } if (!$mariadb->destination()) { - echo 'Mariadb without destination' . $mariadb->name . 'deleting\n'; + echo 'Mariadb without destination: ' . $mariadb->name . ' deleting\n'; $mariadb->delete(); } if (!data_get($mariadb, 'destination.server')) { - echo 'Mariadb without server' . $mariadb->name . 'deleting\n'; + echo 'Mariadb without server: ' . $mariadb->name . ' deleting\n'; $mariadb->delete(); } } @@ -233,15 +233,15 @@ class Init extends Command $services = Service::all(); foreach ($services as $service) { if (!data_get($service, 'environment')) { - echo 'Service without environment' . $service->name . 'deleting\n'; + echo 'Service without environment: ' . $service->name . ' deleting\n'; $service->delete(); } if (!$service->destination()) { - echo 'Service without destination' . $service->name . 'deleting\n'; + echo 'Service without destination: ' . $service->name . ' deleting\n'; $service->delete(); } if (!data_get($service, 'server')) { - echo 'Service without server' . $service->name . 'deleting\n'; + echo 'Service without server: ' . $service->name . ' deleting\n'; $service->delete(); } } @@ -252,7 +252,7 @@ class Init extends Command $serviceApplications = ServiceApplication::all(); foreach ($serviceApplications as $service) { if (!data_get($service, 'service')) { - echo 'ServiceApplication without service' . $service->name . 'deleting\n'; + echo 'ServiceApplication without service: ' . $service->name . ' deleting\n'; $service->delete(); } } @@ -263,7 +263,7 @@ class Init extends Command $serviceDatabases = ServiceDatabase::all(); foreach ($serviceDatabases as $service) { if (!data_get($service, 'service')) { - echo 'ServiceDatabase without service' . $service->name . 'deleting\n'; + echo 'ServiceDatabase without service: ' . $service->name . ' deleting\n'; $service->delete(); } } From f7fca69a23bb0a0924633f7edf227f928fbe7be9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 11:53:50 +0100 Subject: [PATCH 05/19] update sentry key --- config/sentry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/sentry.php b/config/sentry.php index ca9e80d7c..b5b534784 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -3,7 +3,7 @@ return [ // @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/ - 'dsn' => 'https://bea22abf110618b07252032aa2e07859@o1082494.ingest.sentry.io/4505347448045568', + 'dsn' => 'https://1bbc8f762199a52aee39196adb3e8d1a@o1082494.ingest.sentry.io/4505347448045568', // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) From 4ea8916d5359eb06cc658a9adb0e177b5f498dbb Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 11:55:08 +0100 Subject: [PATCH 06/19] fix: update Coolify script --- app/Actions/Server/UpdateCoolify.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index 6fd74025c..4c2c57f60 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -18,7 +18,7 @@ class UpdateCoolify try { $settings = InstanceSettings::get(); ray('Running InstanceAutoUpdateJob'); - $this->server = Server::find(0)->first(); + $this->server = Server::find(0); if (!$this->server) { return; } From d93bf97919df71d624c74362bdfb5df2aeac8048 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 12:01:21 +0100 Subject: [PATCH 07/19] cleanup on start --- docker/prod-ssu/etc/s6-overlay/s6-rc.d/init-script/up | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/prod-ssu/etc/s6-overlay/s6-rc.d/init-script/up b/docker/prod-ssu/etc/s6-overlay/s6-rc.d/init-script/up index 3b252b782..b563c067f 100644 --- a/docker/prod-ssu/etc/s6-overlay/s6-rc.d/init-script/up +++ b/docker/prod-ssu/etc/s6-overlay/s6-rc.d/init-script/up @@ -1,3 +1,3 @@ #!/command/execlineb -P s6-setuidgid webuser -php /var/www/html/artisan app:init +php /var/www/html/artisan app:init --cleanup From 2dc175be63428010cb1a4602de6cd8d2515951c3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 12:01:27 +0100 Subject: [PATCH 08/19] fix: null notify --- app/Jobs/ApplicationDeploymentJob.php | 4 ++-- app/Jobs/CheckLogDrainContainerJob.php | 6 +++--- app/Jobs/DatabaseBackupJob.php | 4 ++-- app/Jobs/ServerStatusJob.php | 2 +- app/Livewire/Notifications/DiscordSettings.php | 2 +- app/Livewire/Notifications/EmailSettings.php | 2 +- app/Livewire/Notifications/TelegramSettings.php | 2 +- app/Livewire/Settings/Email.php | 2 +- app/Models/Server.php | 4 ++-- app/Models/User.php | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 9e9725bd1..652fd2262 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1341,10 +1341,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); } queue_next_deployment($this->application); if ($status === ApplicationDeploymentStatus::FINISHED->value) { - $this->application->environment->project->team->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); + $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); } if ($status === ApplicationDeploymentStatus::FAILED->value) { - $this->application->environment->project->team->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview)); + $this->application->environment->project->team?->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview)); } } diff --git a/app/Jobs/CheckLogDrainContainerJob.php b/app/Jobs/CheckLogDrainContainerJob.php index e66a0c08a..eb677265b 100644 --- a/app/Jobs/CheckLogDrainContainerJob.php +++ b/app/Jobs/CheckLogDrainContainerJob.php @@ -63,19 +63,19 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted Sleep::for(10)->seconds(); if ($this->healthcheck()) { if ($this->server->log_drain_notification_sent) { - $this->server->team->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); + $this->server->team?->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); $this->server->update(['log_drain_notification_sent' => false]); } return; } if (!$this->server->log_drain_notification_sent) { ray('Log drain container still unhealthy. Sending notification...'); - $this->server->team->notify(new ContainerStopped('Coolify Log Drainer', $this->server, null)); + $this->server->team?->notify(new ContainerStopped('Coolify Log Drainer', $this->server, null)); $this->server->update(['log_drain_notification_sent' => true]); } } else { if ($this->server->log_drain_notification_sent) { - $this->server->team->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); + $this->server->team?->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); $this->server->update(['log_drain_notification_sent' => false]); } } diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 1ba855f4e..8a854128a 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -286,7 +286,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted if ($this->backup->save_s3) { $this->upload_to_s3(); } - $this->team->notify(new BackupSuccess($this->backup, $this->database)); + $this->team?->notify(new BackupSuccess($this->backup, $this->database)); $this->backup_log->update([ 'status' => 'success', 'message' => $this->backup_output, @@ -302,7 +302,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted ]); } send_internal_notification('DatabaseBackupJob failed with: ' . $e->getMessage()); - $this->team->notify(new BackupFailed($this->backup, $this->database, $this->backup_output)); + $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output)); throw $e; } } diff --git a/app/Jobs/ServerStatusJob.php b/app/Jobs/ServerStatusJob.php index cfe61598f..9dacea95c 100644 --- a/app/Jobs/ServerStatusJob.php +++ b/app/Jobs/ServerStatusJob.php @@ -54,7 +54,7 @@ class ServerStatusJob implements ShouldQueue, ShouldBeEncrypted } else { $this->server->high_disk_usage_notification_sent = true; $this->server->save(); - $this->server->team->notify(new HighDiskUsage($this->server, $this->disk_usage, $this->server->settings->cleanup_after_percentage)); + $this->server->team?->notify(new HighDiskUsage($this->server, $this->disk_usage, $this->server->settings->cleanup_after_percentage)); } } else { DockerCleanupJob::dispatchSync($this->server); diff --git a/app/Livewire/Notifications/DiscordSettings.php b/app/Livewire/Notifications/DiscordSettings.php index cf8b116d4..f5f0d5591 100644 --- a/app/Livewire/Notifications/DiscordSettings.php +++ b/app/Livewire/Notifications/DiscordSettings.php @@ -52,7 +52,7 @@ class DiscordSettings extends Component public function sendTestNotification() { - $this->team->notify(new Test()); + $this->team?->notify(new Test()); $this->dispatch('success', 'Test notification sent.'); } } diff --git a/app/Livewire/Notifications/EmailSettings.php b/app/Livewire/Notifications/EmailSettings.php index f3b121851..cdbaef051 100644 --- a/app/Livewire/Notifications/EmailSettings.php +++ b/app/Livewire/Notifications/EmailSettings.php @@ -70,7 +70,7 @@ class EmailSettings extends Component } public function sendTestNotification() { - $this->team->notify(new Test($this->emails)); + $this->team?->notify(new Test($this->emails)); $this->dispatch('success', 'Test Email sent successfully.'); } public function instantSaveInstance() diff --git a/app/Livewire/Notifications/TelegramSettings.php b/app/Livewire/Notifications/TelegramSettings.php index 08f1be005..0f581a515 100644 --- a/app/Livewire/Notifications/TelegramSettings.php +++ b/app/Livewire/Notifications/TelegramSettings.php @@ -58,7 +58,7 @@ class TelegramSettings extends Component public function sendTestNotification() { - $this->team->notify(new Test()); + $this->team?->notify(new Test()); $this->dispatch('success', 'Test notification sent.'); } } diff --git a/app/Livewire/Settings/Email.php b/app/Livewire/Settings/Email.php index d005462a8..471c18e9c 100644 --- a/app/Livewire/Settings/Email.php +++ b/app/Livewire/Settings/Email.php @@ -106,7 +106,7 @@ class Email extends Component public function sendTestNotification() { - $this->settings->notify(new Test($this->emails)); + $this->settings?->notify(new Test($this->emails)); $this->dispatch('success', 'Test email sent.'); } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 37a5ffe2a..790b30025 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -164,7 +164,7 @@ class Server extends BaseModel if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) { if ($this->unreachable_notification_sent === false) { ray('Server unreachable, sending notification...'); - $this->team->notify(new Unreachable($this)); + $this->team?->notify(new Unreachable($this)); $this->update(['unreachable_notification_sent' => true]); } $this->settings()->update([ @@ -401,7 +401,7 @@ class Server extends BaseModel } if (data_get($server, 'unreachable_notification_sent') === true) { - $server->team->notify(new Revived($server)); + $server->team?->notify(new Revived($server)); $server->update(['unreachable_notification_sent' => false]); } diff --git a/app/Models/User.php b/app/Models/User.php index ee963a523..c099eb2b6 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -98,7 +98,7 @@ class User extends Authenticatable implements SendsEmail } public function sendPasswordResetNotification($token): void { - $this->notify(new TransactionalEmailsResetPassword($token)); + $this?->notify(new TransactionalEmailsResetPassword($token)); } public function isAdmin() From 69343f974a14d45b82072a23260b5e1096d8e5bc Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 12:08:12 +0100 Subject: [PATCH 09/19] soft delete models --- app/Console/Commands/Init.php | 69 ++++++++++++------ app/Models/Application.php | 2 + app/Models/ServiceApplication.php | 3 +- app/Models/ServiceDatabase.php | 3 +- app/Models/StandaloneMariadb.php | 3 +- app/Models/StandaloneMongodb.php | 3 +- app/Models/StandaloneMysql.php | 3 +- app/Models/StandalonePostgresql.php | 3 +- app/Models/StandaloneRedis.php | 3 +- .../2023_12_13_110214_add_soft_deletes.php | 71 +++++++++++++++++++ 10 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 database/migrations/2023_12_13_110214_add_soft_deletes.php diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 96b843876..12d540aab 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -115,16 +115,19 @@ class Init extends Command $applications = Application::all(); foreach ($applications as $application) { if (!data_get($application, 'environment')) { - echo 'Application without environment: ' . $application->name . ' deleting\n'; + echo 'Application without environment: ' . $application->name . ' soft deleting\n'; $application->delete(); + continue; } if (!$application->destination()) { - echo 'Application without destination: ' . $application->name . ' deleting\n'; + echo 'Application without destination: ' . $application->name . ' soft deleting\n'; $application->delete(); + continue; } if (!data_get($application, 'destination.server')) { - echo 'Application without server: ' . $application->name . ' deleting\n'; + echo 'Application without server: ' . $application->name . ' soft deleting\n'; $application->delete(); + continue; } } } catch (\Throwable $e) { @@ -134,16 +137,19 @@ class Init extends Command $postgresqls = StandalonePostgresql::all(); foreach ($postgresqls as $postgresql) { if (!data_get($postgresql, 'environment')) { - echo 'Postgresql without environment: ' . $postgresql->name . ' deleting\n'; + echo 'Postgresql without environment: ' . $postgresql->name . ' soft deleting\n'; $postgresql->delete(); + continue; } if (!$postgresql->destination()) { - echo 'Postgresql without destination: ' . $postgresql->name . ' deleting\n'; + echo 'Postgresql without destination: ' . $postgresql->name . ' soft deleting\n'; $postgresql->delete(); + continue; } if (!data_get($postgresql, 'destination.server')) { - echo 'Postgresql without server: ' . $postgresql->name . ' deleting\n'; + echo 'Postgresql without server: ' . $postgresql->name . ' soft deleting\n'; $postgresql->delete(); + continue; } } } catch (\Throwable $e) { @@ -153,16 +159,19 @@ class Init extends Command $redis = StandaloneRedis::all(); foreach ($redis as $redis) { if (!data_get($redis, 'environment')) { - echo 'Redis without environment: ' . $redis->name . ' deleting\n'; + echo 'Redis without environment: ' . $redis->name . ' soft deleting\n'; $redis->delete(); + continue; } if (!$redis->destination()) { - echo 'Redis without destination: ' . $redis->name . ' deleting\n'; + echo 'Redis without destination: ' . $redis->name . ' soft deleting\n'; $redis->delete(); + continue; } if (!data_get($redis, 'destination.server')) { - echo 'Redis without server: ' . $redis->name . ' deleting\n'; + echo 'Redis without server: ' . $redis->name . ' soft deleting\n'; $redis->delete(); + continue; } } } catch (\Throwable $e) { @@ -173,16 +182,19 @@ class Init extends Command $mongodbs = StandaloneMongodb::all(); foreach ($mongodbs as $mongodb) { if (!data_get($mongodb, 'environment')) { - echo 'Mongodb without environment: ' . $mongodb->name . ' deleting\n'; + echo 'Mongodb without environment: ' . $mongodb->name . ' soft deleting\n'; $mongodb->delete(); + continue; } if (!$mongodb->destination()) { - echo 'Mongodb without destination: ' . $mongodb->name . ' deleting\n'; + echo 'Mongodb without destination: ' . $mongodb->name . ' soft deleting\n'; $mongodb->delete(); + continue; } if (!data_get($mongodb, 'destination.server')) { - echo 'Mongodb without server: ' . $mongodb->name . ' deleting\n'; + echo 'Mongodb without server: ' . $mongodb->name . ' soft deleting\n'; $mongodb->delete(); + continue; } } } catch (\Throwable $e) { @@ -193,16 +205,19 @@ class Init extends Command $mysqls = StandaloneMysql::all(); foreach ($mysqls as $mysql) { if (!data_get($mysql, 'environment')) { - echo 'Mysql without environment: ' . $mysql->name . ' deleting\n'; + echo 'Mysql without environment: ' . $mysql->name . ' soft deleting\n'; $mysql->delete(); + continue; } if (!$mysql->destination()) { - echo 'Mysql without destination: ' . $mysql->name . ' deleting\n'; + echo 'Mysql without destination: ' . $mysql->name . ' soft deleting\n'; $mysql->delete(); + continue; } if (!data_get($mysql, 'destination.server')) { - echo 'Mysql without server: ' . $mysql->name . ' deleting\n'; + echo 'Mysql without server: ' . $mysql->name . ' soft deleting\n'; $mysql->delete(); + continue; } } } catch (\Throwable $e) { @@ -213,16 +228,19 @@ class Init extends Command $mariadbs = StandaloneMariadb::all(); foreach ($mariadbs as $mariadb) { if (!data_get($mariadb, 'environment')) { - echo 'Mariadb without environment: ' . $mariadb->name . ' deleting\n'; + echo 'Mariadb without environment: ' . $mariadb->name . ' soft deleting\n'; $mariadb->delete(); + continue; } if (!$mariadb->destination()) { - echo 'Mariadb without destination: ' . $mariadb->name . ' deleting\n'; + echo 'Mariadb without destination: ' . $mariadb->name . ' soft deleting\n'; $mariadb->delete(); + continue; } if (!data_get($mariadb, 'destination.server')) { - echo 'Mariadb without server: ' . $mariadb->name . ' deleting\n'; + echo 'Mariadb without server: ' . $mariadb->name . ' soft deleting\n'; $mariadb->delete(); + continue; } } } catch (\Throwable $e) { @@ -233,16 +251,19 @@ class Init extends Command $services = Service::all(); foreach ($services as $service) { if (!data_get($service, 'environment')) { - echo 'Service without environment: ' . $service->name . ' deleting\n'; + echo 'Service without environment: ' . $service->name . ' soft deleting\n'; $service->delete(); + continue; } if (!$service->destination()) { - echo 'Service without destination: ' . $service->name . ' deleting\n'; + echo 'Service without destination: ' . $service->name . ' soft deleting\n'; $service->delete(); + continue; } if (!data_get($service, 'server')) { - echo 'Service without server: ' . $service->name . ' deleting\n'; + echo 'Service without server: ' . $service->name . ' soft deleting\n'; $service->delete(); + continue; } } } catch (\Throwable $e) { @@ -252,8 +273,9 @@ class Init extends Command $serviceApplications = ServiceApplication::all(); foreach ($serviceApplications as $service) { if (!data_get($service, 'service')) { - echo 'ServiceApplication without service: ' . $service->name . ' deleting\n'; + echo 'ServiceApplication without service: ' . $service->name . ' soft deleting\n'; $service->delete(); + continue; } } } catch (\Throwable $e) { @@ -263,8 +285,9 @@ class Init extends Command $serviceDatabases = ServiceDatabase::all(); foreach ($serviceDatabases as $service) { if (!data_get($service, 'service')) { - echo 'ServiceDatabase without service: ' . $service->name . ' deleting\n'; + echo 'ServiceDatabase without service: ' . $service->name . ' soft deleting\n'; $service->delete(); + continue; } } } catch (\Throwable $e) { diff --git a/app/Models/Application.php b/app/Models/Application.php index d56be8f0a..e58d4a028 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Collection; use Spatie\Activitylog\Models\Activity; use Illuminate\Support\Str; @@ -13,6 +14,7 @@ use Visus\Cuid2\Cuid2; class Application extends BaseModel { + use SoftDeletes; protected $guarded = []; protected static function booted() diff --git a/app/Models/ServiceApplication.php b/app/Models/ServiceApplication.php index b8e3f1a41..510395266 100644 --- a/app/Models/ServiceApplication.php +++ b/app/Models/ServiceApplication.php @@ -4,11 +4,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Cache; class ServiceApplication extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected static function booted() diff --git a/app/Models/ServiceDatabase.php b/app/Models/ServiceDatabase.php index 79c1dd176..0bde42c20 100644 --- a/app/Models/ServiceDatabase.php +++ b/app/Models/ServiceDatabase.php @@ -3,10 +3,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\SoftDeletes; class ServiceDatabase extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected static function booted() diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index 8893632d3..33c00260e 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -6,10 +6,11 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; class StandaloneMariadb extends BaseModel { - use HasFactory; + use HasFactory,SoftDeletes; protected $guarded = []; protected $casts = [ diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index c041c9407..d08c04adb 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -5,10 +5,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; class StandaloneMongodb extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected static function booted() diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index a4691b9b2..02f8f82c4 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -5,10 +5,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; class StandaloneMysql extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected $casts = [ diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index e0db00d76..df9d28460 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -5,10 +5,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; class StandalonePostgresql extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected $casts = [ diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 95add8315..7ccde7f68 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -5,10 +5,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\SoftDeletes; class StandaloneRedis extends BaseModel { - use HasFactory; + use HasFactory, SoftDeletes; protected $guarded = []; protected static function booted() diff --git a/database/migrations/2023_12_13_110214_add_soft_deletes.php b/database/migrations/2023_12_13_110214_add_soft_deletes.php new file mode 100644 index 000000000..ab7b562b4 --- /dev/null +++ b/database/migrations/2023_12_13_110214_add_soft_deletes.php @@ -0,0 +1,71 @@ +softDeletes(); + }); + Schema::table('standalone_postgresqls', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('standalone_redis', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('standalone_mongodbs', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('standalone_mysqls', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('standalone_mariadbs', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('service_applications', function (Blueprint $table) { + $table->softDeletes(); + }); + Schema::table('service_databases', function (Blueprint $table) { + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('applications', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('standalone_postgresqls', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('standalone_redis', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('standalone_mongodbs', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('standalone_mysqls', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('standalone_mariadbs', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('service_applications', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + Schema::table('service_databases', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + + } +}; From ff8d8371ad4f07a1c6bcce6184a71c43de80bd0b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 12:13:20 +0100 Subject: [PATCH 10/19] fix: check queued deployments as well --- app/Console/Commands/Init.php | 2 +- app/Models/Application.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 12d540aab..ec4d75484 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -99,7 +99,7 @@ class Init extends Command // Cleanup any failed deployments try { - $halted_deployments = ApplicationDeploymentQueue::where('status', '==', 'in_progress')->get(); + $halted_deployments = ApplicationDeploymentQueue::where('status', '==', ApplicationDeploymentStatus::IN_PROGRESS)->where('status', '==', ApplicationDeploymentStatus::QUEUED)->get(); foreach ($halted_deployments as $deployment) { $deployment->status = ApplicationDeploymentStatus::FAILED->value; $deployment->save(); diff --git a/app/Models/Application.php b/app/Models/Application.php index e58d4a028..d3ddc4e43 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\ApplicationDeploymentStatus; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; @@ -340,7 +341,7 @@ class Application extends BaseModel } public function isDeploymentInprogress() { - $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'in_progress')->count(); + $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', ApplicationDeploymentStatus::IN_PROGRESS)->where('status', ApplicationDeploymentStatus::QUEUED)->count(); if ($deployments > 0) { return true; } From e0289e29498bb5cd6da9759617bd8cc0a18efe42 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 12:35:56 +0100 Subject: [PATCH 11/19] feat: randomly sleep between executions --- app/Jobs/ContainerStatusJob.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 5599c6de4..0bdfca84e 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -17,6 +17,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Arr; +use Illuminate\Support\Sleep; class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted { @@ -37,10 +38,10 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted $this->handle(); } - public function handle() { - // ray("checking container statuses for {$this->server->id}"); + $rand = rand(1, 15); + Sleep::for($rand)->seconds(); try { if (!$this->server->isServerReady()) { return; From 52d84c5e9ec8eca76580ce5a8fc8ea2e1950bb0e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 14:22:23 +0100 Subject: [PATCH 12/19] refactor: clone project --- app/Livewire/Project/CloneProject.php | 16 +++--- .../livewire/project/clone-project.blade.php | 50 +++++++++---------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/app/Livewire/Project/CloneProject.php b/app/Livewire/Project/CloneProject.php index 3a6a1db6f..7ce89f8de 100644 --- a/app/Livewire/Project/CloneProject.php +++ b/app/Livewire/Project/CloneProject.php @@ -19,12 +19,14 @@ class CloneProject extends Component public $servers; public ?Environment $environment = null; public ?int $selectedServer = null; + public ?int $selectedDestination = null; public ?Server $server = null; public $resources = []; public string $newProjectName = ''; protected $messages = [ 'selectedServer' => 'Please select a server.', + 'selectedDestination' => 'Please select a server & destination.', 'newProjectName' => 'Please enter a name for the new project.', ]; public function mount($project_uuid) @@ -34,7 +36,7 @@ class CloneProject extends Component $this->environment = $this->project->environments->where('name', $this->environment_name)->first(); $this->project_id = $this->project->id; $this->servers = currentTeam()->servers; - $this->newProjectName = $this->project->name . ' (clone)'; + $this->newProjectName = str($this->project->name . '-clone-' . (string)new Cuid2(7))->slug(); } public function render() @@ -42,9 +44,10 @@ class CloneProject extends Component return view('livewire.project.clone-project'); } - public function selectServer($server_id) + public function selectServer($server_id, $destination_id) { $this->selectedServer = $server_id; + $this->selectedDestination = $destination_id; $this->server = $this->servers->where('id', $server_id)->first(); } @@ -52,7 +55,7 @@ class CloneProject extends Component { try { $this->validate([ - 'selectedServer' => 'required', + 'selectedDestination' => 'required', 'newProjectName' => 'required', ]); $foundProject = Project::where('name', $this->newProjectName)->first(); @@ -81,7 +84,8 @@ class CloneProject extends Component 'fqdn' => generateFqdn($this->server, $uuid), 'status' => 'exited', 'environment_id' => $newEnvironment->id, - 'destination_id' => $this->selectedServer, + // This is not correct, but we need to set it to something + 'destination_id' => $this->selectedDestination, ]); $newApplication->save(); $environmentVaribles = $application->environment_variables()->get(); @@ -107,7 +111,7 @@ class CloneProject extends Component 'status' => 'exited', 'started_at' => null, 'environment_id' => $newEnvironment->id, - 'destination_id' => $this->selectedServer, + 'destination_id' => $this->selectedDestination, ]); $newDatabase->save(); $environmentVaribles = $database->environment_variables()->get(); @@ -133,7 +137,7 @@ class CloneProject extends Component $newService = $service->replicate()->fill([ 'uuid' => $uuid, 'environment_id' => $newEnvironment->id, - 'destination_id' => $this->selectedServer, + 'destination_id' => $this->selectedDestination, ]); $newService->save(); foreach ($newService->applications() as $application) { diff --git a/resources/views/livewire/project/clone-project.blade.php b/resources/views/livewire/project/clone-project.blade.php index 7d1fd9070..3e6203281 100644 --- a/resources/views/livewire/project/clone-project.blade.php +++ b/resources/views/livewire/project/clone-project.blade.php @@ -1,36 +1,36 @@
-
-

Clone

- Clone to a New Project -
-
Quickly clone a project
+

Clone

+
Quickly clone all resources to a new project
+
+
+ + Clone
-

Servers

-
- @foreach ($servers as $srv) -
-
-
{{ $srv->name }}
- @isset($selectedServer) -
- {{ $srv->description }}
- @else -
- {{ $srv->description }}
- @endisset - +
+ @foreach ($servers->sortBy('id') as $server) +
+

{{ $server->name }}

+
{{ $server->description }}
+
Docker Networks
+
+ @foreach ($server->destinations() as $destination) +
+ {{ $destination->name }} +
+ @endforeach
@endforeach
+

Resources

-
+
@foreach ($environment->applications->sortBy('name') as $application) -
+
{{ $application->name }}
{{ $application->description }}
@@ -38,7 +38,7 @@
@endforeach @foreach ($environment->databases()->sortBy('name') as $database) -
+
{{ $database->name }}
{{ $database->description }}
@@ -46,7 +46,7 @@
@endforeach @foreach ($environment->services->sortBy('name') as $service) -
+
{{ $service->name }}
{{ $service->description }}
From 1ff1664b6cfca4ea9f14f84525a4b1f0fa4a936e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 14:44:11 +0100 Subject: [PATCH 13/19] fix: copy invitation --- .../views/components/forms/input.blade.php | 19 ++++++++++--------- .../views/livewire/team/invitations.blade.php | 19 ++++++++++++++++--- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/resources/views/components/forms/input.blade.php b/resources/views/components/forms/input.blade.php index 3e9c3a35d..66f0791d1 100644 --- a/resources/views/components/forms/input.blade.php +++ b/resources/views/components/forms/input.blade.php @@ -22,19 +22,20 @@
@endif - merge(['class' => $defaultClass . ' pl-10']) }} @required($required) - wire:model={{ $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 }}" placeholder="{{ $attributes->get('placeholder') }}" + merge(['class' => $defaultClass . ' pl-10']) }} + @required($required) @if ($id !== 'null') wire:model={{ $id }} @endif + 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 }}" placeholder="{{ $attributes->get('placeholder') }}" aria-placeholder="{{ $attributes->get('placeholder') }}">
@else - merge(['class' => $defaultClass]) }} @required($required) - @readonly($readonly) wire:model={{ $id }} wire:dirty.class.remove='text-white' - wire:dirty.class="input-warning" wire:loading.attr="disabled" type="{{ $type }}" - @disabled($disabled) id="{{ $id }}" name="{{ $name }}" - placeholder="{{ $attributes->get('placeholder') }}"> + merge(['class' => $defaultClass]) }} @required($required) @readonly($readonly) + @if ($id !== 'null') wire:model={{ $id }} @endif wire:dirty.class.remove='text-white' wire:dirty.class="input-warning" + wire:loading.attr="disabled" type="{{ $type }}" @disabled($disabled) + @if ($id !== 'null') id={{ $id }} @endif name="{{ $name }}" placeholder="{{ $attributes->get('placeholder') }}"> @endif @if (!$label && $helper) diff --git a/resources/views/livewire/team/invitations.blade.php b/resources/views/livewire/team/invitations.blade.php index b3b590fde..8fc8f9cf3 100644 --- a/resources/views/livewire/team/invitations.blade.php +++ b/resources/views/livewire/team/invitations.blade.php @@ -18,8 +18,12 @@ {{ $invite->email }} {{ $invite->via }} {{ $invite->role }} - - Copy Invitation Link + + + Revoke @@ -31,6 +35,15 @@
- @endif
+ +@script + +@endscript From 02c8b9f4716861b1459d478124a63f4e7758edf3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 15:22:37 +0100 Subject: [PATCH 14/19] fix: password reset / invitation link requests --- app/Http/Controllers/Controller.php | 24 ++++++++++++++----- .../Middleware/CheckForcePasswordReset.php | 2 +- .../Middleware/DecideWhatToDoWithUser.php | 3 +++ bootstrap/helpers/subscriptions.php | 10 -------- resources/views/auth/reset-password.blade.php | 4 ++-- resources/views/layouts/simple.blade.php | 1 + .../livewire/force-password-reset.blade.php | 4 ++-- 7 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 08f7a7376..6338d7625 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -39,7 +39,7 @@ class Controller extends BaseController } else { $team = $user->teams()->first(); } - if (is_null(data_get($user, 'email_verified_at'))){ + if (is_null(data_get($user, 'email_verified_at'))) { $user->email_verified_at = now(); $user->save(); } @@ -137,16 +137,28 @@ class Controller extends BaseController public function acceptInvitation() { try { - $invitation = TeamInvitation::whereUuid(request()->route('uuid'))->firstOrFail(); + $resetPassword = request()->query('reset-password'); + $invitationUuid = request()->route('uuid'); + $invitation = TeamInvitation::whereUuid($invitationUuid)->firstOrFail(); $user = User::whereEmail($invitation->email)->firstOrFail(); - if (auth()->user()->id !== $user->id) { - abort(401); - } $invitationValid = $invitation->isValid(); if ($invitationValid) { + if ($resetPassword) { + $user->update([ + 'password' => Hash::make($invitationUuid), + 'force_password_reset' => true + ]); + } + if ($user->teams()->where('team_id', $invitation->team->id)->exists()) { + $invitation->delete(); + return redirect()->route('team.index'); + } $user->teams()->attach($invitation->team->id, ['role' => $invitation->role]); - refreshSession($invitation->team); $invitation->delete(); + if (auth()->user()?->id !== $user->id) { + return redirect()->route('login'); + } + refreshSession($invitation->team); return redirect()->route('team.index'); } else { abort(401); diff --git a/app/Http/Middleware/CheckForcePasswordReset.php b/app/Http/Middleware/CheckForcePasswordReset.php index e8129deda..79b3819f7 100644 --- a/app/Http/Middleware/CheckForcePasswordReset.php +++ b/app/Http/Middleware/CheckForcePasswordReset.php @@ -24,7 +24,7 @@ class CheckForcePasswordReset } $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') { + if ($request->routeIs('auth.force-password-reset') || $request->path() === 'force-password-reset' || $request->path() === 'livewire/update' || $request->path() === 'logout') { return $next($request); } return redirect()->route('auth.force-password-reset'); diff --git a/app/Http/Middleware/DecideWhatToDoWithUser.php b/app/Http/Middleware/DecideWhatToDoWithUser.php index 19a09125a..1381396df 100644 --- a/app/Http/Middleware/DecideWhatToDoWithUser.php +++ b/app/Http/Middleware/DecideWhatToDoWithUser.php @@ -11,6 +11,9 @@ class DecideWhatToDoWithUser { public function handle(Request $request, Closure $next): Response { + if(auth()?->user()?->currentTeam()){ + refreshSession(auth()->user()->currentTeam()); + } if (!auth()->user() || !isCloud() || isInstanceAdmin()) { if (!isCloud() && showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) { return redirect('boarding'); diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php index c994199f2..47ea21e46 100644 --- a/bootstrap/helpers/subscriptions.php +++ b/bootstrap/helpers/subscriptions.php @@ -128,11 +128,6 @@ function allowedPathsForUnsubscribedAccounts() 'logout', 'waitlist', 'force-password-reset', - // 'livewire/message/force-password-reset', - // 'livewire/message/check-license', - // 'livewire/message/switch-team', - // 'livewire/message/subscription.pricing-plans', - // 'livewire/message/help', 'livewire/update' ]; } @@ -141,8 +136,6 @@ function allowedPathsForBoardingAccounts() return [ ...allowedPathsForUnsubscribedAccounts(), 'boarding', - // 'livewire/message/boarding.index', - // 'livewire/message/activity-monitor', 'livewire/update' ]; } @@ -151,9 +144,6 @@ function allowedPathsForInvalidAccounts() { 'logout', 'verify', 'force-password-reset', - // 'livewire/message/force-password-reset', - // 'livewire/message/verify-email', - // 'livewire/message/help', 'livewire/update' ]; } diff --git a/resources/views/auth/reset-password.blade.php b/resources/views/auth/reset-password.blade.php index ae417a0d9..6b248cfee 100644 --- a/resources/views/auth/reset-password.blade.php +++ b/resources/views/auth/reset-password.blade.php @@ -1,13 +1,13 @@
-
+
-

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

+ {{ __('auth.reset_password') }}
diff --git a/resources/views/layouts/simple.blade.php b/resources/views/layouts/simple.blade.php index c3a25cda8..77bff99ab 100644 --- a/resources/views/layouts/simple.blade.php +++ b/resources/views/layouts/simple.blade.php @@ -1,6 +1,7 @@ @extends('layouts.base') @section('body') @parent +
{{ $slot }}
diff --git a/resources/views/livewire/force-password-reset.blade.php b/resources/views/livewire/force-password-reset.blade.php index 42f1576a4..d6951d0ad 100644 --- a/resources/views/livewire/force-password-reset.blade.php +++ b/resources/views/livewire/force-password-reset.blade.php @@ -1,12 +1,12 @@
-
+
-

Set your initial password

+ Set your initial password
From b06b465ffa49b9b52af20c3be012ffe7679bf757 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 15:29:45 +0100 Subject: [PATCH 15/19] fix: add catch all route --- resources/views/livewire/dashboard.blade.php | 2 +- routes/web.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index 70f25b8fb..c6f56872a 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -69,7 +69,7 @@ @if ($servers->count() === 1)
@else -
+
@endif @foreach ($servers as $server) group(function () { ]); })->name('destination.show'); }); + +Route::any('/{any}', function () { + if (auth()->user()) { + return redirect('/'); + } + return redirect('/login'); +})->where('any', '.*'); From 638bcf9732fc5f25c2b3ea3431af834b0ab1d80c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 15:34:33 +0100 Subject: [PATCH 16/19] update --- app/Jobs/DeleteResourceJob.php | 2 +- app/Livewire/Project/Shared/Danger.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Jobs/DeleteResourceJob.php b/app/Jobs/DeleteResourceJob.php index f8df38a2a..347eb40d0 100644 --- a/app/Jobs/DeleteResourceJob.php +++ b/app/Jobs/DeleteResourceJob.php @@ -59,7 +59,7 @@ class DeleteResourceJob implements ShouldQueue, ShouldBeEncrypted $this->resource->delete(); DeleteService::dispatch($this->resource); } else { - $this->resource->delete(); + $this->resource->forceDelete(); } } catch (\Throwable $e) { send_internal_notification('ContainerStoppingJob failed with: ' . $e->getMessage()); diff --git a/app/Livewire/Project/Shared/Danger.php b/app/Livewire/Project/Shared/Danger.php index 39dc38310..d85dfb876 100644 --- a/app/Livewire/Project/Shared/Danger.php +++ b/app/Livewire/Project/Shared/Danger.php @@ -24,7 +24,7 @@ class Danger extends Component public function delete() { try { - DeleteResourceJob::dispatchSync($this->resource); + DeleteResourceJob::dispatch($this->resource); return $this->redirectRoute('project.resources', [ 'project_uuid' => $this->projectUuid, 'environment_name' => $this->environmentName From db13dd93042494ef6cc9067281cb88575c4635c3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 13 Dec 2023 15:40:57 +0100 Subject: [PATCH 17/19] fix: revert random container job delay --- app/Jobs/ContainerStatusJob.php | 2 -- app/Jobs/DeleteResourceJob.php | 4 ++-- app/Livewire/Project/Shared/Danger.php | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php index 0bdfca84e..9989ed8cb 100644 --- a/app/Jobs/ContainerStatusJob.php +++ b/app/Jobs/ContainerStatusJob.php @@ -40,8 +40,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted public function handle() { - $rand = rand(1, 15); - Sleep::for($rand)->seconds(); try { if (!$this->server->isServerReady()) { return; diff --git a/app/Jobs/DeleteResourceJob.php b/app/Jobs/DeleteResourceJob.php index 347eb40d0..cf7c6462a 100644 --- a/app/Jobs/DeleteResourceJob.php +++ b/app/Jobs/DeleteResourceJob.php @@ -32,9 +32,10 @@ class DeleteResourceJob implements ShouldQueue, ShouldBeEncrypted try { $server = $this->resource->destination->server; if (!$server->isFunctional()) { - $this->resource->delete(); + $this->resource->forceDelete(); return 'Server is not functional'; } + $this->resource->delete(); switch ($this->resource->type()) { case 'application': StopApplication::run($this->resource); @@ -56,7 +57,6 @@ class DeleteResourceJob implements ShouldQueue, ShouldBeEncrypted break; } if ($this->resource->type() === 'service') { - $this->resource->delete(); DeleteService::dispatch($this->resource); } else { $this->resource->forceDelete(); diff --git a/app/Livewire/Project/Shared/Danger.php b/app/Livewire/Project/Shared/Danger.php index d85dfb876..39dc38310 100644 --- a/app/Livewire/Project/Shared/Danger.php +++ b/app/Livewire/Project/Shared/Danger.php @@ -24,7 +24,7 @@ class Danger extends Component public function delete() { try { - DeleteResourceJob::dispatch($this->resource); + DeleteResourceJob::dispatchSync($this->resource); return $this->redirectRoute('project.resources', [ 'project_uuid' => $this->projectUuid, 'environment_name' => $this->environmentName From a0abde8652513ee83f10e6cf0435080db0c4a31d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 14 Dec 2023 14:24:54 +0100 Subject: [PATCH 18/19] ui: add image name to service stack + better options visibility --- resources/css/app.css | 42 ++++++- .../livewire/project/service/index.blade.php | 108 ++++++++++++------ 2 files changed, 113 insertions(+), 37 deletions(-) diff --git a/resources/css/app.css b/resources/css/app.css index 3b9d9ca93..868cbd9c0 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -5,25 +5,32 @@ html { @apply text-neutral-400; } + body { @apply text-sm antialiased scrollbar; } + button[isError] { @apply bg-red-600 hover:bg-red-700; } + .scrollbar { @apply scrollbar-thumb-coollabs-100 scrollbar-track-coolgray-200 scrollbar-w-2; } + .main { @apply pt-4 pl-24 pr-10 mx-auto; } + .custom-modal { @apply flex flex-col gap-2 px-8 py-4 border bg-base-100 border-coolgray-200; } + .label-text, label { @apply text-neutral-400; } + .navbar-main { @apply flex items-end gap-6 py-2 border-b-2 border-solid border-coolgray-200; } @@ -31,89 +38,117 @@ label { .loading { @apply w-4 text-warning; } + h1 { @apply text-3xl font-bold text-white; } + h2 { @apply text-2xl font-bold text-white; } + h3 { @apply text-xl font-bold text-white; } + h4 { @apply text-base font-bold text-white; } + a { @apply text-neutral-400 hover:text-white link link-hover hover:bg-transparent; } + .kbd-custom { @apply px-2 text-xs border border-dashed rounded border-neutral-700 text-warning; } + .icon { @apply w-6 h-6; } + .icon:hover { @apply text-white; } + .box { @apply flex p-2 transition-colors cursor-pointer min-h-[4rem] bg-coolgray-100 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem]; } + .box-without-bg { - @apply flex p-2 transition-colors h-16 min-h-full hover:text-white hover:no-underline min-h-[4rem]; + @apply flex p-2 transition-colors min-h-full hover:text-white hover:no-underline min-h-[4rem]; } + .description { @apply pt-2 text-xs font-bold text-neutral-500 group-hover:text-white; } + .lds-heart { animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1); } + @keyframes lds-heart { 0% { transform: scale(1); } + 5% { transform: scale(1.2); } + 39% { transform: scale(0.85); } + 45% { transform: scale(1); } + 60% { transform: scale(0.95); } + 100% { transform: scale(0.9); } } + .bg-coollabs-gradient { @apply text-transparent text-white bg-gradient-to-r from-purple-500 via-pink-500 to-red-500; } + .text-helper { @apply inline-block font-bold text-warning; } + table { @apply min-w-full divide-y divide-coolgray-200; } + thead { @apply uppercase; } + tbody { @apply divide-y divide-coolgray-200; } + tr { @apply text-neutral-400; } + tr th { @apply px-3 py-3.5 text-left text-white; } + tr th:first-child { @apply py-3.5 pl-4 pr-3 sm:pl-6; } + tr td { @apply px-3 py-4 whitespace-nowrap; } + tr td:first-child { @apply pl-4 pr-3 font-bold sm:pl-6; } @@ -121,12 +156,15 @@ tr td:first-child { .buyme { @apply block px-3 py-2 mt-10 text-sm font-semibold leading-6 text-center text-white rounded-md shadow-sm bg-coolgray-200 hover:bg-coolgray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coolgray-200 hover:no-underline; } + .subtitle { @apply pt-2 pb-10; } + .fullscreen { - @apply fixed top-0 left-0 w-full h-full z-[9999] bg-coolgray-100 overflow-y-auto scrollbar pb-4 ; + @apply fixed top-0 left-0 w-full h-full z-[9999] bg-coolgray-100 overflow-y-auto scrollbar pb-4; } + input.input-sm { @apply pr-10; } diff --git a/resources/views/livewire/project/service/index.blade.php b/resources/views/livewire/project/service/index.blade.php index 1daade6af..8be375332 100644 --- a/resources/views/livewire/project/service/index.blade.php +++ b/resources/views/livewire/project/service/index.blade.php @@ -44,26 +44,44 @@ $application->status)->contains(['running']), 'border-l border-dashed border-warning' => Str::of( $application->status)->contains(['starting']), - 'flex gap-2 box group', + 'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group', ])> - - @if ($application->human_name) - {{ Str::headline($application->human_name) }} - @else - {{ Str::headline($application->name) }} - @endif - @if ($application->configuration_required) - (configuration required) - @endif - @if ($application->description) - {{ Str::limit($application->description, 60) }} - @endif - @if ($application->fqdn) - {{ Str::limit($application->fqdn, 60) }} - @endif -
{{ $application->status }}
-
+
+
+
+ @if ($application->human_name) + {{ Str::headline($application->human_name) }} + @else + {{ Str::headline($application->name) }} + @endif + ({{ $application->image }}) +
+ @if ($application->configuration_required) + (configuration required) + @endif + @if ($application->description) + {{ Str::limit($application->description, 60) }} + @endif + @if ($application->fqdn) + {{ Str::limit($application->fqdn, 60) }} + @endif +
{{ $application->status }}
+
+ +
@endforeach @foreach ($databases as $database) @@ -74,23 +92,43 @@ $database->status)->contains(['running']), 'border-l border-dashed border-warning' => Str::of( $database->status)->contains(['restarting']), - 'flex gap-2 box group', + 'flex gap-2 box-without-bg bg-coolgray-100 hover:text-neutral-300 group', ])> - - @if ($database->human_name) - {{ Str::headline($database->human_name) }} - @else - {{ Str::headline($database->name) }} - @endif - @if ($database->configuration_required) - (configuration required) - @endif - @if ($database->description) - {{ Str::limit($database->description, 60) }} - @endif -
{{ $database->status }}
-
+ + +
+
+
+ @if ($database->human_name) + {{ Str::headline($database->human_name) }} + @else + {{ Str::headline($database->name) }} + @endif + ({{ $database->image }}) +
+ @if ($database->configuration_required) + (configuration required) + @endif + @if ($database->description) + {{ Str::limit($database->description, 60) }} + @endif +
{{ $database->status }}
+
+ +
@endforeach
From 75d1ec4f42c8188402a8d4d2943b1d7d2bd0f06d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 14 Dec 2023 14:50:38 +0100 Subject: [PATCH 19/19] feat: pull latest images for services --- app/Actions/Service/StartService.php | 1 + app/Actions/Service/StopService.php | 1 + app/Actions/Shared/PullImage.php | 25 +++++++++++++++++++ app/Livewire/Project/Service/Navbar.php | 15 +++++++++++ .../components/services/navbar.blade.php | 20 ++++++++++++++- 5 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 app/Actions/Shared/PullImage.php diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php index dc722aa83..a90b368ab 100644 --- a/app/Actions/Service/StartService.php +++ b/app/Actions/Service/StartService.php @@ -11,6 +11,7 @@ class StartService use AsAction; public function handle(Service $service) { + ray('Starting service: ' . $service->name); $network = $service->destination->network; $service->saveComposeConfigs(); $commands[] = "cd " . $service->workdir(); diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index f7de50165..d9ac6376e 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -10,6 +10,7 @@ class StopService use AsAction; public function handle(Service $service) { + ray('Stopping service: ' . $service->name); $applications = $service->applications()->get(); foreach ($applications as $application) { instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server); diff --git a/app/Actions/Shared/PullImage.php b/app/Actions/Shared/PullImage.php new file mode 100644 index 000000000..42713b227 --- /dev/null +++ b/app/Actions/Shared/PullImage.php @@ -0,0 +1,25 @@ +saveComposeConfigs(); + + $commands[] = "cd " . $resource->workdir(); + $commands[] = "echo 'Saved configuration files to {$resource->workdir()}.'"; + $commands[] = "docker compose pull"; + + $server = data_get($resource, 'server'); + + if (!$server) return; + + instant_remote_process($commands, $resource->server); + } +} diff --git a/app/Livewire/Project/Service/Navbar.php b/app/Livewire/Project/Service/Navbar.php index 3e2c3485c..d401a1022 100644 --- a/app/Livewire/Project/Service/Navbar.php +++ b/app/Livewire/Project/Service/Navbar.php @@ -2,6 +2,7 @@ namespace App\Livewire\Project\Service; +use App\Actions\Shared\PullImage; use App\Actions\Service\StartService; use App\Actions\Service\StopService; use App\Events\ServiceStatusChanged; @@ -69,4 +70,18 @@ class Navbar extends Component } ServiceStatusChanged::dispatch(); } + public function restart() + { + $this->checkDeployments(); + if ($this->isDeploymentProgress) { + $this->dispatch('error', 'There is a deployment in progress.'); + return; + } + PullImage::run($this->service); + $this->dispatch('image-pulled'); + StopService::run($this->service); + $this->service->parse(); + $activity = StartService::run($this->service); + $this->dispatch('newMonitorActivity', $activity->id); + } } diff --git a/resources/views/components/services/navbar.blade.php b/resources/views/components/services/navbar.blade.php index 84ad7c6e1..c25bb3eac 100644 --- a/resources/views/components/services/navbar.blade.php +++ b/resources/views/components/services/navbar.blade.php @@ -1,4 +1,4 @@ -