mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Added image user checking before deletion. Fixes #13.
This commit is contained in:
parent
03f5f9e9b9
commit
69eff86ff5
@ -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);
|
||||
|
@ -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');
|
||||
|
@ -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
|
||||
|
4
resources/assets/js/jquery-extensions.js
vendored
4
resources/assets/js/jquery-extensions.js
vendored
@ -41,3 +41,7 @@ jQuery.fn.showFailure = function (messageMap) {
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
jQuery.fn.submitForm = function() {
|
||||
$(this).closest('form').submit();
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
@ -31,8 +31,19 @@
|
||||
</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>
|
||||
|
Loading…
Reference in New Issue
Block a user