]> BookStack Code Mirror - bookstack/commitdiff
Started extraction of image controller to separate controllers
authorDan Brown <redacted>
Sat, 27 Apr 2019 13:18:00 +0000 (14:18 +0100)
committerDan Brown <redacted>
Sat, 27 Apr 2019 13:18:00 +0000 (14:18 +0100)
17 files changed:
app/Auth/Permissions/PermissionService.php
app/Http/Controllers/ImageController.php
app/Http/Controllers/Images/CoverImageController.php [new file with mode: 0644]
app/Http/Controllers/Images/DrawioImageController.php [new file with mode: 0644]
app/Http/Controllers/Images/GalleryImageController.php [new file with mode: 0644]
app/Http/Controllers/Images/SystemImageController.php [new file with mode: 0644]
app/Http/Controllers/Images/UserImageController.php [new file with mode: 0644]
app/Http/Controllers/UserController.php
app/Uploads/ImageRepo.php
database/migrations/2019_04_21_131855_set_user_profile_images_uploaded_to.php
resources/assets/js/components/wysiwyg-editor.js
resources/assets/js/services/drawio.js
resources/assets/js/vues/image-manager.js
resources/views/books/edit.blade.php
resources/views/components/image-manager.blade.php
resources/views/shelves/edit.blade.php
routes/web.php

index 7e710edaf4be8f8cdb1c6d58ddb83fbc4e9f67f1..a5ab4ea9a8e51109c7225bc82ccca1799470205d 100644 (file)
@@ -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;
     }
 
index ae2d743052fe1b1e70e014f16dbb2e270c964caa..df77581767cb858776fd389f9fd64a8835a531a2 100644 (file)
@@ -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 (file)
index 0000000..807fddc
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Entities\EntityProvider;
+use BookStack\Entities\Repos\EntityRepo;
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+use BookStack\Http\Controllers\Controller;
+
+class CoverImageController extends Controller
+{
+    protected $imageRepo;
+    protected $entityRepo;
+
+    /**
+     * CoverImageController constructor.
+     * @param ImageRepo $imageRepo
+     * @param EntityRepo $entityRepo
+     */
+    public function __construct(ImageRepo $imageRepo, EntityRepo $entityRepo)
+    {
+        $this->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 (file)
index 0000000..eb0e328
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+use BookStack\Http\Controllers\Controller;
+
+class DrawioImageController extends Controller
+{
+    protected $imageRepo;
+
+    /**
+     * DrawioImageController constructor.
+     * @param ImageRepo $imageRepo
+     */
+    public function __construct(ImageRepo $imageRepo)
+    {
+        $this->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 (file)
index 0000000..3508746
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+use BookStack\Http\Controllers\Controller;
+
+class GalleryImageController extends Controller
+{
+    protected $imageRepo;
+
+    /**
+     * GalleryImageController constructor.
+     * @param ImageRepo $imageRepo
+     */
+    public function __construct(ImageRepo $imageRepo)
+    {
+        $this->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 (file)
index 0000000..1c4de2f
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+use BookStack\Http\Controllers\Controller;
+
+class SystemImageController extends Controller
+{
+    protected $imageRepo;
+
+    /**
+     * SystemImageController constructor.
+     * @param ImageRepo $imageRepo
+     */
+    public function __construct(ImageRepo $imageRepo)
+    {
+        $this->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 (file)
index 0000000..492d867
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Http\Request;
+use BookStack\Http\Controllers\Controller;
+
+class UserImageController extends Controller
+{
+    protected $imageRepo;
+
+    /**
+     * UserImageController constructor.
+     * @param ImageRepo $imageRepo
+     */
+    public function __construct(ImageRepo $imageRepo)
+    {
+        $this->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);
+    }
+
+}
index 1bb5d46cdabba8ad19b86aac81060438ec257cfa..a93e8d9c9c44a79721d1cec4b2a4b9c69f43c4fd 100644 (file)
@@ -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);
 
index c13d995bdae266f6e2fedbb2e4bb5d04e2d3ce3c..235889eee330939a563fb93a11db9bb0ec04b699 100644 (file)
@@ -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);
-    }
-
-    /**
-     * Search for images by query, of a particular type.
-     * @param string $type
-     * @param int $page
-     * @param int $pageSize
-     * @param string $searchTerm
-     * @return array
-     */
-    public function searchPaginatedByType(Request $request, $type, $searchTerm, $page = 0, $pageSize = 24)
-    {
-        // TODO - Filter by uploaded_to
-        $images = $this->image->newQuery()
-            ->where('type', '=', strtolower($type))
-            ->where('name', 'LIKE', '%' . $searchTerm . '%');
+        // Filter by entity if cover
+        if (strpos($type, 'cover_') === 0) {
+            $entityType = explode('_', $type)[1];
+            $imageQuery = $this->restrictionService->filterRelatedEntity($entityType, $imageQuery, 'images', 'uploaded_to');
+        }
 
-        if ($type === 'gallery') {
-            $images = $this->restrictionService->filterRelatedPages($images, 'images', 'uploaded_to');
+        if ($whereClause !== null) {
+            $imageQuery = $imageQuery->where($whereClause);
         }
 
-        return $this->returnPaginated($images, $page, $pageSize);
+        return $this->returnPaginated($imageQuery, $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
+     * Get paginated gallery images within a specific page or book.
+     * @param string $type
+     * @param string $filterType
+     * @param int $page
      * @param int $pageSize
+     * @param int|null $uploadedTo
+     * @param string|null $search
      * @return array
      */
-    public function getGalleryFiltered($filter, $pageId, $pageNum = 0, $pageSize = 24)
+    public function getEntityFiltered(
+        string $type,
+        string $filterType = null,
+        int $page = 0,
+        int $pageSize = 24,
+        int $uploadedTo = null,
+        string $search = null
+    )
     {
-        $images = $this->image->where('type', '=', 'gallery');
-
-        $page = $this->page->findOrFail($pageId);
+        $contextPage = $this->page->findOrFail($uploadedTo);
+        $parentFilter = null;
 
-        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);
+        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);
+                }
+            };
         }
 
-        $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';
+    }
 }
index f1d00b3e5ea1a5083fead9b693f9b6a02a7cb937..a61bd1830a9ddefab67cd959695c3853833c7e29 100644 (file)
@@ -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]);
     }
 }
index ce5cfbf4e66c9fe990cb2fe86bc21d8a5c0f2214..3f60ff03169b2120d602e105025372bab8d8c0e0 100644 (file)
@@ -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(`<div drawio-diagram contenteditable="false"><img src="${loadingImage}" id="${id}"></div>`);
             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);
     }
 
index b4fcfd59fea63d2fab05d4b449152f2bc4577fb4..6acf091f02ace85b78af1e239cf160ccbb46e214 100644 (file)
@@ -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
index 843aae378ace9661436b724ae5382d50c9f0944a..dd1d9d17adcd4be1aebb2addf9095d1cb1f0f861 100644 (file)
@@ -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;
-
-        this.$http.get(url, {params: query}).then(response => {
-            this.images = this.images.concat(response.data.images);
-            this.hasMore = response.data.hasMore;
-            page++;
-        });
+    async fetchData() {
+        let query = {
+            page,
+            search: this.searching ? this.searchTerm : null,
+            uploaded_to: this.uploadedTo || null,
+            filter_type: this.filter,
+        };
+
+        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 {
index f048b543b63adff54b5100345f57d5f3bc8e0a78..a02029a105012a45910c56f0d6c72909292dd538 100644 (file)
@@ -23,5 +23,5 @@
         </div>
     </div>
 
-    @include('components.image-manager', ['imageType' => 'cover'])
+    @include('components.image-manager', ['imageType' => 'cover', 'uploaded_to'])
 @stop
\ No newline at end of file
index df577b54525cc0b416986cd18508067eed8056cb..7c9084ad102fa1b2690517c950d413a5cc59be0a 100644 (file)
             <div class="flex-fill image-manager-body">
 
                 <div class="image-manager-content">
-                    <div v-if="imageType === 'gallery'" class="image-manager-header primary-background-light nav-tabs grid third">
-                        <div class="tab-item" title="{{ trans('components.image_all_title') }}" :class="{selected: (view=='all')}" @click="setView('all')">@icon('images') {{ trans('components.image_all') }}</div>
-                        <div class="tab-item" title="{{ trans('components.image_book_title') }}" :class="{selected: (view=='book')}" @click="setView('book')">@icon('book', ['class' => 'text-book svg-icon']) {{ trans('entities.book') }}</div>
-                        <div class="tab-item" title="{{ trans('components.image_page_title') }}" :class="{selected: (view=='page')}" @click="setView('page')">@icon('page', ['class' => 'text-page svg-icon']) {{ trans('entities.page') }}</div>
+                    <div v-if="imageType === 'gallery' || imageType === 'drawio'" class="image-manager-header primary-background-light nav-tabs grid third">
+                        <div class="tab-item" title="{{ trans('components.image_all_title') }}" :class="{selected: !filter}" @click="setFilterType(null)">@icon('images') {{ trans('components.image_all') }}</div>
+                        <div class="tab-item" title="{{ trans('components.image_book_title') }}" :class="{selected: (filter=='book')}" @click="setFilterType('book')">@icon('book', ['class' => 'text-book svg-icon']) {{ trans('entities.book') }}</div>
+                        <div class="tab-item" title="{{ trans('components.image_page_title') }}" :class="{selected: (filter=='page')}" @click="setFilterType('page')">@icon('page', ['class' => 'text-page svg-icon']) {{ trans('entities.page') }}</div>
                     </div>
-                    <div v-show="view === 'all'" >
+                    <div>
                         <form @submit.prevent="searchImages" class="contained-search-box">
                             <input placeholder="{{ trans('components.image_search_hint') }}" v-model="searchTerm">
                             <button :class="{active: searching}" title="{{ trans('common.search_clear') }}" type="button" @click="cancelSearch()" class="text-button cancel">@icon('close')</button>
@@ -63,7 +63,7 @@
                                     <button type="button" class="button icon outline" @click="deleteImage">@icon('delete')</button>
 
                                 </div>
-                                <button class="button anim fadeIn float right" v-show="selectedImage" @click="callbackAndHide(selectedImage)">
+                                <button class="button primary anim fadeIn float right" v-show="selectedImage" @click="callbackAndHide(selectedImage)">
                                     {{ trans('components.image_select_image') }}
                                 </button>
                                 <div class="clearfix"></div>
index 8b99e8b515ba56a64700a490fbe44dad7598dbfa..c51330ce0fbe8adfe88e0d88774d32f6fb55c7cc 100644 (file)
@@ -23,5 +23,5 @@
         </div>
     </div>
 
-    @include('components.image-manager', ['imageType' => 'cover'])
+    @include('components.image-manager', ['imageType' => 'cover_bookshelf', 'uploaded_to' => $shelf->id])
 @stop
\ No newline at end of file
index 933179aa7ec2d7e2e661c5d4bbcb27c7ba39e3f7..cecd6745613cb3ce107ac634c13c5f3da9faabbd 100644 (file)
@@ -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');