diff --git a/backend/app/Controllers/ElementController.php b/backend/app/Controllers/ElementController.php index 1cfc205..6a63a85 100644 --- a/backend/app/Controllers/ElementController.php +++ b/backend/app/Controllers/ElementController.php @@ -9,17 +9,14 @@ use App\Element\UseCases\UpdateElement\UpdateElement; use App\Element\UseCases\UpdateElement\UpdateElementRequest; use App\Exceptions\BadRequestException; use App\Exceptions\NotFoundException; -use App\Shared\Files\FileUploader; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Http\UploadedFile; class ElementController { public function __construct( private GetElement $getElement, private UpdateElement $updateElement, - private FileUploader $fileUploader, ) { } @@ -55,15 +52,12 @@ class ElementController ], 200); } - public function update(Request $request): JsonResponse + public function update(?int $id, Request $request): JsonResponse { - $iconImage = $this->uploadedFileInput($request, 'iconImage'); - $pdf = $this->uploadedFileInput($request, 'pdf'); - try { $element = $this->updateElement->execute( new UpdateElementRequest( - id: $this->intInput($request, 'elementId'), + id: $id, title: $this->stringInput($request, 'title'), description: $this->stringInput($request, 'description'), iconImageUrl: $this->stringInput( @@ -73,14 +67,6 @@ class ElementController richText: $this->stringInput($request, 'richText'), pdfPath: $this->stringInput($request, 'pdfPath'), youtubeUrl: $this->stringInput($request, 'youtubeUrl'), - iconImageContents: $iconImage['contents'], - iconImageOriginalName: $iconImage['originalName'], - iconImageMimeType: $iconImage['mimeType'], - iconImageSizeBytes: $iconImage['sizeBytes'], - pdfContents: $pdf['contents'], - pdfOriginalName: $pdf['originalName'], - pdfMimeType: $pdf['mimeType'], - pdfSizeBytes: $pdf['sizeBytes'], ) ); } catch (BadRequestException $exception) { @@ -98,31 +84,9 @@ class ElementController ], 200); } - private function intInput(Request $request, string $key): ?int - { - $value = $request->input($key); - if (is_int($value)) { - return $value; - } - - if (is_string($value) && ctype_digit($value)) { - return (int) $value; - } - - return null; - } - private function stringInput(Request $request, string $key): ?string { - if (! $request->exists($key)) { - return null; - } - $value = $request->input($key); - if ($value === null) { - return ''; - } - if (! is_string($value)) { return null; } @@ -130,45 +94,6 @@ class ElementController return $value; } - /** - * @return array{ - * contents: string|null, - * originalName: string|null, - * mimeType: string|null, - * sizeBytes: int|null - * } - */ - private function uploadedFileInput(Request $request, string $key): array - { - $emptyFileInput = [ - 'contents' => null, - 'originalName' => null, - 'mimeType' => null, - 'sizeBytes' => null, - ]; - - if (! $request->hasFile($key)) { - return $emptyFileInput; - } - - $file = $request->file($key); - if (! $file instanceof UploadedFile) { - return $emptyFileInput; - } - - $realPath = $file->getRealPath(); - if ($realPath === false) { - return $emptyFileInput; - } - - return [ - 'contents' => (string) file_get_contents($realPath), - 'originalName' => $file->getClientOriginalName(), - 'mimeType' => (string) $file->getMimeType(), - 'sizeBytes' => (int) $file->getSize(), - ]; - } - /** * @return array{ * id: int, @@ -186,29 +111,10 @@ class ElementController 'id' => $element->getId(), 'title' => $element->getTitle(), 'description' => $element->getDescription(), - 'iconImageUrl' => $this->storageUrl( - $element->getIconImageUrl(), - 'element-icons/', - ), + 'iconImageUrl' => $element->getIconImageUrl(), 'richText' => $element->getRichText(), - 'pdfPath' => $this->storageUrl( - $element->getPdfPath(), - 'element-pdfs/', - ), + 'pdfPath' => $element->getPdfPath(), 'youtubeUrl' => $element->getYoutubeUrl(), ]; } - - private function storageUrl(?string $path, string $folderPrefix): ?string - { - if ($path === null) { - return null; - } - - if (str_starts_with($path, $folderPrefix)) { - return $this->fileUploader->url($path); - } - - return $path; - } } diff --git a/backend/app/Element/UseCases/UpdateElement/UpdateElement.php b/backend/app/Element/UseCases/UpdateElement/UpdateElement.php index 0533b16..9f8811a 100644 --- a/backend/app/Element/UseCases/UpdateElement/UpdateElement.php +++ b/backend/app/Element/UseCases/UpdateElement/UpdateElement.php @@ -16,8 +16,6 @@ class UpdateElement private UpdateRichText $updateRichText, private UpdatePdfPath $updatePdfPath, private UpdateYoutubeUrl $updateYoutubeUrl, - private UpdateIconImage $updateIconImage, - private UpdatePdf $updatePdf, private ElementRepository $elementRepository, ) { } @@ -37,9 +35,7 @@ class UpdateElement && $request->iconImageUrl === null && $request->richText === null && $request->pdfPath === null - && $request->youtubeUrl === null - && $request->iconImageContents === null - && $request->pdfContents === null; + && $request->youtubeUrl === null; if ($hasNoFields) { throw new BadRequestException('nothing to update'); } @@ -82,28 +78,6 @@ class UpdateElement youtubeUrl: $request->youtubeUrl, )); } - if ($request->iconImageContents !== null) { - $this->updateIconImage->execute( - new UpdateIconImageRequest( - id: $request->id, - iconImageContents: $request->iconImageContents, - iconImageOriginalName: $request->iconImageOriginalName, - iconImageMimeType: $request->iconImageMimeType, - iconImageSizeBytes: $request->iconImageSizeBytes, - ) - ); - } - if ($request->pdfContents !== null) { - $this->updatePdf->execute( - new UpdatePdfRequest( - id: $request->id, - pdfContents: $request->pdfContents, - pdfOriginalName: $request->pdfOriginalName, - pdfMimeType: $request->pdfMimeType, - pdfSizeBytes: $request->pdfSizeBytes, - ) - ); - } $element = $this->elementRepository->find($request->id); if ($element === null) { diff --git a/backend/app/Element/UseCases/UpdateElement/UpdateElementRequest.php b/backend/app/Element/UseCases/UpdateElement/UpdateElementRequest.php index aa1aa06..0b5e766 100644 --- a/backend/app/Element/UseCases/UpdateElement/UpdateElementRequest.php +++ b/backend/app/Element/UseCases/UpdateElement/UpdateElementRequest.php @@ -12,14 +12,6 @@ class UpdateElementRequest public ?string $richText, public ?string $pdfPath, public ?string $youtubeUrl, - public ?string $iconImageContents, - public ?string $iconImageOriginalName, - public ?string $iconImageMimeType, - public ?int $iconImageSizeBytes, - public ?string $pdfContents, - public ?string $pdfOriginalName, - public ?string $pdfMimeType, - public ?int $pdfSizeBytes, ) { } } diff --git a/backend/app/Element/UseCases/UpdateElement/UpdateIconImage.php b/backend/app/Element/UseCases/UpdateElement/UpdateIconImage.php deleted file mode 100644 index 45d274f..0000000 --- a/backend/app/Element/UseCases/UpdateElement/UpdateIconImage.php +++ /dev/null @@ -1,81 +0,0 @@ -id === null) { - throw new BadRequestException('id is required'); - } - - if ( - $request->iconImageContents === null - || $request->iconImageOriginalName === null - || $request->iconImageMimeType === null - || $request->iconImageSizeBytes === null - ) { - throw new BadRequestException('icon image is required'); - } - - if ( - ! in_array( - $request->iconImageMimeType, - self::ALLOWED_MIME_TYPES, - true, - ) - ) { - throw new BadRequestException( - 'icon image must be a jpeg, png or webp image', - ); - } - - if ($request->iconImageSizeBytes > self::MAX_SIZE_BYTES) { - throw new BadRequestException( - 'icon image must be 5MB or smaller', - ); - } - - $element = $this->elementRepository->find($request->id); - if ($element === null) { - throw new NotFoundException('Element not found'); - } - - $iconImage = new FileToUpload( - contents: $request->iconImageContents, - originalName: $request->iconImageOriginalName, - mimeType: $request->iconImageMimeType, - sizeBytes: $request->iconImageSizeBytes, - ); - $path = $this->fileUploader->upload($iconImage, 'element-icons'); - $element->setIconImageUrl($path); - - return $this->elementRepository->update($element); - } -} diff --git a/backend/app/Element/UseCases/UpdateElement/UpdateIconImageRequest.php b/backend/app/Element/UseCases/UpdateElement/UpdateIconImageRequest.php deleted file mode 100644 index a119053..0000000 --- a/backend/app/Element/UseCases/UpdateElement/UpdateIconImageRequest.php +++ /dev/null @@ -1,15 +0,0 @@ -nullableString($request->iconImageUrl); - if ($iconImageUrl === null) { - $this->deleteManagedFile($element->getIconImageUrl()); - } - - $element->setIconImageUrl($iconImageUrl); + $element->setIconImageUrl($this->nullableString( + $request->iconImageUrl, + )); return $this->elementRepository->update($element); } @@ -53,13 +47,4 @@ class UpdateIconImageUrl return $value; } - - private function deleteManagedFile(?string $path): void - { - if ($path === null) { - return; - } - - $this->fileUploader->delete($path); - } } diff --git a/backend/app/Element/UseCases/UpdateElement/UpdatePdf.php b/backend/app/Element/UseCases/UpdateElement/UpdatePdf.php deleted file mode 100644 index 0a13f09..0000000 --- a/backend/app/Element/UseCases/UpdateElement/UpdatePdf.php +++ /dev/null @@ -1,75 +0,0 @@ -id === null) { - throw new BadRequestException('id is required'); - } - - if ( - $request->pdfContents === null - || $request->pdfOriginalName === null - || $request->pdfMimeType === null - || $request->pdfSizeBytes === null - ) { - throw new BadRequestException('pdf is required'); - } - - if ( - ! in_array( - $request->pdfMimeType, - self::ALLOWED_MIME_TYPES, - true, - ) - ) { - throw new BadRequestException('pdf must be a pdf file'); - } - - if ($request->pdfSizeBytes > self::MAX_SIZE_BYTES) { - throw new BadRequestException('pdf must be 10MB or smaller'); - } - - $element = $this->elementRepository->find($request->id); - if ($element === null) { - throw new NotFoundException('Element not found'); - } - - $pdf = new FileToUpload( - contents: $request->pdfContents, - originalName: $request->pdfOriginalName, - mimeType: $request->pdfMimeType, - sizeBytes: $request->pdfSizeBytes, - ); - $path = $this->fileUploader->upload($pdf, 'element-pdfs'); - $element->setPdfPath($path); - - return $this->elementRepository->update($element); - } -} diff --git a/backend/app/Element/UseCases/UpdateElement/UpdatePdfPath.php b/backend/app/Element/UseCases/UpdateElement/UpdatePdfPath.php index 404c78b..d6fde1e 100644 --- a/backend/app/Element/UseCases/UpdateElement/UpdatePdfPath.php +++ b/backend/app/Element/UseCases/UpdateElement/UpdatePdfPath.php @@ -6,14 +6,11 @@ use App\Element\Element; use App\Element\ElementRepository; use App\Exceptions\BadRequestException; use App\Exceptions\NotFoundException; -use App\Shared\Files\FileUploader; class UpdatePdfPath { - public function __construct( - private ElementRepository $elementRepository, - private FileUploader $fileUploader, - ) { + public function __construct(private ElementRepository $elementRepository) + { } /** @@ -35,12 +32,7 @@ class UpdatePdfPath throw new NotFoundException('Element not found'); } - $pdfPath = $this->nullableString($request->pdfPath); - if ($pdfPath === null) { - $this->deleteManagedFile($element->getPdfPath()); - } - - $element->setPdfPath($pdfPath); + $element->setPdfPath($this->nullableString($request->pdfPath)); return $this->elementRepository->update($element); } @@ -53,13 +45,4 @@ class UpdatePdfPath return $value; } - - private function deleteManagedFile(?string $path): void - { - if ($path === null) { - return; - } - - $this->fileUploader->delete($path); - } } diff --git a/backend/app/Element/UseCases/UpdateElement/UpdatePdfRequest.php b/backend/app/Element/UseCases/UpdateElement/UpdatePdfRequest.php deleted file mode 100644 index 98ac3bf..0000000 --- a/backend/app/Element/UseCases/UpdateElement/UpdatePdfRequest.php +++ /dev/null @@ -1,15 +0,0 @@ -app->bind( - FileUploader::class, - LaravelFileUploader::class, - ); } } diff --git a/backend/app/Shared/Files/FileToUpload.php b/backend/app/Shared/Files/FileToUpload.php deleted file mode 100644 index e8b8f41..0000000 --- a/backend/app/Shared/Files/FileToUpload.php +++ /dev/null @@ -1,34 +0,0 @@ -contents; - } - - public function getOriginalName(): string - { - return $this->originalName; - } - - public function getMimeType(): string - { - return $this->mimeType; - } - - public function getSizeBytes(): int - { - return $this->sizeBytes; - } -} diff --git a/backend/app/Shared/Files/FileUploader.php b/backend/app/Shared/Files/FileUploader.php deleted file mode 100644 index ac30916..0000000 --- a/backend/app/Shared/Files/FileUploader.php +++ /dev/null @@ -1,12 +0,0 @@ -extensionFor($file); - Storage::disk('public')->put($path, $file->getContents()); - - return $path; - } - - public function url(string $path): string - { - return Storage::disk('public')->url($path); - } - - public function delete(string $path): void - { - Storage::disk('public')->delete($path); - } - - private function extensionFor(FileToUpload $file): string - { - $mimeExtensions = [ - 'image/jpeg' => '.jpg', - 'image/png' => '.png', - 'image/webp' => '.webp', - 'application/pdf' => '.pdf', - ]; - if (isset($mimeExtensions[$file->getMimeType()])) { - return $mimeExtensions[$file->getMimeType()]; - } - - $originalExtension = pathinfo( - $file->getOriginalName(), - PATHINFO_EXTENSION, - ); - if ($originalExtension !== '') { - return '.' . $originalExtension; - } - - return ''; - } -} diff --git a/backend/database/seeders/ElementSeeder.php b/backend/database/seeders/ElementSeeder.php index c7df012..ba89ab1 100644 --- a/backend/database/seeders/ElementSeeder.php +++ b/backend/database/seeders/ElementSeeder.php @@ -6,7 +6,6 @@ use App\Element\CreateElementDto; use App\Element\ElementRepository; use App\Set\SetRepository; use Illuminate\Database\Seeder; -use Illuminate\Support\Facades\Storage; use RuntimeException; class ElementSeeder extends Seeder @@ -16,18 +15,11 @@ class ElementSeeder extends Seeder $setRepository = app(SetRepository::class); $elementRepository = app(ElementRepository::class); $baderechSet = $setRepository->find(1); - $rootIconImageUrl = $this->seedStorageFile( - 'element-icons/baderech-haavodah-icon.png', - ); - $introductionPdfPath = $this->seedStorageFile( - 'element-pdfs/baderech.pdf', - ); - $rootElement = $elementRepository->create(new CreateElementDto( set: $baderechSet, title: $baderechSet->getName(), description: $baderechSet->getDescription(), - iconImageUrl: $rootIconImageUrl, + iconImageUrl: '/assets/baderech-haavodah-icon.png', richText: '', pdfPath: null, youtubeUrl: null, @@ -44,7 +36,7 @@ class ElementSeeder extends Seeder . 'unlock the ability to live with strength, confidence, ' . 'and hope.', 'richText' => $this->introductionRichText(), - 'pdfPath' => $introductionPdfPath, + 'pdfPath' => '/assets/pdfs/baderech.pdf', ], [ 'title' => '2. Foundations', @@ -124,22 +116,6 @@ class ElementSeeder extends Seeder )); } - private function seedStorageFile( - string $storagePath, - ): string { - $sourcePath = base_path( - "database/seeders/assets/$storagePath", - ); - $contents = file_get_contents($sourcePath); - if ($contents === false) { - throw new RuntimeException("Seed file missing: $sourcePath"); - } - - Storage::disk('public')->put($storagePath, $contents); - - return $storagePath; - } - private function introductionRichText(): string { return '
A structured path for growth
', - pdfPath: 'element-pdfs/original.pdf', - youtubeUrl: null, - parentElement: null, - )); - $this->createSession('valid-token'); - - $response = $this->withCredentials() - ->withUnencryptedCookie('auth_token', 'valid-token') - ->postJson('/api/element/update', [ - 'elementId' => $element->getId(), - 'iconImageUrl' => '', - 'pdfPath' => '', - ]); - - $response->assertOk(); - $body = $response->json(); - $this->assertNull($body['element']['iconImageUrl']); - $this->assertNull($body['element']['pdfPath']); - $updatedElement = $elementRepository->find($element->getId()); - $this->assertNotNull($updatedElement); - $this->assertNull($updatedElement->getIconImageUrl()); - $this->assertNull($updatedElement->getPdfPath()); - Storage::disk('public')->assertMissing( - 'element-icons/original-icon.png', - ); - Storage::disk('public')->assertMissing( - 'element-pdfs/original.pdf', - ); - } - - public function testIconImageUploadRequiresAuthentication(): void - { - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $setRepository->create(new CreateSetDto( - name: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: '/assets/baderech-haavodah-icon.png', - )); - $element = $elementRepository->create(new CreateElementDto( - set: $set, - title: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: null, - richText: 'A structured path for growth
', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - - $response = $this->post( - '/api/element/update', - [ - 'elementId' => (string) $element->getId(), - 'iconImage' => $this->iconImageUpload(), - ], - ); - - $response->assertUnauthorized(); - $response->assertExactJson([ - 'error' => 'unauthenticated', - ]); - } - - public function testAuthenticatedIconImageUploadReturnsElementPayload(): void - { - Storage::fake('public'); - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $setRepository->create(new CreateSetDto( - name: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: '/assets/baderech-haavodah-icon.png', - )); - $element = $elementRepository->create(new CreateElementDto( - set: $set, - title: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: null, - richText: 'A structured path for growth
', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - $this->createSession('valid-token'); - - $response = $this->withCredentials() - ->withUnencryptedCookie('auth_token', 'valid-token') - ->post( - '/api/element/update', - [ - 'elementId' => (string) $element->getId(), - 'iconImage' => $this->iconImageUpload(), - ], - ); - - $response->assertOk(); - $body = $response->json(); - $this->assertSame($element->getId(), $body['element']['id']); - $this->assertStringContainsString( - '/storage/element-icons/', - $body['element']['iconImageUrl'], - ); - $updatedElement = $elementRepository->find($element->getId()); - $this->assertNotNull($updatedElement); - $updatedIconImageUrl = $updatedElement->getIconImageUrl(); - $this->assertIsString($updatedIconImageUrl); - $this->assertStringStartsWith( - 'element-icons/', - $updatedIconImageUrl, - ); - Storage::disk('public')->assertExists($updatedIconImageUrl); - } - - public function testPdfUploadRequiresAuthentication(): void - { - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $setRepository->create(new CreateSetDto( - name: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: '/assets/baderech-haavodah-icon.png', - )); - $element = $elementRepository->create(new CreateElementDto( - set: $set, - title: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: null, - richText: 'A structured path for growth
', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - - $response = $this->post( - '/api/element/update', - [ - 'elementId' => (string) $element->getId(), - 'pdf' => $this->pdfUpload(), - ], - ); - - $response->assertUnauthorized(); - $response->assertExactJson([ - 'error' => 'unauthenticated', - ]); - } - - public function testAuthenticatedPdfUploadReturnsElementPayload(): void - { - Storage::fake('public'); - $setRepository = app(SetRepository::class); - $elementRepository = app(ElementRepository::class); - $set = $setRepository->create(new CreateSetDto( - name: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: '/assets/baderech-haavodah-icon.png', - )); - $element = $elementRepository->create(new CreateElementDto( - set: $set, - title: 'Baderech HaAvodah', - description: 'A structured path for growth', - iconImageUrl: null, - richText: 'A structured path for growth
', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - $this->createSession('valid-token'); - - $response = $this->withCredentials() - ->withUnencryptedCookie('auth_token', 'valid-token') - ->post( - '/api/element/update', - [ - 'elementId' => (string) $element->getId(), - 'pdf' => $this->pdfUpload(), - ], - ); - - $response->assertOk(); - $body = $response->json(); - $this->assertSame($element->getId(), $body['element']['id']); - $this->assertStringContainsString( - '/storage/element-pdfs/', - $body['element']['pdfPath'], - ); - $updatedElement = $elementRepository->find($element->getId()); - $this->assertNotNull($updatedElement); - $updatedPdfPath = $updatedElement->getPdfPath(); - $this->assertIsString($updatedPdfPath); - $this->assertStringStartsWith('element-pdfs/', $updatedPdfPath); - Storage::disk('public')->assertExists($updatedPdfPath); - } - private function createSession(string $token): void { $userRepository = app(UserRepository::class); @@ -434,30 +211,4 @@ class ElementsEndpointTest extends TestCase ), )); } - - private function iconImageUpload(): UploadedFile - { - $fixturePath = __DIR__ . '/../fixtures/icon.png'; - - return new UploadedFile( - $fixturePath, - 'icon.png', - 'image/png', - null, - true, - ); - } - - private function pdfUpload(): UploadedFile - { - $fixturePath = __DIR__ . '/../fixtures/baderech.pdf'; - - return new UploadedFile( - $fixturePath, - 'baderech.pdf', - 'application/pdf', - null, - true, - ); - } } diff --git a/backend/tests/Unit/Controllers/ElementControllerTest.php b/backend/tests/Unit/Controllers/ElementControllerTest.php index 5416d92..99bfa3e 100644 --- a/backend/tests/Unit/Controllers/ElementControllerTest.php +++ b/backend/tests/Unit/Controllers/ElementControllerTest.php @@ -8,18 +8,13 @@ use App\Element\Element; use App\Element\UseCases\GetElement\GetElement; use App\Element\UseCases\UpdateElement\UpdateDescription; use App\Element\UseCases\UpdateElement\UpdateElement; -use App\Element\UseCases\UpdateElement\UpdateIconImage; use App\Element\UseCases\UpdateElement\UpdateIconImageUrl; -use App\Element\UseCases\UpdateElement\UpdatePdf; use App\Element\UseCases\UpdateElement\UpdatePdfPath; use App\Element\UseCases\UpdateElement\UpdateRichText; use App\Element\UseCases\UpdateElement\UpdateTitle; use App\Element\UseCases\UpdateElement\UpdateYoutubeUrl; use App\Set\Set as DomainSet; -use Illuminate\Http\Request; -use Illuminate\Http\UploadedFile; use Tests\Fakes\FakeElementRepository; -use Tests\Fakes\FakeFileUploader; use Tests\TestCase; class ElementControllerTest extends TestCase @@ -28,35 +23,20 @@ class ElementControllerTest extends TestCase private FakeElementRepository $elementRepo; - private FakeFileUploader $fileUploader; - protected function setUp(): void { $this->elementRepo = new FakeElementRepository(); - $this->fileUploader = new FakeFileUploader(); $getElement = new GetElement($this->elementRepo); $updateElement = new UpdateElement( new UpdateTitle($this->elementRepo), new UpdateDescription($this->elementRepo), - new UpdateIconImageUrl($this->elementRepo, $this->fileUploader), + new UpdateIconImageUrl($this->elementRepo), new UpdateRichText($this->elementRepo), - new UpdatePdfPath($this->elementRepo, $this->fileUploader), + new UpdatePdfPath($this->elementRepo), new UpdateYoutubeUrl($this->elementRepo), - new UpdateIconImage( - $this->elementRepo, - $this->fileUploader, - ), - new UpdatePdf( - $this->elementRepo, - $this->fileUploader, - ), $this->elementRepo, ); - $this->controller = new ElementController( - $getElement, - $updateElement, - $this->fileUploader, - ); + $this->controller = new ElementController($getElement, $updateElement); } public function testShowReturnsElementPayload(): void @@ -155,88 +135,6 @@ class ElementControllerTest extends TestCase ); } - public function testUpdateWithIconImageReturnsElementPayload(): void - { - $set = $this->createSet(1, 'Baderech'); - $element = $this->createElement( - $set, - 'Baderech HaAvodah', - 'A structured path for growth', - null, - 'A structured path for growth
', - null, - null, - null, - ); - $fixturePath = __DIR__ . '/../../fixtures/icon.png'; - $request = new Request([], [ - 'elementId' => (string) $element->getId(), - ], [], [], [ - 'iconImage' => new UploadedFile( - $fixturePath, - 'icon.png', - 'image/png', - null, - true, - ), - ], ['REQUEST_METHOD' => 'POST']); - - $response = $this->controller->update($request); - - $this->assertEquals(200, $response->getStatusCode()); - $body = json_decode($response->getContent(), true); - $this->assertSame($element->getId(), $body['element']['id']); - $this->assertSame( - 'https://test.local/storage/element-icons/fake-icon.png', - $body['element']['iconImageUrl'], - ); - $this->assertSame( - 'element-icons', - $this->fileUploader->uploads[0]['folder'], - ); - } - - public function testUpdateWithPdfReturnsElementPayload(): void - { - $set = $this->createSet(1, 'Baderech'); - $element = $this->createElement( - $set, - 'Baderech HaAvodah', - 'A structured path for growth', - null, - 'A structured path for growth
', - null, - null, - null, - ); - $fixturePath = __DIR__ . '/../../fixtures/baderech.pdf'; - $request = new Request([], [ - 'elementId' => (string) $element->getId(), - ], [], [], [ - 'pdf' => new UploadedFile( - $fixturePath, - 'baderech.pdf', - 'application/pdf', - null, - true, - ), - ], ['REQUEST_METHOD' => 'POST']); - - $response = $this->controller->update($request); - - $this->assertEquals(200, $response->getStatusCode()); - $body = json_decode($response->getContent(), true); - $this->assertSame($element->getId(), $body['element']['id']); - $this->assertSame( - 'https://test.local/storage/element-pdfs/fake-baderech.pdf', - $body['element']['pdfPath'], - ); - $this->assertSame( - 'element-pdfs', - $this->fileUploader->uploads[0]['folder'], - ); - } - private function createSet(int $id, string $name): DomainSet { return new DomainSet( diff --git a/backend/tests/Unit/Element/UseCases/UpdateElementFieldsTest.php b/backend/tests/Unit/Element/UseCases/UpdateElementFieldsTest.php index ca39700..7c27c9c 100644 --- a/backend/tests/Unit/Element/UseCases/UpdateElementFieldsTest.php +++ b/backend/tests/Unit/Element/UseCases/UpdateElementFieldsTest.php @@ -19,19 +19,15 @@ use App\Element\UseCases\UpdateElement\UpdateYoutubeUrlRequest; use App\Exceptions\BadRequestException; use App\Set\Set as DomainSet; use Tests\Fakes\FakeElementRepository; -use Tests\Fakes\FakeFileUploader; use Tests\TestCase; class UpdateElementFieldsTest extends TestCase { private FakeElementRepository $elementRepo; - private FakeFileUploader $fileUploader; - protected function setUp(): void { $this->elementRepo = new FakeElementRepository(); - $this->fileUploader = new FakeFileUploader(); } public function testUpdateTitleUpdatesOnlyTitle(): void @@ -92,10 +88,7 @@ class UpdateElementFieldsTest extends TestCase public function testUpdateIconImageUrlClearsEmptyString(): void { $element = $this->createFilledElement(); - $updateIconImageUrl = new UpdateIconImageUrl( - $this->elementRepo, - $this->fileUploader, - ); + $updateIconImageUrl = new UpdateIconImageUrl($this->elementRepo); $updatedElement = $updateIconImageUrl->execute( new UpdateIconImageUrlRequest( @@ -106,10 +99,6 @@ class UpdateElementFieldsTest extends TestCase $this->assertNull($updatedElement->getIconImageUrl()); $this->assertSame($element->getTitle(), $updatedElement->getTitle()); - $this->assertSame( - ['/assets/original-icon.png'], - $this->fileUploader->deletedPaths, - ); } public function testUpdateRichTextUpdatesOnlyRichText(): void @@ -137,10 +126,7 @@ class UpdateElementFieldsTest extends TestCase public function testUpdatePdfPathClearsEmptyString(): void { $element = $this->createFilledElement(); - $updatePdfPath = new UpdatePdfPath( - $this->elementRepo, - $this->fileUploader, - ); + $updatePdfPath = new UpdatePdfPath($this->elementRepo); $updatedElement = $updatePdfPath->execute( new UpdatePdfPathRequest(id: $element->getId(), pdfPath: '') @@ -148,10 +134,6 @@ class UpdateElementFieldsTest extends TestCase $this->assertNull($updatedElement->getPdfPath()); $this->assertSame($element->getTitle(), $updatedElement->getTitle()); - $this->assertSame( - ['/assets/pdfs/original.pdf'], - $this->fileUploader->deletedPaths, - ); } public function testUpdateYoutubeUrlClearsEmptyString(): void @@ -172,16 +154,6 @@ class UpdateElementFieldsTest extends TestCase private function createFilledElement(): Element { - return $this->createElementWithMedia( - '/assets/original-icon.png', - '/assets/pdfs/original.pdf', - ); - } - - private function createElementWithMedia( - ?string $iconImageUrl, - ?string $pdfPath, - ): Element { $set = new DomainSet( id: 1, name: 'Baderech', @@ -193,9 +165,9 @@ class UpdateElementFieldsTest extends TestCase set: $set, title: 'Original title', description: 'Original description', - iconImageUrl: $iconImageUrl, + iconImageUrl: '/assets/original-icon.png', richText: 'Original rich text
', - pdfPath: $pdfPath, + pdfPath: '/assets/pdfs/original.pdf', youtubeUrl: 'https://www.youtube.com/watch?v=yHx-r4p6hHU', parentElement: null, )); diff --git a/backend/tests/Unit/Element/UseCases/UpdateElementTest.php b/backend/tests/Unit/Element/UseCases/UpdateElementTest.php index 8d823e3..0ce0d88 100644 --- a/backend/tests/Unit/Element/UseCases/UpdateElementTest.php +++ b/backend/tests/Unit/Element/UseCases/UpdateElementTest.php @@ -5,12 +5,10 @@ namespace Tests\Unit\Element\UseCases; use App\Element\CreateElementDto; use App\Element\Element; use App\Element\UseCases\UpdateElement\UpdateDescription; +use App\Element\UseCases\UpdateElement\UpdateIconImageUrl; use App\Element\UseCases\UpdateElement\UpdateElement; use App\Element\UseCases\UpdateElement\UpdateElementRequest; -use App\Element\UseCases\UpdateElement\UpdateIconImage; -use App\Element\UseCases\UpdateElement\UpdateIconImageUrl; use App\Element\UseCases\UpdateElement\UpdatePdfPath; -use App\Element\UseCases\UpdateElement\UpdatePdf; use App\Element\UseCases\UpdateElement\UpdateRichText; use App\Element\UseCases\UpdateElement\UpdateTitle; use App\Element\UseCases\UpdateElement\UpdateYoutubeUrl; @@ -18,36 +16,24 @@ use App\Exceptions\BadRequestException; use App\Exceptions\NotFoundException; use App\Set\Set as DomainSet; use Tests\Fakes\FakeElementRepository; -use Tests\Fakes\FakeFileUploader; use Tests\TestCase; class UpdateElementTest extends TestCase { private FakeElementRepository $elementRepo; - private FakeFileUploader $fileUploader; - private UpdateElement $updateElement; protected function setUp(): void { $this->elementRepo = new FakeElementRepository(); - $this->fileUploader = new FakeFileUploader(); $this->updateElement = new UpdateElement( new UpdateTitle($this->elementRepo), new UpdateDescription($this->elementRepo), - new UpdateIconImageUrl($this->elementRepo, $this->fileUploader), + new UpdateIconImageUrl($this->elementRepo), new UpdateRichText($this->elementRepo), - new UpdatePdfPath($this->elementRepo, $this->fileUploader), + new UpdatePdfPath($this->elementRepo), new UpdateYoutubeUrl($this->elementRepo), - new UpdateIconImage( - $this->elementRepo, - $this->fileUploader, - ), - new UpdatePdf( - $this->elementRepo, - $this->fileUploader, - ), $this->elementRepo, ); } @@ -75,14 +61,6 @@ class UpdateElementTest extends TestCase richText: 'Updated rich text
', pdfPath: '/assets/pdfs/updated.pdf', youtubeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, ) ); @@ -137,14 +115,6 @@ class UpdateElementTest extends TestCase richText: 'Updated rich text
', pdfPath: '', youtubeUrl: '', - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, ) ); @@ -176,14 +146,6 @@ class UpdateElementTest extends TestCase richText: null, pdfPath: null, youtubeUrl: null, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, ) ); @@ -210,58 +172,6 @@ class UpdateElementTest extends TestCase ); } - public function testUpdatesUploadedFiles(): void - { - $set = $this->createSet(1, 'Baderech'); - $element = $this->createElement( - $set, - 'Original title', - 'Original description', - null, - 'Original rich text
', - null, - null, - null, - ); - - $updatedElement = $this->updateElement->execute( - new UpdateElementRequest( - id: $element->getId(), - title: null, - description: null, - iconImageUrl: null, - richText: null, - pdfPath: null, - youtubeUrl: null, - iconImageContents: 'binary-image-bytes', - iconImageOriginalName: 'icon.png', - iconImageMimeType: 'image/png', - iconImageSizeBytes: 1024, - pdfContents: 'binary-pdf-bytes', - pdfOriginalName: 'baderech.pdf', - pdfMimeType: 'application/pdf', - pdfSizeBytes: 1024, - ) - ); - - $this->assertSame( - 'element-icons/fake-icon.png', - $updatedElement->getIconImageUrl(), - ); - $this->assertSame( - 'element-pdfs/fake-baderech.pdf', - $updatedElement->getPdfPath(), - ); - $this->assertSame( - 'element-icons', - $this->fileUploader->uploads[0]['folder'], - ); - $this->assertSame( - 'element-pdfs', - $this->fileUploader->uploads[1]['folder'], - ); - } - public function testThrowsWhenIdMissing(): void { $this->expectException(BadRequestException::class); @@ -275,14 +185,6 @@ class UpdateElementTest extends TestCase richText: 'Updated rich text
', pdfPath: null, youtubeUrl: null, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, )); } @@ -299,14 +201,6 @@ class UpdateElementTest extends TestCase richText: null, pdfPath: null, youtubeUrl: null, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, )); } @@ -323,14 +217,6 @@ class UpdateElementTest extends TestCase richText: 'Updated rich text
', pdfPath: null, youtubeUrl: null, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, )); } @@ -347,14 +233,6 @@ class UpdateElementTest extends TestCase richText: 'Updated rich text
', pdfPath: null, youtubeUrl: null, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, )); } diff --git a/backend/tests/Unit/Element/UseCases/UpdateIconImageTest.php b/backend/tests/Unit/Element/UseCases/UpdateIconImageTest.php deleted file mode 100644 index af8ae7f..0000000 --- a/backend/tests/Unit/Element/UseCases/UpdateIconImageTest.php +++ /dev/null @@ -1,175 +0,0 @@ -elementRepository = new FakeElementRepository(); - $this->fileUploader = new FakeFileUploader(); - $this->useCase = new UpdateIconImage( - $this->elementRepository, - $this->fileUploader, - ); - } - - /** - * @return array{ - * iconImageContents: string, - * iconImageOriginalName: string, - * iconImageMimeType: string, - * iconImageSizeBytes: int - * } - */ - private function imageArgs(): array - { - return [ - 'iconImageContents' => 'binary-image-bytes', - 'iconImageOriginalName' => 'icon.png', - 'iconImageMimeType' => 'image/png', - 'iconImageSizeBytes' => 1024, - ]; - } - - public function testUploadsIconImageAndStoresPath(): void - { - $element = $this->createElement(); - - $updatedElement = $this->useCase->execute( - new UpdateIconImageRequest( - ...$this->imageArgs(), - id: $element->getId(), - ) - ); - - $this->assertSame( - 'element-icons/fake-icon.png', - $updatedElement->getIconImageUrl(), - ); - $this->assertSame( - 'element-icons/fake-icon.png', - $this->elementRepository - ->find($element->getId()) - ->getIconImageUrl(), - ); - $this->assertSame( - 'element-icons', - $this->fileUploader->uploads[0]['folder'], - ); - } - - public function testNullIdThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('id is required'); - - $this->useCase->execute( - new UpdateIconImageRequest( - ...$this->imageArgs(), - id: null, - ) - ); - } - - public function testNullIconImageThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('icon image is required'); - - $this->useCase->execute( - new UpdateIconImageRequest( - id: 1, - iconImageContents: null, - iconImageOriginalName: null, - iconImageMimeType: null, - iconImageSizeBytes: null, - ) - ); - } - - public function testDisallowedMimeThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage( - 'icon image must be a jpeg, png or webp image', - ); - - $this->useCase->execute( - new UpdateIconImageRequest( - id: 1, - iconImageContents: 'not-an-image', - iconImageOriginalName: 'icon.pdf', - iconImageMimeType: 'application/pdf', - iconImageSizeBytes: 1024, - ) - ); - } - - public function testOversizedIconImageThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('icon image must be 5MB or smaller'); - - $this->useCase->execute( - new UpdateIconImageRequest( - id: 1, - iconImageContents: 'big', - iconImageOriginalName: 'icon.png', - iconImageMimeType: 'image/png', - iconImageSizeBytes: 6 * 1024 * 1024, - ) - ); - } - - public function testMissingElementThrowsNotFound(): void - { - $this->expectException(NotFoundException::class); - $this->expectExceptionMessage('Element not found'); - - $this->useCase->execute( - new UpdateIconImageRequest( - ...$this->imageArgs(), - id: 999, - ) - ); - } - - private function createElement(): Element - { - $set = new DomainSet( - id: 1, - name: 'Baderech', - description: 'Baderech description', - iconImageUrl: '/assets/baderech-icon.png', - ); - - return $this->elementRepository->create(new CreateElementDto( - set: $set, - title: 'Original title', - description: 'Original description', - iconImageUrl: null, - richText: '', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - } -} diff --git a/backend/tests/Unit/Element/UseCases/UpdatePdfTest.php b/backend/tests/Unit/Element/UseCases/UpdatePdfTest.php deleted file mode 100644 index 9a3b30b..0000000 --- a/backend/tests/Unit/Element/UseCases/UpdatePdfTest.php +++ /dev/null @@ -1,173 +0,0 @@ -elementRepository = new FakeElementRepository(); - $this->fileUploader = new FakeFileUploader(); - $this->useCase = new UpdatePdf( - $this->elementRepository, - $this->fileUploader, - ); - } - - /** - * @return array{ - * pdfContents: string, - * pdfOriginalName: string, - * pdfMimeType: string, - * pdfSizeBytes: int - * } - */ - private function pdfArgs(): array - { - return [ - 'pdfContents' => 'binary-pdf-bytes', - 'pdfOriginalName' => 'baderech.pdf', - 'pdfMimeType' => 'application/pdf', - 'pdfSizeBytes' => 1024, - ]; - } - - public function testUploadsPdfAndStoresPath(): void - { - $element = $this->createElement(); - - $updatedElement = $this->useCase->execute( - new UpdatePdfRequest( - ...$this->pdfArgs(), - id: $element->getId(), - ) - ); - - $this->assertSame( - 'element-pdfs/fake-baderech.pdf', - $updatedElement->getPdfPath(), - ); - $storedElement = $this->elementRepository->find($element->getId()); - $this->assertNotNull($storedElement); - $this->assertSame( - 'element-pdfs/fake-baderech.pdf', - $storedElement->getPdfPath(), - ); - $this->assertSame( - 'element-pdfs', - $this->fileUploader->uploads[0]['folder'], - ); - } - - public function testNullIdThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('id is required'); - - $this->useCase->execute( - new UpdatePdfRequest( - ...$this->pdfArgs(), - id: null, - ) - ); - } - - public function testNullPdfThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('pdf is required'); - - $this->useCase->execute( - new UpdatePdfRequest( - id: 1, - pdfContents: null, - pdfOriginalName: null, - pdfMimeType: null, - pdfSizeBytes: null, - ) - ); - } - - public function testDisallowedMimeThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('pdf must be a pdf file'); - - $this->useCase->execute( - new UpdatePdfRequest( - id: 1, - pdfContents: 'not-a-pdf', - pdfOriginalName: 'icon.png', - pdfMimeType: 'image/png', - pdfSizeBytes: 1024, - ) - ); - } - - public function testOversizedPdfThrowsBadRequest(): void - { - $this->expectException(BadRequestException::class); - $this->expectExceptionMessage('pdf must be 10MB or smaller'); - - $this->useCase->execute( - new UpdatePdfRequest( - id: 1, - pdfContents: 'big', - pdfOriginalName: 'baderech.pdf', - pdfMimeType: 'application/pdf', - pdfSizeBytes: 11 * 1024 * 1024, - ) - ); - } - - public function testMissingElementThrowsNotFound(): void - { - $this->expectException(NotFoundException::class); - $this->expectExceptionMessage('Element not found'); - - $this->useCase->execute( - new UpdatePdfRequest( - ...$this->pdfArgs(), - id: 999, - ) - ); - } - - private function createElement(): Element - { - $set = new DomainSet( - id: 1, - name: 'Baderech', - description: 'Baderech description', - iconImageUrl: '/assets/baderech-icon.png', - ); - - return $this->elementRepository->create(new CreateElementDto( - set: $set, - title: 'Original title', - description: 'Original description', - iconImageUrl: null, - richText: '', - pdfPath: null, - youtubeUrl: null, - parentElement: null, - )); - } -} diff --git a/backend/tests/fixtures/baderech.pdf b/backend/tests/fixtures/baderech.pdf deleted file mode 100644 index 8864294..0000000 Binary files a/backend/tests/fixtures/baderech.pdf and /dev/null differ diff --git a/backend/tests/fixtures/icon.png b/backend/tests/fixtures/icon.png deleted file mode 100644 index 72603bb..0000000 Binary files a/backend/tests/fixtures/icon.png and /dev/null differ diff --git a/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts index 38dc7a1..8678ec2 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/admin-element.cy.ts @@ -12,17 +12,26 @@ function loginAsAdmin(): void { function fillElementForm( title: string, description: string, + iconImageUrl: string, richText: string, + pdfPath: string, youtubeUrl: string, ): void { cy.get('[data-cy="admin-element-title"]').clear().type(title) cy.get('[data-cy="admin-element-description"]').clear().type(description) + cy.get('[data-cy="admin-element-icon-image-url"]') + .clear() + .type(iconImageUrl) cy.get('[data-cy="admin-element-rich-text"]').clear() if (richText !== '') { cy.get('[data-cy="admin-element-rich-text"]').type(richText, { parseSpecialCharSequences: false, }) } + cy.get('[data-cy="admin-element-pdf-path"]').clear() + if (pdfPath !== '') { + cy.get('[data-cy="admin-element-pdf-path"]').type(pdfPath) + } cy.get('[data-cy="admin-element-youtube-url"]').clear() if (youtubeUrl !== '') { cy.get('[data-cy="admin-element-youtube-url"]').type(youtubeUrl) @@ -70,6 +79,7 @@ describe('admin element editing', () => { it('saves element edits and restores the seed content through the UI', () => { const originalTitle = 'Baderech HaAvodah' const originalDescription = 'a structured path for inner and outer growth' + const originalIconImageUrl = '/assets/baderech-haavodah-icon.png' const updatedTitle = 'Baderech HaAvodah Updated' const updatedDescription = 'Updated admin description' const updatedRichText = 'Updated admin rich text
' @@ -80,8 +90,10 @@ describe('admin element editing', () => { fillElementForm( updatedTitle, updatedDescription, + originalIconImageUrl, updatedRichText, '', + '', ) cy.get('[data-cy="admin-element-save"]').click() @@ -98,6 +110,8 @@ describe('admin element editing', () => { fillElementForm( originalTitle, originalDescription, + originalIconImageUrl, + '', '', '', ) @@ -106,89 +120,4 @@ describe('admin element editing', () => { .should('be.visible') .and('contain.text', 'Saved') }) - - it('uploads icon and pdf files immediately through the UI', () => { - cy.resetDb() - loginAsAdmin() - cy.visit('/admin/element/1') - cy.intercept('POST', /\/api\/element\/update$/).as('updateElement') - - cy.get('[data-cy="admin-element-icon-image-input"]').selectFile( - 'public/assets/baderech-haavodah-icon.png', - { force: true }, - ) - cy.wait('@updateElement') - cy.get('[data-cy="admin-element-icon-image-status"]') - .should('be.visible') - .and('contain.text', 'Icon image updated') - cy.get('[data-cy="admin-element-current-icon"]') - .should('be.visible') - .and('have.attr', 'src') - .and('include', '/storage/element-icons/') - - cy.get('[data-cy="admin-element-pdf-input"]').selectFile( - 'public/assets/pdfs/baderech.pdf', - { force: true }, - ) - cy.wait('@updateElement') - cy.get('[data-cy="admin-element-pdf-status"]') - .should('be.visible') - .and('contain.text', 'PDF updated') - cy.get('[data-cy="admin-element-current-pdf"]') - .should('be.visible') - .and('have.attr', 'href') - .and('include', '/storage/element-pdfs/') - - cy.contains('header.site-header a', 'View Element').click() - cy.get('[data-cy="element-icon"]') - .should('be.visible') - .and('have.attr', 'src') - .and('include', '/storage/element-icons/') - cy.get('[data-cy="element-pdf-link"]') - .should('be.visible') - .and('have.attr', 'href') - .and('include', '/storage/element-pdfs/') - - cy.resetDb() - }) - - it('removes uploaded icon and pdf files immediately through the UI', () => { - cy.resetDb() - loginAsAdmin() - cy.visit('/admin/element/1') - cy.intercept('POST', /\/api\/element\/update$/).as('updateElement') - - cy.get('[data-cy="admin-element-icon-image-input"]').selectFile( - 'public/assets/baderech-haavodah-icon.png', - { force: true }, - ) - cy.wait('@updateElement') - cy.get('[data-cy="admin-element-pdf-input"]').selectFile( - 'public/assets/pdfs/baderech.pdf', - { force: true }, - ) - cy.wait('@updateElement') - - cy.contains('button', 'Remove icon image').click() - cy.wait('@updateElement') - cy.get('[data-cy="admin-element-icon-image-status"]') - .should('be.visible') - .and('contain.text', 'Icon image removed') - cy.get('[data-cy="admin-element-current-icon"]').should('not.exist') - cy.contains('No icon image').should('be.visible') - - cy.contains('button', 'Remove PDF').click() - cy.wait('@updateElement') - cy.get('[data-cy="admin-element-pdf-status"]') - .should('be.visible') - .and('contain.text', 'PDF removed') - cy.get('[data-cy="admin-element-current-pdf"]').should('not.exist') - cy.contains('No PDF').should('be.visible') - - cy.contains('header.site-header a', 'View Element').click() - cy.get('[data-cy="element-icon"]').should('not.exist') - cy.get('[data-cy="element-pdf-link"]').should('not.exist') - - cy.resetDb() - }) }) diff --git a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts index e0f361a..b3e1424 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts @@ -47,7 +47,7 @@ describe('media page sets', () => { cy.get('[data-cy="element-icon"]') .should('be.visible') .and('have.attr', 'src') - .and('include', '/storage/element-icons/baderech-haavodah-icon.png') + .and('include', '/assets/baderech-haavodah-icon.png') cy.get('[data-cy="element-rich-text"]').should('not.exist') cy.get('[data-cy="element-youtube-embed"]') .should('not.exist') @@ -117,12 +117,9 @@ describe('media page sets', () => { .should('have.css', 'text-align', 'center') cy.get('[data-cy="element-youtube-embed"]').should('not.exist') cy.contains('[data-cy="element-pdf-link"]', 'View PDF') - .as('pdfLink') .should('be.visible') + .and('have.attr', 'href', '/assets/pdfs/baderech.pdf') .and('have.attr', 'target', '_blank') - cy.get('@pdfLink') - .and('have.attr', 'href') - .and('include', '/storage/element-pdfs/baderech.pdf') cy.contains('[data-cy="child-element-link"]', introductionAudioTitle) .as('introductionAudioLink') .should('have.attr', 'href', '/element/8') diff --git a/frontend/rabbi_gerzi/src/stores/elements.ts b/frontend/rabbi_gerzi/src/stores/elements.ts index 3155637..9da179f 100644 --- a/frontend/rabbi_gerzi/src/stores/elements.ts +++ b/frontend/rabbi_gerzi/src/stores/elements.ts @@ -22,7 +22,9 @@ interface ElementResponse { export interface UpdateElementInput { title: string description: string + iconImageUrl: string richText: string + pdfPath: string youtubeUrl: string } @@ -30,21 +32,11 @@ interface UpdateElementResponse { element: Element } -interface ElementPatchInput { - title?: string - description?: string - iconImageUrl?: string - richText?: string - pdfPath?: string - youtubeUrl?: string -} - interface ErrorResponse { error?: string } const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string -const ELEMENT_UPDATE_URL = `${API_BASE_URL}/api/element/update` export const useElementsStore = defineStore('elements', () => { const element = refNo icon image
-- {{ iconImageStatus }} -
-No PDF
-- {{ pdfStatus }} -
-