]> BookStack Code Mirror - bookstack/commitdiff
Attached images to pages and added restriction filtering
authorDan Brown <redacted>
Sun, 13 Mar 2016 13:30:47 +0000 (13:30 +0000)
committerDan Brown <redacted>
Sun, 13 Mar 2016 13:30:47 +0000 (13:30 +0000)
Closes #79

app/Http/Controllers/ImageController.php
app/Repos/ImageRepo.php
app/Services/ImageService.php
app/Services/RestrictionService.php
database/migrations/2016_03_13_082138_add_page_drafts.php [moved from database/migrations/2016_03_13_082138_image_entities_and_page_drafts.php with 54% similarity]
resources/assets/js/controllers.js
resources/assets/js/directives.js
resources/views/pages/create.blade.php
resources/views/pages/edit.blade.php
resources/views/partials/image-manager.blade.php

index 36e44c755ddcd83f022eb0c3196ac200ecc0eb02..7820f6f91fb402867a364638b75b0b2fe0a7fc76 100644 (file)
@@ -20,8 +20,8 @@ class ImageController extends Controller
 
     /**
      * ImageController constructor.
-     * @param Image     $image
-     * @param File      $file
+     * @param Image $image
+     * @param File $file
      * @param ImageRepo $imageRepo
      */
     public function __construct(Image $image, File $file, ImageRepo $imageRepo)
@@ -34,6 +34,7 @@ class ImageController extends Controller
 
     /**
      * Get all images for a specific type, Paginated
+     * @param string $type
      * @param int $page
      * @return \Illuminate\Http\JsonResponse
      */
@@ -56,7 +57,7 @@ class ImageController extends Controller
 
     /**
      * Handles image uploads for use on pages.
-     * @param string  $type
+     * @param string $type
      * @param Request $request
      * @return \Illuminate\Http\JsonResponse
      */
@@ -64,13 +65,15 @@ class ImageController extends Controller
     {
         $this->checkPermission('image-create-all');
         $this->validate($request, [
-            'file' => 'image|mimes:jpeg,gif,png'
+            'file' => 'image|mimes:jpeg,gif,png',
+            'uploaded_to' => 'integer|exists:pages,id'
         ]);
 
         $imageUpload = $request->file('file');
 
         try {
-            $image = $this->imageRepo->saveNew($imageUpload, $type);
+            $uploadedTo = $request->has('uploaded_to') ? $request->get('uploaded_to') : 0;
+            $image = $this->imageRepo->saveNew($imageUpload, $type, $uploadedTo);
         } catch (ImageUploadException $e) {
             return response($e->getMessage(), 500);
         }
@@ -96,7 +99,7 @@ class ImageController extends Controller
 
     /**
      * Update image details
-     * @param         $imageId
+     * @param integer $imageId
      * @param Request $request
      * @return \Illuminate\Http\JsonResponse
      */
@@ -114,8 +117,8 @@ class ImageController extends Controller
     /**
      * Deletes an image and all thumbnail/image files
      * @param PageRepo $pageRepo
-     * @param Request  $request
-     * @param int      $id
+     * @param Request $request
+     * @param int $id
      * @return \Illuminate\Http\JsonResponse
      */
     public function destroy(PageRepo $pageRepo, Request $request, $id)
index d41909ac5e06a0626155e6857aa117898387c818..2e2624a6ea5e851a6d52ea87b6547848be9d118b 100644 (file)
@@ -3,6 +3,7 @@
 
 use BookStack\Image;
 use BookStack\Services\ImageService;
+use BookStack\Services\RestrictionService;
 use Setting;
 use Symfony\Component\HttpFoundation\File\UploadedFile;
 
@@ -11,16 +12,19 @@ class ImageRepo
 
     protected $image;
     protected $imageService;
+    protected $restictionService;
 
     /**
      * ImageRepo constructor.
-     * @param Image        $image
+     * @param Image $image
      * @param ImageService $imageService
+     * @param RestrictionService $restrictionService
      */
-    public function __construct(Image $image, ImageService $imageService)
+    public function __construct(Image $image, ImageService $imageService, RestrictionService $restrictionService)
     {
         $this->image = $image;
         $this->imageService = $imageService;
+        $this->restictionService = $restrictionService;
     }
 
 
@@ -34,13 +38,12 @@ class ImageRepo
         return $this->image->findOrFail($id);
     }
 
-
     /**
      * Gets a load images paginated, filtered by image type.
      * @param string $type
-     * @param int    $page
-     * @param int    $pageSize
-     * @param bool|int   $userFilter
+     * @param int $page
+     * @param int $pageSize
+     * @param bool|int $userFilter
      * @return array
      */
     public function getPaginatedByType($type, $page = 0, $pageSize = 24, $userFilter = false)
@@ -51,6 +54,7 @@ class ImageRepo
             $images = $images->where('created_by', '=', $userFilter);
         }
 
+        $images = $this->restictionService->filterRelatedPages($images, 'images', 'uploaded_to');
         $images = $images->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get();
         $hasMore = count($images) > $pageSize;
 
@@ -68,12 +72,13 @@ 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
      * @return Image
      */
-    public function saveNew(UploadedFile $uploadFile, $type)
+    public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0)
     {
-        $image = $this->imageService->saveNewFromUpload($uploadFile, $type);
+        $image = $this->imageService->saveNewFromUpload($uploadFile, $type, $uploadedTo);
         $this->loadThumbs($image);
         return $image;
     }
@@ -123,9 +128,9 @@ class ImageRepo
      * Checks the cache then storage to avoid creating / accessing the filesystem on every check.
      *
      * @param Image $image
-     * @param int   $width
-     * @param int   $height
-     * @param bool  $keepRatio
+     * @param int $width
+     * @param int $height
+     * @param bool $keepRatio
      * @return string
      */
     public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
index aefc8a4fb4920d977b02136fc8045555cb902677..dd965c90fb449368f92a787d5f9b58d2eedf609d 100644 (file)
@@ -41,14 +41,16 @@ class ImageService
     /**
      * Saves a new image from an upload.
      * @param UploadedFile $uploadedFile
-     * @param  string      $type
+     * @param  string $type
+     * @param int $uploadedTo
      * @return mixed
+     * @throws ImageUploadException
      */
-    public function saveNewFromUpload(UploadedFile $uploadedFile, $type)
+    public function saveNewFromUpload(UploadedFile $uploadedFile, $type, $uploadedTo = 0)
     {
         $imageName = $uploadedFile->getClientOriginalName();
         $imageData = file_get_contents($uploadedFile->getRealPath());
-        return $this->saveNew($imageName, $imageData, $type);
+        return $this->saveNew($imageName, $imageData, $type, $uploadedTo);
     }
 
 
@@ -73,10 +75,11 @@ class ImageService
      * @param string $imageName
      * @param string $imageData
      * @param string $type
+     * @param int $uploadedTo
      * @return Image
      * @throws ImageUploadException
      */
-    private function saveNew($imageName, $imageData, $type)
+    private function saveNew($imageName, $imageData, $type, $uploadedTo = 0)
     {
         $storage = $this->getStorage();
         $secureUploads = setting('app-secure-images');
@@ -100,7 +103,8 @@ class ImageService
             'name'       => $imageName,
             'path'       => $fullPath,
             'url'        => $this->getPublicUrl($fullPath),
-            'type'       => $type
+            'type'       => $type,
+            'uploaded_to' => $uploadedTo
         ];
 
         if (auth()->user() && auth()->user()->id !== 0) {
index 6bc612bb0d3614aa29ad003b7419c60d72f69246..d207248662183c1e236aab875fa83a20df2d0095 100644 (file)
@@ -50,10 +50,10 @@ class RestrictionService
     public function enforcePageRestrictions($query, $action = 'view')
     {
         // Prevent drafts being visible to others.
-        $query = $query->where(function($query) {
+        $query = $query->where(function ($query) {
             $query->where('draft', '=', false);
             if ($this->currentUser) {
-                $query->orWhere(function($query) {
+                $query->orWhere(function ($query) {
                     $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser->id);
                 });
             }
@@ -264,6 +264,30 @@ class RestrictionService
         });
     }
 
+    /**
+     * Filters pages that are a direct relation to another item.
+     * @param $query
+     * @param $tableName
+     * @param $entityIdColumn
+     * @return mixed
+     */
+    public function filterRelatedPages($query, $tableName, $entityIdColumn)
+    {
+        if ($this->isAdmin) return $query;
+        $this->currentAction = 'view';
+        $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn];
+        return $query->where(function ($query) use (&$tableDetails) {
+            $query->where(function ($query) use (&$tableDetails) {
+                $query->whereExists(function ($query) use (&$tableDetails) {
+                    $query->select('*')->from('pages')->whereRaw('pages.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
+                        ->where(function ($query) {
+                            $this->pageRestrictionQuery($query);
+                        });
+                })->orWhere($tableDetails['entityIdColumn'], '=', 0);
+            });
+        });
+    }
+
     /**
      * The query to check the restrictions on an entity.
      * @param $query
similarity index 54%
rename from database/migrations/2016_03_13_082138_image_entities_and_page_drafts.php
rename to database/migrations/2016_03_13_082138_add_page_drafts.php
index 0852372f128f979bec23272670d5cf6ee7b7eeb0..794ee6a5fa3bc0749cdcf534a01313cb2cfffe41 100644 (file)
@@ -3,7 +3,7 @@
 use Illuminate\Database\Schema\Blueprint;
 use Illuminate\Database\Migrations\Migration;
 
-class ImageEntitiesAndPageDrafts extends Migration
+class AddPageDrafts extends Migration
 {
     /**
      * Run the migrations.
@@ -12,12 +12,6 @@ class ImageEntitiesAndPageDrafts extends Migration
      */
     public function up()
     {
-        Schema::table('images', function (Blueprint $table) {
-            $table->string('entity_type', 100);
-            $table->integer('entity_id');
-            $table->index(['entity_type', 'entity_id']);
-        });
-
         Schema::table('pages', function(Blueprint $table) {
             $table->boolean('draft')->default(false);
             $table->index('draft');
@@ -31,12 +25,6 @@ class ImageEntitiesAndPageDrafts extends Migration
      */
     public function down()
     {
-        Schema::table('images', function (Blueprint $table) {
-            $table->dropIndex(['entity_type', 'entity_id']);
-            $table->dropColumn('entity_type');
-            $table->dropColumn('entity_id');
-        });
-
         Schema::table('pages', function (Blueprint $table) {
             $table->dropColumn('draft');
         });
index f3c80f73ec92fe62c85a237d7bb93d5b6365a99e..29a448265299c46292f0e48dedc462892cd18454 100644 (file)
@@ -13,6 +13,7 @@ module.exports = function (ngApp, events) {
             $scope.hasMore = false;
             $scope.imageUpdateSuccess = false;
             $scope.imageDeleteSuccess = false;
+            $scope.uploadedTo = $attrs.uploadedTo;
 
             var page = 0;
             var previousClickTime = 0;
index 72d35d45506dbc997bc6c99c9ca10ba9dda5ff97..71b35fb42efde3c6d4e4820623c8132a9d14e609 100644 (file)
@@ -110,7 +110,8 @@ module.exports = function (ngApp, events) {
             scope: {
                 uploadUrl: '@',
                 eventSuccess: '=',
-                eventError: '='
+                eventError: '=',
+                uploadedTo: '@'
             },
             link: function (scope, element, attrs) {
                 var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
@@ -120,6 +121,8 @@ module.exports = function (ngApp, events) {
                         dz.on('sending', function (file, xhr, data) {
                             var token = window.document.querySelector('meta[name=token]').getAttribute('content');
                             data.append('_token', token);
+                            var uploadedTo = typeof scope.uploadedTo === 'undefined' ? 0 : scope.uploadedTo;
+                            data.append('uploaded_to', uploadedTo);
                         });
                         if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess);
                         dz.on('success', function (file, data) {
index f532cc2b6f06a897841f79716a8dfd0c335c049d..2c6403e487e2a198fc23af0481727131ecf77eb9 100644 (file)
@@ -13,5 +13,5 @@
             @include('pages/form', ['model' => $draft])
         </form>
     </div>
-    @include('partials/image-manager', ['imageType' => 'gallery'])
+    @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $draft->id])
 @stop
\ No newline at end of file
index 751ed79c71cf854b83f0401ab649dda70ea71d7a..0ad06fc537dedc27cb86fcc7a295072fa8fa65ea 100644 (file)
@@ -14,6 +14,6 @@
             @include('pages/form', ['model' => $page])
         </form>
     </div>
-    @include('partials/image-manager', ['imageType' => 'gallery'])
+    @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id])
 
 @stop
\ No newline at end of file
index bf7bf445cf3f5de27bb6a27005e77359e075da8f..a394975d82d192f435d6bce97ea556d95bfa7aa0 100644 (file)
@@ -1,4 +1,4 @@
-<div id="image-manager" image-type="{{ $imageType }}" ng-controller="ImageManagerController">
+<div id="image-manager" image-type="{{ $imageType }}" ng-controller="ImageManagerController" uploaded-to="{{ $uploaded_to or 0 }}">
     <div class="overlay anim-slide" ng-show="showing" ng-cloak ng-click="hide()">
         <div class="image-manager-body" ng-click="$event.stopPropagation()">
 
@@ -22,7 +22,7 @@
 
             <div class="image-manager-sidebar">
                 <h2>Images</h2>
-                <drop-zone upload-url="@{{getUploadUrl()}}" event-success="uploadSuccess"></drop-zone>
+                <drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
                 <div class="image-manager-details anim fadeIn" ng-show="selectedImage">
 
                     <hr class="even">