2023-10-04 07:58:39 +00:00
< ? php
2023-12-07 18:06:32 +00:00
namespace App\Livewire\Project\Service ;
2023-10-04 07:58:39 +00:00
use App\Models\LocalPersistentVolume ;
2025-08-26 08:27:31 +00:00
use Illuminate\Foundation\Auth\Access\AuthorizesRequests ;
2023-10-04 07:58:39 +00:00
use Livewire\Component ;
class Storage extends Component
{
2025-08-26 08:27:31 +00:00
use AuthorizesRequests ;
2023-10-04 07:58:39 +00:00
public $resource ;
2024-06-10 20:43:34 +00:00
2024-08-05 18:00:57 +00:00
public $fileStorage ;
2025-10-01 16:46:21 +00:00
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 = null ;
public string $file_storage_directory_source = '' ;
public string $file_storage_directory_destination = '' ;
2024-04-15 17:47:17 +00:00
public function getListeners ()
2023-10-04 07:58:39 +00:00
{
2024-08-05 18:00:57 +00:00
$teamId = auth () -> user () -> currentTeam () -> id ;
2024-04-15 17:47:17 +00:00
return [
2024-08-05 18:00:57 +00:00
" echo-private:team. { $teamId } ,FileStorageChanged " => 'refreshStoragesFromEvent' ,
2024-08-05 18:07:08 +00:00
'refreshStorages' ,
2024-04-15 17:47:17 +00:00
'addNewVolume' ,
];
2023-10-04 07:58:39 +00:00
}
2024-06-10 20:43:34 +00:00
2024-08-05 18:00:57 +00:00
public function mount ()
{
2025-10-01 16:46:21 +00:00
if ( str ( $this -> resource -> getMorphClass ()) -> contains ( 'Standalone' )) {
$this -> file_storage_directory_source = database_configuration_dir () . " / { $this -> resource -> uuid } " ;
} else {
$this -> file_storage_directory_source = application_configuration_dir () . " / { $this -> resource -> uuid } " ;
}
if ( $this -> resource -> getMorphClass () === \App\Models\Application :: class ) {
if ( $this -> resource -> destination -> server -> isSwarm ()) {
$this -> isSwarm = true ;
}
}
2024-08-05 18:00:57 +00:00
$this -> refreshStorages ();
}
public function refreshStoragesFromEvent ()
{
$this -> refreshStorages ();
$this -> dispatch ( 'warning' , 'File storage changed. Usually it means that the file / directory is already defined on the server, so Coolify set it up for you properly on the UI.' );
}
public function refreshStorages ()
{
$this -> fileStorage = $this -> resource -> fileStorages () -> get ();
2025-12-11 20:23:46 +00:00
$this -> resource -> load ( 'persistentStorages.resource' );
2025-10-01 06:23:21 +00:00
}
public function getFilesProperty ()
{
return $this -> fileStorage -> where ( 'is_directory' , false );
}
public function getDirectoriesProperty ()
{
return $this -> fileStorage -> where ( 'is_directory' , true );
}
public function getVolumeCountProperty ()
{
return $this -> resource -> persistentStorages () -> count ();
}
public function getFileCountProperty ()
{
return $this -> files -> count ();
}
public function getDirectoryCountProperty ()
{
return $this -> directories -> count ();
2024-08-05 18:00:57 +00:00
}
2025-10-01 16:46:21 +00:00
public function submitPersistentVolume ()
2023-10-04 07:58:39 +00:00
{
try {
2025-08-26 08:27:31 +00:00
$this -> authorize ( 'update' , $this -> resource );
2025-10-01 16:46:21 +00:00
$this -> validate ([
'name' => 'required|string' ,
'mount_path' => 'required|string' ,
'host_path' => $this -> isSwarm ? 'required|string' : 'string|nullable' ,
]);
$name = $this -> resource -> uuid . '-' . $this -> name ;
2023-10-04 07:58:39 +00:00
LocalPersistentVolume :: create ([
2025-10-01 16:46:21 +00:00
'name' => $name ,
'mount_path' => $this -> mount_path ,
'host_path' => $this -> host_path ,
2023-10-04 07:58:39 +00:00
'resource_id' => $this -> resource -> id ,
'resource_type' => $this -> resource -> getMorphClass (),
]);
$this -> resource -> refresh ();
2025-10-01 16:46:21 +00:00
$this -> dispatch ( 'success' , 'Volume added successfully' );
$this -> dispatch ( 'closeStorageModal' , 'volume' );
$this -> clearForm ();
$this -> refreshStorages ();
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
}
public function submitFileStorage ()
{
try {
$this -> authorize ( 'update' , $this -> resource );
$this -> validate ([
'file_storage_path' => 'required|string' ,
'file_storage_content' => 'nullable|string' ,
]);
$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 :: class ) {
$fs_path = application_configuration_dir () . '/' . $this -> resource -> uuid . $this -> file_storage_path ;
} elseif ( str ( $this -> resource -> getMorphClass ()) -> contains ( 'Standalone' )) {
$fs_path = database_configuration_dir () . '/' . $this -> resource -> uuid . $this -> file_storage_path ;
} else {
throw new \Exception ( 'No valid resource type for file mount storage type!' );
}
\App\Models\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 ( 'success' , 'File mount added successfully' );
$this -> dispatch ( 'closeStorageModal' , 'file' );
$this -> clearForm ();
$this -> refreshStorages ();
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
}
public function submitFileStorageDirectory ()
{
try {
$this -> authorize ( 'update' , $this -> resource );
$this -> validate ([
'file_storage_directory_source' => 'required|string' ,
'file_storage_directory_destination' => 'required|string' ,
]);
$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 ();
2025-11-27 13:36:31 +00:00
// Validate paths to prevent command injection
validateShellSafePath ( $this -> file_storage_directory_source , 'storage source path' );
validateShellSafePath ( $this -> file_storage_directory_destination , 'storage destination path' );
2025-10-01 16:46:21 +00:00
\App\Models\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 ( 'success' , 'Directory mount added successfully' );
$this -> dispatch ( 'closeStorageModal' , 'directory' );
$this -> clearForm ();
$this -> refreshStorages ();
2023-10-04 07:58:39 +00:00
} catch ( \Throwable $e ) {
return handleError ( $e , $this );
}
}
2024-06-10 20:43:34 +00:00
2025-10-01 16:46:21 +00:00
public function clearForm ()
{
$this -> name = '' ;
$this -> mount_path = '' ;
$this -> host_path = null ;
$this -> file_storage_path = '' ;
$this -> file_storage_content = null ;
$this -> file_storage_directory_destination = '' ;
if ( str ( $this -> resource -> getMorphClass ()) -> contains ( 'Standalone' )) {
$this -> file_storage_directory_source = database_configuration_dir () . " / { $this -> resource -> uuid } " ;
} else {
$this -> file_storage_directory_source = application_configuration_dir () . " / { $this -> resource -> uuid } " ;
}
}
2024-04-15 17:47:17 +00:00
public function render ()
{
return view ( 'livewire.project.service.storage' );
}
2023-10-04 07:58:39 +00:00
}