From 80dd1e4a409c5cac79d5dca5888787d5385017ae Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Mon, 5 Sep 2016 12:01:30 +0100 Subject: [PATCH] Implemented a progress bar for uploading photos, and allowed multiple uploads using the single upload file control --- app/Console/Commands/ProcessUploadCommand.php | 26 +++++- app/Console/Kernel.php | 6 +- .../Controllers/Admin/AlbumController.php | 38 +++++++++ .../Controllers/Admin/PhotoController.php | 52 +++++++----- app/Upload.php | 5 ++ ...2016_09_02_144354_create_uploads_table.php | 5 ++ ...9_05_102036_add_upload_is_ready_column.php | 34 ++++++++ public/themes/bootstrap3/theme.css | 11 ++- .../admin/album_upload_progress.blade.php | 84 +++++++++++++++++++ .../themes/base/admin/show_album.blade.php | 4 +- .../themes/base/partials/navbar.blade.php | 7 +- routes/web.php | 5 ++ 12 files changed, 247 insertions(+), 30 deletions(-) create mode 100644 database/migrations/2016_09_05_102036_add_upload_is_ready_column.php create mode 100644 resources/views/themes/base/admin/album_upload_progress.blade.php diff --git a/app/Console/Commands/ProcessUploadCommand.php b/app/Console/Commands/ProcessUploadCommand.php index 6d3eed3..6e895e2 100644 --- a/app/Console/Commands/ProcessUploadCommand.php +++ b/app/Console/Commands/ProcessUploadCommand.php @@ -62,24 +62,46 @@ class ProcessUploadCommand extends Command { $uploadsToProcess = Upload::where([ ['is_completed', false], - ['is_processing', false] + ['is_processing', false], + ['is_ready', true] ]) ->orderBy('created_at') ->get(); + /** @var Upload $upload */ foreach ($uploadsToProcess as $upload) { + $upload->is_processing = 1; + $upload->save(); + $this->output->writeln(sprintf('Processing upload #%d', $upload->id)); $this->handleUpload($upload); + + $upload->is_completed = 1; + $upload->is_processing = 0; + $upload->save(); } } private function handleUpload(Upload $upload) { $photos = $upload->uploadPhotos; + + /** @var UploadPhoto $photo */ foreach ($photos as $photo) { - $this->handlePhoto($photo); + try + { + $this->handlePhoto($photo); + $upload->number_successful++; + } + catch (\Exception $ex) + { + $upload->number_failed++; + $photo->delete(); + } + + $upload->save(); } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 4190201..abc7e77 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -29,7 +29,11 @@ class Kernel extends ConsoleKernel $schedule->command('twilight:process-uploads') ->everyMinute() ->when(function () { - return (Upload::where('is_completed', 0)->count() > 0); + return (Upload::where([ + 'is_completed' => 0, + 'is_processing' => 0, + 'is_ready' => 1 + ])->count() > 0); }); } diff --git a/app/Http/Controllers/Admin/AlbumController.php b/app/Http/Controllers/Admin/AlbumController.php index f9d513e..da600c4 100644 --- a/app/Http/Controllers/Admin/AlbumController.php +++ b/app/Http/Controllers/Admin/AlbumController.php @@ -6,6 +6,7 @@ use App\Album; use App\Facade\Theme; use App\Http\Controllers\Controller; use App\Http\Requests; +use App\Upload; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; @@ -94,6 +95,22 @@ class AlbumController extends Controller return Theme::render('admin.edit_album', ['album' => $album]); } + public function monitorUpload($id, $upload_id) + { + $this->authorize('admin-access'); + + $upload = AlbumController::loadUpload($upload_id, $id); + + return Theme::render('admin.album_upload_progress', ['upload' => $upload, 'album' => $upload->album]); + } + + public function monitorUploadJson($id, $upload_id) + { + $this->authorize('admin-access'); + + return response()->json(AlbumController::loadUpload($upload_id, $id)->toArray()); + } + /** * Update the specified resource in storage. * @@ -142,4 +159,25 @@ class AlbumController extends Controller return $album; } + + /** + * @param $id + * @param $albumId + * @return Upload|null + */ + private static function loadUpload($id, $albumId) + { + $upload = Upload::where([ + 'id' => intval($id), + 'album_id' => intval($albumId) + ])->first(); + + if (is_null($upload)) + { + App::abort(404); + return null; + } + + return $upload; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Admin/PhotoController.php b/app/Http/Controllers/Admin/PhotoController.php index d9a0311..004bd98 100644 --- a/app/Http/Controllers/Admin/PhotoController.php +++ b/app/Http/Controllers/Admin/PhotoController.php @@ -42,35 +42,49 @@ class PhotoController extends Controller { $this->authorize('admin-access'); - /** @var UploadedFile $photoFile */ - $photoFile = UploadedFile::createFromBase($request->files->get('photo')); + $photoFiles = $request->files->get('photo'); // Load the linked album $album = AlbumController::loadAlbum($request->get('album_id')); - /** @var File $savedFile */ - $savedFile = $album->getAlbumSource()->saveUploadedPhoto($album, $photoFile); - - $photo = new Photo(); - $photo->album_id = $album->id; - $photo->name = $photoFile->getClientOriginalName(); - $photo->file_name = $savedFile->getFilename(); - $photo->mime_type = $savedFile->getMimeType(); - $photo->file_size = $savedFile->getSize(); - $photo->save(); - $upload = new Upload(); + $upload->album_id = $album->id; $upload->is_completed = false; $upload->is_processing = false; - $upload->number_photos = 1; + $upload->is_ready = false; + $upload->number_photos = 0; $upload->save(); - $uploadPhoto = new UploadPhoto(); - $uploadPhoto->upload_id = $upload->id; - $uploadPhoto->photo_id = $photo->id; - $uploadPhoto->save(); + foreach ($photoFiles as $photoFile) + { + $photoFile = UploadedFile::createFromBase($photoFile); - exit(); + /** @var File $savedFile */ + $savedFile = $album->getAlbumSource()->saveUploadedPhoto($album, $photoFile); + + $photo = new Photo(); + $photo->album_id = $album->id; + $photo->name = $photoFile->getClientOriginalName(); + $photo->file_name = $savedFile->getFilename(); + $photo->mime_type = $savedFile->getMimeType(); + $photo->file_size = $savedFile->getSize(); + $photo->save(); + + $upload->number_photos++; + + $uploadPhoto = new UploadPhoto(); + $uploadPhoto->upload_id = $upload->id; + $uploadPhoto->photo_id = $photo->id; + $uploadPhoto->save(); + } + + $upload->is_ready = true; + $upload->save(); + + return redirect(route('albums.monitorUpload', [ + 'id' => $album->id, + 'upload_id' => $upload->id + ])); } /** diff --git a/app/Upload.php b/app/Upload.php index cafe392..2219ea9 100644 --- a/app/Upload.php +++ b/app/Upload.php @@ -26,6 +26,11 @@ class Upload extends Model protected $hidden = [ ]; + public function album() + { + return $this->belongsTo(Album::class); + } + public function uploadPhotos() { return $this->hasMany(UploadPhoto::class); diff --git a/database/migrations/2016_09_02_144354_create_uploads_table.php b/database/migrations/2016_09_02_144354_create_uploads_table.php index 928ce1d..9ca67d0 100644 --- a/database/migrations/2016_09_02_144354_create_uploads_table.php +++ b/database/migrations/2016_09_02_144354_create_uploads_table.php @@ -15,12 +15,17 @@ class CreateUploadsTable extends Migration { Schema::create('uploads', function (Blueprint $table) { $table->increments('id'); + $table->unsignedInteger('album_id'); $table->boolean('is_completed'); $table->boolean('is_processing'); $table->integer('number_photos')->default(0); $table->integer('number_successful')->default(0); $table->integer('number_failed')->default(0); $table->timestamps(); + + $table->foreign('album_id') + ->references('id')->on('albums') + ->onDelete('cascade'); }); } diff --git a/database/migrations/2016_09_05_102036_add_upload_is_ready_column.php b/database/migrations/2016_09_05_102036_add_upload_is_ready_column.php new file mode 100644 index 0000000..e352ffd --- /dev/null +++ b/database/migrations/2016_09_05_102036_add_upload_is_ready_column.php @@ -0,0 +1,34 @@ +boolean('is_ready'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('uploads', function (Blueprint $table) + { + $table->dropColumn('is_ready'); + }); + } +} diff --git a/public/themes/bootstrap3/theme.css b/public/themes/bootstrap3/theme.css index 1562a1e..c371e6b 100644 --- a/public/themes/bootstrap3/theme.css +++ b/public/themes/bootstrap3/theme.css @@ -13,9 +13,14 @@ } .navbar .avatar { - left: -28px; - position: absolute; - top: 9px; + border-radius: 20px; + margin-left: 5px; + margin-right: 5px; +} + +.panel .progress { + margin-top: 20px; + margin-bottom: 0; } .tab-content { diff --git a/resources/views/themes/base/admin/album_upload_progress.blade.php b/resources/views/themes/base/admin/album_upload_progress.blade.php new file mode 100644 index 0000000..cfe5279 --- /dev/null +++ b/resources/views/themes/base/admin/album_upload_progress.blade.php @@ -0,0 +1,84 @@ +@extends('themes.base.layout') +@section('title', 'Processing...') + +@section('content') +
+
+
+
+
Processing...
+
+

Your upload is now being processed.

+
+
+
+
+
+ + +
+
+
+@endsection + +@push('scripts') + +@endpush \ No newline at end of file diff --git a/resources/views/themes/base/admin/show_album.blade.php b/resources/views/themes/base/admin/show_album.blade.php index 549cc5b..0e0bd66 100644 --- a/resources/views/themes/base/admin/show_album.blade.php +++ b/resources/views/themes/base/admin/show_album.blade.php @@ -19,13 +19,13 @@ {{-- Tab panes --}}
-

Upload a single image

+

Upload single images

{!! Form::open(['route' => 'photos.store', 'method' => 'POST', 'files' => true]) !!} {!! Form::hidden('album_id', $album->id) !!}
- {!! Form::file('photo', ['class' => 'control-label']) !!} + {!! Form::file('photo[]', ['class' => 'control-label', 'multiple' => 'multiple']) !!}
diff --git a/resources/views/themes/base/partials/navbar.blade.php b/resources/views/themes/base/partials/navbar.blade.php index 6053e38..051826b 100644 --- a/resources/views/themes/base/partials/navbar.blade.php +++ b/resources/views/themes/base/partials/navbar.blade.php @@ -42,9 +42,10 @@
  • Register
  • @else