mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-04 10:42:23 +00:00
170 lines
5.5 KiB
PHP
170 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Project\Database\Sqlite;
|
|
|
|
use App\Models\Application;
|
|
use App\Models\LocalPersistentVolume;
|
|
use App\Models\StandaloneSqlite;
|
|
use App\Support\ValidationPatterns;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Support\Collection;
|
|
use Livewire\Component;
|
|
|
|
class ConnectApplication extends Component
|
|
{
|
|
use AuthorizesRequests;
|
|
|
|
public StandaloneSqlite $database;
|
|
|
|
public string $applicationUuid = '';
|
|
|
|
public string $mountPath = StandaloneSqlite::DATA_DIRECTORY;
|
|
|
|
/**
|
|
* Docker volume that holds the database files.
|
|
*/
|
|
public string $volumeName = '';
|
|
|
|
/**
|
|
* Applications on the same server. Compose applications are listed but disabled,
|
|
* because Coolify renames named volumes in compose files.
|
|
*
|
|
* @var array<int, array{value: string, label: string, disabled: bool}>
|
|
*/
|
|
public array $applicationOptions = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->authorize('view', $this->database);
|
|
|
|
$this->volumeName = $this->database->persistentStorages()
|
|
->whereNull('host_path')
|
|
->orderBy('id')
|
|
->value('name') ?? 'sqlite-data-'.$this->database->uuid;
|
|
|
|
$this->applicationOptions = $this->connectableApplications()
|
|
->map(fn (Application $application) => [
|
|
'value' => $application->uuid,
|
|
'label' => $this->applicationLabel($application),
|
|
'disabled' => $this->isComposeApplication($application),
|
|
])
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Mount the data volume into the selected application and open its storage page.
|
|
*/
|
|
public function connect()
|
|
{
|
|
$this->authorize('view', $this->database);
|
|
|
|
$this->validate([
|
|
'applicationUuid' => 'required|string',
|
|
'mountPath' => ['required', 'string', 'regex:'.ValidationPatterns::DIRECTORY_PATH_PATTERN],
|
|
], [
|
|
'applicationUuid.required' => 'Select an application first.',
|
|
'mountPath.regex' => 'Mount path must start with / and only contain safe path characters.',
|
|
]);
|
|
|
|
$application = $this->selectedApplication();
|
|
if ($application) {
|
|
$this->authorize('update', $application);
|
|
}
|
|
|
|
try {
|
|
if (! $application) {
|
|
throw new \Exception('The selected application is not available on this server.');
|
|
}
|
|
|
|
if ($this->isComposeApplication($application)) {
|
|
throw new \Exception('Docker Compose applications are not supported: Coolify renames named volumes in compose files.');
|
|
}
|
|
|
|
if ($application->persistentStorages()->where('standalone_sqlite_id', $this->database->id)->exists()) {
|
|
throw new \Exception("{$application->name} already mounts this database volume.");
|
|
}
|
|
|
|
LocalPersistentVolume::create([
|
|
'name' => $this->volumeName,
|
|
'mount_path' => $this->mountPath,
|
|
'host_path' => null,
|
|
'standalone_sqlite_id' => $this->database->id,
|
|
'resource_id' => $application->id,
|
|
'resource_type' => $application->getMorphClass(),
|
|
'is_preview_suffix_enabled' => false,
|
|
]);
|
|
|
|
return redirect()->route('project.application.persistent-storage', $this->applicationRouteParameters($application));
|
|
} catch (\Throwable $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.project.database.sqlite.connect-application');
|
|
}
|
|
|
|
/**
|
|
* Applications owned by the current team that run on the same server as the database.
|
|
*
|
|
* @return Collection<int, Application>
|
|
*/
|
|
private function connectableApplications(): Collection
|
|
{
|
|
$serverId = $this->database->destination?->server_id;
|
|
if ($serverId === null) {
|
|
return collect();
|
|
}
|
|
|
|
return Application::ownedByCurrentTeam()
|
|
->with(['destination', 'environment.project'])
|
|
->get()
|
|
->filter(fn (Application $application) => $application->destination?->server_id === $serverId)
|
|
->values();
|
|
}
|
|
|
|
private function selectedApplication(): ?Application
|
|
{
|
|
if (blank($this->applicationUuid)) {
|
|
return null;
|
|
}
|
|
|
|
return $this->connectableApplications()->firstWhere('uuid', $this->applicationUuid);
|
|
}
|
|
|
|
private function applicationLabel(Application $application): string
|
|
{
|
|
$label = $application->name;
|
|
|
|
$project = $application->environment?->project?->name;
|
|
$environment = $application->environment?->name;
|
|
if ($project && $environment) {
|
|
$label .= " ({$project} / {$environment})";
|
|
}
|
|
|
|
if ($this->isComposeApplication($application)) {
|
|
$label .= ' · Docker Compose (not supported)';
|
|
}
|
|
|
|
return $label;
|
|
}
|
|
|
|
private function isComposeApplication(Application $application): bool
|
|
{
|
|
return $application->build_pack === 'dockercompose';
|
|
}
|
|
|
|
/**
|
|
* @return array{project_uuid: string, environment_uuid: string, application_uuid: string}
|
|
*/
|
|
private function applicationRouteParameters(Application $application): array
|
|
{
|
|
return [
|
|
'project_uuid' => $application->environment->project->uuid,
|
|
'environment_uuid' => $application->environment->uuid,
|
|
'application_uuid' => $application->uuid,
|
|
];
|
|
}
|
|
}
|