From aadc39684f3ed8bf46ce99b011deb25414025d69 Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Fri, 28 Oct 2016 05:30:57 +0100 Subject: [PATCH] BLUE-8: Modified the upload/analysis functionality to work strictly with local files, so only the final results are uploaded to OpenStack, saving on bandwidth --- app/Helpers/FileHelper.php | 48 ++++++++++++++++ .../Controllers/Admin/AlbumController.php | 6 +- .../Controllers/Admin/PhotoController.php | 39 +++++++++---- app/Services/PhotoService.php | 9 ++- public/themes/base/js/app.js | 4 +- .../themes/base/admin/analyse_album.blade.php | 57 +------------------ .../themes/base/admin/show_album.blade.php | 8 ++- routes/web.php | 4 +- 8 files changed, 97 insertions(+), 78 deletions(-) create mode 100644 app/Helpers/FileHelper.php diff --git a/app/Helpers/FileHelper.php b/app/Helpers/FileHelper.php new file mode 100644 index 0000000..9009105 --- /dev/null +++ b/app/Helpers/FileHelper.php @@ -0,0 +1,48 @@ +guessExtension(); + if (!is_null($extension)) + { + $tempFilename .= '.' . $extension; + } + } + + $uploadedFile->move(dirname($tempFilename), basename($tempFilename)); + return new File($tempFilename); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AlbumController.php b/app/Http/Controllers/Admin/AlbumController.php index 9af7df0..ab556e7 100644 --- a/app/Http/Controllers/Admin/AlbumController.php +++ b/app/Http/Controllers/Admin/AlbumController.php @@ -5,6 +5,7 @@ namespace app\Http\Controllers\Admin; use App\Album; use App\Facade\Theme; use App\Facade\UserConfig; +use App\Helpers\FileHelper; use App\Helpers\MiscHelper; use App\Http\Controllers\Controller; use App\Http\Requests; @@ -26,7 +27,7 @@ class AlbumController extends Controller View::share('is_admin', true); } - public function analyse($id) + public function analyse($id, $queue_token) { $this->authorize('admin-access'); @@ -36,7 +37,7 @@ class AlbumController extends Controller ->orderBy('created_at') ->get(); - return Theme::render('admin.analyse_album', ['album' => $album, 'photos' => $photos]); + return Theme::render('admin.analyse_album', ['album' => $album, 'photos' => $photos, 'queue_token' => $queue_token]); } /** @@ -184,6 +185,7 @@ class AlbumController extends Controller 'max_post_limit' => $postLimit, 'max_post_limit_bulk' => $fileUploadOrPostLowerLimit, 'photos' => $photos, + 'queue_token' => MiscHelper::randomString(), 'success' => $request->session()->get('success'), 'warning' => $request->session()->get('warning') ]); diff --git a/app/Http/Controllers/Admin/PhotoController.php b/app/Http/Controllers/Admin/PhotoController.php index 018af20..fab44df 100644 --- a/app/Http/Controllers/Admin/PhotoController.php +++ b/app/Http/Controllers/Admin/PhotoController.php @@ -6,6 +6,7 @@ use App\Album; use App\AlbumSources\IAlbumSource; use App\Facade\Image; use App\Facade\Theme; +use App\Helpers\FileHelper; use App\Helpers\ImageHelper; use App\Helpers\MiscHelper; use App\Photo; @@ -30,7 +31,7 @@ class PhotoController extends Controller View::share('is_admin', true); } - public function analyse($photoId) + public function analyse($photoId, $queue_token) { $this->authorize('admin-access'); @@ -47,7 +48,7 @@ class PhotoController extends Controller try { $photoService = new PhotoService($photo); - $photoService->analyse(); + $photoService->analyse($queue_token); $result['is_successful'] = true; } @@ -222,6 +223,15 @@ class PhotoController extends Controller $album = $this->loadAlbum($request->get('album_id')); $isSuccessful = false; + // Create the folder to hold the analysis results if not already present + $queueUid = $request->get('queue_token'); + if (strlen($queueUid) == 0) + { + throw new \Exception('No queue_token value was provided!'); + } + + $queueFolder = FileHelper::getQueuePath($queueUid); + foreach ($photoFiles as $photoFile) { $photoFile = UploadedFile::createFromBase($photoFile); @@ -232,7 +242,7 @@ class PhotoController extends Controller else { /** @var File $savedFile */ - $savedFile = $album->getAlbumSource()->saveUploadedPhoto($photoFile); + $savedFile = FileHelper::saveUploadedFile($photoFile, $queueFolder); $photo = new Photo(); $photo->album_id = $album->id; @@ -256,7 +266,8 @@ class PhotoController extends Controller else { return redirect(route('albums.analyse', [ - 'id' => $album->id + 'id' => $album->id, + 'queue_token' => $queueUid ])); } } @@ -276,9 +287,14 @@ class PhotoController extends Controller return redirect(route('albums.show', ['id' => $album->id])); } - // Create a temporary folder to hold the extracted files - $tempFolder = sprintf('%s/btw_upload_%s', env('TEMP_FOLDER', '/tmp'), MiscHelper::randomString()); - mkdir($tempFolder); + // Create the folder to hold the analysis results if not already present + $queueUid = $request->get('queue_token'); + if (strlen($queueUid) == 0) + { + throw new \Exception('No queue_token value was provided!'); + } + + $queueFolder = FileHelper::getQueuePath($queueUid); $mimeType = strtolower($archiveFile->getMimeType()); switch ($mimeType) @@ -286,7 +302,7 @@ class PhotoController extends Controller case 'application/zip': $zip = new \ZipArchive(); $zip->open($archiveFile->getPathname()); - $zip->extractTo($tempFolder); + $zip->extractTo($queueFolder); $zip->close(); break; @@ -295,7 +311,7 @@ class PhotoController extends Controller return redirect(route('albums.show', ['id' => $album->id])); } - $di = new \RecursiveDirectoryIterator($tempFolder, \RecursiveDirectoryIterator::SKIP_DOTS); + $di = new \RecursiveDirectoryIterator($queueFolder, \RecursiveDirectoryIterator::SKIP_DOTS); $recursive = new \RecursiveIteratorIterator($di); /** @var \SplFileInfo $fileInfo */ @@ -336,10 +352,11 @@ class PhotoController extends Controller $photo->save(); } - @rmdir($tempFolder); + @rmdir($queueFolder); return redirect(route('albums.analyse', [ - 'id' => $album->id + 'id' => $album->id, + 'queue_token' => $queueUid ])); } diff --git a/app/Services/PhotoService.php b/app/Services/PhotoService.php index 2d910a8..e78e44d 100644 --- a/app/Services/PhotoService.php +++ b/app/Services/PhotoService.php @@ -4,6 +4,7 @@ namespace App\Services; use App\Album; use App\AlbumSources\IAlbumSource; +use App\Helpers\FileHelper; use App\Helpers\ImageHelper; use App\Helpers\ThemeHelper; use App\Photo; @@ -48,13 +49,15 @@ class PhotoService $this->themeHelper = new ThemeHelper(); } - public function analyse() + public function analyse($queueToken) { /** @var Album $album */ $album = $this->photo->album; - $albumSource = $album->getAlbumSource(); - $photoFile = $albumSource->getPathToPhoto($this->photo); + $photoFile = join(DIRECTORY_SEPARATOR, [ + FileHelper::getQueuePath($queueToken), + $this->photo->storage_file_name + ]); $imageInfo = null; $originalPhotoResource = $this->imageHelper->openImage($photoFile, $imageInfo); diff --git a/public/themes/base/js/app.js b/public/themes/base/js/app.js index 6c70656..4d745e5 100644 --- a/public/themes/base/js/app.js +++ b/public/themes/base/js/app.js @@ -434,11 +434,12 @@ function StorageLocationsViewModel() { /** * This model is used by admin/show_album.blade.php to handle photo uploads. * @param album_id ID of the album the photos are being uploaded to + * @param queue_token Unique token of the upload queue to save the photos to * @param language Array containing language strings * @param urls Array containing URLs * @constructor */ -function UploadPhotosViewModel(album_id, language, urls) { +function UploadPhotosViewModel(album_id, queue_token, language, urls) { var self = this; self.currentStatus = ko.observable(''); @@ -510,6 +511,7 @@ function UploadPhotosViewModel(album_id, language, urls) { self.uploadFile = function uploadImageFile(formObject, imageFile) { var formData = new FormData(); formData.append('album_id', album_id); + formData.append('queue_token', queue_token); formData.append('photo[]', imageFile, imageFile.name); $.ajax( diff --git a/resources/views/themes/base/admin/analyse_album.blade.php b/resources/views/themes/base/admin/analyse_album.blade.php index d9b2069..fc5d2fa 100644 --- a/resources/views/themes/base/admin/analyse_album.blade.php +++ b/resources/views/themes/base/admin/analyse_album.blade.php @@ -56,65 +56,10 @@ viewModel.imagesToAnalyse.push(new AnalyseImageViewModel({ 'id': '{{ $photo->id }}', 'name': '{!! addslashes($photo->name) !!}', - 'url': '{{ route('photos.analyse', ['id' => $photo->id]) }}' + 'url': '{{ route('photos.analyse', ['id' => $photo->id, 'queue_token' => $queue_token]) }}' })); @endforeach ko.applyBindings(viewModel); - - /* - - $(document).ready(function() { - number_total = $('#file-list p').length; - - if (number_total == 0) { - $('#status-panel').hide(); - $('#complete-panel').show(); - } - else - { - $('#file-list p').each(function (index, element) { - var photo_id = $(element).data('photo-id'); - var url = '{{ route('photos.analyse', ['id' => 0]) }}'; - url = url.replace(/0$/, photo_id); - - $.ajax( - url, - { - complete: function () { - redrawProgressBar(); - - if (number_successful + number_error >= number_total) { - $('#status-panel').hide(); - $('#complete-panel').show(); - } - }, - dataType: 'json', - error: function (xhr, textStatus, errorThrown) { - $('i', '#file-list p[data-photo-id=' + photo_id + ']') - .addClass('text-danger') - .addClass('fa-times'); - number_error++; - }, - method: 'POST', - success: function (data) { - if (data.is_successful) { - $('i', '#file-list p[data-photo-id=' + photo_id + ']') - .addClass('text-success') - .addClass('fa-check'); - number_successful++; - } - else { - $('i', '#file-list p[data-photo-id=' + photo_id + ']') - .addClass('text-danger') - .addClass('fa-times'); - number_error++; - } - } - } - ); - }); - } - });*/ @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 0c4e01d..759a89f 100644 --- a/resources/views/themes/base/admin/show_album.blade.php +++ b/resources/views/themes/base/admin/show_album.blade.php @@ -89,6 +89,7 @@
{!! Form::open(['route' => 'photos.store', 'method' => 'POST', 'files' => true, 'id' => 'single-upload-form']) !!} {!! Form::hidden('album_id', $album->id) !!} + {!! Form::hidden('queue_token', $queue_token) !!}
{!! Form::file('photo[]', ['class' => 'control-label', 'multiple' => 'multiple', 'id' => 'single-upload-files']) !!} @@ -120,7 +121,7 @@

@lang('admin.upload_file_failed_continue')

- @lang('forms.continue_action') + @lang('forms.continue_action')

    @@ -141,6 +142,7 @@ {!! Form::open(['route' => 'photos.storeBulk', 'method' => 'POST', 'files' => true, 'id' => 'bulk-upload-form']) !!} {!! Form::hidden('album_id', $album->id) !!} + {!! Form::hidden('queue_token', $queue_token) !!}
    {!! Form::file('archive', ['class' => 'control-label']) !!} @@ -244,14 +246,14 @@ language.upload_status = '{!! addslashes(trans('admin.upload_file_status_progress')) !!}'; var urls = []; - urls.analyse = '{{ route('albums.analyse', ['id' => $album->id]) }}'; + urls.analyse = '{{ route('albums.analyse', ['id' => $album->id, 'queue_token' => $queue_token]) }}'; urls.delete_photo = '{{ route('photos.destroy', ['id' => 0]) }}'; urls.flip_photo = '{{ route('photos.flip', ['id' => 0, 'horizontal' => -1, 'vertical' => -2]) }}'; urls.move_photo = '{{ route('photos.move', ['photoId' => 0]) }}'; urls.regenerate_thumbnails = '{{ route('photos.regenerateThumbnails', ['photoId' => 0]) }}'; urls.rotate_photo = '{{ route('photos.rotate', ['id' => 0, 'angle' => 1]) }}'; - var viewModel = new UploadPhotosViewModel('{{ $album->id }}', language, urls); + var viewModel = new UploadPhotosViewModel('{{ $album->id }}', '{{ $queue_token }}', language, urls); var editViewModel = new EditPhotosViewModel('{{ $album->id }}', language, urls); // Populate the list of albums in the view model diff --git a/routes/web.php b/routes/web.php index 77b10b6..ec5cd5a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,12 +21,12 @@ Route::group(['prefix' => 'admin'], function () { Route::get('settings', 'Admin\DefaultController@settings')->name('admin.settings'); // Album management - Route::get('albums/{id}/analyse', 'Admin\AlbumController@analyse')->name('albums.analyse'); + Route::get('albums/{id}/analyse/{queue_token}', 'Admin\AlbumController@analyse')->name('albums.analyse'); Route::get('albums/{id}/delete', 'Admin\AlbumController@delete')->name('albums.delete'); Route::resource('albums', 'Admin\AlbumController'); // Photo management - Route::post('photos/analyse/{id}', 'Admin\PhotoController@analyse')->name('photos.analyse'); + Route::post('photos/analyse/{id}/{queue_token}', 'Admin\PhotoController@analyse')->name('photos.analyse'); Route::post('photos/flip/{photoId}/{horizontal}/{vertical}', 'Admin\PhotoController@flip')->name('photos.flip'); Route::post('photos/move/{photoId}', 'Admin\PhotoController@move')->name('photos.move'); Route::post('photos/regenerate-thumbnails/{photoId}', 'Admin\PhotoController@regenerateThumbnails')->name('photos.regenerateThumbnails');