]> BookStack Code Mirror - bookstack/commitdiff
Added image user checking before deletion. Fixes #13.
authorDan Brown <redacted>
Tue, 1 Sep 2015 17:28:50 +0000 (18:28 +0100)
committerDan Brown <redacted>
Tue, 1 Sep 2015 17:28:50 +0000 (18:28 +0100)
app/Http/Controllers/ImageController.php
app/Http/routes.php
app/Repos/PageRepo.php
resources/assets/js/jquery-extensions.js
resources/assets/sass/image-manager.scss
resources/views/chapters/form.blade.php
resources/views/pages/form.blade.php
resources/views/pages/image-manager.blade.php

index 6d01fe2ccc423c15062ebeec1a48f93e88e236f0..8eafc79b5e231bac8827733e8969275655214d98 100644 (file)
@@ -9,6 +9,7 @@ use Intervention\Image\Facades\Image as ImageTool;
 use Illuminate\Support\Facades\DB;
 use Oxbow\Http\Requests;
 use Oxbow\Image;
+use Oxbow\Repos\PageRepo;
 
 class ImageController extends Controller
 {
@@ -27,42 +28,6 @@ class ImageController extends Controller
         parent::__construct();
     }
 
-    /**
-     * Returns an image from behind the public-facing application.
-     * @param Request $request
-     * @return \Illuminate\Http\Response
-     */
-    public function getImage(Request $request)
-    {
-        $cacheTime = 60 * 60 * 24;
-        $path = storage_path() . '/' . $request->path();
-        $modifiedTime = $this->file->lastModified($path);
-        $eTag = md5($modifiedTime . $path);
-        $headerLastModified = gmdate('r', $modifiedTime);
-        $headerExpires = gmdate('r', $modifiedTime + $cacheTime);
-
-        $headers = [
-            'Last-Modified' => $headerLastModified,
-            'Cache-Control' => 'must-revalidate',
-            'Pragma'        => 'public',
-            'Expires'       => $headerExpires,
-            'Etag'          => $eTag
-        ];
-
-        $browserModifiedSince = $request->header('If-Modified-Since');
-        $browserNoneMatch = $request->header('If-None-Match');
-        if ($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
-            return response()->make('', 304, $headers);
-        }
-
-        if (file_exists($path)) {
-            return response()->make(file_get_contents($path), 200, array_merge($headers, [
-                'Content-Type'   => $this->file->mimeType($path),
-                'Content-Length' => filesize($path),
-            ]));
-        }
-        abort(404);
-    }
 
     /**
      * Get all images, Paginated
@@ -167,14 +132,23 @@ class ImageController extends Controller
 
     /**
      * Deletes an image and all thumbnail/image files
-     * @param $id
+     * @param PageRepo $pageRepo
+     * @param Request  $request
+     * @param int      $id
      * @return \Illuminate\Http\JsonResponse
      */
-    public function destroy($id)
+    public function destroy(PageRepo $pageRepo, Request $request, $id)
     {
         $this->checkPermission('image-delete');
         $image = $this->image->findOrFail($id);
 
+        // Check if this image is used on any pages
+        $pageSearch = $pageRepo->searchForImage($image->url);
+        $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
+        if ($pageSearch !== false && !$isForced) {
+            return response()->json($pageSearch, 400);
+        }
+
         // Delete files
         $folder = public_path() . dirname($image->url);
         $fileName = basename($image->url);
index b4e515f3e48ebcd8ae9b586354e4c60730985a4e..92e416da85a6d0e51c44f1ee87f6894a5614e2f6 100644 (file)
@@ -59,7 +59,6 @@ Route::group(['middleware' => 'auth'], function () {
     Route::put('/images/update/{imageId}', 'ImageController@update');
     Route::delete('/images/{imageId}', 'ImageController@destroy');
     Route::get('/images/all/{page}', 'ImageController@getAll');
-    Route::get('/images/{any}', 'ImageController@getImage')->where('any', '.*');
 
     // Links
     Route::get('/link/{id}', 'PageController@redirectFromLink');
index 1d2e08580c05b1baa1149e760223edaaa213a229..d150f62685ef2fbe771289ac6d978cd95fdcb635 100644 (file)
@@ -92,6 +92,22 @@ class PageRepo
         return $pages;
     }
 
+    /**
+     * Search for image usage.
+     * @param $imageString
+     * @return mixed
+     */
+    public function searchForImage($imageString)
+    {
+        $pages = $this->page->where('html', 'like', '%'.$imageString.'%')->get();
+        foreach($pages as $page) {
+            $page->url = $page->getUrl();
+            $page->html = '';
+            $page->text = '';
+        }
+        return count($pages) > 0 ? $pages : false;
+    }
+
     /**
      * Updates a page with any fillable data and saves it into the database.
      * @param Page $page
index c28c5d150f8f5d60a331a8e8b9645be3b7772d78..f4302b12bb517420b2954ffcd9590f508ab3611b 100644 (file)
@@ -40,4 +40,8 @@ jQuery.fn.showFailure = function (messageMap) {
         });
     });
 
+};
+
+jQuery.fn.submitForm = function() {
+    $(this).closest('form').submit();
 };
\ No newline at end of file
index fc2d2f36806e314d7a8e83e11e59b3242db54d9f..4e9ce705329041db6fe093590b05eadf06e595e2 100644 (file)
@@ -15,9 +15,6 @@
   left: 0;
   z-index: 999;
   display: flex;
-  p, h1, h2, h3, h4, label, input {
-    color: #444;
-  }
   h1, h2, h3 {
     font-weight: 300;
   }
index cc66c15e0b269a4fb498ca3c252f4d011726499e..7603fb443053e639660e48f9a2dd48ac7f85c770 100644 (file)
@@ -12,6 +12,6 @@
 </div>
 
 <div class="form-group">
-    <a onclick="window.history.back();" class="button muted">Cancel</a>
+    <a href="{{ back()->getTargetUrl() }}" class="button muted">Cancel</a>
     <button type="submit" class="button pos">Save</button>
 </div>
index ed23a9fc2901be05688f84235d58aefd9e3719c7..5a78ba0b47540a1187e24a4fd0636767c0ff22e2 100644 (file)
@@ -14,8 +14,8 @@
                 </div>
                 <div class="col-md-8 faded">
                     <div class="action-buttons">
-                        <a onclick="window.history.back();" class="text-primary"><i class="zmdi zmdi-close"></i>Cancel</a>
-                        <a onclick="$(this).closest('form').submit();" type="submit" class="text-pos"><i class="zmdi zmdi-floppy"></i>Save Page</a>
+                        <a href="{{ back()->getTargetUrl() }}" class="text-primary"><i class="zmdi zmdi-close"></i>Cancel</a>
+                        <a onclick="$(this).submitForm();" type="submit" class="text-pos"><i class="zmdi zmdi-floppy"></i>Save Page</a>
                     </div>
                 </div>
             </div>
index 1a38978117b29c0fc7c0d451fcaca5e6b1bfb885..4e822941cf8ddb893b48b69a5ac3c96909d71ce4 100644 (file)
@@ -1,6 +1,6 @@
 
 <div id="image-manager">
-    <div class="overlay" v-el="overlay" v-on="click: overlayClick" style="display:none;">
+    <div class="overlay" v-el="overlay" v-on="click: overlayClick" >
         <div class="image-manager-body">
             <div class="image-manager-content">
                 <div class="image-manager-list">
                         </div>
                     </form>
                     <hr class="even">
+                    <div v-show="dependantPages">
+                        <p class="text-neg text-small">
+                            This image is used in the pages below, Click delete again to confirm you want to delete this image.
+                        </p>
+                        <ul class="text-neg">
+                            <li v-repeat="page: dependantPages">
+                                <a v-attr="href: page.url" target="_blank" class="text-neg">@{{ page.name }}</a>
+                            </li>
+                        </ul>
+                    </div>
+
                     <form v-on="submit: deleteImage" v-el="imageDeleteForm">
-                        {{ csrf_field() }}
+                        <input type="hidden" v-model="deleteForm._token" value="{{ csrf_token() }}">
                         <button class="button neg"><i class="zmdi zmdi-delete"></i>Delete Image</button>
                     </form>
                 </div>