]> BookStack Code Mirror - bookstack/commitdiff
Change image-selector to not use manager
authorDan Brown <redacted>
Sat, 4 May 2019 14:48:15 +0000 (15:48 +0100)
committerDan Brown <redacted>
Sat, 4 May 2019 14:50:29 +0000 (15:50 +0100)
- Now changes the images directly for user, system & cover.
- Extra permission checks added to edit & delete actions.

30 files changed:
app/Auth/User.php
app/Http/Controllers/BookController.php
app/Http/Controllers/BookshelfController.php
app/Http/Controllers/ImageController.php [deleted file]
app/Http/Controllers/Images/CoverImageController.php [deleted file]
app/Http/Controllers/Images/DrawioImageController.php
app/Http/Controllers/Images/ImageController.php [new file with mode: 0644]
app/Http/Controllers/Images/SystemImageController.php [deleted file]
app/Http/Controllers/Images/UserImageController.php [deleted file]
app/Http/Controllers/SettingController.php
app/Http/Controllers/UserController.php
app/Uploads/Image.php
app/Uploads/ImageRepo.php
app/Uploads/ImageService.php
resources/assets/js/components/image-picker.js
resources/assets/js/components/markdown-editor.js
resources/assets/js/components/wysiwyg-editor.js
resources/assets/js/services/drawio.js
resources/assets/sass/_layout.scss
resources/lang/en/validation.php
resources/views/books/create.blade.php
resources/views/books/edit.blade.php
resources/views/books/form.blade.php
resources/views/components/image-picker.blade.php
resources/views/settings/index.blade.php
resources/views/shelves/create.blade.php
resources/views/shelves/edit.blade.php
resources/views/shelves/form.blade.php
resources/views/users/edit.blade.php
routes/web.php

index 05e77e13d0e4a84e45f0f1f0fd90bdd22bb8e683..12f022b0668491653479e9151ea10373f2fa32eb 100644 (file)
@@ -24,7 +24,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
      * The attributes that are mass assignable.
      * @var array
      */
-    protected $fillable = ['name', 'email', 'image_id'];
+    protected $fillable = ['name', 'email'];
 
     /**
      * The attributes excluded from the model's JSON form.
index 24e0d784d0a87b3b558bb4771584dc6414caeedd..7c8ad5c2fa08eb363b6a878e2193ac653e1f6aba 100644 (file)
@@ -6,6 +6,7 @@ use BookStack\Entities\Book;
 use BookStack\Entities\EntityContextManager;
 use BookStack\Entities\Repos\EntityRepo;
 use BookStack\Entities\ExportService;
+use BookStack\Uploads\ImageRepo;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Views;
@@ -17,6 +18,7 @@ class BookController extends Controller
     protected $userRepo;
     protected $exportService;
     protected $entityContextManager;
+    protected $imageRepo;
 
     /**
      * BookController constructor.
@@ -24,17 +26,20 @@ class BookController extends Controller
      * @param UserRepo $userRepo
      * @param ExportService $exportService
      * @param EntityContextManager $entityContextManager
+     * @param ImageRepo $imageRepo
      */
     public function __construct(
         EntityRepo $entityRepo,
         UserRepo $userRepo,
         ExportService $exportService,
-        EntityContextManager $entityContextManager
+        EntityContextManager $entityContextManager,
+        ImageRepo $imageRepo
     ) {
         $this->entityRepo = $entityRepo;
         $this->userRepo = $userRepo;
         $this->exportService = $exportService;
         $this->entityContextManager = $entityContextManager;
+        $this->imageRepo = $imageRepo;
         parent::__construct();
     }
 
@@ -101,13 +106,15 @@ class BookController extends Controller
      * @param string $shelfSlug
      * @return Response
      * @throws \BookStack\Exceptions\NotFoundException
+     * @throws \BookStack\Exceptions\ImageUploadException
      */
     public function store(Request $request, string $shelfSlug = null)
     {
         $this->checkPermission('book-create-all');
         $this->validate($request, [
             'name' => 'required|string|max:255',
-            'description' => 'string|max:1000'
+            'description' => 'string|max:1000',
+            'image' => $this->imageRepo->getImageValidationRules(),
         ]);
 
         $bookshelf = null;
@@ -117,6 +124,7 @@ class BookController extends Controller
         }
 
         $book = $this->entityRepo->createFromInput('book', $request->all());
+        $this->bookUpdateActions($book, $request);
         Activity::add($book, 'book_create', $book->id);
 
         if ($bookshelf) {
@@ -170,20 +178,27 @@ class BookController extends Controller
 
     /**
      * Update the specified book in storage.
-     * @param  Request $request
+     * @param Request $request
      * @param          $slug
      * @return Response
+     * @throws \BookStack\Exceptions\ImageUploadException
+     * @throws \BookStack\Exceptions\NotFoundException
      */
-    public function update(Request $request, $slug)
+    public function update(Request $request, string $slug)
     {
         $book = $this->entityRepo->getBySlug('book', $slug);
         $this->checkOwnablePermission('book-update', $book);
         $this->validate($request, [
             'name' => 'required|string|max:255',
-            'description' => 'string|max:1000'
+            'description' => 'string|max:1000',
+            'image' => $this->imageRepo->getImageValidationRules(),
         ]);
+
          $book = $this->entityRepo->updateFromInput('book', $book, $request->all());
+         $this->bookUpdateActions($book, $request);
+
          Activity::add($book, 'book_update', $book->id);
+
          return redirect($book->getUrl());
     }
 
@@ -311,7 +326,12 @@ class BookController extends Controller
         $book = $this->entityRepo->getBySlug('book', $bookSlug);
         $this->checkOwnablePermission('book-delete', $book);
         Activity::addMessage('book_delete', 0, $book->name);
+
+        if ($book->cover) {
+            $this->imageRepo->destroyImage($book->cover);
+        }
         $this->entityRepo->destroyBook($book);
+
         return redirect('/books');
     }
 
@@ -383,4 +403,28 @@ class BookController extends Controller
         $textContent = $this->exportService->bookToPlainText($book);
         return $this->downloadResponse($textContent, $bookSlug . '.txt');
     }
+
+    /**
+     * Common actions to run on book update.
+     * Handles updating the cover image.
+     * @param Book $book
+     * @param Request $request
+     * @throws \BookStack\Exceptions\ImageUploadException
+     */
+    protected function bookUpdateActions(Book $book, Request $request)
+    {
+        // Update the cover image if in request
+        if ($request->has('image')) {
+            $newImage = $request->file('image');
+            $image = $this->imageRepo->saveNew($newImage, 'cover_book', $book->id, 512, 512, true);
+            $book->image_id = $image->id;
+            $book->save();
+        }
+
+        if ($request->has('image_reset')) {
+            $this->imageRepo->destroyImage($book->cover);
+            $book->image_id = 0;
+            $book->save();
+        }
+    }
 }
index e63cfd1d5f624ec4b9693e6372b22aae20c00e51..dba2503ef67aecda957d7036529f2b1a1bec2098 100644 (file)
@@ -86,8 +86,9 @@ class BookshelfController extends Controller
 
     /**
      * Store a newly created bookshelf in storage.
-     * @param  Request $request
+     * @param Request $request
      * @return Response
+     * @throws \BookStack\Exceptions\ImageUploadException
      */
     public function store(Request $request)
     {
@@ -284,10 +285,17 @@ class BookshelfController extends Controller
         $this->entityRepo->updateShelfBooks($shelf, $request->get('books', ''));
 
         // Update the cover image if in request
-        if ($request->has('image') && userCan('image-create-all')) {
-            $image = $this->imageRepo->saveNew($request->file('image'), 'cover', $shelf->id);
+        if ($request->has('image')) {
+            $newImage = $request->file('image');
+            $image = $this->imageRepo->saveNew($newImage, 'cover_shelf', $shelf->id, 512, 512, true);
             $shelf->image_id = $image->id;
             $shelf->save();
         }
+
+        if ($request->has('image_reset')) {
+            $this->imageRepo->destroyImage($shelf->cover);
+            $shelf->image_id = 0;
+            $shelf->save();
+        }
     }
 }
diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php
deleted file mode 100644 (file)
index df77581..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-<?php namespace BookStack\Http\Controllers;
-
-use BookStack\Entities\Repos\EntityRepo;
-use BookStack\Exceptions\ImageUploadException;
-use BookStack\Repos\PageRepo;
-use BookStack\Uploads\Image;
-use BookStack\Uploads\ImageRepo;
-use Illuminate\Filesystem\Filesystem as File;
-use Illuminate\Http\Request;
-
-class ImageController extends Controller
-{
-    protected $image;
-    protected $file;
-    protected $imageRepo;
-
-    /**
-     * ImageController constructor.
-     * @param Image $image
-     * @param File $file
-     * @param ImageRepo $imageRepo
-     */
-    public function __construct(Image $image, File $file, ImageRepo $imageRepo)
-    {
-        $this->image = $image;
-        $this->file = $file;
-        $this->imageRepo = $imageRepo;
-        parent::__construct();
-    }
-
-    /**
-     * Provide an image file from storage.
-     * @param string $path
-     * @return mixed
-     */
-    public function showImage(string $path)
-    {
-        $path = storage_path('uploads/images/' . $path);
-        if (!file_exists($path)) {
-            abort(404);
-        }
-
-        return response()->file($path);
-    }
-
-    /**
-     * Get all images for a specific type, Paginated
-     * @param Request $request
-     * @param string $type
-     * @param int $page
-     * @return \Illuminate\Http\JsonResponse
-     */
-    public function getAllByType(Request $request, $type, $page = 0)
-    {
-        $uploadedToFilter = $request->get('uploaded_to', null);
-
-        // For user profile request, check access to user images
-        if ($type === 'user') {
-            $this->checkPermissionOrCurrentUser('users-manage', $uploadedToFilter ?? 0);
-        }
-
-        $imgData = $this->imageRepo->getPaginatedByType($type, $page, 24, $uploadedToFilter);
-        return response()->json($imgData);
-    }
-
-    /**
-     * Search through images within a particular type.
-     * @param $type
-     * @param int $page
-     * @param Request $request
-     * @return mixed
-     */
-    public function searchByType(Request $request, $type, $page = 0)
-    {
-        $this->validate($request, [
-            'term' => 'required|string'
-        ]);
-
-        $searchTerm = $request->get('term');
-        $imgData = $this->imageRepo->searchPaginatedByType($type, $searchTerm, $page, 24);
-        return response()->json($imgData);
-    }
-
-    public function uploadUserImage(Request $request)
-    {
-        // TODO
-    }
-
-    public function uploadSystemImage(Request $request)
-    {
-        // TODO
-    }
-
-    public function uploadCoverImage(Request $request)
-    {
-        // TODO
-    }
-
-    /**
-     * Upload a draw.io image into the system.
-     * @param Request $request
-     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
-     */
-    public function uploadDrawioImage(Request $request)
-    {
-        $this->validate($request, [
-            'image' => 'required|string',
-            'uploaded_to' => 'required|integer'
-        ]);
-        $uploadedTo = $request->get('uploaded_to', 0);
-        $page = $this->
-        $this->checkPermission('image-create-all');
-        $imageBase64Data = $request->get('image');
-
-        try {
-            $image = $this->imageRepo->saveDrawing($imageBase64Data, $uploadedTo);
-        } catch (ImageUploadException $e) {
-            return response($e->getMessage(), 500);
-        }
-
-        return response()->json($image);
-    }
-
-    /**
-     * Handles image uploads for use on pages.
-     * @param string $type
-     * @param Request $request
-     * @return \Illuminate\Http\JsonResponse
-     * @throws \Exception
-     */
-    public function uploadByType($type, Request $request)
-    {
-        $this->checkPermission('image-create-all');
-        $this->validate($request, [
-            'file' => 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'
-        ]);
-
-        if (!$this->imageRepo->isValidType($type)) {
-            return $this->jsonError(trans('errors.image_upload_type_error'));
-        }
-
-        $imageUpload = $request->file('file');
-
-        try {
-            $uploadedTo = $request->get('uploaded_to', 0);
-
-            // For user profile request, check access to user images
-            if ($type === 'user') {
-                $this->checkPermissionOrCurrentUser('users-manage', $uploadedTo ?? 0);
-            }
-
-            $image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo);
-        } 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
-     * @param $width
-     * @param $height
-     * @param $crop
-     * @return \Illuminate\Http\JsonResponse
-     * @throws ImageUploadException
-     * @throws \Exception
-     */
-    public function getThumbnail($id, $width, $height, $crop)
-    {
-        $this->checkPermission('image-create-all');
-        $image = $this->imageRepo->getById($id);
-        $thumbnailUrl = $this->imageRepo->getThumbnail($image, $width, $height, $crop == 'false');
-        return response()->json(['url' => $thumbnailUrl]);
-    }
-
-    /**
-     * Update image details
-     * @param integer $id
-     * @param Request $request
-     * @return \Illuminate\Http\JsonResponse
-     * @throws ImageUploadException
-     * @throws \Exception
-     */
-    public function update($id, Request $request)
-    {
-        $this->validate($request, [
-            'name' => 'required|min:2|string'
-        ]);
-
-        $image = $this->imageRepo->getById($id);
-        $this->checkOwnablePermission('image-update', $image);
-
-        $image = $this->imageRepo->updateImageDetails($image, $request->all());
-        return response()->json($image);
-    }
-
-    /**
-     * Show the usage of an image on pages.
-     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
-     * @param $id
-     * @return \Illuminate\Http\JsonResponse
-     */
-    public function usage(EntityRepo $entityRepo, $id)
-    {
-        $image = $this->imageRepo->getById($id);
-        $pageSearch = $entityRepo->searchForImage($image->url);
-        return response()->json($pageSearch);
-    }
-
-    /**
-     * Deletes an image and all thumbnail/image files
-     * @param int $id
-     * @return \Illuminate\Http\JsonResponse
-     * @throws \Exception
-     */
-    public function destroy($id)
-    {
-        $image = $this->imageRepo->getById($id);
-        $this->checkOwnablePermission('image-delete', $image);
-
-        $this->imageRepo->destroyImage($image);
-        return response()->json(trans('components.images_deleted'));
-    }
-}
diff --git a/app/Http/Controllers/Images/CoverImageController.php b/app/Http/Controllers/Images/CoverImageController.php
deleted file mode 100644 (file)
index fdec56b..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-
-namespace BookStack\Http\Controllers\Images;
-
-// TODO - Replace this with entity-level handling
-// Since won't be part of image manager handling
-// Added some to bookshelf controller already
-
-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');
-    }
-
-}
index eb0e328277b9d1b75dd98eb0263ca8406a393e2d..2deb64d9641b161081c7310706d2ed6be2759ba5 100644 (file)
@@ -64,4 +64,26 @@ class DrawioImageController extends Controller
         return response()->json($image);
     }
 
+    /**
+     * Get the content of an image based64 encoded.
+     * @param $id
+     * @return \Illuminate\Http\JsonResponse|mixed
+     */
+    public function getAsBase64($id)
+    {
+        $image = $this->imageRepo->getById($id);
+        $page = $image->getPage();
+        if ($image === null || $image->type !== 'drawio' || !userCan('page-view', $page)) {
+            return $this->jsonError("Image data could not be found");
+        }
+
+        $imageData = $this->imageRepo->getImageData($image);
+        if ($imageData === null) {
+            return $this->jsonError("Image data could not be found");
+        }
+        return response()->json([
+            'content' => base64_encode($imageData)
+        ]);
+    }
+
 }
diff --git a/app/Http/Controllers/Images/ImageController.php b/app/Http/Controllers/Images/ImageController.php
new file mode 100644 (file)
index 0000000..a76fb5e
--- /dev/null
@@ -0,0 +1,115 @@
+<?php namespace BookStack\Http\Controllers\Images;
+
+use BookStack\Entities\Repos\EntityRepo;
+use BookStack\Exceptions\ImageUploadException;
+use BookStack\Http\Controllers\Controller;
+use BookStack\Repos\PageRepo;
+use BookStack\Uploads\Image;
+use BookStack\Uploads\ImageRepo;
+use Illuminate\Filesystem\Filesystem as File;
+use Illuminate\Http\Request;
+
+class ImageController extends Controller
+{
+    protected $image;
+    protected $file;
+    protected $imageRepo;
+
+    /**
+     * ImageController constructor.
+     * @param Image $image
+     * @param File $file
+     * @param ImageRepo $imageRepo
+     */
+    public function __construct(Image $image, File $file, ImageRepo $imageRepo)
+    {
+        $this->image = $image;
+        $this->file = $file;
+        $this->imageRepo = $imageRepo;
+        parent::__construct();
+    }
+
+    /**
+     * Provide an image file from storage.
+     * @param string $path
+     * @return mixed
+     */
+    public function showImage(string $path)
+    {
+        $path = storage_path('uploads/images/' . $path);
+        if (!file_exists($path)) {
+            abort(404);
+        }
+
+        return response()->file($path);
+    }
+
+
+    /**
+     * Update image details
+     * @param integer $id
+     * @param Request $request
+     * @return \Illuminate\Http\JsonResponse
+     * @throws ImageUploadException
+     * @throws \Exception
+     */
+    public function update($id, Request $request)
+    {
+        $this->validate($request, [
+            'name' => 'required|min:2|string'
+        ]);
+
+        $image = $this->imageRepo->getById($id);
+        $this->checkImagePermission($image);
+        $this->checkOwnablePermission('image-update', $image);
+
+        $image = $this->imageRepo->updateImageDetails($image, $request->all());
+        return response()->json($image);
+    }
+
+    /**
+     * Show the usage of an image on pages.
+     * @param \BookStack\Entities\Repos\EntityRepo $entityRepo
+     * @param $id
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function usage(EntityRepo $entityRepo, $id)
+    {
+        $image = $this->imageRepo->getById($id);
+        $this->checkImagePermission($image);
+        $pageSearch = $entityRepo->searchForImage($image->url);
+        return response()->json($pageSearch);
+    }
+
+    /**
+     * Deletes an image and all thumbnail/image files
+     * @param int $id
+     * @return \Illuminate\Http\JsonResponse
+     * @throws \Exception
+     */
+    public function destroy($id)
+    {
+        $image = $this->imageRepo->getById($id);
+        $this->checkOwnablePermission('image-delete', $image);
+        $this->checkImagePermission($image);
+
+        $this->imageRepo->destroyImage($image);
+        return response()->json(trans('components.images_deleted'));
+    }
+
+    /**
+     * Check related page permission and ensure type is drawio or gallery.
+     * @param Image $image
+     */
+    protected function checkImagePermission(Image $image)
+    {
+        if ($image->type !== 'drawio' || $image->type !== 'gallery') {
+            $this->showPermissionError();
+        }
+
+        $relatedPage = $image->getPage();
+        if ($relatedPage) {
+            $this->checkOwnablePermission('page-view', $relatedPage);
+        }
+    }
+}
diff --git a/app/Http/Controllers/Images/SystemImageController.php b/app/Http/Controllers/Images/SystemImageController.php
deleted file mode 100644 (file)
index ad3de96..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-// TODO - Replace this with setting-level handling
-// Since won't be part of image manager handling
-
-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
deleted file mode 100644 (file)
index 312ccf4..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-
-namespace BookStack\Http\Controllers\Images;
-
-// TODO - Replace this with user-controller-level handling
-// Since won't be part of image manager handling
-
-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 159e19a2bb441d8b8ef3d296ad0ef856471fbe9f..650833c7f33bd7a9a5d5e6e97a4446688c22b775 100644 (file)
@@ -1,6 +1,7 @@
 <?php namespace BookStack\Http\Controllers;
 
 use BookStack\Auth\User;
+use BookStack\Uploads\ImageRepo;
 use BookStack\Uploads\ImageService;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
@@ -8,6 +9,19 @@ use Setting;
 
 class SettingController extends Controller
 {
+    protected $imageRepo;
+
+    /**
+     * SettingController constructor.
+     * @param $imageRepo
+     */
+    public function __construct(ImageRepo $imageRepo)
+    {
+        $this->imageRepo = $imageRepo;
+        parent::__construct();
+    }
+
+
     /**
      * Display a listing of the settings.
      * @return Response
@@ -35,6 +49,9 @@ class SettingController extends Controller
     {
         $this->preventAccessForDemoUsers();
         $this->checkPermission('settings-manage');
+        $this->validate($request, [
+            'app_logo' => $this->imageRepo->getImageValidationRules(),
+        ]);
 
         // Cycles through posted settings and update them
         foreach ($request->all() as $name => $value) {
@@ -42,7 +59,21 @@ class SettingController extends Controller
                 continue;
             }
             $key = str_replace('setting-', '', trim($name));
-            Setting::put($key, $value);
+            setting()->put($key, $value);
+        }
+
+        // Update logo image if set
+        if ($request->has('app_logo')) {
+            $logoFile = $request->file('app_logo');
+            $this->imageRepo->destroyByType('system');
+            $image = $this->imageRepo->saveNew($logoFile, 'system', 0, null, 86);
+            setting()->put('app-logo', $image->url);
+        }
+
+        // Clear logo image if requested
+        if ($request->get('app_logo_reset', null)) {
+            $this->imageRepo->destroyByType('system');
+            setting()->remove('app-logo');
         }
 
         session()->flash('success', trans('settings.settings_save_success'));
index a93e8d9c9c44a79721d1cec4b2a4b9c69f43c4fd..c7a7c5646cb5097dafbc04c46cf1ea390a91db82 100644 (file)
@@ -4,6 +4,7 @@ use BookStack\Auth\Access\SocialAuthService;
 use BookStack\Auth\User;
 use BookStack\Auth\UserRepo;
 use BookStack\Exceptions\UserUpdateException;
+use BookStack\Uploads\ImageRepo;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 
@@ -12,16 +13,19 @@ class UserController extends Controller
 
     protected $user;
     protected $userRepo;
+    protected $imageRepo;
 
     /**
      * UserController constructor.
-     * @param User     $user
+     * @param User $user
      * @param UserRepo $userRepo
+     * @param ImageRepo $imageRepo
      */
-    public function __construct(User $user, UserRepo $userRepo)
+    public function __construct(User $user, UserRepo $userRepo, ImageRepo $imageRepo)
     {
         $this->user = $user;
         $this->userRepo = $userRepo;
+        $this->imageRepo = $imageRepo;
         parent::__construct();
     }
 
@@ -94,6 +98,7 @@ class UserController extends Controller
             $this->userRepo->setUserRoles($user, $roles);
         }
 
+        // TODO - Check this uses new profile assignment
         $this->userRepo->downloadAndAssignUserAvatar($user);
 
         return redirect('/settings/users');
@@ -121,10 +126,11 @@ class UserController extends Controller
 
     /**
      * Update the specified user in storage.
-     * @param  Request $request
-     * @param  int $id
+     * @param Request $request
+     * @param int $id
      * @return Response
      * @throws UserUpdateException
+     * @throws \BookStack\Exceptions\ImageUploadException
      */
     public function update(Request $request, $id)
     {
@@ -136,7 +142,8 @@ class UserController extends Controller
             'email'            => 'min:2|email|unique:users,email,' . $id,
             'password'         => 'min:5|required_with:password_confirm',
             'password-confirm' => 'same:password|required_with:password',
-            'setting'          => 'array'
+            'setting'          => 'array',
+            'profile_image'    => $this->imageRepo->getImageValidationRules(),
         ]);
 
         $user = $this->userRepo->getById($id);
@@ -166,10 +173,23 @@ class UserController extends Controller
             }
         }
 
+        // Save profile image if in request
+        if ($request->has('profile_image')) {
+            $imageUpload = $request->file('profile_image');
+            $this->imageRepo->destroyImage($user->avatar);
+            $image = $this->imageRepo->saveNew($imageUpload, 'user', $user->id);
+            $user->image_id = $image->id;
+        }
+
+        // Delete the profile image if set to
+        if ($request->has('profile_image_reset')) {
+            $this->imageRepo->destroyImage($user->avatar);
+        }
+
         $user->save();
         session()->flash('success', trans('settings.users_edit_success'));
 
-        $redirectUrl = userCan('users-manage') ? '/settings/users' : '/settings/users/' . $user->id;
+        $redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id);
         return redirect($redirectUrl);
     }
 
index df6d9fb0d151ef00cd8c579bdccc3891e3626974..6fa5db2a562e703fa0d18aa12b5abb753de0e80b 100644 (file)
@@ -1,5 +1,6 @@
 <?php namespace BookStack\Uploads;
 
+use BookStack\Entities\Page;
 use BookStack\Ownable;
 use Images;
 
@@ -20,4 +21,14 @@ class Image extends Ownable
     {
         return Images::getThumbnail($this, $width, $height, $keepRatio);
     }
+
+    /**
+     * Get the page this image has been uploaded to.
+     * Only applicable to gallery or drawio image types.
+     * @return Page|null
+     */
+    public function getPage()
+    {
+        return $this->belongsTo(Page::class, 'uploaded_to')->first();
+    }
 }
index 235889eee330939a563fb93a11db9bb0ec04b699..dbf652ddf2f9595a3fe82444d77109e34a04a65f 100644 (file)
@@ -2,7 +2,6 @@
 
 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;
 
@@ -38,7 +37,7 @@ class ImageRepo
     /**
      * Get an image with the given id.
      * @param $id
-     * @return mixed
+     * @return Image
      */
     public function getById($id)
     {
@@ -100,16 +99,8 @@ class ImageRepo
             $imageQuery = $imageQuery->where('name', 'LIKE', '%' . $search . '%');
         }
 
-        // Filter by page access if gallery
-        if ($type === 'gallery') {
-            $imageQuery = $this->restrictionService->filterRelatedEntity('page', $imageQuery, 'images', 'uploaded_to');
-        }
-
-        // Filter by entity if cover
-        if (strpos($type, 'cover_') === 0) {
-            $entityType = explode('_', $type)[1];
-            $imageQuery = $this->restrictionService->filterRelatedEntity($entityType, $imageQuery, 'images', 'uploaded_to');
-        }
+        // Filter by page access
+        $imageQuery = $this->restrictionService->filterRelatedEntity('page', $imageQuery, 'images', 'uploaded_to');
 
         if ($whereClause !== null) {
             $imageQuery = $imageQuery->where($whereClause);
@@ -157,15 +148,17 @@ class ImageRepo
     /**
      * Save a new image into storage and return the new image.
      * @param UploadedFile $uploadFile
-     * @param  string $type
+     * @param string $type
      * @param int $uploadedTo
+     * @param int|null $resizeWidth
+     * @param int|null $resizeHeight
+     * @param bool $keepRatio
      * @return Image
      * @throws \BookStack\Exceptions\ImageUploadException
-     * @throws \Exception
      */
-    public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0)
+    public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0, int $resizeWidth = null, int $resizeHeight = null, bool $keepRatio = true)
     {
-        $image = $this->imageService->saveNewFromUpload($uploadFile, $type, $uploadedTo);
+        $image = $this->imageService->saveNewFromUpload($uploadFile, $type, $uploadedTo, $resizeWidth, $resizeHeight, $keepRatio);
         $this->loadThumbs($image);
         return $image;
     }
@@ -208,12 +201,27 @@ class ImageRepo
      * @return bool
      * @throws \Exception
      */
-    public function destroyImage(Image $image)
+    public function destroyImage(Image $image = null)
     {
-        $this->imageService->destroy($image);
+        if ($image) {
+            $this->imageService->destroy($image);
+        }
         return true;
     }
 
+    /**
+     * Destroy all images of a certain type.
+     * @param string $imageType
+     * @throws \Exception
+     */
+    public function destroyByType(string $imageType)
+    {
+        $images = $this->image->where('type', '=', $imageType)->get();
+        foreach ($images as $image) {
+            $this->destroyImage($image);
+        }
+    }
+
 
     /**
      * Load thumbnails onto an image object.
@@ -241,7 +249,7 @@ class ImageRepo
      * @throws \BookStack\Exceptions\ImageUploadException
      * @throws \Exception
      */
-    public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
+    protected function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
     {
         try {
             return $this->imageService->getThumbnail($image, $width, $height, $keepRatio);
@@ -264,18 +272,6 @@ class ImageRepo
         }
     }
 
-    /**
-     * Check if the provided image type is valid.
-     * @param $type
-     * @return bool
-     */
-    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
index 1dd8b713d66747ec57110733f2a00702828cf0f5..63c3b31722c3cb7746f48486fffe5b9615349a8e 100644 (file)
@@ -9,6 +9,7 @@ use Illuminate\Contracts\Cache\Repository as Cache;
 use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 use Intervention\Image\Exception\NotSupportedException;
 use Intervention\Image\ImageManager;
+use phpDocumentor\Reflection\Types\Integer;
 use Symfony\Component\HttpFoundation\File\UploadedFile;
 
 class ImageService extends UploadService
@@ -57,15 +58,30 @@ class ImageService extends UploadService
     /**
      * Saves a new image from an upload.
      * @param UploadedFile $uploadedFile
-     * @param  string $type
+     * @param string $type
      * @param int $uploadedTo
+     * @param int|null $resizeWidth
+     * @param int|null $resizeHeight
+     * @param bool $keepRatio
      * @return mixed
      * @throws ImageUploadException
      */
-    public function saveNewFromUpload(UploadedFile $uploadedFile, $type, $uploadedTo = 0)
+    public function saveNewFromUpload(
+        UploadedFile $uploadedFile,
+        string $type,
+        int $uploadedTo = 0,
+        int $resizeWidth = null,
+        int $resizeHeight = null,
+        bool $keepRatio = true
+    )
     {
         $imageName = $uploadedFile->getClientOriginalName();
         $imageData = file_get_contents($uploadedFile->getRealPath());
+
+        if ($resizeWidth !== null || $resizeHeight !== null) {
+            $imageData = $this->resizeImage($imageData, $resizeWidth, $resizeHeight, $keepRatio);
+        }
+
         return $this->saveNew($imageName, $imageData, $type, $uploadedTo);
     }
 
@@ -122,7 +138,7 @@ class ImageService extends UploadService
         $secureUploads = setting('app-secure-images');
         $imageName = str_replace(' ', '-', $imageName);
 
-        $imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/';
+        $imagePath = '/uploads/images/' . $type . '/' . Date('Y-m') . '/';
 
         while ($storage->exists($imagePath . $imageName)) {
             $imageName = str_random(3) . $imageName;
@@ -201,8 +217,28 @@ class ImageService extends UploadService
             return $this->getPublicUrl($thumbFilePath);
         }
 
+        $thumbData = $this->resizeImage($storage->get($imagePath), $width, $height, $keepRatio);
+
+        $storage->put($thumbFilePath, $thumbData);
+        $storage->setVisibility($thumbFilePath, 'public');
+        $this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 72);
+
+        return $this->getPublicUrl($thumbFilePath);
+    }
+
+    /**
+     * Resize image data.
+     * @param string $imageData
+     * @param int $width
+     * @param int $height
+     * @param bool $keepRatio
+     * @return string
+     * @throws ImageUploadException
+     */
+    protected function resizeImage(string $imageData, $width = 220, $height = null, $keepRatio = true)
+    {
         try {
-            $thumb = $this->imageTool->make($storage->get($imagePath));
+            $thumb = $this->imageTool->make($imageData);
         } catch (Exception $e) {
             if ($e instanceof \ErrorException || $e instanceof NotSupportedException) {
                 throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
@@ -211,20 +247,14 @@ class ImageService extends UploadService
         }
 
         if ($keepRatio) {
-            $thumb->resize($width, null, function ($constraint) {
+            $thumb->resize($width, $height, function ($constraint) {
                 $constraint->aspectRatio();
                 $constraint->upsize();
             });
         } else {
             $thumb->fit($width, $height);
         }
-
-        $thumbData = (string)$thumb->encode();
-        $storage->put($thumbFilePath, $thumbData);
-        $storage->setVisibility($thumbFilePath, 'public');
-        $this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 72);
-
-        return $this->getPublicUrl($thumbFilePath);
+        return (string)$thumb->encode();
     }
 
     /**
index 7cbed450903a899311ab374b4ae1a472fb6d2533..7455fa622379a798ae102dd65dc7c72aed28417e 100644 (file)
@@ -4,54 +4,50 @@ class ImagePicker {
     constructor(elem) {
         this.elem = elem;
         this.imageElem = elem.querySelector('img');
-        this.input = elem.querySelector('input');
+        this.imageInput = elem.querySelector('input[type=file]');
+        this.resetInput = elem.querySelector('input[data-reset-input]');
+        this.removeInput = elem.querySelector('input[data-remove-input]');
 
-        this.isUsingIds = elem.getAttribute('data-current-id') !== '';
-        this.isResizing = elem.getAttribute('data-resize-height') && elem.getAttribute('data-resize-width');
-        this.isResizeCropping = elem.getAttribute('data-resize-crop') !== '';
+        this.defaultImage = elem.getAttribute('data-default-image');
 
-        let selectButton = elem.querySelector('button[data-action="show-image-manager"]');
-        selectButton.addEventListener('click', this.selectImage.bind(this));
-
-        let resetButton = elem.querySelector('button[data-action="reset-image"]');
+        const resetButton = elem.querySelector('button[data-action="reset-image"]');
         resetButton.addEventListener('click', this.reset.bind(this));
 
-        let removeButton = elem.querySelector('button[data-action="remove-image"]');
+        const removeButton = elem.querySelector('button[data-action="remove-image"]');
         if (removeButton) {
             removeButton.addEventListener('click', this.removeImage.bind(this));
         }
-    }
 
-    selectImage() {
-        window.ImageManager.show(image => {
-            if (!this.isResizing) {
-                this.setImage(image);
-                return;
-            }
+        this.imageInput.addEventListener('change', this.fileInputChange.bind(this));
+    }
 
-            let requestString = '/images/thumb/' + image.id + '/' + this.elem.getAttribute('data-resize-width') + '/' + this.elem.getAttribute('data-resize-height') + '/' + (this.isResizeCropping ? 'true' : 'false');
+    fileInputChange() {
+        this.resetInput.setAttribute('disabled', 'disabled');
+        if (this.removeInput) {
+            this.removeInput.setAttribute('disabled', 'disabled');
+        }
 
-            window.$http.get(window.baseUrl(requestString)).then(resp => {
-                image.url = resp.data.url;
-                this.setImage(image);
-            });
-        });
+        for (let file of this.imageInput.files) {
+            this.imageElem.src = window.URL.createObjectURL(file);
+        }
+        this.imageElem.classList.remove('none');
     }
 
     reset() {
-        this.setImage({id: 0, url: this.elem.getAttribute('data-default-image')});
-    }
-
-    setImage(image) {
-        this.imageElem.src = image.url;
-        this.input.value = this.isUsingIds ? image.id : image.url;
+        this.imageInput.value = '';
+        this.imageElem.src = this.defaultImage;
+        this.resetInput.removeAttribute('disabled');
+        if (this.removeInput) {
+            this.removeInput.setAttribute('disabled', 'disabled');
+        }
         this.imageElem.classList.remove('none');
     }
 
     removeImage() {
-        this.imageElem.src = this.elem.getAttribute('data-default-image');
+        this.imageInput.value = '';
         this.imageElem.classList.add('none');
-        this.input.value = 'none';
+        this.removeInput.removeAttribute('disabled');
+        this.resetInput.setAttribute('disabled', 'disabled');
     }
 
 }
index 55cf67813e0d51e156a533e073ca337f94eff1c6..b099a7ca9dbb3a26a43790fb64ba7dbe89b41d07 100644 (file)
@@ -394,9 +394,7 @@ class MarkdownEditor {
         const drawingId = imgContainer.getAttribute('drawio-diagram');
 
         DrawIO.show(() => {
-            return window.$http.get(window.baseUrl(`/images/base64/${drawingId}`)).then(resp => {
-                return `data:image/png;base64,${resp.data.content}`;
-            });
+            return DrawIO.load(drawingId);
         }, (pngData) => {
 
             let data = {
index 3f60ff03169b2120d602e105025372bab8d8c0e0..b894c3fa6151653f42d06a124140e32d358b4dd6 100644 (file)
@@ -299,9 +299,7 @@ function drawIoPlugin() {
         }
 
         let drawingId = currentNode.getAttribute('drawio-diagram');
-        return window.$http.get(window.baseUrl(`/images/base64/${drawingId}`)).then(resp => {
-            return `data:image/png;base64,${resp.data.content}`;
-        });
+        return DrawIO.load(drawingId);
     }
 
     window.tinymce.PluginManager.add('drawio', function(editor, url) {
index 6acf091f02ace85b78af1e239cf160ccbb46e214..a570737d11f5bcc0d77964d46fc03a93ab41bd96 100644 (file)
@@ -75,4 +75,14 @@ async function upload(imageData, pageUploadedToId) {
     return resp.data;
 }
 
-export default {show, close, upload};
\ No newline at end of file
+/**
+ * Load an existing image, by fetching it as Base64 from the system.
+ * @param drawingId
+ * @returns {Promise<string>}
+ */
+async function load(drawingId) {
+    const resp = await window.$http.get(window.baseUrl(`/images/drawio/base64/${drawingId}`));
+    return `data:image/png;base64,${resp.data.content}`;
+}
+
+export default {show, close, upload, load};
\ No newline at end of file
index 137048935209292d62f466903701538f369cbf25..9bb4e1c70dcba36a6351b97e153a44090de80cb2 100644 (file)
@@ -140,6 +140,10 @@ body.flexbox {
   display: inline-block;
 }
 
+.hidden {
+  display: none;
+}
+
 .float {
   float: left;
   &.right {
index 9baeb9f3059ae63c8f5f4d19525b838770fe2927..210980ac2e172244dbcb9a52016afff7fcb5ef8d 100644 (file)
@@ -71,6 +71,7 @@ return [
     'timezone'             => 'The :attribute must be a valid zone.',
     'unique'               => 'The :attribute has already been taken.',
     'url'                  => 'The :attribute format is invalid.',
+    'uploaded'             => 'The file could not be uploaded. The server may not accept files of this size.',
 
     // Custom validation lines
     'custom' => [
index 882ce556a177525cebd9ceb7c30ccf7f3f48ed20..40b781441ddda044dc8f59c6f6a4079fe3321277 100644 (file)
@@ -33,5 +33,4 @@
         </div>
     </div>
 
-    @include('components.image-manager', ['imageType' => 'cover'])
 @stop
\ No newline at end of file
index a02029a105012a45910c56f0d6c72909292dd538..2e51ed6e956fb947b905b97282d895ef38f1137c 100644 (file)
 
         <div class="content-wrap card">
             <h1 class="list-heading">{{ trans('entities.books_edit') }}</h1>
-            <form action="{{ $book->getUrl() }}" method="POST">
+            <form action="{{ $book->getUrl() }}" method="POST" enctype="multipart/form-data">
                 <input type="hidden" name="_method" value="PUT">
                 @include('books.form', ['model' => $book])
             </form>
         </div>
     </div>
-
-    @include('components.image-manager', ['imageType' => 'cover', 'uploaded_to'])
 @stop
\ No newline at end of file
index ebbc279fdb515d85dab7f88ed736a71498ca8128..4edec240a03e9a961bca643f45c5ba5a518058c0 100644 (file)
         <p class="small">{{ trans('common.cover_image_description') }}</p>
 
         @include('components.image-picker', [
-            'resizeHeight' => '512',
-            'resizeWidth' => '512',
-            'showRemove' => false,
             'defaultImage' => baseUrl('/book_default_cover.png'),
-            'currentImage' => isset($model) ? $model->getBookCover() : baseUrl('/book_default_cover.png') ,
-            'currentId' => isset($model) && $model->image_id ? $model->image_id : 0,
-            'name' => 'image_id',
+            'currentImage' => (isset($model) && $model->cover) ? $model->getBookCover() : baseUrl('/book_default_cover.png') ,
+            'name' => 'image',
             'imageClass' => 'cover'
         ])
     </div>
index 10df50293388ece55f892778e7c21e64f0ec8b1e..73885aeb4548c54aa085c795caed53f081de72f7 100644 (file)
@@ -1,22 +1,32 @@
-<div class="image-picker" image-picker="{{$name}}" data-default-image="{{ $defaultImage }}" data-resize-height="{{ $resizeHeight }}" data-resize-width="{{ $resizeWidth }}" data-current-id="{{ $currentId ?? '' }}" data-resize-crop="{{ $resizeCrop ?? '' }}">
+<div class="image-picker @if($errors->has($name)) has-error @endif"
+     image-picker="{{$name}}"
+     data-default-image="{{ $defaultImage }}">
 
     <div class="grid half">
         <div class="text-center">
             <img @if($currentImage && $currentImage !== 'none') src="{{$currentImage}}" @else src="{{$defaultImage}}" @endif  class="{{$imageClass}} @if($currentImage=== 'none') none @endif" alt="{{ trans('components.image_preview') }}">
         </div>
         <div class="text-center">
-            <button class="button outline small" type="button" data-action="show-image-manager">{{ trans('components.image_select_image') }}</button>
+
+            <label for="{{ $name }}" class="button outline">{{ trans('components.image_select_image') }}</label>
+            <input type="file" class="hidden" accept="image/*" name="{{ $name }}" id="{{ $name }}">
+            <input type="hidden" data-reset-input name="{{ $name }}_reset" value="true" disabled="disabled">
+            @if(isset($removeName))
+                <input type="hidden" data-remove-input name="{{ $removeName }}" value="{{ $removeValue }}" disabled="disabled">
+            @endif
+
             <br>
             <button class="text-button text-muted" data-action="reset-image" type="button">{{ trans('common.reset') }}</button>
 
-            @if ($showRemove)
+            @if(isset($removeName))
                 <span class="sep">|</span>
                 <button class="text-button text-muted" data-action="remove-image" type="button">{{ trans('common.remove') }}</button>
             @endif
         </div>
     </div>
 
-    <input type="hidden" name="{{$name}}" id="{{$name}}" value="{{ isset($currentId) && ($currentId !== 0 && $currentId !== false) ? $currentId : $currentImage}}">
-{{--    TODO - Revamp to be custom file upload button, instead of being linked to image manager--}}
-{{--    TODO - Remove image manager use where this is used and clean image manager for drawing/gallery use.--}}
+    @if($errors->has($name))
+        <div class="text-neg text-small">{{ $errors->first($name) }}</div>
+    @endif
+
 </div>
\ No newline at end of file
index 582bb078e092eeb8d75f3e00075ca5c424feae8a..2dabe9dec5830b29a293fc3535b62aa97930c320 100644 (file)
@@ -79,7 +79,7 @@
 
         <div class="card content-wrap auto-height">
             <h2 class="list-heading">{{ trans('settings.app_customization') }}</h2>
-            <form action="{{ baseUrl("/settings") }}" method="POST">
+            <form action="{{ baseUrl("/settings") }}" method="POST" enctype="multipart/form-data">
                 {!! csrf_field() !!}
 
                 <div class="setting-list">
                         </div>
                         <div>
                             @include('components.image-picker', [
-                                     'resizeHeight' => '43',
-                                     'resizeWidth' => '200',
-                                     'showRemove' => true,
+                                     'removeName' => 'setting-app-logo',
+                                     'removeValue' => 'none',
                                      'defaultImage' => baseUrl('/logo.png'),
                                      'currentImage' => setting('app-logo'),
-                                     'name' => 'setting-app-logo',
+                                     'name' => 'app_logo',
                                      'imageClass' => 'logo-image',
-                                     'currentId' => false
                                  ])
                         </div>
                     </div>
index 72bf904fea1a7ec372e86aae2081b8c12a38c9b7..706e15d07faafcb6f3f6855c8671375d79e46cb5 100644 (file)
@@ -26,6 +26,4 @@
 
     </div>
 
-    @include('components.image-manager', ['imageType' => 'cover'])
-
 @stop
\ No newline at end of file
index fa8a3d63b865fcde61f4aeb37e5ba6344d338d28..8c2cd4f45e7d11d816a3472a9e0b109c0aeb392d 100644 (file)
@@ -16,7 +16,7 @@
 
         <div class="card content-wrap">
             <h1 class="list-heading">{{ trans('entities.shelves_edit') }}</h1>
-            <form action="{{ $shelf->getUrl() }}" method="POST">
+            <form action="{{ $shelf->getUrl() }}" method="POST" enctype="multipart/form-data">
                 <input type="hidden" name="_method" value="PUT">
                 @include('shelves.form', ['model' => $shelf])
             </form>
index 8a270a894a2eda4a1a56555e7b67229f4bea4a35..4191f421de0e10ab44484283d38f8fb14b0ed81b 100644 (file)
         <p class="small">{{ trans('common.cover_image_description') }}</p>
 
         @include('components.image-picker', [
-            'resizeHeight' => '512',
-            'resizeWidth' => '512',
-            'showRemove' => false,
             'defaultImage' => baseUrl('/book_default_cover.png'),
-            'currentImage' => isset($shelf) ? $shelf->getBookCover() : baseUrl('/book_default_cover.png') ,
-            'currentId' => isset($shelf) && $shelf->image_id ? $shelf->image_id : 0,
-            'name' => 'image_id',
+            'currentImage' => (isset($shelf) && $shelf->cover) ? $shelf->getBookCover() : baseUrl('/book_default_cover.png') ,
+            'name' => 'image',
             'imageClass' => 'cover'
         ])
     </div>
index 7c8175d9ae0d1aae98f47e9e260c55df6dc28fba..377500193dc7d3b910667224a31e8645585a83e9 100644 (file)
@@ -9,7 +9,7 @@
 
         <div class="card content-wrap">
             <h1 class="list-heading">{{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h1>
-            <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
+            <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post" enctype="multipart/form-data">
                 {!! csrf_field() !!}
                 <input type="hidden" name="_method" value="PUT">
 
@@ -29,7 +29,7 @@
                                 'defaultImage' => baseUrl('/user_avatar.png'),
                                 'currentImage' => $user->getAvatar(80),
                                 'currentId' => $user->image_id,
-                                'name' => 'image_id',
+                                'name' => 'profile_image',
                                 'imageClass' => 'avatar large'
                             ])
                         </div>
@@ -87,5 +87,4 @@
         @endif
     </div>
 
-    @include('components.image-manager', ['imageType' => 'user', 'uploaded_to' => $user->id])
 @stop
index 975ab5b17665206d95397bc95c0700906a6cdf3e..25d7ab6928585ddfe9672136f33311dd9660bc13 100644 (file)
@@ -6,7 +6,8 @@ Route::get('/robots.txt', 'HomeController@getRobots');
 // Authenticated routes...
 Route::group(['middleware' => 'auth'], function () {
 
-    Route::get('/uploads/images/{path}', 'ImageController@showImage')
+    // Secure images routing
+    Route::get('/uploads/images/{path}', 'Images\ImageController@showImage')
         ->where('path', '.*$');
 
     Route::group(['prefix' => 'pages'], function() {
@@ -105,27 +106,19 @@ Route::group(['middleware' => 'auth'], function () {
     // Image routes
     Route::group(['prefix' => 'images'], function () {
 
-        // TODO - Check auth on these
-        // TODO - Maybe check types for only gallery or drawing
-        // 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');
-
         // Gallery
         Route::get('/gallery', 'Images\GalleryImageController@list');
         Route::post('/gallery', 'Images\GalleryImageController@create');
 
         // Drawio
         Route::get('/drawio', 'Images\DrawioImageController@list');
+        Route::get('/drawio/base64/{id}', 'Images\DrawioImageController@getAsBase64');
         Route::post('/drawio', 'Images\DrawioImageController@create');
 
-
-        // TODO - Check auth on these
-        // TODO - Maybe check types for only gallery or drawing
-        // Or add to gallery/drawio controllers
-        Route::put('/{id}', 'ImageController@update');
-        Route::delete('/{id}', 'ImageController@destroy');
+        // Shared gallery & draw.io endpoint
+        Route::get('/usage/{id}', 'Images\ImageController@usage');
+        Route::put('/{id}', 'Images\ImageController@update');
+        Route::delete('/{id}', 'Images\ImageController@destroy');
     });
 
     // Attachments routes