From b6ee3791d6040385b5f9a08a7316f4e6582e11fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Viguier?= Date: Sat, 20 Jan 2024 15:29:45 +0100 Subject: [PATCH] Fix upload on smart albums (#2218) --- .../Components/Forms/Add/ImportFromServer.php | 37 ----- .../Components/Forms/Add/ImportFromUrl.php | 6 + app/Livewire/Components/Forms/Add/Upload.php | 7 + app/Livewire/Forms/ImportFromServerForm.php | 126 ------------------ tests/Livewire/Forms/ImportFromServerTest.php | 43 ------ 5 files changed, 13 insertions(+), 206 deletions(-) delete mode 100644 app/Livewire/Forms/ImportFromServerForm.php diff --git a/app/Livewire/Components/Forms/Add/ImportFromServer.php b/app/Livewire/Components/Forms/Add/ImportFromServer.php index ef67252571b..23f8d0fa064 100644 --- a/app/Livewire/Components/Forms/Add/ImportFromServer.php +++ b/app/Livewire/Components/Forms/Add/ImportFromServer.php @@ -2,17 +2,12 @@ namespace App\Livewire\Components\Forms\Add; -use App\Actions\Import\FromServer; -use App\Contracts\Livewire\Params; use App\Contracts\Models\AbstractAlbum; -use App\Livewire\Forms\ImportFromServerForm; use App\Livewire\Traits\InteractWithModal; use App\Policies\AlbumPolicy; -use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; use Illuminate\View\View; use Livewire\Component; -use Symfony\Component\HttpFoundation\StreamedResponse; /** * This defines the Import From Server modals. @@ -24,14 +19,6 @@ class ImportFromServer extends Component */ use InteractWithModal; - public ImportFromServerForm $form; - private FromServer $fromServer; - - public function boot(): void - { - $this->fromServer = resolve(FromServer::class); - } - /** * We load the parameters. * @@ -42,8 +29,6 @@ public function boot(): void public function mount(array $params = ['parentID' => null]): void { Gate::authorize(AlbumPolicy::CAN_IMPORT_FROM_SERVER, AbstractAlbum::class); - - $this->form->init($params[Params::PARENT_ID] ?? null); } /** @@ -65,26 +50,4 @@ public function close(): void { $this->closeModal(); } - - /** - * Hook the submit button. - * - * @return StreamedResponse - */ - public function submit(): StreamedResponse - { - Gate::authorize(AlbumPolicy::CAN_IMPORT_FROM_SERVER, AbstractAlbum::class); - - // Empty error bag - $this->resetErrorBag(); - - $this->form->prepare(); - $this->form->validate(); - - /** @var int $userId */ - $userId = Auth::id(); - - // Validate - return $this->fromServer->do($this->form->paths, $this->form->getAlbum(), $this->form->getImportMode(), $userId); - } } diff --git a/app/Livewire/Components/Forms/Add/ImportFromUrl.php b/app/Livewire/Components/Forms/Add/ImportFromUrl.php index ec292b4708a..6f92b9ea282 100644 --- a/app/Livewire/Components/Forms/Add/ImportFromUrl.php +++ b/app/Livewire/Components/Forms/Add/ImportFromUrl.php @@ -5,6 +5,7 @@ use App\Actions\Import\FromUrl; use App\Contracts\Livewire\Params; use App\Contracts\Models\AbstractAlbum; +use App\Enum\SmartAlbumType; use App\Exceptions\MassImportException; use App\Livewire\Components\Pages\Gallery\Album as PageGalleryAlbum; use App\Livewire\Forms\ImportFromUrlForm; @@ -48,6 +49,11 @@ public function mount(array $params = ['parentID' => null]): void { $albumId = $params[Params::PARENT_ID] ?? null; + // remove smart albums => if we are in one: upload to unsorted (i.e. albumId = null) + if (SmartAlbumType::tryFrom($albumId) !== null) { + $albumId = null; + } + /** @var Album $album */ $album = $albumId === null ? null : Album::query()->findOrFail($albumId); diff --git a/app/Livewire/Components/Forms/Add/Upload.php b/app/Livewire/Components/Forms/Add/Upload.php index 55834adc012..bcf74b96dd6 100644 --- a/app/Livewire/Components/Forms/Add/Upload.php +++ b/app/Livewire/Components/Forms/Add/Upload.php @@ -5,6 +5,7 @@ use App\Contracts\Livewire\Params; use App\Contracts\Models\AbstractAlbum; use App\Enum\Livewire\FileStatus; +use App\Enum\SmartAlbumType; use App\Exceptions\PhotoSkippedException; use App\Facades\Helpers; use App\Image\Files\NativeLocalFile; @@ -53,6 +54,12 @@ class Upload extends Component public function mount(array $params = ['parentID' => null]): void { $this->albumId = $params[Params::PARENT_ID] ?? null; + + // remove smart albums => if we are in one: upload to unsorted (i.e. albumId = null) + if (SmartAlbumType::tryFrom($this->albumId) !== null) { + $this->albumId = null; + } + $album = $this->albumId === null ? null : Album::findOrFail($this->albumId); Gate::authorize(AlbumPolicy::CAN_UPLOAD, [AbstractAlbum::class, $album]); diff --git a/app/Livewire/Forms/ImportFromServerForm.php b/app/Livewire/Forms/ImportFromServerForm.php deleted file mode 100644 index a672b7998f7..00000000000 --- a/app/Livewire/Forms/ImportFromServerForm.php +++ /dev/null @@ -1,126 +0,0 @@ - */ - public array $paths = []; - public bool $delete_imported; - public bool $skip_duplicates; - public bool $import_via_symlink; - public bool $resync_metadata; - - /** - * This allows Livewire to know which values of the $configs we - * want to display in the wire:model. Sort of a white listing. - * - * @return array - */ - protected function rules(): array - { - return [ - RequestAttribute::ALBUM_ID_ATTRIBUTE => ['present', new RandomIDRule(true)], - RequestAttribute::PATH_ATTRIBUTE => 'required|array|min:1', - RequestAttribute::PATH_ATTRIBUTE . '.*' => 'required|string|distinct', - RequestAttribute::DELETE_IMPORTED_ATTRIBUTE => 'sometimes|boolean', - RequestAttribute::SKIP_DUPLICATES_ATTRIBUTE => 'sometimes|boolean', - RequestAttribute::IMPORT_VIA_SYMLINK_ATTRIBUTE => 'sometimes|boolean', - RequestAttribute::RESYNC_METADATA_ATTRIBUTE => 'sometimes|boolean', - ]; - } - - /** - * split path into paths array. - * - * @return void - */ - public function prepare() - { - $subject = $this->path; - - // We split the given path string at unescaped spaces into an - // array or more precisely we create an array whose entries - // match strings with non-space characters or escaped spaces. - // After splitting, the escaped spaces must be replaced by - // proper spaces as escaping of spaces is a GUI-only thing to - // allow input of several paths into a single input field. - $matches = $this->split_escaped(' ', '\\', $subject); - - // drop first element: matched elements start at index 1 - // array_shift($matches); - $this->paths = array_map(fn ($v) => str_replace('\\ ', ' ', $v), $matches); - - // Remove empty elements - $this->paths = array_filter($this->paths, fn ($v) => $v === ''); - } - - /** - * Dark magic code from Stack Overflow - * https://stackoverflow.com/a/27135602. - * - * @param string $delimiter - * @param string $escaper - * @param string $text - * - * @return string[] - */ - private function split_escaped(string $delimiter, string $escaper, string $text): array - { - $d = preg_quote($delimiter, '~'); - $e = preg_quote($escaper, '~'); - $tokens = preg_split( - '~' . $e . '(' . $e . '|' . $d . ')(*SKIP)(*FAIL)|' . $d . '~', - $text - ); - $escaperReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $escaper); - $delimiterReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $delimiter); - - return preg_replace( - ['~' . $e . $e . '~', '~' . $e . $d . '~'], - [$escaperReplacement, $delimiterReplacement], - $tokens - ); - } - - /** - * Initialize form data. - * - * @param ?string $albumID - * - * @return void - */ - public function init(?string $albumID): void - { - $this->albumID = $albumID; - $this->path = public_path('uploads/import/'); - $this->delete_imported = Configs::getValueAsBool('delete_imported'); - $this->import_via_symlink = !Configs::getValueAsBool('delete_imported') && Configs::getValueAsBool('import_via_symlink'); - $this->skip_duplicates = Configs::getValueAsBool('skip_duplicates'); - $this->resync_metadata = false; - } - - public function getAlbum(): null|Album - { - /** @var Album $album */ - $album = $this->albumID === null ? null : Album::query()->findOrFail($this->albumID); - - return $album; - } - - public function getImportMode(): ImportMode - { - return new ImportMode($this->delete_imported, $this->skip_duplicates, $this->import_via_symlink, $this->resync_metadata); - } -} diff --git a/tests/Livewire/Forms/ImportFromServerTest.php b/tests/Livewire/Forms/ImportFromServerTest.php index 3a994e5ce24..1da8e00594e 100644 --- a/tests/Livewire/Forms/ImportFromServerTest.php +++ b/tests/Livewire/Forms/ImportFromServerTest.php @@ -15,7 +15,6 @@ use App\Livewire\Components\Forms\Add\ImportFromServer; use Illuminate\Foundation\Testing\DatabaseTransactions; use Livewire\Livewire; -use Tests\Feature\Constants\TestConstants; use Tests\Livewire\Base\BaseLivewireTest; class ImportFromServerTest extends BaseLivewireTest @@ -37,48 +36,6 @@ public function testLoggedInNoRights(): void ->assertForbidden(); } - public function testLoggedInAndError(): void - { - Livewire::actingAs($this->admin)->test(ImportFromServer::class) - ->assertViewIs('livewire.forms.add.import-from-server') - ->assertOk() - ->set('form.path', '') - ->call('submit') - ->assertOk() - ->assertHasErrors('form.paths.0'); - } - - // public function testLoggedInWithDeleteImported() : void { - // copy(base_path(TestConstants::SAMPLE_FILE_NIGHT_IMAGE), static::importPath('night.jpg')); - - // Livewire::actingAs($this->admin)->test(ImportFromServer::class) - // ->assertViewIs('livewire.forms.add.import-from-server') - // ->assertOk() - // ->set('form.path', static::importPath()) - // ->assertSet('form.delete_imported', false) - // ->call('submit') - // ->assertOk() - // ->assertHasNoErrors('form.paths.0'); - - // $this->assertEquals(true, file_exists(static::importPath('night.jpg'))); - // } - - // public function testLoggedInWithoutDeleteImported() : void { - // copy(base_path(TestConstants::SAMPLE_FILE_NIGHT_IMAGE), static::importPath('night.jpg')); - - // Livewire::actingAs($this->admin)->test(ImportFromServer::class) - // ->assertViewIs('livewire.forms.add.import-from-server') - // ->assertOk() - // ->set('form.path', static::importPath()) - // ->set('form.delete_imported', true) - // ->assertSet('form.delete_imported', true) - // ->call('submit') - // ->assertOk() - // ->assertHasNoErrors('form.paths.0'); - - // $this->assertEquals(false, file_exists(static::importPath('night.jpg'))); - // } - public function testLoggedInClose(): void { Livewire::actingAs($this->admin)->test(ImportFromServer::class)