From: Dan Brown Date: Sat, 20 Jan 2018 14:06:44 +0000 (+0000) Subject: Merge branch 'master' into draw.io to fetch auth image changes X-Git-Tag: v0.20.0~1^2~21^2~6 X-Git-Url: http://source.bookstackapp.com/bookstack/commitdiff_plain/0c383eee5badf7fef3dbc643fae017d98e726750?ds=inline;hp=-c Merge branch 'master' into draw.io to fetch auth image changes --- 0c383eee5badf7fef3dbc643fae017d98e726750 diff --combined app/Http/Controllers/ImageController.php index 81e300a68,d78350754..c44b6e480 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@@ -1,6 -1,7 +1,7 @@@ file($path); + } + /** * Get all images for a specific type, Paginated * @param string $type @@@ -96,7 -112,6 +112,7 @@@ * @param string $type * @param Request $request * @return \Illuminate\Http\JsonResponse + * @throws \Exception */ public function uploadByType($type, Request $request) { @@@ -104,12 -119,11 +120,12 @@@ $this->validate($request, [ 'file' => 'is_image' ]); + // TODO - Restrict & validate types $imageUpload = $request->file('file'); try { - $uploadedTo = $request->filled('uploaded_to') ? $request->get('uploaded_to') : 0; + $uploadedTo = $request->get('uploaded_to', 0); $image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo); } catch (ImageUploadException $e) { return response($e->getMessage(), 500); @@@ -118,73 -132,6 +134,73 @@@ return response()->json($image); } + /** + * Upload a drawing to the system. + * @param Request $request + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response + */ + public function uploadDrawing(Request $request) + { + $this->validate($request, [ + 'image' => 'required|string', + 'uploaded_to' => 'required|integer' + ]); + $this->checkPermission('image-create-all'); + $imageBase64Data = $request->get('image'); + + try { + $uploadedTo = $request->get('uploaded_to', 0); + $image = $this->imageRepo->saveDrawing($imageBase64Data, $uploadedTo); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + + /** + * Replace the data content of a drawing. + * @param string $id + * @param Request $request + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response + */ + public function replaceDrawing(string $id, Request $request) + { + $this->validate($request, [ + 'image' => 'required|string' + ]); + $this->checkPermission('image-create-all'); + + $imageBase64Data = $request->get('image'); + $image = $this->imageRepo->getById($id); + $this->checkOwnablePermission('image-update', $image); + + try { + $image = $this->imageRepo->replaceDrawingContent($image, $imageBase64Data); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + + /** + * Get the content of an image based64 encoded. + * @param $id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getBase64Image($id) + { + $image = $this->imageRepo->getById($id); + $imageData = $this->imageRepo->getImageData($image); + if ($imageData === null) { + return $this->jsonError("Image data could not be found"); + } + return response()->json([ + 'content' => base64_encode($imageData) + ]); + } + /** * Generate a sized thumbnail for an image. * @param $id @@@ -192,8 -139,6 +208,8 @@@ * @param $height * @param $crop * @return \Illuminate\Http\JsonResponse + * @throws ImageUploadException + * @throws \Exception */ public function getThumbnail($id, $width, $height, $crop) { @@@ -208,8 -153,6 +224,8 @@@ * @param integer $imageId * @param Request $request * @return \Illuminate\Http\JsonResponse + * @throws ImageUploadException + * @throws \Exception */ public function update($imageId, Request $request) { diff --combined app/Repos/ImageRepo.php index 492834446,5f04a74b1..3918d5f67 --- a/app/Repos/ImageRepo.php +++ b/app/Repos/ImageRepo.php @@@ -132,8 -132,6 +132,8 @@@ class ImageRep * @param string $type * @param int $uploadedTo * @return Image + * @throws \BookStack\Exceptions\ImageUploadException + * @throws \Exception */ public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0) { @@@ -142,39 -140,11 +142,39 @@@ return $image; } + /** + * Save a drawing the the database; + * @param string $base64Uri + * @param int $uploadedTo + * @return Image + * @throws \BookStack\Exceptions\ImageUploadException + */ + public function saveDrawing(string $base64Uri, int $uploadedTo) + { + $name = 'Drawing-' . user()->getShortName(40) . '-' . strval(time()) . '.png'; + $image = $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawing', $uploadedTo); + return $image; + } + + /** + * Replace the image content of a drawing. + * @param Image $image + * @param string $base64Uri + * @return Image + * @throws \BookStack\Exceptions\ImageUploadException + */ + public function replaceDrawingContent(Image $image, string $base64Uri) + { + return $this->imageService->replaceImageDataFromBase64Uri($image, $base64Uri); + } + /** * Update the details of an image via an array of properties. * @param Image $image * @param array $updateDetails * @return Image + * @throws \BookStack\Exceptions\ImageUploadException + * @throws \Exception */ public function updateImageDetails(Image $image, $updateDetails) { @@@ -200,8 -170,6 +200,8 @@@ /** * Load thumbnails onto an image object. * @param Image $image + * @throws \BookStack\Exceptions\ImageUploadException + * @throws \Exception */ private function loadThumbs(Image $image) { @@@ -215,38 -183,21 +215,37 @@@ * Get the thumbnail for an image. * If $keepRatio is true only the width will be used. * Checks the cache then storage to avoid creating / accessing the filesystem on every check. - * * @param Image $image * @param int $width * @param int $height * @param bool $keepRatio * @return string + * @throws \BookStack\Exceptions\ImageUploadException + * @throws \Exception */ public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false) { try { return $this->imageService->getThumbnail($image, $width, $height, $keepRatio); - } catch (FileNotFoundException $exception) { - $image->delete(); - return []; + } catch (\Exception $exception) { + dd($exception); + return null; } } + /** + * Get the raw image data from an Image. + * @param Image $image + * @return null|string + */ + public function getImageData(Image $image) + { + try { + return $this->imageService->getImageData($image); + } catch (\Exception $exception) { + return null; + } + } + } diff --combined app/Services/ImageService.php index 1da68ddf1,43375ee09..5eea285e5 --- a/app/Services/ImageService.php +++ b/app/Services/ImageService.php @@@ -46,50 -46,6 +46,50 @@@ class ImageService extends UploadServic return $this->saveNew($imageName, $imageData, $type, $uploadedTo); } + /** + * Save a new image from a uri-encoded base64 string of data. + * @param string $base64Uri + * @param string $name + * @param string $type + * @param int $uploadedTo + * @return Image + * @throws ImageUploadException + */ + public function saveNewFromBase64Uri(string $base64Uri, string $name, string $type, $uploadedTo = 0) + { + $splitData = explode(';base64,', $base64Uri); + if (count($splitData) < 2) { + throw new ImageUploadException("Invalid base64 image data provided"); + } + $data = base64_decode($splitData[1]); + return $this->saveNew($name, $data, $type, $uploadedTo); + } + + /** + * Replace the data for an image via a Base64 encoded string. + * @param Image $image + * @param string $base64Uri + * @return Image + * @throws ImageUploadException + */ + public function replaceImageDataFromBase64Uri(Image $image, string $base64Uri) + { + $splitData = explode(';base64,', $base64Uri); + if (count($splitData) < 2) { + throw new ImageUploadException("Invalid base64 image data provided"); + } + $data = base64_decode($splitData[1]); + $storage = $this->getStorage(); + + try { + $storage->put($image->path, $data); + } catch (Exception $e) { + throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $image->path])); + } + + return $image; + } + /** * Gets an image from url and saves it to the database. * @param $url @@@ -125,8 -81,6 +125,6 @@@ $imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/'; - if ($this->isLocal()) $imagePath = '/public' . $imagePath; - while ($storage->exists($imagePath . $imageName)) { $imageName = str_random(3) . $imageName; } @@@ -139,8 -93,6 +137,6 @@@ throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $fullPath])); } - if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath); - $imageDetails = [ 'name' => $imageName, 'path' => $fullPath, @@@ -155,8 -107,8 +151,8 @@@ $imageDetails['updated_by'] = $userId; } - $image = Image::forceCreate($imageDetails); - + $image = (new Image()); + $image->forceFill($imageDetails)->save(); return $image; } @@@ -167,14 -119,13 +163,13 @@@ */ protected function getPath(Image $image) { - return ($this->isLocal()) ? ('public/' . $image->path) : $image->path; + return $image->path; } /** * Get the thumbnail for an image. * If $keepRatio is true only the width will be used. * Checks the cache then storage to avoid creating / accessing the filesystem on every check. - * * @param Image $image * @param int $width * @param int $height @@@ -194,7 -145,6 +189,6 @@@ } $storage = $this->getStorage(); - if ($storage->exists($thumbFilePath)) { return $this->getPublicUrl($thumbFilePath); } @@@ -204,9 -154,8 +198,8 @@@ } catch (Exception $e) { if ($e instanceof \ErrorException || $e instanceof NotSupportedException) { throw new ImageUploadException(trans('errors.cannot_create_thumbs')); - } else { - throw $e; } + throw $e; } if ($keepRatio) { @@@ -226,19 -175,6 +219,19 @@@ return $this->getPublicUrl($thumbFilePath); } + /** + * Get the raw data content from an image. + * @param Image $image + * @return string + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function getImageData(Image $image) + { + $imagePath = $this->getPath($image); + $storage = $this->getStorage(); + return $storage->get($imagePath); + } + /** * Destroys an Image object along with its files and thumbnails. * @param Image $image @@@ -308,13 -244,11 +301,11 @@@ $storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket']; } } - $this->storageUrl = $storageUrl; } - if ($this->isLocal()) $filePath = str_replace_first('public/', '', $filePath); - - return ($this->storageUrl == false ? rtrim(baseUrl(''), '/') : rtrim($this->storageUrl, '/')) . $filePath; + $basePath = ($this->storageUrl == false) ? baseUrl('/') : $this->storageUrl; + return rtrim($basePath, '/') . $filePath; } diff --combined routes/web.php index 08c919e26,06805714d..a69e672e4 --- a/routes/web.php +++ b/routes/web.php @@@ -5,6 -5,9 +5,9 @@@ Route::get('/translations', 'HomeContro // Authenticated routes... Route::group(['middleware' => 'auth'], function () { + Route::get('/uploads/images/{path}', 'ImageController@showImage') + ->where('path', '.*$'); + Route::group(['prefix' => 'pages'], function() { Route::get('/recently-created', 'PageController@showRecentlyCreated'); Route::get('/recently-updated', 'PageController@showRecentlyUpdated'); @@@ -86,16 -89,13 +89,16 @@@ Route::get('/user/all/{page}', 'ImageController@getAllForUserType'); // Standard get, update and deletion for all types Route::get('/thumb/{id}/{width}/{height}/{crop}', 'ImageController@getThumbnail'); + Route::get('/base64/{id}', 'ImageController@getBase64Image'); Route::put('/update/{imageId}', 'ImageController@update'); + Route::post('/drawing/upload', 'ImageController@uploadDrawing'); + Route::put('/drawing/upload/{id}', 'ImageController@replaceDrawing'); Route::post('/{type}/upload', 'ImageController@uploadByType'); Route::get('/{type}/all', 'ImageController@getAllByType'); Route::get('/{type}/all/{page}', 'ImageController@getAllByType'); Route::get('/{type}/search/{page}', 'ImageController@searchByType'); Route::get('/gallery/{filter}/{page}', 'ImageController@getGalleryFiltered'); - Route::delete('/{imageId}', 'ImageController@destroy'); + Route::delete('/{id}', 'ImageController@destroy'); }); // Attachments routes