mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-15 09:14:08 +00:00
Remove duplicate configureMediaDisk() from AppServiceProvider — all FileDisk and media-library config is now in AppConfigProvider's configureFileSystemFromDatabase(). Replace setConfig() calls with inline config registration everywhere to avoid mutating filesystems.default, which caused infinite request loops on the File Disk admin page.
145 lines
4.1 KiB
PHP
145 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\FileDisk;
|
|
use App\Models\Setting;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
class MigrateMediaToPrivateDisk extends Command
|
|
{
|
|
protected $signature = 'media:secure {--dry-run : Show what would be moved without moving}';
|
|
|
|
protected $description = 'Move sensitive media files (receipts) from the public disk to the private disk';
|
|
|
|
public function handle(): int
|
|
{
|
|
$targetDisk = $this->resolveTargetDisk();
|
|
|
|
if (! $targetDisk) {
|
|
$this->error('No target disk found. Set a default FileDisk or configure media_disk_id setting.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$prefix = env('DYNAMIC_DISK_PREFIX', 'temp_');
|
|
$targetDiskName = $prefix.$targetDisk->driver;
|
|
|
|
// Register disk config without mutating filesystems.default
|
|
$credentials = collect(json_decode($targetDisk->credentials));
|
|
$baseConfig = config('filesystems.disks.'.$targetDisk->driver, []);
|
|
|
|
foreach ($baseConfig as $key => $value) {
|
|
if ($credentials->has($key)) {
|
|
$baseConfig[$key] = $credentials[$key];
|
|
}
|
|
}
|
|
|
|
config(['filesystems.disks.'.$targetDiskName => $baseConfig]);
|
|
$targetRoot = $baseConfig['root'] ?? null;
|
|
|
|
if (! $targetRoot) {
|
|
$this->error('Could not resolve target disk root path.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$records = DB::table('media')
|
|
->where('disk', 'public')
|
|
->where(function ($query) {
|
|
$query->where('collection_name', 'receipts');
|
|
})
|
|
->get();
|
|
|
|
if ($records->isEmpty()) {
|
|
$this->info('No media files to migrate.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info('Found '.$records->count().' file(s) to migrate.');
|
|
|
|
if ($this->option('dry-run')) {
|
|
foreach ($records as $record) {
|
|
$this->line(" Would move: media/{$record->id}/{$record->file_name}");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$moved = 0;
|
|
$skipped = 0;
|
|
$publicMediaRoot = public_path('media');
|
|
|
|
$bar = $this->output->createProgressBar($records->count());
|
|
$bar->start();
|
|
|
|
foreach ($records as $record) {
|
|
$relativePath = $record->id.DIRECTORY_SEPARATOR.$record->file_name;
|
|
$sourcePath = $publicMediaRoot.DIRECTORY_SEPARATOR.$relativePath;
|
|
$destPath = $targetRoot.DIRECTORY_SEPARATOR.$relativePath;
|
|
|
|
if (! file_exists($sourcePath)) {
|
|
$skipped++;
|
|
$bar->advance();
|
|
|
|
continue;
|
|
}
|
|
|
|
$destDir = dirname($destPath);
|
|
if (! File::isDirectory($destDir)) {
|
|
File::makeDirectory($destDir, 0755, true);
|
|
}
|
|
|
|
File::move($sourcePath, $destPath);
|
|
|
|
DB::table('media')
|
|
->where('id', $record->id)
|
|
->update(['disk' => $targetDiskName]);
|
|
|
|
$moved++;
|
|
$bar->advance();
|
|
}
|
|
|
|
$bar->finish();
|
|
$this->newLine(2);
|
|
|
|
$this->info("Done. Moved: {$moved}, Skipped (missing): {$skipped}");
|
|
|
|
// Clean up empty directories in public/media
|
|
$this->cleanEmptyDirectories($publicMediaRoot);
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
private function resolveTargetDisk(): ?FileDisk
|
|
{
|
|
$mediaDiskId = Setting::getSetting('media_disk_id');
|
|
|
|
if ($mediaDiskId) {
|
|
return FileDisk::find($mediaDiskId);
|
|
}
|
|
|
|
return FileDisk::where('set_as_default', true)->first();
|
|
}
|
|
|
|
private function cleanEmptyDirectories(string $path): void
|
|
{
|
|
if (! File::isDirectory($path)) {
|
|
return;
|
|
}
|
|
|
|
$directories = File::directories($path);
|
|
|
|
foreach ($directories as $dir) {
|
|
$this->cleanEmptyDirectories($dir);
|
|
|
|
if (count(File::allFiles($dir)) === 0 && count(File::directories($dir)) === 0) {
|
|
File::deleteDirectory($dir);
|
|
}
|
|
}
|
|
}
|
|
}
|