From 88d09a2a3b76a2d914d523dc03fcf695849ba1b7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 28 Jan 2018 13:18:28 +0000 Subject: [PATCH] Added drawing endpoint tests Also refactored ImageTests away from BrowserKit Also added image upload type validation. --- app/Http/Controllers/ImageController.php | 5 +- app/Repos/ImageRepo.php | 13 ++- resources/lang/en/errors.php | 1 + tests/BrowserKitTest.php | 7 -- tests/ImageTest.php | 121 +++++++++++++++++++---- tests/test-data/test-image.jpg | Bin 5238 -> 0 bytes tests/test-data/test-image.png | Bin 0 -> 158 bytes 7 files changed, 119 insertions(+), 28 deletions(-) delete mode 100644 tests/test-data/test-image.jpg create mode 100644 tests/test-data/test-image.png diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php index c44b6e480..e675bff0c 100644 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@ -120,7 +120,10 @@ class ImageController extends Controller $this->validate($request, [ 'file' => 'is_image' ]); - // TODO - Restrict & validate types + + if (!$this->imageRepo->isValidType($type)) { + return $this->jsonError(trans('errors.image_upload_type_error')); + } $imageUpload = $request->file('file'); diff --git a/app/Repos/ImageRepo.php b/app/Repos/ImageRepo.php index 97839c27f..0c15a4310 100644 --- a/app/Repos/ImageRepo.php +++ b/app/Repos/ImageRepo.php @@ -1,12 +1,9 @@ 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', 'image_upload_error' => 'An error occurred uploading the image', + 'image_upload_type_error' => 'The image type being uploaded is invalid', // Attachments 'attachment_page_mismatch' => 'Page mismatch during attachment update', diff --git a/tests/BrowserKitTest.php b/tests/BrowserKitTest.php index d5c9911f8..b5c32cef5 100644 --- a/tests/BrowserKitTest.php +++ b/tests/BrowserKitTest.php @@ -13,13 +13,6 @@ abstract class BrowserKitTest extends TestCase use DatabaseTransactions; - /** - * The base URL to use while testing the application. - * - * @var string - */ - protected $baseUrl = 'http://localhost'; - // Local user instances private $admin; private $editor; diff --git a/tests/ImageTest.php b/tests/ImageTest.php index 3bb41138b..822cc969b 100644 --- a/tests/ImageTest.php +++ b/tests/ImageTest.php @@ -1,8 +1,20 @@ getTestImageFilePath(), $fileName, 'image/jpeg', 5238); } /** @@ -28,13 +40,12 @@ class ImageTest extends BrowserKitTest * Uploads an image with the given name. * @param $name * @param int $uploadedTo - * @return string + * @return \Illuminate\Foundation\Testing\TestResponse */ protected function uploadImage($name, $uploadedTo = 0) { $file = $this->getTestImage($name); - $this->call('POST', '/images/gallery/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []); - return $this->getTestImagePath('gallery', $name); + return $this->call('POST', '/images/gallery/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []); } /** @@ -49,19 +60,20 @@ class ImageTest extends BrowserKitTest public function test_image_upload() { - $page = \BookStack\Page::first(); + $page = Page::first(); $this->asAdmin(); $admin = $this->getAdmin(); - $imageName = 'first-image.jpg'; + $imageName = 'first-image.png'; - $relPath = $this->uploadImage($imageName, $page->id); - $this->assertResponseOk(); + $upload = $this->uploadImage($imageName, $page->id); + $upload->assertStatus(200); + $relPath = $this->getTestImagePath('gallery', $imageName); $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image not found at path: '. public_path($relPath)); $this->deleteImage($relPath); - $this->seeInDatabase('images', [ + $this->assertDatabaseHas('images', [ 'url' => $this->baseUrl . $relPath, 'type' => 'gallery', 'uploaded_to' => $page->id, @@ -75,17 +87,18 @@ class ImageTest extends BrowserKitTest public function test_image_delete() { - $page = \BookStack\Page::first(); + $page = Page::first(); $this->asAdmin(); - $imageName = 'first-image.jpg'; + $imageName = 'first-image.png'; - $relPath = $this->uploadImage($imageName, $page->id); - $image = \BookStack\Image::first(); + $this->uploadImage($imageName, $page->id); + $image = Image::first(); + $relPath = $this->getTestImagePath('gallery', $imageName); - $this->call('DELETE', '/images/' . $image->id); - $this->assertResponseOk(); + $delete = $this->delete( '/images/' . $image->id); + $delete->assertStatus(200); - $this->dontSeeInDatabase('images', [ + $this->assertDatabaseMissing('images', [ 'url' => $this->baseUrl . $relPath, 'type' => 'gallery' ]); @@ -93,4 +106,78 @@ class ImageTest extends BrowserKitTest $this->assertFalse(file_exists(public_path($relPath)), 'Uploaded image has not been deleted as expected'); } + public function testBase64Get() + { + $page = Page::first(); + $this->asAdmin(); + $imageName = 'first-image.png'; + + $this->uploadImage($imageName, $page->id); + $image = Image::first(); + + $imageGet = $this->getJson("/images/base64/{$image->id}"); + $imageGet->assertJson([ + 'content' => 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=' + ]); + } + + public function test_drawing_base64_upload() + { + $page = Page::first(); + $editor = $this->getEditor(); + $this->actingAs($editor); + + $upload = $this->postJson('images/drawing/upload', [ + 'uploaded_to' => $page->id, + 'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=' + ]); + + $upload->assertStatus(200); + $upload->assertJson([ + 'type' => 'drawio', + 'uploaded_to' => $page->id, + 'created_by' => $editor->id, + 'updated_by' => $editor->id, + ]); + + $image = Image::where('type', '=', 'drawio')->first(); + $this->assertTrue(file_exists(public_path($image->path)), 'Uploaded image not found at path: '. public_path($image->path)); + + $testImageData = file_get_contents($this->getTestImageFilePath()); + $uploadedImageData = file_get_contents(public_path($image->path)); + $this->assertTrue($testImageData === $uploadedImageData, "Uploaded image file data does not match our test image as expected"); + } + + public function test_drawing_replacing() + { + $page = Page::first(); + $editor = $this->getEditor(); + $this->actingAs($editor); + + $this->postJson('images/drawing/upload', [ + 'uploaded_to' => $page->id, + 'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDQ4S1RUeKwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12NctNWSAQkwMaACUvkAfCkBmjyhGl4AAAAASUVORK5CYII=' + ]); + + $image = Image::where('type', '=', 'drawio')->first(); + + $replace = $this->putJson("images/drawing/upload/{$image->id}", [ + 'image' => 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII=' + ]); + + $replace->assertStatus(200); + $replace->assertJson([ + 'type' => 'drawio', + 'uploaded_to' => $page->id, + 'created_by' => $editor->id, + 'updated_by' => $editor->id, + ]); + + $this->assertTrue(file_exists(public_path($image->path)), 'Uploaded image not found at path: '. public_path($image->path)); + + $testImageData = file_get_contents($this->getTestImageFilePath()); + $uploadedImageData = file_get_contents(public_path($image->path)); + $this->assertTrue($testImageData === $uploadedImageData, "Uploaded image file data does not match our test image as expected"); + } + } \ No newline at end of file diff --git a/tests/test-data/test-image.jpg b/tests/test-data/test-image.jpg deleted file mode 100644 index fb8da91011c2d691eb038afe579d60a8451d28cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5238 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