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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 literal 0 HcmV?d00001