diff --git a/README.md b/README.md
index 97580b875..354c385e7 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,7 @@ Special thanks to our biggest sponsor, [CCCareers](https://cccareers.org/)!
+
diff --git a/app/Actions/Database/StartClickhouse.php b/app/Actions/Database/StartClickhouse.php
index 5f567802f..414d6b407 100644
--- a/app/Actions/Database/StartClickhouse.php
+++ b/app/Actions/Database/StartClickhouse.php
@@ -29,6 +29,7 @@ class StartClickhouse
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
@@ -93,6 +94,11 @@ class StartClickhouse
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartDragonfly.php b/app/Actions/Database/StartDragonfly.php
index 92daf195d..04348c40a 100644
--- a/app/Actions/Database/StartDragonfly.php
+++ b/app/Actions/Database/StartDragonfly.php
@@ -32,6 +32,7 @@ class StartDragonfly
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
@@ -94,6 +95,11 @@ class StartDragonfly
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartKeydb.php b/app/Actions/Database/StartKeydb.php
index 8c833efd5..672308d89 100644
--- a/app/Actions/Database/StartKeydb.php
+++ b/app/Actions/Database/StartKeydb.php
@@ -32,6 +32,7 @@ class StartKeydb
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->add_custom_keydb();
@@ -92,6 +93,11 @@ class StartKeydb
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartMariadb.php b/app/Actions/Database/StartMariadb.php
index c79df0dc5..652d8fa29 100644
--- a/app/Actions/Database/StartMariadb.php
+++ b/app/Actions/Database/StartMariadb.php
@@ -28,6 +28,7 @@ class StartMariadb
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->add_custom_mysql();
@@ -86,6 +87,11 @@ class StartMariadb
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartMongodb.php b/app/Actions/Database/StartMongodb.php
index 46b426ad8..38e2621bd 100644
--- a/app/Actions/Database/StartMongodb.php
+++ b/app/Actions/Database/StartMongodb.php
@@ -30,6 +30,7 @@ class StartMongodb
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->add_custom_mongo_conf();
@@ -94,6 +95,11 @@ class StartMongodb
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartMysql.php b/app/Actions/Database/StartMysql.php
index 6fdc8cdad..604e72fde 100644
--- a/app/Actions/Database/StartMysql.php
+++ b/app/Actions/Database/StartMysql.php
@@ -28,6 +28,7 @@ class StartMysql
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->add_custom_mysql();
@@ -86,6 +87,11 @@ class StartMysql
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartPostgresql.php b/app/Actions/Database/StartPostgresql.php
index 8db874ea6..554e347d9 100644
--- a/app/Actions/Database/StartPostgresql.php
+++ b/app/Actions/Database/StartPostgresql.php
@@ -29,6 +29,7 @@ class StartPostgresql
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->generate_init_scripts();
@@ -92,6 +93,11 @@ class StartPostgresql
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Actions/Database/StartRedis.php b/app/Actions/Database/StartRedis.php
index 5b6ab2999..055d82600 100644
--- a/app/Actions/Database/StartRedis.php
+++ b/app/Actions/Database/StartRedis.php
@@ -32,6 +32,7 @@ class StartRedis
];
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->database->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables();
$this->add_custom_redis();
@@ -96,6 +97,11 @@ class StartRedis
if (count($persistent_storages) > 0) {
$docker_compose['services'][$container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php
index 7d6721252..200d3dd1c 100644
--- a/app/Http/Controllers/Webhook/Stripe.php
+++ b/app/Http/Controllers/Webhook/Stripe.php
@@ -150,6 +150,10 @@ class Stripe extends Controller
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
}
if (!$subscription) {
+ if ($status === 'incomplete_expired') {
+ send_internal_notification('Subscription incomplete expired for customer: ' . $customerId);
+ return response("Subscription incomplete expired", 200);
+ }
send_internal_notification('No subscription found for: ' . $customerId);
return response("No subscription found", 400);
}
@@ -166,9 +170,11 @@ class Stripe extends Controller
$quantity = data_get($data, 'items.data.0.quantity', 10);
}
$team = data_get($subscription, 'team');
- $team->update([
- 'custom_server_limit' => $quantity,
- ]);
+ if ($team) {
+ $team->update([
+ 'custom_server_limit' => $quantity,
+ ]);
+ }
ServerLimitCheckJob::dispatch($team);
}
$subscription->update([
@@ -210,7 +216,9 @@ class Stripe extends Controller
$customerId = data_get($data, 'customer');
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
$team = data_get($subscription, 'team');
- $team->trialEnded();
+ if ($team) {
+ $team->trialEnded();
+ }
$subscription->update([
'stripe_subscription_id' => null,
'stripe_plan_id' => null,
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 99864de0c..2cd359334 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -1359,6 +1359,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$onlyPort = $ports[0];
}
$persistent_storages = $this->generate_local_persistent_volumes();
+ $persistent_file_volumes = $this->application->fileStorages()->get();
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
// $environment_variables = $this->generate_environment_variables($ports);
$this->save_environment_variables();
@@ -1559,6 +1560,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
if (count($persistent_storages) > 0) {
$docker_compose['services'][$this->container_name]['volumes'] = $persistent_storages;
}
+ if (count($persistent_file_volumes) > 0) {
+ $docker_compose['services'][$this->container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
+ return "$item->fs_path:$item->mount_path";
+ })->toArray();
+ }
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
diff --git a/app/Jobs/ServerStatusJob.php b/app/Jobs/ServerStatusJob.php
index 5266b0842..d104185c0 100644
--- a/app/Jobs/ServerStatusJob.php
+++ b/app/Jobs/ServerStatusJob.php
@@ -47,13 +47,17 @@ class ServerStatusJob implements ShouldQueue, ShouldBeEncrypted
if (config('coolify.is_sentinel_enabled')) {
$this->server->checkSentinel();
}
- $this->check_docker_engine();
}
} catch (\Throwable $e) {
send_internal_notification('ServerStatusJob failed with: ' . $e->getMessage());
ray($e->getMessage());
return handleError($e);
}
+ try {
+ // $this->check_docker_engine();
+ } catch (\Throwable $e) {
+ // Do nothing
+ }
}
private function check_docker_engine()
{
diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php
index c56290a06..2b5ef9eca 100644
--- a/app/Livewire/Project/New/Select.php
+++ b/app/Livewire/Project/New/Select.php
@@ -91,7 +91,7 @@ class Select extends Component
});
} else {
$this->search = null;
- $this->allServices = get_service_templates();
+ $this->allServices = get_service_templates($force);
$this->services = $this->allServices->filter(function ($service, $key) {
return str_contains(strtolower($key), strtolower($this->search));
});
diff --git a/app/Livewire/Project/Service/FileStorage.php b/app/Livewire/Project/Service/FileStorage.php
index 1703caf8f..f10c49794 100644
--- a/app/Livewire/Project/Service/FileStorage.php
+++ b/app/Livewire/Project/Service/FileStorage.php
@@ -7,13 +7,20 @@ use App\Models\LocalFileVolume;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
use App\Models\StandaloneClickhouse;
+use App\Models\StandaloneDragonfly;
+use App\Models\StandaloneKeydb;
+use App\Models\StandaloneMariadb;
+use App\Models\StandaloneMongodb;
+use App\Models\StandaloneMysql;
+use App\Models\StandalonePostgresql;
+use App\Models\StandaloneRedis;
use Livewire\Component;
use Illuminate\Support\Str;
class FileStorage extends Component
{
public LocalFileVolume $fileStorage;
- public ServiceApplication|ServiceDatabase|StandaloneClickhouse|Application $resource;
+ public ServiceApplication|StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase|Application $resource;
public string $fs_path;
public ?string $workdir = null;
@@ -27,7 +34,7 @@ class FileStorage extends Component
{
$this->resource = $this->fileStorage->service;
if (Str::of($this->fileStorage->fs_path)->startsWith('.')) {
- $this->workdir = $this->resource->service->workdir();
+ $this->workdir = $this->resource->service?->workdir();
$this->fs_path = Str::of($this->fileStorage->fs_path)->after('.');
} else {
$this->workdir = null;
diff --git a/app/Livewire/Project/Shared/Storages/Add.php b/app/Livewire/Project/Shared/Storages/Add.php
index 2bfbf7baf..66c2cd764 100644
--- a/app/Livewire/Project/Shared/Storages/Add.php
+++ b/app/Livewire/Project/Shared/Storages/Add.php
@@ -3,21 +3,31 @@
namespace App\Livewire\Project\Shared\Storages;
use App\Models\Application;
+use App\Models\LocalFileVolume;
use Livewire\Component;
class Add extends Component
{
+ public $resource;
public $uuid;
public $parameters;
public $isSwarm = false;
public string $name;
public string $mount_path;
public ?string $host_path = null;
+ public string $file_storage_path;
+ public string $file_storage_content;
+ public string $file_storage_directory_source;
+ public string $file_storage_directory_destination;
public $rules = [
'name' => 'required|string',
'mount_path' => 'required|string',
'host_path' => 'string|nullable',
+ 'file_storage_path' => 'string',
+ 'file_storage_content' => 'string',
+ 'file_storage_directory_source' => 'string',
+ 'file_storage_directory_destination' => 'string',
];
protected $listeners = ['clearAddStorage' => 'clear'];
@@ -26,10 +36,16 @@ class Add extends Component
'name' => 'name',
'mount_path' => 'mount',
'host_path' => 'host',
+ 'file_storage_path' => 'file storage path',
+ 'file_storage_content' => 'file storage content',
+ 'file_storage_directory_source' => 'file storage directory source',
+ 'file_storage_directory_destination' => 'file storage directory destination',
];
public function mount()
{
+ $this->file_storage_directory_source = application_configuration_dir() . "/{$this->resource->uuid}";
+ $this->uuid = $this->resource->uuid;
$this->parameters = get_route_parameters();
if (data_get($this->parameters, 'application_uuid')) {
$applicationUuid = $this->parameters['application_uuid'];
@@ -43,8 +59,53 @@ class Add extends Component
}
}
}
+ public function submitFileStorage()
+ {
+ try {
+ $this->file_storage_path = trim($this->file_storage_path);
+ $this->file_storage_path = str($this->file_storage_path)->start('/')->value();
+ if ($this->resource->getMorphClass() === 'App\Models\Application') {
+ $fs_path = application_configuration_dir() . '/' . $this->resource->uuid . $this->file_storage_path;
+ }
+ LocalFileVolume::create(
+ [
+ 'fs_path' => $fs_path,
+ 'mount_path' => $this->file_storage_path,
+ 'content' => $this->file_storage_content,
+ 'is_directory' => false,
+ 'resource_id' => $this->resource->id,
+ 'resource_type' => get_class($this->resource)
+ ],
+ );
+ $this->dispatch('refresh_storages');
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
- public function submit()
+ }
+ public function submitFileStorageDirectory()
+ {
+ try {
+ $this->file_storage_directory_source = trim($this->file_storage_directory_source);
+ $this->file_storage_directory_source = str($this->file_storage_directory_source)->start('/')->value();
+ $this->file_storage_directory_destination = trim($this->file_storage_directory_destination);
+ $this->file_storage_directory_destination = str($this->file_storage_directory_destination)->start('/')->value();
+ LocalFileVolume::create(
+ [
+ 'fs_path' => $this->file_storage_directory_source,
+ 'mount_path' => $this->file_storage_directory_destination,
+ 'is_directory' => true,
+ 'resource_id' => $this->resource->id,
+ 'resource_type' => get_class($this->resource)
+ ],
+ );
+ $this->dispatch('refresh_storages');
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
+
+ }
+ public function submitPersistentVolume()
{
try {
$this->validate($this->rules);
@@ -54,7 +115,7 @@ class Add extends Component
'mount_path' => $this->mount_path,
'host_path' => $this->host_path,
]);
- $this->dispatch('closeStorageModal');
+
} catch (\Throwable $e) {
return handleError($e, $this);
}
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index ee5a52d56..c8c8ee4e9 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -465,25 +465,24 @@ function sslip(Server $server)
return "http://{$server->ip}.sslip.io";
}
-function get_service_templates()
+function get_service_templates(bool $force = false): Collection
{
- // if (isDev()) {
- // $services = File::get(base_path('templates/service-templates.json'));
- // $services = collect(json_decode($services))->sortKeys();
- // } else {
- // try {
- // $response = Http::retry(3, 50)->get(config('constants.services.official'));
- // if ($response->failed()) {
- // return collect([]);
- // }
- // $services = $response->json();
- // $services = collect($services)->sortKeys();
- // } catch (\Throwable $e) {
- // $services = collect([]);
- // }
- // }
- $services = File::get(base_path('templates/service-templates.json'));
- return collect(json_decode($services))->sortKeys();
+ if ($force) {
+ try {
+ $response = Http::retry(3, 50)->get(config('constants.services.official'));
+ if ($response->failed()) {
+ return collect([]);
+ }
+ $services = $response->json();
+ return collect($services);
+ } catch (\Throwable $e) {
+ $services = File::get(base_path('templates/service-templates.json'));
+ return collect(json_decode($services))->sortKeys();
+ }
+ } else {
+ $services = File::get(base_path('templates/service-templates.json'));
+ return collect(json_decode($services))->sortKeys();
+ }
}
function getResourceByUuid(string $uuid, ?int $teamId = null)
diff --git a/config/sentry.php b/config/sentry.php
index 249bd9af2..ee9bf2b80 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.286',
+ 'release' => '4.0.0-beta.287',
// 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 e1564b9d9..d6123be0a 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@