Revamped image system to use driver-agnotstic storage and be more efficent
This commit is contained in:
		
							parent
							
								
									46c905df8a
								
							
						
					
					
						commit
						c88096b7e2
					
				
							
								
								
									
										13
									
								
								.env.example
								
								
								
								
							
							
						
						
									
										13
									
								
								.env.example
								
								
								
								
							| 
						 | 
					@ -14,12 +14,23 @@ CACHE_DRIVER=file
 | 
				
			||||||
SESSION_DRIVER=file
 | 
					SESSION_DRIVER=file
 | 
				
			||||||
QUEUE_DRIVER=sync
 | 
					QUEUE_DRIVER=sync
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Storage
 | 
				
			||||||
 | 
					STORAGE_TYPE=local
 | 
				
			||||||
 | 
					# Amazon S3 Config
 | 
				
			||||||
 | 
					STORAGE_S3_KEY=false
 | 
				
			||||||
 | 
					STORAGE_S3_SECRET=false
 | 
				
			||||||
 | 
					STORAGE_S3_REGION=false
 | 
				
			||||||
 | 
					STORAGE_S3_BUCKET=false
 | 
				
			||||||
 | 
					# Storage URL
 | 
				
			||||||
 | 
					# Used to prefix image urls for when using custom domains/cdns
 | 
				
			||||||
 | 
					STORAGE_URL=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Social Authentication information. Defaults as off.
 | 
					# Social Authentication information. Defaults as off.
 | 
				
			||||||
GITHUB_APP_ID=false
 | 
					GITHUB_APP_ID=false
 | 
				
			||||||
GITHUB_APP_SECRET=false
 | 
					GITHUB_APP_SECRET=false
 | 
				
			||||||
GOOGLE_APP_ID=false
 | 
					GOOGLE_APP_ID=false
 | 
				
			||||||
GOOGLE_APP_SECRET=false
 | 
					GOOGLE_APP_SECRET=false
 | 
				
			||||||
# URL for social login redirects, NO TRAILING SLASH
 | 
					# URL used for social login redirects, NO TRAILING SLASH
 | 
				
			||||||
APP_URL=http://bookstack.dev
 | 
					APP_URL=http://bookstack.dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Mail settings
 | 
					# Mail settings
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace BookStack\Http\Controllers;
 | 
					namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Repos\ImageRepo;
 | 
				
			||||||
use Illuminate\Filesystem\Filesystem as File;
 | 
					use Illuminate\Filesystem\Filesystem as File;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
use Illuminate\Support\Facades\Auth;
 | 
					use Illuminate\Support\Facades\Auth;
 | 
				
			||||||
| 
						 | 
					@ -14,16 +15,19 @@ class ImageController extends Controller
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected $image;
 | 
					    protected $image;
 | 
				
			||||||
    protected $file;
 | 
					    protected $file;
 | 
				
			||||||
 | 
					    protected $imageRepo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ImageController constructor.
 | 
					     * ImageController constructor.
 | 
				
			||||||
     * @param Image     $image
 | 
					     * @param Image     $image
 | 
				
			||||||
     * @param File      $file
 | 
					     * @param File      $file
 | 
				
			||||||
 | 
					     * @param ImageRepo $imageRepo
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Image $image, File $file)
 | 
					    public function __construct(Image $image, File $file, ImageRepo $imageRepo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->image = $image;
 | 
					        $this->image = $image;
 | 
				
			||||||
        $this->file = $file;
 | 
					        $this->file = $file;
 | 
				
			||||||
 | 
					        $this->imageRepo = $imageRepo;
 | 
				
			||||||
        parent::__construct();
 | 
					        parent::__construct();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,108 +37,31 @@ class ImageController extends Controller
 | 
				
			||||||
     * @param int $page
 | 
					     * @param int $page
 | 
				
			||||||
     * @return \Illuminate\Http\JsonResponse
 | 
					     * @return \Illuminate\Http\JsonResponse
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getAll($page = 0)
 | 
					    public function getAllGallery($page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $pageSize = 30;
 | 
					        $imgData = $this->imageRepo->getAllGallery($page);
 | 
				
			||||||
        $images = $this->image->orderBy('created_at', 'desc')
 | 
					        return response()->json($imgData);
 | 
				
			||||||
            ->skip($page * $pageSize)->take($pageSize)->get();
 | 
					 | 
				
			||||||
        foreach ($images as $image) {
 | 
					 | 
				
			||||||
            $this->loadSizes($image);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $hasMore = $this->image->orderBy('created_at', 'desc')
 | 
					 | 
				
			||||||
                ->skip(($page + 1) * $pageSize)->take($pageSize)->count() > 0;
 | 
					 | 
				
			||||||
        return response()->json([
 | 
					 | 
				
			||||||
            'images' => $images,
 | 
					 | 
				
			||||||
            'hasMore' => $hasMore
 | 
					 | 
				
			||||||
        ]);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Loads the standard thumbnail sizes for an image.
 | 
					 | 
				
			||||||
     * @param Image $image
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private function loadSizes(Image $image)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $image->thumbnail = $this->getThumbnail($image, 150, 150);
 | 
					 | 
				
			||||||
        $image->display = $this->getThumbnail($image, 840, 0, true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Get the thumbnail for an image.
 | 
					 | 
				
			||||||
     * If $keepRatio is true only the width will be used.
 | 
					 | 
				
			||||||
     * @param      $image
 | 
					 | 
				
			||||||
     * @param int  $width
 | 
					 | 
				
			||||||
     * @param int  $height
 | 
					 | 
				
			||||||
     * @param bool $keepRatio
 | 
					 | 
				
			||||||
     * @return string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function getThumbnail($image, $width = 220, $height = 220, $keepRatio = false)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $explodedPath = explode('/', $image->url);
 | 
					 | 
				
			||||||
        $dirPrefix = $keepRatio ? 'scaled-' : 'thumbs-';
 | 
					 | 
				
			||||||
        array_splice($explodedPath, 4, 0, [$dirPrefix . $width . '-' . $height]);
 | 
					 | 
				
			||||||
        $thumbPath = implode('/', $explodedPath);
 | 
					 | 
				
			||||||
        $thumbFilePath = public_path() . $thumbPath;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Return the thumbnail url path if already exists
 | 
					 | 
				
			||||||
        if (file_exists($thumbFilePath)) {
 | 
					 | 
				
			||||||
            return $thumbPath;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Otherwise create the thumbnail
 | 
					 | 
				
			||||||
        $thumb = ImageTool::make(public_path() . $image->url);
 | 
					 | 
				
			||||||
        if($keepRatio) {
 | 
					 | 
				
			||||||
            $thumb->resize($width, null, function ($constraint) {
 | 
					 | 
				
			||||||
                $constraint->aspectRatio();
 | 
					 | 
				
			||||||
                $constraint->upsize();
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $thumb->fit($width, $height);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Create thumbnail folder if it does not exist
 | 
					 | 
				
			||||||
        if (!file_exists(dirname($thumbFilePath))) {
 | 
					 | 
				
			||||||
            mkdir(dirname($thumbFilePath), 0775, true);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //Save Thumbnail
 | 
					 | 
				
			||||||
        $thumb->save($thumbFilePath);
 | 
					 | 
				
			||||||
        return $thumbPath;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Handles image uploads for use on pages.
 | 
					     * Handles image uploads for use on pages.
 | 
				
			||||||
     * @param Request $request
 | 
					     * @param Request $request
 | 
				
			||||||
     * @return \Illuminate\Http\JsonResponse
 | 
					     * @return \Illuminate\Http\JsonResponse
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function upload(Request $request)
 | 
					    public function uploadGallery(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-create');
 | 
					        $this->checkPermission('image-create');
 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'file' => 'image|mimes:jpeg,gif,png'
 | 
					            'file' => 'image|mimes:jpeg,gif,png'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $imageUpload = $request->file('file');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
 | 
					        $imageUpload = $request->file('file');
 | 
				
			||||||
        $storageName = substr(sha1(time()), 0, 10) . '-' . $name;
 | 
					        $image = $this->imageRepo->saveNew($imageUpload, 'gallery');
 | 
				
			||||||
        $imagePath = '/uploads/images/' . Date('Y-m-M') . '/';
 | 
					        return response()->json($image);
 | 
				
			||||||
        $storagePath = public_path() . $imagePath;
 | 
					 | 
				
			||||||
        $fullPath = $storagePath . $storageName;
 | 
					 | 
				
			||||||
        while (file_exists($fullPath)) {
 | 
					 | 
				
			||||||
            $storageName = substr(sha1(rand()), 0, 3) . $storageName;
 | 
					 | 
				
			||||||
            $fullPath = $storagePath . $storageName;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $imageUpload->move($storagePath, $storageName);
 | 
					 | 
				
			||||||
        // Create and save image object
 | 
					 | 
				
			||||||
        $this->image->name = $name;
 | 
					 | 
				
			||||||
        $this->image->url = $imagePath . $storageName;
 | 
					 | 
				
			||||||
        $this->image->created_by = auth()->user()->id;
 | 
					 | 
				
			||||||
        $this->image->updated_by = auth()->user()->id;
 | 
					 | 
				
			||||||
        $this->image->save();
 | 
					 | 
				
			||||||
        $this->loadSizes($this->image);
 | 
					 | 
				
			||||||
        return response()->json($this->image);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Update image details
 | 
					     * Update image details
 | 
				
			||||||
     * @param         $imageId
 | 
					     * @param         $imageId
 | 
				
			||||||
| 
						 | 
					@ -147,13 +74,12 @@ class ImageController extends Controller
 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name' => 'required|min:2|string'
 | 
					            'name' => 'required|min:2|string'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $image = $this->image->findOrFail($imageId);
 | 
					        $image = $this->imageRepo->getById($imageId);
 | 
				
			||||||
        $image->fill($request->all());
 | 
					        $image = $this->imageRepo->updateImageDetails($image, $request->all());
 | 
				
			||||||
        $image->save();
 | 
					        return response()->json($image);
 | 
				
			||||||
        $this->loadSizes($image);
 | 
					 | 
				
			||||||
        return response()->json($this->image);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Deletes an image and all thumbnail/image files
 | 
					     * Deletes an image and all thumbnail/image files
 | 
				
			||||||
     * @param PageRepo $pageRepo
 | 
					     * @param PageRepo $pageRepo
 | 
				
			||||||
| 
						 | 
					@ -164,41 +90,18 @@ class ImageController extends Controller
 | 
				
			||||||
    public function destroy(PageRepo $pageRepo, Request $request, $id)
 | 
					    public function destroy(PageRepo $pageRepo, Request $request, $id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-delete');
 | 
					        $this->checkPermission('image-delete');
 | 
				
			||||||
        $image = $this->image->findOrFail($id);
 | 
					        $image = $this->imageRepo->getById($id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Check if this image is used on any pages
 | 
					        // 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);
 | 
					        $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
 | 
				
			||||||
        if ($pageSearch !== false && !$isForced) {
 | 
					        if (!$isForced) {
 | 
				
			||||||
 | 
					            $pageSearch = $pageRepo->searchForImage($image->url);
 | 
				
			||||||
 | 
					            if ($pageSearch !== false) {
 | 
				
			||||||
                return response()->json($pageSearch, 400);
 | 
					                return response()->json($pageSearch, 400);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Delete files
 | 
					 | 
				
			||||||
        $folder = public_path() . dirname($image->url);
 | 
					 | 
				
			||||||
        $fileName = basename($image->url);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Delete thumbnails
 | 
					 | 
				
			||||||
        foreach (glob($folder . '/*') as $file) {
 | 
					 | 
				
			||||||
            if (is_dir($file)) {
 | 
					 | 
				
			||||||
                $thumbName = $file . '/' . $fileName;
 | 
					 | 
				
			||||||
                if (file_exists($file)) {
 | 
					 | 
				
			||||||
                    unlink($thumbName);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                // Remove thumb folder if empty
 | 
					 | 
				
			||||||
                if (count(glob($file . '/*')) === 0) {
 | 
					 | 
				
			||||||
                    rmdir($file);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Delete file and database entry
 | 
					        $this->imageRepo->destroyImage($image);
 | 
				
			||||||
        unlink($folder . '/' . $fileName);
 | 
					 | 
				
			||||||
        $image->delete();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Delete parent folder if empty
 | 
					 | 
				
			||||||
        if (count(glob($folder . '/*')) === 0) {
 | 
					 | 
				
			||||||
            rmdir($folder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return response()->json('Image Deleted');
 | 
					        return response()->json('Image Deleted');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,8 +45,6 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Uploads
 | 
					 | 
				
			||||||
    Route::post('/upload/image', 'ImageController@upload');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Users
 | 
					    // Users
 | 
				
			||||||
    Route::get('/users', 'UserController@index');
 | 
					    Route::get('/users', 'UserController@index');
 | 
				
			||||||
| 
						 | 
					@ -58,10 +56,13 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			||||||
    Route::delete('/users/{id}', 'UserController@destroy');
 | 
					    Route::delete('/users/{id}', 'UserController@destroy');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Image routes
 | 
					    // Image routes
 | 
				
			||||||
    Route::get('/images/all', 'ImageController@getAll');
 | 
					    Route::group(['prefix' => 'images'], function() {
 | 
				
			||||||
    Route::put('/images/update/{imageId}', 'ImageController@update');
 | 
					        Route::get('/gallery/all', 'ImageController@getAllGallery');
 | 
				
			||||||
    Route::delete('/images/{imageId}', 'ImageController@destroy');
 | 
					        Route::get('/gallery/all/{page}', 'ImageController@getAllGallery');
 | 
				
			||||||
    Route::get('/images/all/{page}', 'ImageController@getAll');
 | 
					        Route::post('/gallery/upload', 'ImageController@uploadGallery');
 | 
				
			||||||
 | 
					        Route::put('/update/{imageId}', 'ImageController@update');
 | 
				
			||||||
 | 
					        Route::delete('/{imageId}', 'ImageController@destroy');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Links
 | 
					    // Links
 | 
				
			||||||
    Route::get('/link/{id}', 'PageController@redirectFromLink');
 | 
					    Route::get('/link/{id}', 'PageController@redirectFromLink');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,12 @@ class BookRepo
 | 
				
			||||||
        return Views::getUserRecentlyViewed($count, $page, $this->book);
 | 
					        return Views::getUserRecentlyViewed($count, $page, $this->book);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the most viewed books.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param int $page
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public function getPopular($count = 10, $page = 0)
 | 
					    public function getPopular($count = 10, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return Views::getPopular($count, $page, $this->book);
 | 
					        return Views::getPopular($count, $page, $this->book);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,265 @@
 | 
				
			||||||
 | 
					<?php namespace BookStack\Repos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Image;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
 | 
				
			||||||
 | 
					use Intervention\Image\ImageManager as ImageTool;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 | 
				
			||||||
 | 
					use Illuminate\Contracts\Cache\Repository as Cache;
 | 
				
			||||||
 | 
					use Setting;
 | 
				
			||||||
 | 
					use Symfony\Component\HttpFoundation\File\UploadedFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ImageRepo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $image;
 | 
				
			||||||
 | 
					    protected $imageTool;
 | 
				
			||||||
 | 
					    protected $fileSystem;
 | 
				
			||||||
 | 
					    protected $cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @var FileSystemInstance
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected $storageInstance;
 | 
				
			||||||
 | 
					    protected $storageUrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * ImageRepo constructor.
 | 
				
			||||||
 | 
					     * @param Image      $image
 | 
				
			||||||
 | 
					     * @param ImageTool  $imageTool
 | 
				
			||||||
 | 
					     * @param FileSystem $fileSystem
 | 
				
			||||||
 | 
					     * @param Cache      $cache
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(Image $image, ImageTool $imageTool, FileSystem $fileSystem, Cache $cache)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->image = $image;
 | 
				
			||||||
 | 
					        $this->imageTool = $imageTool;
 | 
				
			||||||
 | 
					        $this->fileSystem = $fileSystem;
 | 
				
			||||||
 | 
					        $this->cache = $cache;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get an image with the given id.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->image->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all images for the standard gallery view that's used for
 | 
				
			||||||
 | 
					     * adding images to shared content such as pages.
 | 
				
			||||||
 | 
					     * @param int $page
 | 
				
			||||||
 | 
					     * @param int $pageSize
 | 
				
			||||||
 | 
					     * @return array
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAllGallery($page = 0, $pageSize = 24)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $images = $this->image->where('type', '=', 'gallery')
 | 
				
			||||||
 | 
					            ->orderBy('created_at', 'desc')->skip($pageSize * $page)->take($pageSize + 1)->get();
 | 
				
			||||||
 | 
					        $hasMore = count($images) > $pageSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $returnImages = $images->take(24);
 | 
				
			||||||
 | 
					        $returnImages->each(function ($image) {
 | 
				
			||||||
 | 
					            $this->loadThumbs($image);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'images' => $returnImages,
 | 
				
			||||||
 | 
					            'hasMore' => $hasMore
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a new image into storage and return the new image.
 | 
				
			||||||
 | 
					     * @param UploadedFile $uploadFile
 | 
				
			||||||
 | 
					     * @param  string      $type
 | 
				
			||||||
 | 
					     * @return Image
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function saveNew(UploadedFile $uploadFile, $type)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $storage = $this->getStorage();
 | 
				
			||||||
 | 
					        $secureUploads = Setting::get('app-secure-images');
 | 
				
			||||||
 | 
					        $imageName = str_replace(' ', '-', $uploadFile->getClientOriginalName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($secureUploads) $imageName = str_random(16) . '-' . $imageName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $imagePath = '/uploads/images/' . $type . '/' . Date('Y-m-M') . '/';
 | 
				
			||||||
 | 
					        while ($storage->exists($imagePath . $imageName)) {
 | 
				
			||||||
 | 
					            $imageName = str_random(3) . $imageName;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $fullPath = $imagePath . $imageName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $storage->put($fullPath, file_get_contents($uploadFile->getRealPath()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $userId = auth()->user()->id;
 | 
				
			||||||
 | 
					        $image = $this->image->forceCreate([
 | 
				
			||||||
 | 
					            'name' => $imageName,
 | 
				
			||||||
 | 
					            'path' => $fullPath,
 | 
				
			||||||
 | 
					            'url' => $this->getPublicUrl($fullPath),
 | 
				
			||||||
 | 
					            'type' => $type,
 | 
				
			||||||
 | 
					            'created_by' => $userId,
 | 
				
			||||||
 | 
					            'updated_by' => $userId
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->loadThumbs($image);
 | 
				
			||||||
 | 
					        return $image;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update the details of an image via an array of properties.
 | 
				
			||||||
 | 
					     * @param Image $image
 | 
				
			||||||
 | 
					     * @param array $updateDetails
 | 
				
			||||||
 | 
					     * @return Image
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateImageDetails(Image $image, $updateDetails)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $image->fill($updateDetails);
 | 
				
			||||||
 | 
					        $image->save();
 | 
				
			||||||
 | 
					        $this->loadThumbs($image);
 | 
				
			||||||
 | 
					        return $image;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroys an Image object along with its files and thumbnails.
 | 
				
			||||||
 | 
					     * @param Image $image
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function destroyImage(Image $image)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $storage = $this->getStorage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $imageFolder = dirname($image->path);
 | 
				
			||||||
 | 
					        $imageFileName = basename($image->path);
 | 
				
			||||||
 | 
					        $allImages = collect($storage->allFiles($imageFolder));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $imagesToDelete = $allImages->filter(function ($imagePath) use ($imageFileName) {
 | 
				
			||||||
 | 
					            $expectedIndex = strlen($imagePath) - strlen($imageFileName);
 | 
				
			||||||
 | 
					            return strpos($imagePath, $imageFileName) === $expectedIndex;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $storage->delete($imagesToDelete->all());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Cleanup of empty folders
 | 
				
			||||||
 | 
					        foreach ($storage->directories($imageFolder) as $directory) {
 | 
				
			||||||
 | 
					            if ($this->isFolderEmpty($directory)) $storage->deleteDirectory($directory);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if ($this->isFolderEmpty($imageFolder)) $storage->deleteDirectory($imageFolder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $image->delete();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check whether or not a folder is empty.
 | 
				
			||||||
 | 
					     * @param $path
 | 
				
			||||||
 | 
					     * @return int
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function isFolderEmpty($path)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $files = $this->getStorage()->files($path);
 | 
				
			||||||
 | 
					        $folders = $this->getStorage()->directories($path);
 | 
				
			||||||
 | 
					        return count($files) === 0 && count($folders) === 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Load thumbnails onto an image object.
 | 
				
			||||||
 | 
					     * @param Image $image
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function loadThumbs(Image $image)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $image->thumbs = [
 | 
				
			||||||
 | 
					            'gallery' => $this->getThumbnail($image, 150, 150),
 | 
				
			||||||
 | 
					            'display' => $this->getThumbnail($image, 840, 0, true)
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the thumbnail for an image.
 | 
				
			||||||
 | 
					     * If $keepRatio is true only the width will be used.
 | 
				
			||||||
 | 
					     * 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
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $thumbDirName = '/' . ($keepRatio ? 'scaled-' : 'thumbs-') . $width . '-' . $height . '/';
 | 
				
			||||||
 | 
					        $thumbFilePath = dirname($image->path) . $thumbDirName . basename($image->path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($this->cache->has('images-' . $image->id . '-' . $thumbFilePath) && $this->cache->get('images-' . $thumbFilePath)) {
 | 
				
			||||||
 | 
					            return $this->getPublicUrl($thumbFilePath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $storage = $this->getStorage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($storage->exists($thumbFilePath)) {
 | 
				
			||||||
 | 
					            return $this->getPublicUrl($thumbFilePath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Otherwise create the thumbnail
 | 
				
			||||||
 | 
					        $thumb = $this->imageTool->make($storage->get($image->path));
 | 
				
			||||||
 | 
					        if ($keepRatio) {
 | 
				
			||||||
 | 
					            $thumb->resize($width, null, function ($constraint) {
 | 
				
			||||||
 | 
					                $constraint->aspectRatio();
 | 
				
			||||||
 | 
					                $constraint->upsize();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $thumb->fit($width, $height);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $thumbData = (string)$thumb->encode();
 | 
				
			||||||
 | 
					        $storage->put($thumbFilePath, $thumbData);
 | 
				
			||||||
 | 
					        $this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 72);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->getPublicUrl($thumbFilePath);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets a public facing url for an image by checking relevant environment variables.
 | 
				
			||||||
 | 
					     * @param $filePath
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function getPublicUrl($filePath)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->storageUrl === null) {
 | 
				
			||||||
 | 
					            $storageUrl = env('STORAGE_URL');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Get the standard public s3 url if s3 is set as storage type
 | 
				
			||||||
 | 
					            if ($storageUrl == false && env('STORAGE_TYPE') === 's3') {
 | 
				
			||||||
 | 
					                $storageDetails = config('filesystems.disks.s3');
 | 
				
			||||||
 | 
					                $storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'] . $filePath;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $this->storageUrl = $storageUrl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ($this->storageUrl == false ? '' : rtrim($this->storageUrl, '/')) . $filePath;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the storage that will be used for storing images.
 | 
				
			||||||
 | 
					     * @return FileSystemInstance
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function getStorage()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->storageInstance !== null) return $this->storageInstance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $storageType = env('STORAGE_TYPE');
 | 
				
			||||||
 | 
					        $this->storageInstance = $this->fileSystem->disk($storageType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->storageInstance;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,8 @@
 | 
				
			||||||
        "intervention/image": "^2.3",
 | 
					        "intervention/image": "^2.3",
 | 
				
			||||||
        "laravel/socialite": "^2.0",
 | 
					        "laravel/socialite": "^2.0",
 | 
				
			||||||
        "barryvdh/laravel-ide-helper": "^2.1",
 | 
					        "barryvdh/laravel-ide-helper": "^2.1",
 | 
				
			||||||
        "barryvdh/laravel-debugbar": "^2.0"
 | 
					        "barryvdh/laravel-debugbar": "^2.0",
 | 
				
			||||||
 | 
					        "league/flysystem-aws-s3-v3": "^1.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "require-dev": {
 | 
					    "require-dev": {
 | 
				
			||||||
        "fzaninotto/faker": "~1.4",
 | 
					        "fzaninotto/faker": "~1.4",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,9 +4,87 @@
 | 
				
			||||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
 | 
					        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
 | 
				
			||||||
        "This file is @generated automatically"
 | 
					        "This file is @generated automatically"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    "hash": "c2067be65a036c540976c649dfd3763a",
 | 
					    "hash": "19725116631f01881caafa33052eecb9",
 | 
				
			||||||
    "content-hash": "6581b2cca64df1f4d3df219552fbfd78",
 | 
					    "content-hash": "f1dbd776f0ae13ec99e4e6d99510cd8e",
 | 
				
			||||||
    "packages": [
 | 
					    "packages": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "aws/aws-sdk-php",
 | 
				
			||||||
 | 
					            "version": "3.11.4",
 | 
				
			||||||
 | 
					            "source": {
 | 
				
			||||||
 | 
					                "type": "git",
 | 
				
			||||||
 | 
					                "url": "https://github.com/aws/aws-sdk-php.git",
 | 
				
			||||||
 | 
					                "reference": "2524c78e0fa1ed049719b8b6b0696f0b6dfb1ca2"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "dist": {
 | 
				
			||||||
 | 
					                "type": "zip",
 | 
				
			||||||
 | 
					                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2524c78e0fa1ed049719b8b6b0696f0b6dfb1ca2",
 | 
				
			||||||
 | 
					                "reference": "2524c78e0fa1ed049719b8b6b0696f0b6dfb1ca2",
 | 
				
			||||||
 | 
					                "shasum": ""
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require": {
 | 
				
			||||||
 | 
					                "guzzlehttp/guzzle": "~5.3|~6.0.1|~6.1",
 | 
				
			||||||
 | 
					                "guzzlehttp/promises": "~1.0",
 | 
				
			||||||
 | 
					                "guzzlehttp/psr7": "~1.0",
 | 
				
			||||||
 | 
					                "mtdowling/jmespath.php": "~2.2",
 | 
				
			||||||
 | 
					                "php": ">=5.5"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require-dev": {
 | 
				
			||||||
 | 
					                "andrewsville/php-token-reflection": "^1.4",
 | 
				
			||||||
 | 
					                "aws/aws-php-sns-message-validator": "~1.0",
 | 
				
			||||||
 | 
					                "behat/behat": "~3.0",
 | 
				
			||||||
 | 
					                "doctrine/cache": "~1.4",
 | 
				
			||||||
 | 
					                "ext-dom": "*",
 | 
				
			||||||
 | 
					                "ext-json": "*",
 | 
				
			||||||
 | 
					                "ext-openssl": "*",
 | 
				
			||||||
 | 
					                "ext-pcre": "*",
 | 
				
			||||||
 | 
					                "ext-simplexml": "*",
 | 
				
			||||||
 | 
					                "ext-spl": "*",
 | 
				
			||||||
 | 
					                "nette/neon": "^2.3",
 | 
				
			||||||
 | 
					                "phpunit/phpunit": "~4.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "suggest": {
 | 
				
			||||||
 | 
					                "doctrine/cache": "To use the DoctrineCacheAdapter",
 | 
				
			||||||
 | 
					                "ext-curl": "To send requests using cURL",
 | 
				
			||||||
 | 
					                "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "type": "library",
 | 
				
			||||||
 | 
					            "extra": {
 | 
				
			||||||
 | 
					                "branch-alias": {
 | 
				
			||||||
 | 
					                    "dev-master": "3.0-dev"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "autoload": {
 | 
				
			||||||
 | 
					                "psr-4": {
 | 
				
			||||||
 | 
					                    "Aws\\": "src/"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "files": [
 | 
				
			||||||
 | 
					                    "src/functions.php"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "notification-url": "https://packagist.org/downloads/",
 | 
				
			||||||
 | 
					            "license": [
 | 
				
			||||||
 | 
					                "Apache-2.0"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "authors": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "name": "Amazon Web Services",
 | 
				
			||||||
 | 
					                    "homepage": "http://aws.amazon.com"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
 | 
				
			||||||
 | 
					            "homepage": "http://aws.amazon.com/sdkforphp",
 | 
				
			||||||
 | 
					            "keywords": [
 | 
				
			||||||
 | 
					                "amazon",
 | 
				
			||||||
 | 
					                "aws",
 | 
				
			||||||
 | 
					                "cloud",
 | 
				
			||||||
 | 
					                "dynamodb",
 | 
				
			||||||
 | 
					                "ec2",
 | 
				
			||||||
 | 
					                "glacier",
 | 
				
			||||||
 | 
					                "s3",
 | 
				
			||||||
 | 
					                "sdk"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "time": "2015-12-04 01:19:53"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "name": "barryvdh/laravel-debugbar",
 | 
					            "name": "barryvdh/laravel-debugbar",
 | 
				
			||||||
            "version": "v2.0.6",
 | 
					            "version": "v2.0.6",
 | 
				
			||||||
| 
						 | 
					@ -1074,6 +1152,53 @@
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "time": "2015-09-30 22:26:59"
 | 
					            "time": "2015-09-30 22:26:59"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "league/flysystem-aws-s3-v3",
 | 
				
			||||||
 | 
					            "version": "1.0.9",
 | 
				
			||||||
 | 
					            "source": {
 | 
				
			||||||
 | 
					                "type": "git",
 | 
				
			||||||
 | 
					                "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
 | 
				
			||||||
 | 
					                "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "dist": {
 | 
				
			||||||
 | 
					                "type": "zip",
 | 
				
			||||||
 | 
					                "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/595e24678bf78f8107ebc9355d8376ae0eb712c6",
 | 
				
			||||||
 | 
					                "reference": "595e24678bf78f8107ebc9355d8376ae0eb712c6",
 | 
				
			||||||
 | 
					                "shasum": ""
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require": {
 | 
				
			||||||
 | 
					                "aws/aws-sdk-php": "^3.0.0",
 | 
				
			||||||
 | 
					                "league/flysystem": "~1.0",
 | 
				
			||||||
 | 
					                "php": ">=5.5.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require-dev": {
 | 
				
			||||||
 | 
					                "henrikbjorn/phpspec-code-coverage": "~1.0.1",
 | 
				
			||||||
 | 
					                "phpspec/phpspec": "^2.0.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "type": "library",
 | 
				
			||||||
 | 
					            "extra": {
 | 
				
			||||||
 | 
					                "branch-alias": {
 | 
				
			||||||
 | 
					                    "dev-master": "1.0-dev"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "autoload": {
 | 
				
			||||||
 | 
					                "psr-4": {
 | 
				
			||||||
 | 
					                    "League\\Flysystem\\AwsS3v3\\": "src/"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "notification-url": "https://packagist.org/downloads/",
 | 
				
			||||||
 | 
					            "license": [
 | 
				
			||||||
 | 
					                "MIT"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "authors": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "name": "Frank de Jonge",
 | 
				
			||||||
 | 
					                    "email": "info@frenky.net"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "description": "Flysystem adapter for the AWS S3 SDK v3.x",
 | 
				
			||||||
 | 
					            "time": "2015-11-19 08:44:16"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "name": "league/oauth1-client",
 | 
					            "name": "league/oauth1-client",
 | 
				
			||||||
            "version": "1.6.1",
 | 
					            "version": "1.6.1",
 | 
				
			||||||
| 
						 | 
					@ -1314,6 +1439,61 @@
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "time": "2015-01-11 23:07:46"
 | 
					            "time": "2015-01-11 23:07:46"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "mtdowling/jmespath.php",
 | 
				
			||||||
 | 
					            "version": "2.2.0",
 | 
				
			||||||
 | 
					            "source": {
 | 
				
			||||||
 | 
					                "type": "git",
 | 
				
			||||||
 | 
					                "url": "https://github.com/jmespath/jmespath.php.git",
 | 
				
			||||||
 | 
					                "reference": "a7d99d0c836e69d27b7bfca1d33ca2759fba3289"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "dist": {
 | 
				
			||||||
 | 
					                "type": "zip",
 | 
				
			||||||
 | 
					                "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a7d99d0c836e69d27b7bfca1d33ca2759fba3289",
 | 
				
			||||||
 | 
					                "reference": "a7d99d0c836e69d27b7bfca1d33ca2759fba3289",
 | 
				
			||||||
 | 
					                "shasum": ""
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require": {
 | 
				
			||||||
 | 
					                "php": ">=5.4.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "require-dev": {
 | 
				
			||||||
 | 
					                "phpunit/phpunit": "~4.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "bin": [
 | 
				
			||||||
 | 
					                "bin/jp.php"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "type": "library",
 | 
				
			||||||
 | 
					            "extra": {
 | 
				
			||||||
 | 
					                "branch-alias": {
 | 
				
			||||||
 | 
					                    "dev-master": "2.0-dev"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "autoload": {
 | 
				
			||||||
 | 
					                "psr-4": {
 | 
				
			||||||
 | 
					                    "JmesPath\\": "src/"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "files": [
 | 
				
			||||||
 | 
					                    "src/JmesPath.php"
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "notification-url": "https://packagist.org/downloads/",
 | 
				
			||||||
 | 
					            "license": [
 | 
				
			||||||
 | 
					                "MIT"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "authors": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "name": "Michael Dowling",
 | 
				
			||||||
 | 
					                    "email": "mtdowling@gmail.com",
 | 
				
			||||||
 | 
					                    "homepage": "https://github.com/mtdowling"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "description": "Declaratively specify how to extract elements from a JSON document",
 | 
				
			||||||
 | 
					            "keywords": [
 | 
				
			||||||
 | 
					                "json",
 | 
				
			||||||
 | 
					                "jsonpath"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "time": "2015-05-27 17:21:31"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "name": "nesbot/carbon",
 | 
					            "name": "nesbot/carbon",
 | 
				
			||||||
            "version": "1.21.0",
 | 
					            "version": "1.21.0",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@ return [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'local' => [
 | 
					        'local' => [
 | 
				
			||||||
            'driver' => 'local',
 | 
					            'driver' => 'local',
 | 
				
			||||||
            'root'   => storage_path('app'),
 | 
					            'root'   => public_path(),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'ftp' => [
 | 
					        'ftp' => [
 | 
				
			||||||
| 
						 | 
					@ -64,10 +64,10 @@ return [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        's3' => [
 | 
					        's3' => [
 | 
				
			||||||
            'driver' => 's3',
 | 
					            'driver' => 's3',
 | 
				
			||||||
            'key'    => 'your-key',
 | 
					            'key'    => env('STORAGE_S3_KEY', 'your-key'),
 | 
				
			||||||
            'secret' => 'your-secret',
 | 
					            'secret' => env('STORAGE_S3_SECRET', 'your-secret'),
 | 
				
			||||||
            'region' => 'your-region',
 | 
					            'region' => env('STORAGE_S3_REGION', 'your-region'),
 | 
				
			||||||
            'bucket' => 'your-bucket',
 | 
					            'bucket' => env('STORAGE_S3_BUCKET', 'your-bucket'),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'rackspace' => [
 | 
					        'rackspace' => [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Image;
 | 
				
			||||||
 | 
					use Illuminate\Database\Schema\Blueprint;
 | 
				
			||||||
 | 
					use Illuminate\Database\Migrations\Migration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddImageUploadTypes extends Migration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Run the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function up()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::table('images', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->string('path', 400);
 | 
				
			||||||
 | 
					            $table->string('type')->index();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Image::all()->each(function($image) {
 | 
				
			||||||
 | 
					            $image->path = $image->url;
 | 
				
			||||||
 | 
					            $image->type = 'gallery';
 | 
				
			||||||
 | 
					            $image->save();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reverse the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function down()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::table('images', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->dropColumn('type');
 | 
				
			||||||
 | 
					            $table->dropColumn('path');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
                        <div v-for="image in images">
 | 
					                        <div v-for="image in images">
 | 
				
			||||||
                            <img class="anim fadeIn"
 | 
					                            <img class="anim fadeIn"
 | 
				
			||||||
                                 :class="{selected: (image==selectedImage)}"
 | 
					                                 :class="{selected: (image==selectedImage)}"
 | 
				
			||||||
                                 :src="image.thumbnail" :alt="image.title" :title="image.name"
 | 
					                                 :src="image.thumbs.gallery" :alt="image.title" :title="image.name"
 | 
				
			||||||
                                 @click="imageClick(image)"
 | 
					                                 @click="imageClick(image)"
 | 
				
			||||||
                                 :style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}">
 | 
					                                 :style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}">
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
| 
						 | 
					@ -88,7 +88,7 @@
 | 
				
			||||||
        methods: {
 | 
					        methods: {
 | 
				
			||||||
            fetchData: function () {
 | 
					            fetchData: function () {
 | 
				
			||||||
                var _this = this;
 | 
					                var _this = this;
 | 
				
			||||||
                this.$http.get('/images/all/' + _this.page, function (data) {
 | 
					                this.$http.get('/images/gallery/all/' + _this.page, function (data) {
 | 
				
			||||||
                    _this.images = _this.images.concat(data.images);
 | 
					                    _this.images = _this.images.concat(data.images);
 | 
				
			||||||
                    _this.hasMore = data.hasMore;
 | 
					                    _this.hasMore = data.hasMore;
 | 
				
			||||||
                    _this.page++;
 | 
					                    _this.page++;
 | 
				
			||||||
| 
						 | 
					@ -98,7 +98,7 @@
 | 
				
			||||||
            setupDropZone: function () {
 | 
					            setupDropZone: function () {
 | 
				
			||||||
                var _this = this;
 | 
					                var _this = this;
 | 
				
			||||||
                var dropZone = new Dropzone(_this.$els.dropZone, {
 | 
					                var dropZone = new Dropzone(_this.$els.dropZone, {
 | 
				
			||||||
                    url: '/upload/image',
 | 
					                    url: '/images/gallery/upload',
 | 
				
			||||||
                    init: function () {
 | 
					                    init: function () {
 | 
				
			||||||
                        var dz = this;
 | 
					                        var dz = this;
 | 
				
			||||||
                        this.on("sending", function (file, xhr, data) {
 | 
					                        this.on("sending", function (file, xhr, data) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,7 @@ module.exports = {
 | 
				
			||||||
            onclick: function() {
 | 
					            onclick: function() {
 | 
				
			||||||
                ImageManager.show(function(image) {
 | 
					                ImageManager.show(function(image) {
 | 
				
			||||||
                    var html = '<a href="'+image.url+'" target="_blank">';
 | 
					                    var html = '<a href="'+image.url+'" target="_blank">';
 | 
				
			||||||
                    html += '<img src="'+image.display+'" alt="'+image.name+'">';
 | 
					                    html += '<img src="'+image.thumbs.display+'" alt="'+image.name+'">';
 | 
				
			||||||
                    html += '</a>';
 | 
					                    html += '</a>';
 | 
				
			||||||
                    editor.execCommand('mceInsertContent', false, html);
 | 
					                    editor.execCommand('mceInsertContent', false, html);
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,11 @@
 | 
				
			||||||
                    <label>Allow public viewing?</label>
 | 
					                    <label>Allow public viewing?</label>
 | 
				
			||||||
                    <toggle-switch name="setting-app-public" value="{{ Setting::get('app-public') }}"></toggle-switch>
 | 
					                    <toggle-switch name="setting-app-public" value="{{ Setting::get('app-public') }}"></toggle-switch>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="form-group">
 | 
				
			||||||
 | 
					                    <label>Enable higher security image uploads?</label>
 | 
				
			||||||
 | 
					                    <p class="small">For performance reasons, all images are public by default, This option adds a random, hard-to-guess characters in front of image names. Ensure directory indexes are not enabled to prevent easy access.</p>
 | 
				
			||||||
 | 
					                    <toggle-switch name="setting-app-secure-images" value="{{ Setting::get('app-secure-images') }}"></toggle-switch>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="col-md-6">
 | 
					            <div class="col-md-6">
 | 
				
			||||||
                <div class="form-group" id="logo-control">
 | 
					                <div class="form-group" id="logo-control">
 | 
				
			||||||
| 
						 | 
					@ -57,7 +62,7 @@
 | 
				
			||||||
                    </select>
 | 
					                    </select>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="form-group">
 | 
					                <div class="form-group">
 | 
				
			||||||
                    <label for="setting-registration-confirmation">Require Email Confirmation?</label>
 | 
					                    <label for="setting-registration-confirmation">Require email confirmation?</label>
 | 
				
			||||||
                    <p class="small">If domain restriction is used then email confirmation will be required and the below value will be ignored.</p>
 | 
					                    <p class="small">If domain restriction is used then email confirmation will be required and the below value will be ignored.</p>
 | 
				
			||||||
                    <toggle-switch name="setting-registration-confirmation" value="{{ Setting::get('registration-confirmation') }}"></toggle-switch>
 | 
					                    <toggle-switch name="setting-registration-confirmation" value="{{ Setting::get('registration-confirmation') }}"></toggle-switch>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue