From a87ae1601061322e7e7b2dc11658f56467761787 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 27 Apr 2019 14:18:00 +0100 Subject: [PATCH] Started extraction of image controller to separate controllers --- app/Auth/Permissions/PermissionService.php | 11 +- app/Http/Controllers/ImageController.php | 29 ----- .../Images/CoverImageController.php | 95 ++++++++++++++ .../Images/DrawioImageController.php | 67 ++++++++++ .../Images/GalleryImageController.php | 65 ++++++++++ .../Images/SystemImageController.php | 64 +++++++++ .../Images/UserImageController.php | 70 ++++++++++ app/Http/Controllers/UserController.php | 16 +-- app/Uploads/ImageRepo.php | 122 +++++++++++------- ...55_set_user_profile_images_uploaded_to.php | 15 +++ .../assets/js/components/wysiwyg-editor.js | 35 +++-- resources/assets/js/services/drawio.js | 11 +- resources/assets/js/vues/image-manager.js | 96 +++++++------- resources/views/books/edit.blade.php | 2 +- .../views/components/image-manager.blade.php | 12 +- resources/views/shelves/edit.blade.php | 2 +- routes/web.php | 32 +++-- 17 files changed, 571 insertions(+), 173 deletions(-) create mode 100644 app/Http/Controllers/Images/CoverImageController.php create mode 100644 app/Http/Controllers/Images/DrawioImageController.php create mode 100644 app/Http/Controllers/Images/GalleryImageController.php create mode 100644 app/Http/Controllers/Images/SystemImageController.php create mode 100644 app/Http/Controllers/Images/UserImageController.php diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 7e710edaf..a5ab4ea9a 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -732,18 +732,21 @@ class PermissionService } /** - * Filters pages that are a direct relation to another item. + * Add conditions to a query to filter the selection to related entities + * where permissions are granted. + * @param $entityType * @param $query * @param $tableName * @param $entityIdColumn * @return mixed */ - public function filterRelatedPages($query, $tableName, $entityIdColumn) + public function filterRelatedEntity($entityType, $query, $tableName, $entityIdColumn) { $this->currentAction = 'view'; $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn]; - $pageMorphClass = $this->entityProvider->page->getMorphClass(); + $pageMorphClass = $this->entityProvider->get($entityType)->getMorphClass(); + $q = $query->where(function ($query) use ($tableDetails, $pageMorphClass) { $query->where(function ($query) use (&$tableDetails, $pageMorphClass) { $query->whereExists(function ($permissionQuery) use (&$tableDetails, $pageMorphClass) { @@ -761,7 +764,9 @@ class PermissionService }); })->orWhere($tableDetails['entityIdColumn'], '=', 0); }); + $this->clean(); + return $q; } diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php index ae2d74305..df7758176 100644 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@ -81,35 +81,6 @@ class ImageController extends Controller return response()->json($imgData); } - /** - * Get gallery images with a specific filter such as book or page - * @param $filter - * @param int $page - * @param Request $request - * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response - */ - public function getGalleryFiltered(Request $request, $filter, $page = 0) - { - $this->validate($request, [ - 'uploaded_to' => 'required|integer' - ]); - - $validFilters = collect(['page', 'book']); - if (!$validFilters->contains($filter)) { - return response('Invalid filter', 500); - } - - $pageId = $request->get('uploaded_to'); - $imgData = $this->imageRepo->getGalleryFiltered(strtolower($filter), $pageId, $page, 24); - - return response()->json($imgData); - } - - public function uploadGalleryImage(Request $request) - { - // TODO - } - public function uploadUserImage(Request $request) { // TODO diff --git a/app/Http/Controllers/Images/CoverImageController.php b/app/Http/Controllers/Images/CoverImageController.php new file mode 100644 index 000000000..807fddc38 --- /dev/null +++ b/app/Http/Controllers/Images/CoverImageController.php @@ -0,0 +1,95 @@ +imageRepo = $imageRepo; + $this->entityRepo = $entityRepo; + + parent::__construct(); + } + + /** + * Get a list of cover images, in a list. + * Can be paged and filtered by entity. + * @param Request $request + * @param string $entity + * @return \Illuminate\Http\JsonResponse + */ + public function list(Request $request, $entity) + { + if (!$this->isValidEntityTypeForCover($entity)) { + return $this->jsonError(trans('errors.image_upload_type_error')); + } + + $page = $request->get('page', 1); + $searchTerm = $request->get('search', null); + + $type = 'cover_' . $entity; + $imgData = $this->imageRepo->getPaginatedByType($type, $page, 24, null, $searchTerm); + return response()->json($imgData); + } + + /** + * Store a new cover image in the system. + * @param Request $request + * @param string $entity + * @return Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function create(Request $request, $entity) + { + $this->checkPermission('image-create-all'); + $this->validate($request, [ + 'file' => $this->imageRepo->getImageValidationRules(), + 'uploaded_to' => 'required|integer' + ]); + + if (!$this->isValidEntityTypeForCover($entity)) { + return $this->jsonError(trans('errors.image_upload_type_error')); + } + + $uploadedTo = $request->get('uploaded_to', 0); + $entityInstance = $this->entityRepo->getById($entity, $uploadedTo); + $this->checkOwnablePermission($entity . '-update', $entityInstance); + + try { + $type = 'cover_' . $entity; + $imageUpload = $request->file('file'); + $image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + + /** + * Check if the given entity type is valid entity to have cover images. + * @param string $entityType + * @return bool + */ + protected function isValidEntityTypeForCover(string $entityType) + { + return ($entityType === 'book' || $entityType === 'bookshelf'); + } + +} diff --git a/app/Http/Controllers/Images/DrawioImageController.php b/app/Http/Controllers/Images/DrawioImageController.php new file mode 100644 index 000000000..eb0e32827 --- /dev/null +++ b/app/Http/Controllers/Images/DrawioImageController.php @@ -0,0 +1,67 @@ +imageRepo = $imageRepo; + parent::__construct(); + } + + /** + * Get a list of gallery images, in a list. + * Can be paged and filtered by entity. + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function list(Request $request) + { + $page = $request->get('page', 1); + $searchTerm = $request->get('search', null); + $uploadedToFilter = $request->get('uploaded_to', null); + $parentTypeFilter = $request->get('filter_type', null); + + $imgData = $this->imageRepo->getEntityFiltered('drawio', $parentTypeFilter, $page, 24, $uploadedToFilter, $searchTerm); + return response()->json($imgData); + } + + /** + * Store a new gallery image in the system. + * @param Request $request + * @return Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function create(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); + } + +} diff --git a/app/Http/Controllers/Images/GalleryImageController.php b/app/Http/Controllers/Images/GalleryImageController.php new file mode 100644 index 000000000..35087463b --- /dev/null +++ b/app/Http/Controllers/Images/GalleryImageController.php @@ -0,0 +1,65 @@ +imageRepo = $imageRepo; + parent::__construct(); + } + + /** + * Get a list of gallery images, in a list. + * Can be paged and filtered by entity. + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function list(Request $request) + { + $page = $request->get('page', 1); + $searchTerm = $request->get('search', null); + $uploadedToFilter = $request->get('uploaded_to', null); + $parentTypeFilter = $request->get('filter_type', null); + + $imgData = $this->imageRepo->getEntityFiltered('gallery', $parentTypeFilter, $page, 24, $uploadedToFilter, $searchTerm); + return response()->json($imgData); + } + + /** + * Store a new gallery image in the system. + * @param Request $request + * @return Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function create(Request $request) + { + $this->checkPermission('image-create-all'); + $this->validate($request, [ + 'file' => $this->imageRepo->getImageValidationRules() + ]); + + try { + $imageUpload = $request->file('file'); + $uploadedTo = $request->get('uploaded_to', 0); + $image = $this->imageRepo->saveNew($imageUpload, 'gallery', $uploadedTo); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + +} diff --git a/app/Http/Controllers/Images/SystemImageController.php b/app/Http/Controllers/Images/SystemImageController.php new file mode 100644 index 000000000..1c4de2f70 --- /dev/null +++ b/app/Http/Controllers/Images/SystemImageController.php @@ -0,0 +1,64 @@ +imageRepo = $imageRepo; + parent::__construct(); + } + + /** + * Get a list of system images, in a list. + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function list(Request $request) + { + $this->checkPermission('settings-manage'); + $page = $request->get('page', 1); + $searchTerm = $request->get('search', null); + + $imgData = $this->imageRepo->getPaginatedByType('system', $page, 24, null, $searchTerm); + return response()->json($imgData); + } + + /** + * Store a new system image. + * @param Request $request + * @return Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function create(Request $request) + { + $this->checkPermission('image-create-all'); + $this->checkPermission('settings-manage'); + + $this->validate($request, [ + 'file' => $this->imageRepo->getImageValidationRules() + ]); + + try { + $imageUpload = $request->file('file'); + $image = $this->imageRepo->saveNew($imageUpload, 'system', 0); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + +} diff --git a/app/Http/Controllers/Images/UserImageController.php b/app/Http/Controllers/Images/UserImageController.php new file mode 100644 index 000000000..492d867e5 --- /dev/null +++ b/app/Http/Controllers/Images/UserImageController.php @@ -0,0 +1,70 @@ +imageRepo = $imageRepo; + parent::__construct(); + } + + /** + * Get a list of user profile images, in a list. + * @param Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function list(Request $request) + { + $page = $request->get('page', 1); + $searchTerm = $request->get('search', null); + $userId = $request->get('uploaded_to', null); + + $this->checkPermissionOrCurrentUser('users-manage', $userId); + + $imgData = $this->imageRepo->getPaginatedByType('user', $page, 24, $userId, $searchTerm); + return response()->json($imgData); + } + + /** + * Store a new user profile image in the system. + * @param Request $request + * @return Illuminate\Http\JsonResponse + * @throws \Exception + */ + public function create(Request $request) + { + $this->checkPermission('image-create-all'); + + $this->validate($request, [ + 'uploaded_to' => 'required|integer', + 'file' => $this->imageRepo->getImageValidationRules() + ]); + + $userId = $request->get('uploaded_to', null); + $this->checkPermissionOrCurrentUser('users-manage', $userId); + + try { + $imageUpload = $request->file('file'); + $uploadedTo = $request->get('uploaded_to', 0); + $image = $this->imageRepo->saveNew($imageUpload, 'user', $uploadedTo); + } catch (ImageUploadException $e) { + return response($e->getMessage(), 500); + } + + return response()->json($image); + } + +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 1bb5d46cd..a93e8d9c9 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -107,9 +107,7 @@ class UserController extends Controller */ public function edit($id, SocialAuthService $socialAuthService) { - $this->checkPermissionOr('users-manage', function () use ($id) { - return $this->currentUser->id == $id; - }); + $this->checkPermissionOrCurrentUser('users-manage', $id); $user = $this->user->findOrFail($id); @@ -131,9 +129,7 @@ class UserController extends Controller public function update(Request $request, $id) { $this->preventAccessForDemoUsers(); - $this->checkPermissionOr('users-manage', function () use ($id) { - return $this->currentUser->id == $id; - }); + $this->checkPermissionOrCurrentUser('users-manage', $id); $this->validate($request, [ 'name' => 'min:2', @@ -184,9 +180,7 @@ class UserController extends Controller */ public function delete($id) { - $this->checkPermissionOr('users-manage', function () use ($id) { - return $this->currentUser->id == $id; - }); + $this->checkPermissionOrCurrentUser('users-manage', $id); $user = $this->userRepo->getById($id); $this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name])); @@ -202,9 +196,7 @@ class UserController extends Controller public function destroy($id) { $this->preventAccessForDemoUsers(); - $this->checkPermissionOr('users-manage', function () use ($id) { - return $this->currentUser->id == $id; - }); + $this->checkPermissionOrCurrentUser('users-manage', $id); $user = $this->userRepo->getById($id); diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index c13d995bd..235889eee 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -3,6 +3,7 @@ use BookStack\Auth\Permissions\PermissionService; use BookStack\Entities\Page; use BookStack\Http\Requests\Request; +use Illuminate\Database\Eloquent\Builder; use Symfony\Component\HttpFoundation\File\UploadedFile; class ImageRepo @@ -20,7 +21,12 @@ class ImageRepo * @param \BookStack\Auth\Permissions\PermissionService $permissionService * @param \BookStack\Entities\Page $page */ - public function __construct(Image $image, ImageService $imageService, PermissionService $permissionService, Page $page) + public function __construct( + Image $image, + ImageService $imageService, + PermissionService $permissionService, + Page $page + ) { $this->image = $image; $this->imageService = $imageService; @@ -48,92 +54,104 @@ class ImageRepo * @param bool $filterOnPage * @return array */ - private function returnPaginated($query, $page = 0, $pageSize = 24) + private function returnPaginated($query, $page = 1, $pageSize = 24) { - $images = $query->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get(); + $images = $query->orderBy('created_at', 'desc')->skip($pageSize * ($page - 1))->take($pageSize + 1)->get(); $hasMore = count($images) > $pageSize; - $returnImages = $images->take(24); + $returnImages = $images->take($pageSize); $returnImages->each(function ($image) { $this->loadThumbs($image); }); return [ 'images' => $returnImages, - 'hasMore' => $hasMore + 'has_more' => $hasMore ]; } /** - * Gets a load images paginated, filtered by image type. + * Fetch a list of images in a paginated format, filtered by image type. + * Can be filtered by uploaded to and also by name. * @param string $type * @param int $page * @param int $pageSize * @param int $uploadedTo + * @param string|null $search + * @param callable|null $whereClause * @return array */ - public function getPaginatedByType(string $type, int $page = 0, int $pageSize = 24, int $uploadedTo = null) + public function getPaginatedByType( + string $type, + int $page = 0, + int $pageSize = 24, + int $uploadedTo = null, + string $search = null, + callable $whereClause = null + ) { - $images = $this->image->newQuery()->where('type', '=', strtolower($type)); + $imageQuery = $this->image->newQuery()->where('type', '=', strtolower($type)); if ($uploadedTo !== null) { - $images = $images->where('uploaded_to', '=', $uploadedTo); + $imageQuery = $imageQuery->where('uploaded_to', '=', $uploadedTo); + } + + if ($search !== null) { + $imageQuery = $imageQuery->where('name', 'LIKE', '%' . $search . '%'); } // Filter by page access if gallery if ($type === 'gallery') { - $images = $this->restrictionService->filterRelatedPages($images, 'images', 'uploaded_to'); + $imageQuery = $this->restrictionService->filterRelatedEntity('page', $imageQuery, 'images', 'uploaded_to'); } - return $this->returnPaginated($images, $page, $pageSize); + // Filter by entity if cover + if (strpos($type, 'cover_') === 0) { + $entityType = explode('_', $type)[1]; + $imageQuery = $this->restrictionService->filterRelatedEntity($entityType, $imageQuery, 'images', 'uploaded_to'); + } + + if ($whereClause !== null) { + $imageQuery = $imageQuery->where($whereClause); + } + + return $this->returnPaginated($imageQuery, $page, $pageSize); } /** - * Search for images by query, of a particular type. + * Get paginated gallery images within a specific page or book. * @param string $type + * @param string $filterType * @param int $page * @param int $pageSize - * @param string $searchTerm + * @param int|null $uploadedTo + * @param string|null $search * @return array */ - public function searchPaginatedByType(Request $request, $type, $searchTerm, $page = 0, $pageSize = 24) + public function getEntityFiltered( + string $type, + string $filterType = null, + int $page = 0, + int $pageSize = 24, + int $uploadedTo = null, + string $search = null + ) { - // TODO - Filter by uploaded_to - $images = $this->image->newQuery() - ->where('type', '=', strtolower($type)) - ->where('name', 'LIKE', '%' . $searchTerm . '%'); + $contextPage = $this->page->findOrFail($uploadedTo); + $parentFilter = null; - if ($type === 'gallery') { - $images = $this->restrictionService->filterRelatedPages($images, 'images', 'uploaded_to'); + if ($filterType === 'book' || $filterType === 'page') { + $parentFilter = function(Builder $query) use ($filterType, $contextPage) { + if ($filterType === 'page') { + $query->where('uploaded_to', '=', $contextPage->id); + } elseif ($filterType === 'book') { + $validPageIds = $contextPage->book->pages()->get(['id'])->pluck('id')->toArray(); + $query->whereIn('uploaded_to', $validPageIds); + } + }; } - return $this->returnPaginated($images, $page, $pageSize); - } - - /** - * Get gallery images with a particular filter criteria such as - * being within the current book or page. - * @param $filter - * @param $pageId - * @param int $pageNum - * @param int $pageSize - * @return array - */ - public function getGalleryFiltered($filter, $pageId, $pageNum = 0, $pageSize = 24) - { - $images = $this->image->where('type', '=', 'gallery'); - - $page = $this->page->findOrFail($pageId); - - if ($filter === 'page') { - $images = $images->where('uploaded_to', '=', $page->id); - } elseif ($filter === 'book') { - $validPageIds = $page->book->pages->pluck('id')->toArray(); - $images = $images->whereIn('uploaded_to', $validPageIds); - } - - $images = $this->restrictionService->filterRelatedPages($images, 'images', 'uploaded_to'); - return $this->returnPaginated($images, $pageNum, $pageSize); + return $this->getPaginatedByType($type, $page, $pageSize, null, $search, $parentFilter); } /** @@ -253,7 +271,17 @@ class ImageRepo */ public function isValidType($type) { + // TODO - To delete? $validTypes = ['gallery', 'cover', 'system', 'user']; return in_array($type, $validTypes); } + + /** + * Get the validation rules for image files. + * @return string + */ + public function getImageValidationRules() + { + return 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'; + } } diff --git a/database/migrations/2019_04_21_131855_set_user_profile_images_uploaded_to.php b/database/migrations/2019_04_21_131855_set_user_profile_images_uploaded_to.php index f1d00b3e5..a61bd1830 100644 --- a/database/migrations/2019_04_21_131855_set_user_profile_images_uploaded_to.php +++ b/database/migrations/2019_04_21_131855_set_user_profile_images_uploaded_to.php @@ -18,6 +18,17 @@ class SetUserProfileImagesUploadedTo extends Migration ->update([ 'uploaded_to' => DB::raw('`created_by`') ]); + + DB::table('images') + ->where('type', '=', 'cover') + ->update(['type' => 'cover_book']); + + $firstBook = DB::table('books')->first(['id']); + if ($firstBook) { + DB::table('images') + ->where('type', '=', 'cover_book') + ->update(['uploaded_to' => $firstBook->id]); + } } /** @@ -32,5 +43,9 @@ class SetUserProfileImagesUploadedTo extends Migration ->update([ 'uploaded_to' => 0 ]); + + DB::table('images') + ->where('type', '=', 'cover_book') + ->update(['type' => 'cover', 'uploaded_to' => 0]); } } diff --git a/resources/assets/js/components/wysiwyg-editor.js b/resources/assets/js/components/wysiwyg-editor.js index ce5cfbf4e..3f60ff031 100644 --- a/resources/assets/js/components/wysiwyg-editor.js +++ b/resources/assets/js/components/wysiwyg-editor.js @@ -257,39 +257,38 @@ function drawIoPlugin() { DrawIO.show(drawingInit, updateContent); } - function updateContent(pngData) { - let id = "image-" + Math.random().toString(16).slice(2); - let loadingImage = window.baseUrl('/loading.gif'); - let data = { - image: pngData, - uploaded_to: Number(document.getElementById('page-editor').getAttribute('page-id')) - }; + async function updateContent(pngData) { + const id = "image-" + Math.random().toString(16).slice(2); + const loadingImage = window.baseUrl('/loading.gif'); + const pageId = Number(document.getElementById('page-editor').getAttribute('page-id')); // Handle updating an existing image if (currentNode) { DrawIO.close(); let imgElem = currentNode.querySelector('img'); - window.$http.post(window.baseUrl(`/images/drawing/upload`), data).then(resp => { - pageEditor.dom.setAttrib(imgElem, 'src', resp.data.url); - pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', resp.data.id); - }).catch(err => { + try { + const img = await DrawIO.upload(pngData, pageId); + pageEditor.dom.setAttrib(imgElem, 'src', img.url); + pageEditor.dom.setAttrib(currentNode, 'drawio-diagram', img.id); + } catch (err) { window.$events.emit('error', trans('errors.image_upload_error')); console.log(err); - }); + } return; } - setTimeout(() => { + setTimeout(async () => { pageEditor.insertContent(`
`); DrawIO.close(); - window.$http.post(window.baseUrl('/images/drawing/upload'), data).then(resp => { - pageEditor.dom.setAttrib(id, 'src', resp.data.url); - pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', resp.data.id); - }).catch(err => { + try { + const img = await DrawIO.upload(pngData, pageId); + pageEditor.dom.setAttrib(id, 'src', img.url); + pageEditor.dom.get(id).parentNode.setAttribute('drawio-diagram', img.id); + } catch (err) { pageEditor.dom.remove(id); window.$events.emit('error', trans('errors.image_upload_error')); console.log(err); - }); + } }, 5); } diff --git a/resources/assets/js/services/drawio.js b/resources/assets/js/services/drawio.js index b4fcfd59f..6acf091f0 100644 --- a/resources/assets/js/services/drawio.js +++ b/resources/assets/js/services/drawio.js @@ -66,4 +66,13 @@ function drawPostMessage(data) { iFrame.contentWindow.postMessage(JSON.stringify(data), '*'); } -export default {show, close}; \ No newline at end of file +async function upload(imageData, pageUploadedToId) { + let data = { + image: imageData, + uploaded_to: pageUploadedToId, + }; + const resp = await window.$http.post(window.baseUrl(`/images/drawio`), data); + return resp.data; +} + +export default {show, close, upload}; \ No newline at end of file diff --git a/resources/assets/js/vues/image-manager.js b/resources/assets/js/vues/image-manager.js index 843aae378..dd1d9d17a 100644 --- a/resources/assets/js/vues/image-manager.js +++ b/resources/assets/js/vues/image-manager.js @@ -1,7 +1,7 @@ import * as Dates from "../services/dates"; import dropzone from "./components/dropzone"; -let page = 0; +let page = 1; let previousClickTime = 0; let previousClickImage = 0; let dataLoaded = false; @@ -20,7 +20,7 @@ const data = { selectedImage: false, dependantPages: false, showing: false, - view: 'all', + filter: null, hasMore: false, searching: false, searchTerm: '', @@ -56,32 +56,37 @@ const methods = { this.$el.children[0].components.overlay.hide(); }, - fetchData() { - let url = baseUrl + page; - let query = {}; - if (this.uploadedTo !== false) query.uploaded_to = this.uploadedTo; - if (this.searching) query.term = this.searchTerm; + async fetchData() { + let query = { + page, + search: this.searching ? this.searchTerm : null, + uploaded_to: this.uploadedTo || null, + filter_type: this.filter, + }; - this.$http.get(url, {params: query}).then(response => { - this.images = this.images.concat(response.data.images); - this.hasMore = response.data.hasMore; - page++; - }); + const {data} = await this.$http.get(baseUrl, {params: query}); + this.images = this.images.concat(data.images); + this.hasMore = data.has_more; + page++; }, - setView(viewName) { - this.view = viewName; + setFilterType(filterType) { + this.filter = filterType; this.resetState(); this.fetchData(); }, resetState() { this.cancelSearch(); + this.resetListView(); + this.deleteConfirm = false; + baseUrl = window.baseUrl(`/images/${this.imageType}`); + }, + + resetListView() { this.images = []; this.hasMore = false; - this.deleteConfirm = false; - page = 0; - baseUrl = window.baseUrl(`/images/${this.imageType}/${this.view}/`); + page = 1; }, searchImages() { @@ -94,10 +99,7 @@ const methods = { } this.searching = true; - this.images = []; - this.hasMore = false; - page = 0; - baseUrl = window.baseUrl(`/images/${this.imageType}/search/`); + this.resetListView(); this.fetchData(); }, @@ -110,10 +112,10 @@ const methods = { }, imageSelect(image) { - let dblClickTime = 300; - let currentTime = Date.now(); - let timeDiff = currentTime - previousClickTime; - let isDblClick = timeDiff < dblClickTime && image.id === previousClickImage; + const dblClickTime = 300; + const currentTime = Date.now(); + const timeDiff = currentTime - previousClickTime; + const isDblClick = timeDiff < dblClickTime && image.id === previousClickImage; if (isDblClick) { this.callbackAndHide(image); @@ -132,11 +134,11 @@ const methods = { this.hide(); }, - saveImageDetails() { + async saveImageDetails() { let url = window.baseUrl(`/images/${this.selectedImage.id}`); - this.$http.put(url, this.selectedImage).then(response => { - this.$events.emit('success', trans('components.image_update_success')); - }).catch(error => { + try { + await this.$http.put(url, this.selectedImage) + } catch (error) { if (error.response.status === 422) { let errors = error.response.data; let message = ''; @@ -145,27 +147,29 @@ const methods = { }); this.$events.emit('error', message); } - }); + } }, - deleteImage() { + async deleteImage() { if (!this.deleteConfirm) { - let url = window.baseUrl(`/images/usage/${this.selectedImage.id}`); - this.$http.get(url).then(resp => { - this.dependantPages = resp.data; - }).catch(console.error).then(() => { - this.deleteConfirm = true; - }); + const url = window.baseUrl(`/images/usage/${this.selectedImage.id}`); + try { + const {data} = await this.$http.get(url); + this.dependantPages = data; + } catch (error) { + console.error(error); + } + this.deleteConfirm = true; return; } - let url = window.baseUrl(`/images/${this.selectedImage.id}`); - this.$http.delete(url).then(resp => { - this.images.splice(this.images.indexOf(this.selectedImage), 1); - this.selectedImage = false; - this.$events.emit('success', trans('components.image_delete_success')); - this.deleteConfirm = false; - }); + + const url = window.baseUrl(`/images/${this.selectedImage.id}`); + await this.$http.delete(url); + this.images.splice(this.images.indexOf(this.selectedImage), 1); + this.selectedImage = false; + this.$events.emit('success', trans('components.image_delete_success')); + this.deleteConfirm = false; }, getDate(stringDate) { @@ -180,7 +184,7 @@ const methods = { const computed = { uploadUrl() { - return window.baseUrl(`/images/${this.imageType}/upload`); + return window.baseUrl(`/images/${this.imageType}`); } }; @@ -188,7 +192,7 @@ function mounted() { window.ImageManager = this; this.imageType = this.$el.getAttribute('image-type'); this.uploadedTo = this.$el.getAttribute('uploaded-to'); - baseUrl = window.baseUrl('/images/' + this.imageType + '/all/') + baseUrl = window.baseUrl('/images/' + this.imageType) } export default { diff --git a/resources/views/books/edit.blade.php b/resources/views/books/edit.blade.php index f048b543b..a02029a10 100644 --- a/resources/views/books/edit.blade.php +++ b/resources/views/books/edit.blade.php @@ -23,5 +23,5 @@ - @include('components.image-manager', ['imageType' => 'cover']) + @include('components.image-manager', ['imageType' => 'cover', 'uploaded_to']) @stop \ No newline at end of file diff --git a/resources/views/components/image-manager.blade.php b/resources/views/components/image-manager.blade.php index df577b545..7c9084ad1 100644 --- a/resources/views/components/image-manager.blade.php +++ b/resources/views/components/image-manager.blade.php @@ -10,12 +10,12 @@
- - @include('components.image-manager', ['imageType' => 'cover']) + @include('components.image-manager', ['imageType' => 'cover_bookshelf', 'uploaded_to' => $shelf->id]) @stop \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 933179aa7..cecd67456 100644 --- a/routes/web.php +++ b/routes/web.php @@ -103,27 +103,41 @@ Route::group(['middleware' => 'auth'], function () { Route::get('/user/{userId}', 'UserController@showProfilePage'); // Image routes - Route::group(['prefix' => 'images'], function() { + Route::group(['prefix' => 'images'], function () { + // Get for user images // Route::get('/user/all', 'ImageController@getAllForUserType'); // 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::get('/usage/{id}', 'ImageController@usage'); - 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::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'); + + // Gallery + Route::get('/gallery', 'Images\GalleryImageController@list'); + Route::post('/gallery', 'Images\GalleryImageController@create'); + // Drawio + Route::get('/drawio', 'Images\DrawioImageController@list'); + Route::post('/drawio', 'Images\DrawioImageController@create'); + // User + Route::get('/user', 'Images\UserImageController@list'); + Route::post('/user', 'Images\UserImageController@create'); + // System + Route::get('/system', 'Images\SystemImageController@list'); + Route::post('/system', 'Images\SystemImageController@create'); + // Cover + Route::get('/cover_{entity}', 'Images\CoverImageController@list'); + Route::post('/cover_{entity}', 'Images\CoverImageController@create'); // TODO - Remove use of abstract "Type" variable (Above) // TODO - Clearly define each endpoint so logic for each is clear // TODO - Move into per-type controllers // TODO - Test and fully think about permissions and each stage - Route::post('/drawio', 'ImageController@uploadDrawioImage'); - Route::post('/gallery', 'ImageController@uploadGalleryImage'); - Route::post('/user', 'ImageController@uploadUserImage'); - Route::post('/system', 'ImageController@uploadSystemImage'); Route::post('/cover', 'ImageController@uploadCoverImage'); Route::put('/{id}', 'ImageController@update');