Added a command to regenerate thumbnails for a single photo or entire album. Photos can now be edited in bulk on the album page.

This commit is contained in:
Andy Heathershaw 2016-09-07 21:44:28 +01:00
parent 626cd5b2ec
commit 1a08ef1828
18 changed files with 273 additions and 47 deletions

View File

@ -7,26 +7,9 @@ APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_DATABASE=blue_twilight
DB_USERNAME=blue_twilight
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=
SESSION_DRIVER=file

View File

@ -3,14 +3,12 @@
namespace App\Console\Commands;
use App\Album;
use App\AlbumSources\IAlbumSource;
use App\Helpers\ImageHelper;
use App\Helpers\ThemeHelper;
use App\Photo;
use App\Upload;
use App\UploadPhoto;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class ProcessUploadCommand extends Command
{

View File

@ -0,0 +1,120 @@
<?php
namespace App\Console\Commands;
use App\Album;
use App\Helpers\ImageHelper;
use App\Helpers\ThemeHelper;
use App\Photo;
use Illuminate\Console\Command;
class RegenerateThumbnailsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'twilight:regenerate-thumbnails {--album} {id}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Recreates thumbnails for an image or an album.';
/**
* @var ImageHelper
*/
private $imageHelper;
/**
* @var ThemeHelper
*/
private $themeHelper;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(ImageHelper $imageHelper, ThemeHelper $themeHelper)
{
parent::__construct();
$this->imageHelper = $imageHelper;
$this->themeHelper = $themeHelper;
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$id = intval($this->argument('id'));
if ($this->option('album'))
{
$this->handleAlbum($id);
}
else
{
$this->handlePhoto($id);
}
}
private function handleAlbum($id)
{
$album = Album::where('id', $id)->first();
if (is_null($album))
{
throw new \Exception(sprintf('The album with ID %d could not be found', $id));
}
/** @var Photo $photo */
foreach ($album->photos as $photo)
{
$this->regenerateThumbnailsForPhoto($album, $photo);
}
}
private function handlePhoto($id)
{
$photo = Photo::where('id', $id)->first();
if (is_null($photo))
{
throw new \Exception(sprintf('The photo with ID %d could not be found', $id));
}
/** @var Album $album */
$album = $photo->album;
$this->regenerateThumbnailsForPhoto($album, $photo);
}
private function regenerateThumbnailsForPhoto(Album $album, Photo $photo)
{
$albumSource = $album->getAlbumSource();
$originalPhotoResource = $this->imageHelper->openImage($albumSource->getPathToPhoto($album, $photo), $imageInfo);
if (!is_resource($originalPhotoResource))
{
throw new \Exception(sprintf('The original image for photo ID %d could not be found', $id));
}
$this->output->writeln(sprintf('Generating thumbnails for "%s"...', $photo->file_name));
$themeInfo = $this->themeHelper->info();
$thumbnailsRequired = $themeInfo['thumbnails'];
/** @var mixed $thumbnail */
foreach ($thumbnailsRequired as $thumbnail)
{
$generatedThumbnailPath = $this->imageHelper->generateThumbnail($originalPhotoResource, $photo, $thumbnail);
$albumSource->saveThumbnail($album, $photo, $thumbnail, $generatedThumbnailPath);
$this->output->writeln(sprintf('Thumbnail \'%s\' (%dx%d) created', $thumbnail['name'], $thumbnail['width'], $thumbnail['height']));
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Console;
use App\Console\Commands\ProcessUploadCommand;
use App\Console\Commands\RegenerateThumbnailsCommand;
use App\Upload;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -15,7 +16,8 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
ProcessUploadCommand::class
ProcessUploadCommand::class,
RegenerateThumbnailsCommand::class
];
/**

View File

@ -57,6 +57,8 @@ class ConfigHelper
'allow_self_registration' => true,
'app_name' => trans('global.app_name'),
'date_format' => $this->allowedDateFormats()[0],
'items_per_page' => 12,
'items_per_page_admin' => 10,
'require_email_verification' => true,
'sender_address' => sprintf('hostmaster@%s', (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost')),
'sender_name' => (is_null($currentAppName) ? trans('global.app_name') : $currentAppName),

View File

@ -4,11 +4,13 @@ namespace app\Http\Controllers\Admin;
use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Upload;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
class AlbumController extends Controller
{
@ -21,7 +23,9 @@ class AlbumController extends Controller
{
$this->authorize('admin-access');
$albums = Album::all()->sortBy('name');
$albums = Album::orderBy('name')
->withCount('photos')
->paginate(UserConfig::get('items_per_page'));
return Theme::render('admin.list_albums', [
'albums' => $albums
@ -49,6 +53,28 @@ class AlbumController extends Controller
return Theme::render('admin.delete_album', ['album' => $album]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Request $request, $id)
{
$this->authorize('admin-access');
$album = AlbumController::loadAlbum($id);
$photos = $album->photos()
->orderBy(DB::raw('COALESCE(taken_at, created_at)'))
->paginate(UserConfig::get('items_per_page_admin'));
return Theme::render('admin.show_album', [
'album' => $album,
'error' => $request->session()->get('error'),
'photos' => $photos
]);
}
/**
* Store a newly created resource in storage.
*
@ -65,21 +91,6 @@ class AlbumController extends Controller
return redirect(route('albums.index'));
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Request $request, $id)
{
$this->authorize('admin-access');
$album = AlbumController::loadAlbum($id);
return Theme::render('admin.show_album', ['album' => $album, 'error' => $request->session()->get('error')]);
}
/**
* Show the form for editing the specified resource.
*

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin;
use App\Album;
use App\Helpers\MiscHelper;
use App\Photo;
use App\Upload;
@ -9,6 +10,7 @@ use App\UploadPhoto;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\App;
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
use Symfony\Component\HttpFoundation\File\File;
@ -202,6 +204,35 @@ class PhotoController extends Controller
//
}
public function updateBulk(Request $request, $albumId)
{
$photos = $request->get('photo');
/** @var Album $album */
$album = Album::where('id', intval($albumId))->first();
if (is_null($album))
{
App::abort(404);
return null;
}
foreach ($photos as $photoId => $value)
{
/** @var Photo $photo */
$photo = $album->photos()->where('id', intval($photoId))->first();
if (is_null($photo))
{
continue;
}
$photo->fill($value);
$photo->save();
}
return redirect(route('albums.show', array('id' => $albumId)));
}
/**
* Remove the specified resource from storage.
*

View File

@ -4,18 +4,21 @@ namespace App\Http\Controllers\Gallery;
use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use Illuminate\Http\Request;
class AlbumController extends Controller
{
public function index(Request $request, $albumUrlAlias)
public function index($albumUrlAlias)
{
$album = AlbumController::loadAlbum($albumUrlAlias);
$photos = $album->photos()->paginate(UserConfig::get('items_per_page'));
return Theme::render('gallery.album', [
'album' => $album
'album' => $album,
'photos' => $photos
]);
}

View File

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Gallery;
use App\Album;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
@ -11,7 +12,9 @@ class DefaultController extends Controller
{
public function index(Request $request)
{
$albums = Album::withCount('photos')->get()->sortBy('name');
$albums = Album::orderBy('name')
->withCount('photos')
->paginate(UserConfig::get('items_per_page'));
return Theme::render('gallery.index', [
'albums' => $albums,

View File

@ -87,8 +87,18 @@ class AppServiceProvider extends ServiceProvider
$transport = $swiftMailer->getTransport();
$transport->setHost(UserConfig::get('smtp_server'));
$transport->setPort(intval(UserConfig::get('smtp_port')));
$transport->setUsername(UserConfig::get('smtp_username'));
$transport->setPassword(decrypt(UserConfig::get('smtp_password')));
$username = UserConfig::get('smtp_username');
if (!is_null($username))
{
$transport->setUsername($username);
}
$password = UserConfig::get('smtp_password');
if (!is_null($password))
{
$transport->setPassword(decrypt($password));
}
if (UserConfig::get('smtp_encryption'))
{

View File

@ -27,6 +27,7 @@
<td>
<span style="font-size: 1.3em;"><a href="{{ route('albums.show', ['id' => $album->id]) }}">{{ $album->name }}</a></span><br/>
<p>{{ $album->description }}</p>
<p style="margin-bottom: 0;"><b>{{ $album->photos_count }}</b> {{ trans_choice('admin.stats_photos', $album->photos_count) }}</p>
</td>
<td class="text-right">
<a href="{{ route('albums.edit', ['id' => $album->id]) }}" class="btn btn-default">@lang('forms.edit_action')</a>
@ -37,6 +38,10 @@
</tbody>
</table>
<div class="text-center">
{{ $albums->links() }}
</div>
<div style="margin-top: 10px;">
<a href="{{ route('albums.create') }}" class="btn btn-success"><i class="fa fa-fw fa-plus"></i> @lang('admin.create_album_link')</a>
</div>

View File

@ -19,12 +19,29 @@
<div class="tab-content">
{{-- Photos --}}
<div role="tabpanel" class="tab-pane active" id="photos-tab">
@if ($album->photos()->count() == 0)
@if (count($photos) == 0)
<div class="text-center" style="margin-top: 30px;">
<h4 class="text-danger"><b>@lang('admin.album_no_photos_p1')</b></h4>
<p>@lang('admin.album_no_photos_p2')</p>
<p style="margin-top: 30px;"><button id="upload-button" class="btn btn-lg btn-success">@lang('admin.album_no_photos_button')</button></p>
</div>
@else
{!! Form::open(['route' => ['photos.updateBulk', $album->id], 'method' => 'PUT']) !!}
@foreach ($photos as $photo)
@include (Theme::viewName('partials.single_photo_admin'))
@endforeach
<div class="pull-right">
<button type="submit" class="btn btn-success">@lang('forms.save_action')</button>
</div>
<div class="clearfix"></div>
{!! Form::close() !!}
<div class="text-center">
{{ $photos->links() }}
</div>
@endif
</div>

View File

@ -15,11 +15,17 @@
@section('content')
<div class="container">
<div class="row">
@foreach ($album->photos as $photo)
@foreach ($photos as $photo)
<div class="col-xs-12 col-sm-4">
<a href="{{ $photo->url() }}"><img src="{{ $photo->thumbnailUrl('preview') }}" alt="" class="img-thumbnail"/></a>
</div>
@endforeach
</div>
<div class="row" style="margin-top: 15px;">
<div class="col-xs-12 text-center">
{{ $photos->links() }}
</div>
</div>
</div>
@endsection

View File

@ -12,7 +12,7 @@
<p class="text-center">
@php($albumUrl = $album->thumbnailUrl('preview'))
@if (strlen($albumUrl) > 0)
<img class="img-responsive" src="{{ $albumUrl }}"/>
<a href="{{ $album->url() }}"><img class="img-responsive" src="{{ $albumUrl }}"/></a>
@endif
</p>
<p>{{ $album->description }}</p>
@ -26,5 +26,11 @@
</div>
@endforeach
</div>
<div class="row" style="margin-top: 15px;">
<div class="col-xs-12 text-center">
{{ $albums->links() }}
</div>
</div>
</div>
@endsection

View File

@ -18,6 +18,9 @@
<div class="row">
<div class="col-xs-12">
<h1>{{ $photo->name }}</h1>
@if (strlen($photo->description) > 0)
<p>{{ $photo->description }}</p>
@endif
</div>
</div>

View File

@ -0,0 +1,20 @@
@php ($field_prefix = sprintf('photo[%d]', $photo->id))
<hr/>
<div class="photo row">
<div class="col-xs-12 col-sm-2 text-center">
<a href="{{ $photo->thumbnailUrl() }}" target="_blank">
<img src="{{ $photo->thumbnailUrl('admin-preview') }}" style="max-width: 100%;"/>
</a>
</div>
<div class="col-xs-12 col-sm-10">
<div class="form-group">
{!! Form::label($field_prefix . '[name]', trans('forms.name_label'), ['class' => 'control-label']) !!}
{!! Form::text($field_prefix . '[name]', old('name', $photo->name), ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label($field_prefix . '[description]', trans('forms.description_label'), ['class' => 'control-label']) !!}
{!! Form::textarea($field_prefix . '[description]', old('name', $photo->description), ['class' => 'form-control', 'rows' => 4]) !!}
</div>
</div>
</div>

View File

@ -14,6 +14,11 @@
"name": "preview",
"height": 300,
"width": 400
},
{
"name": "admin-preview",
"height": 112,
"width": 150
}
]
}

View File

@ -28,6 +28,7 @@ Route::group(['prefix' => 'admin'], function () {
// Photo management
Route::post('photos/store-bulk', 'Admin\PhotoController@storeBulk')->name('photos.storeBulk');
Route::put('photos/update-bulk/{albumId}', 'Admin\PhotoController@updateBulk')->name('photos.updateBulk');
Route::resource('photos', 'Admin\PhotoController');
});