mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-30 07:32:39 +01:00
Added maintenance view with image-cleanup
This commit is contained in:
parent
1df0bcaf85
commit
2bd6ba9895
@ -55,7 +55,7 @@ class CleanupImages extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$deleted = $this->imageService->deleteUnusedImages($checkRevisions, ['gallery', 'drawio'], $dryRun);
|
||||
$deleted = $this->imageService->deleteUnusedImages($checkRevisions, $dryRun);
|
||||
$deleteCount = count($deleted);
|
||||
|
||||
if ($dryRun) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php namespace BookStack\Http\Controllers;
|
||||
|
||||
use BookStack\Services\ImageService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Setting;
|
||||
@ -13,7 +14,7 @@ class SettingController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$this->checkPermission('settings-manage');
|
||||
$this->setPageTitle('Settings');
|
||||
$this->setPageTitle(trans('settings.settings'));
|
||||
|
||||
// Get application version
|
||||
$version = trim(file_get_contents(base_path('version')));
|
||||
@ -43,4 +44,48 @@ class SettingController extends Controller
|
||||
session()->flash('success', trans('settings.settings_save_success'));
|
||||
return redirect('/settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the page for application maintenance.
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showMaintenance()
|
||||
{
|
||||
$this->checkPermission('settings-manage');
|
||||
$this->setPageTitle(trans('settings.maint'));
|
||||
|
||||
// Get application version
|
||||
$version = trim(file_get_contents(base_path('version')));
|
||||
|
||||
return view('settings/maintenance', ['version' => $version]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to clean-up images in the system.
|
||||
* @param Request $request
|
||||
* @param ImageService $imageService
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function cleanupImages(Request $request, ImageService $imageService)
|
||||
{
|
||||
$this->checkPermission('settings-manage');
|
||||
|
||||
$checkRevisions = !($request->get('ignore_revisions', 'false') === 'true');
|
||||
$dryRun = !($request->has('confirm'));
|
||||
|
||||
$imagesToDelete = $imageService->deleteUnusedImages($checkRevisions, $dryRun);
|
||||
$deleteCount = count($imagesToDelete);
|
||||
if ($deleteCount === 0) {
|
||||
session()->flash('warning', trans('settings.maint_image_cleanup_nothing_found'));
|
||||
return redirect('/settings/maintenance')->withInput();
|
||||
}
|
||||
|
||||
if ($dryRun) {
|
||||
session()->flash('cleanup-images-warning', trans('settings.maint_image_cleanup_warning', ['count' => $deleteCount]));
|
||||
} else {
|
||||
session()->flash('success', trans('settings.maint_image_cleanup_success', ['count' => $deleteCount]));
|
||||
}
|
||||
|
||||
return redirect('/settings/maintenance#image-cleanup')->withInput();
|
||||
}
|
||||
}
|
||||
|
@ -306,11 +306,11 @@ class ImageService extends UploadService
|
||||
*
|
||||
* Returns the path of the images that would be/have been deleted.
|
||||
* @param bool $checkRevisions
|
||||
* @param array $types
|
||||
* @param bool $dryRun
|
||||
* @param array $types
|
||||
* @return array
|
||||
*/
|
||||
public function deleteUnusedImages($checkRevisions = true, $types = ['gallery', 'drawio'], $dryRun = true)
|
||||
public function deleteUnusedImages($checkRevisions = true, $dryRun = true, $types = ['gallery', 'drawio'])
|
||||
{
|
||||
$types = array_intersect($types, ['gallery', 'drawio']);
|
||||
$deletedPaths = [];
|
||||
|
4
resources/assets/icons/spanner.svg
Normal file
4
resources/assets/icons/spanner.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path clip-rule="evenodd" fill="none" d="M0 0h24v24H0z"/>
|
||||
<path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 315 B |
@ -50,6 +50,19 @@ return [
|
||||
'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
|
||||
'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
|
||||
|
||||
/**
|
||||
* Maintenance settings
|
||||
*/
|
||||
|
||||
'maint' => 'Maintenance',
|
||||
'maint_image_cleanup' => 'Cleanup Images',
|
||||
'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.",
|
||||
'maint_image_cleanup_ignore_revisions' => 'Ignore images in revisions',
|
||||
'maint_image_cleanup_run' => 'Run Cleanup',
|
||||
'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?',
|
||||
'maint_image_cleanup_success' => ':count potentially unused images found and deleted!',
|
||||
'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!',
|
||||
|
||||
/**
|
||||
* Role settings
|
||||
*/
|
||||
|
49
resources/views/settings/maintenance.blade.php
Normal file
49
resources/views/settings/maintenance.blade.php
Normal file
@ -0,0 +1,49 @@
|
||||
@extends('simple-layout')
|
||||
|
||||
@section('toolbar')
|
||||
@include('settings/navbar', ['selected' => 'maintenance'])
|
||||
@stop
|
||||
|
||||
@section('body')
|
||||
<div class="container small">
|
||||
|
||||
<div class="text-right text-muted container">
|
||||
<br>
|
||||
BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card" id="image-cleanup">
|
||||
<h3>@icon('images') {{ trans('settings.maint_image_cleanup') }}</h3>
|
||||
<div class="body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<p class="small muted">{{ trans('settings.maint_image_cleanup_desc') }}</p>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<form method="POST" action="{{ baseUrl('/settings/maintenance/cleanup-images') }}">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<div>
|
||||
@if(session()->has('cleanup-images-warning'))
|
||||
<p class="text neg">
|
||||
{{ session()->get('cleanup-images-warning') }}
|
||||
</p>
|
||||
<input type="hidden" name="ignore_revisions" value="{{ session()->getOldInput('ignore_revisions', 'false') }}">
|
||||
<input type="hidden" name="confirm" value="true">
|
||||
@else
|
||||
<label>
|
||||
<input type="checkbox" name="ignore_revisions" value="true">
|
||||
{{ trans('settings.maint_image_cleanup_ignore_revisions') }}
|
||||
</label>
|
||||
@endif
|
||||
</div>
|
||||
<button class="button outline">{{ trans('settings.maint_image_cleanup_run') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -2,6 +2,7 @@
|
||||
<div class="col-md-12 setting-nav nav-tabs">
|
||||
@if($currentUser->can('settings-manage'))
|
||||
<a href="{{ baseUrl('/settings') }}" @if($selected == 'settings') class="selected text-button" @endif>@icon('settings'){{ trans('settings.settings') }}</a>
|
||||
<a href="{{ baseUrl('/settings/maintenance') }}" @if($selected == 'maintenance') class="selected text-button" @endif>@icon('spanner'){{ trans('settings.maint') }}</a>
|
||||
@endif
|
||||
@if($currentUser->can('users-manage'))
|
||||
<a href="{{ baseUrl('/settings/users') }}" @if($selected == 'users') class="selected text-button" @endif>@icon('users'){{ trans('settings.users') }}</a>
|
||||
|
@ -152,6 +152,10 @@ Route::group(['middleware' => 'auth'], function () {
|
||||
Route::get('/', 'SettingController@index')->name('settings');
|
||||
Route::post('/', 'SettingController@update');
|
||||
|
||||
// Maintenance
|
||||
Route::get('/maintenance', 'SettingController@showMaintenance');
|
||||
Route::delete('/maintenance/cleanup-images', 'SettingController@cleanupImages');
|
||||
|
||||
// Users
|
||||
Route::get('/users', 'UserController@index');
|
||||
Route::get('/users/create', 'UserController@create');
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
use BookStack\Image;
|
||||
use BookStack\Page;
|
||||
use BookStack\Repos\EntityRepo;
|
||||
use BookStack\Services\ImageService;
|
||||
|
||||
class ImageTest extends TestCase
|
||||
{
|
||||
@ -234,4 +236,59 @@ class ImageTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_deleted_unused_images()
|
||||
{
|
||||
$page = Page::first();
|
||||
$admin = $this->getAdmin();
|
||||
$this->actingAs($admin);
|
||||
|
||||
$imageName = 'unused-image.png';
|
||||
$relPath = $this->getTestImagePath('gallery', $imageName);
|
||||
$this->deleteImage($relPath);
|
||||
|
||||
$upload = $this->uploadImage($imageName, $page->id);
|
||||
$upload->assertStatus(200);
|
||||
$image = Image::where('type', '=', 'gallery')->first();
|
||||
|
||||
$entityRepo = app(EntityRepo::class);
|
||||
$entityRepo->updatePage($page, $page->book_id, [
|
||||
'name' => $page->name,
|
||||
'html' => $page->html . "<img src=\"{$image->url}\">",
|
||||
'summary' => ''
|
||||
]);
|
||||
|
||||
// Ensure no images are reported as deletable
|
||||
$imageService = app(ImageService::class);
|
||||
$toDelete = $imageService->deleteUnusedImages(true, true);
|
||||
$this->assertCount(0, $toDelete);
|
||||
|
||||
// Save a revision of our page without the image;
|
||||
$entityRepo->updatePage($page, $page->book_id, [
|
||||
'name' => $page->name,
|
||||
'html' => "<p>Hello</p>",
|
||||
'summary' => ''
|
||||
]);
|
||||
|
||||
// Ensure revision images are picked up okay
|
||||
$imageService = app(ImageService::class);
|
||||
$toDelete = $imageService->deleteUnusedImages(true, true);
|
||||
$this->assertCount(0, $toDelete);
|
||||
$toDelete = $imageService->deleteUnusedImages(false, true);
|
||||
$this->assertCount(1, $toDelete);
|
||||
|
||||
// Check image is found when revisions are destroyed
|
||||
$page->revisions()->delete();
|
||||
$toDelete = $imageService->deleteUnusedImages(true, true);
|
||||
$this->assertCount(1, $toDelete);
|
||||
|
||||
// Check the image is deleted
|
||||
$absPath = public_path($relPath);
|
||||
$this->assertTrue(file_exists($absPath), "Existing uploaded file at path {$absPath} exists");
|
||||
$toDelete = $imageService->deleteUnusedImages(true, false);
|
||||
$this->assertCount(1, $toDelete);
|
||||
$this->assertFalse(file_exists($absPath));
|
||||
|
||||
$this->deleteImage($relPath);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user