From ebbc5ba0977ee0483cb34ffb3ea69e3b6421c914 Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Wed, 10 Jul 2019 14:31:04 +0100 Subject: [PATCH] #121: Bulk updates to photos now take place on the queue if enabled (just need to handle album changes) --- app/Console/Commands/ProcessQueueCommand.php | 120 +++++++++- .../Controllers/Admin/PhotoController.php | 217 ++++++++++-------- app/QueueItem.php | 18 +- ..._07_09_203137_create_queue_items_table.php | 7 +- resources/lang/en/admin.php | 1 + 5 files changed, 265 insertions(+), 98 deletions(-) diff --git a/app/Console/Commands/ProcessQueueCommand.php b/app/Console/Commands/ProcessQueueCommand.php index f67332d..0ed8c07 100644 --- a/app/Console/Commands/ProcessQueueCommand.php +++ b/app/Console/Commands/ProcessQueueCommand.php @@ -7,6 +7,7 @@ use App\Photo; use App\QueueItem; use App\Services\PhotoService; use App\Services\RabbitMQService; +use App\User; use App\UserActivity; use Illuminate\Console\Command; @@ -84,6 +85,17 @@ class ProcessQueueCommand extends Command $this->processPhotoAnalyseMessage($queueItem); break; + case 'photo.bulk_action.change_album': + case 'photo.bulk_action.delete': + case 'photo.bulk_action.flip_both': + case 'photo.bulk_action.flip_horizontal': + case 'photo.bulk_action.flip_vertical': + case 'photo.bulk_action.refresh_thumbnails': + case 'photo.bulk_action.rotate_left': + case 'photo.bulk_action.rotate_right': + $this->processPhotoBulkActionMessage($queueItem); + break; + default: $this->output->writeln(sprintf('Action %s is not recognised, skipping', $queueItem->action_type)); return; @@ -102,7 +114,7 @@ class ProcessQueueCommand extends Command } } - private function createActivityRecord(Photo $photo, $type, $activityDateTime = null) + private function createActivityRecord(Photo $photo, $type, $userID, $activityDateTime = null) { if (is_null($activityDateTime)) { @@ -110,7 +122,7 @@ class ProcessQueueCommand extends Command } $userActivity = new UserActivity(); - $userActivity->user_id = $photo->user_id; + $userActivity->user_id = $userID; $userActivity->activity_at = $activityDateTime; $userActivity->type = $type; $userActivity->photo_id = $photo->id; @@ -121,11 +133,12 @@ class ProcessQueueCommand extends Command { $this->output->writeln(sprintf('Analysing photo ID %l (batch: %s)', $queueItem->photo_id, $queueItem->batch_reference)); - $photo = Photo::where('id', $queueItem->photo_id)->first(); - + /** @var Photo $photo */ + $photo = $queueItem->photo; if (is_null($photo)) { $this->output->writeln('Photo does not exist; skipping'); + return; } /* IF CHANGING THIS LOGIC, ALSO CHECK PhotoController::analyse */ @@ -138,7 +151,104 @@ class ProcessQueueCommand extends Command if (!is_null($photo->taken_at)) { // Log an activity record for the user's feed - $this->createActivityRecord($photo, 'photo.taken', $photo->taken_at); + $this->createActivityRecord($photo, 'photo.taken', $queueItem->user_id, $photo->taken_at); + } + } + + private function processPhotoBulkActionMessage(QueueItem $queueItem) + { + $action = str_replace('photo.bulk_action.', '', $queueItem->action_type); + $this->output->writeln(sprintf('Apply action \'%s\' to photo ID %l (batch: %s)', $action, $queueItem->photo_id, $queueItem->batch_reference)); + + /** @var Photo $photo */ + $photo = $queueItem->photo; + if (is_null($photo)) + { + $this->output->writeln('Photo does not exist; skipping'); + return; + } + + /** @var User $user */ + $user = $queueItem->user; + if (is_null($user)) + { + $this->output->writeln('User does not exist; skipping'); + return; + } + + $photoService = new PhotoService($photo); + + switch (strtolower($action)) + { + /* This needs a bit more work - we need to also store the new album ID in the queue_items table */ + /*case 'change_album': + if ($user->can('change-metadata', $photo)) + { + $newAlbumId = intval($request->get('new-album-id')); + if ($newAlbumId == $photo->album_id) + { + // Photo already belongs to this album, don't move + return; + } + + $newAlbum = $this->loadAlbum($newAlbumId, 'upload-photos'); + $photoService->changeAlbum($newAlbum); + $changed = true; + } + break;*/ + + case 'delete': + if ($user->can('delete', $photo)) + { + $photoService->delete(); + } + break; + + case 'flip_both': + if ($user->can('manipulate', $photo)) + { + $photoService->flip(true, true); + } + break; + + case 'flip_horizontal': + if ($user->can('manipulate', $photo)) + { + $photoService->flip(true, false); + } + break; + + case 'flip_vertical': + if ($user->can('manipulate', $photo)) + { + $photoService->flip(false, true); + } + break; + + case 'refresh_thumbnails': + if ($user->can('change-metadata', $photo)) + { + $photoService->regenerateThumbnails(); + } + break; + + case 'rotate_left': + if ($user->can('manipulate', $photo)) + { + $photoService->rotate(90); + } + break; + + case 'rotate_right': + if ($user->can('manipulate', $photo)) + { + $photoService->rotate(270); + } + break; + + default: + $this->output->writeln(sprintf('Action \'%s\' not recognised; skipping')); + return; } } diff --git a/app/Http/Controllers/Admin/PhotoController.php b/app/Http/Controllers/Admin/PhotoController.php index 7fca978..36bf457 100644 --- a/app/Http/Controllers/Admin/PhotoController.php +++ b/app/Http/Controllers/Admin/PhotoController.php @@ -350,6 +350,7 @@ class PhotoController extends Controller 'action_type' => 'photo.analyse', 'album_id' => $photo->album_id, 'photo_id' => $photo->id, + 'user_id' => $this->getUser()->id, 'queued_at' => new \DateTime() ]); $queueItem->save(); @@ -528,7 +529,14 @@ class PhotoController extends Controller $numberChanged = $this->updatePhotoDetails($request, $album); } - $request->session()->flash('success', trans_choice('admin.bulk_photos_changed', $numberChanged, ['number' => $numberChanged])); + $request->session()->flash( + 'success', + trans_choice( + UserConfig::isImageProcessingQueueEnabled() ? 'admin.bulk_photos_changed_queued' : 'admin.bulk_photos_changed', + $numberChanged, + ['number' => $numberChanged] + ) + ); return redirect(route('albums.show', array('id' => $albumId, 'page' => $request->get('page', 1)))); } @@ -570,103 +578,130 @@ class PhotoController extends Controller $action = $request->get('bulk-action'); $numberChanged = 0; - foreach ($photosToProcess as $photo) + if (UserConfig::isImageProcessingQueueEnabled()) { - $changed = false; - $photoService = new PhotoService($photo); - $doNotSave = false; - switch (strtolower($action)) + $queueUid = MiscHelper::randomString(); + + foreach ($photosToProcess as $photo) { - case 'change_album': - if (Auth::user()->can('change-metadata', $photo)) - { - $newAlbumId = intval($request->get('new-album-id')); - if ($newAlbumId == $photo->album_id) - { - // Photo already belongs to this album, don't move - continue; - } + $queueItem = new QueueItem([ + 'batch_reference' => $queueUid, + 'action_type' => sprintf('photo.bulk_action.%s', strtolower($action)), + 'album_id' => $photo->album_id, + 'photo_id' => $photo->id, + 'user_id' => $this->getUser()->id, + 'queued_at' => new \DateTime() + ]); + $queueItem->save(); - $newAlbum = $this->loadAlbum($newAlbumId, 'upload-photos'); - $photoService->changeAlbum($newAlbum); - $changed = true; - } - break; + $rabbitmq = new RabbitMQService(); + $rabbitmq->queueItem($queueItem); - case 'delete': - if (Auth::user()->can('delete', $photo)) - { - $photoService->delete(); - $doNotSave = true; - $changed = true; - } - break; - - case 'flip_both': - if (Auth::user()->can('manipulate', $photo)) - { - $photoService->flip(true, true); - $changed = true; - } - break; - - case 'flip_horizontal': - if (Auth::user()->can('manipulate', $photo)) - { - $photoService->flip(true, false); - $changed = true; - } - break; - - case 'flip_vertical': - if (Auth::user()->can('manipulate', $photo)) - { - $photoService->flip(false, true); - $changed = true; - } - break; - - case 'refresh_thumbnails': - if (Auth::user()->can('change-metadata', $photo)) - { - $photoService->regenerateThumbnails(); - $changed = true; - } - break; - - case 'rotate_left': - if (Auth::user()->can('manipulate', $photo)) - { - $photoService->rotate(90); - $changed = true; - } - break; - - case 'rotate_right': - if (Auth::user()->can('manipulate', $photo)) - { - $photoService->rotate(270); - $changed = true; - } - break; - } - - if (!$doNotSave) - { - $photo->save(); - } - - if (!in_array(strtolower($action), ['delete', 'refresh_thumbnails', 'change_album'])) - { - // Log an activity record for the user's feed - $this->createActivityRecord($photo, 'photo.edited'); - } - - if ($changed) - { $numberChanged++; } } + else + { + foreach ($photosToProcess as $photo) + { + $changed = false; + $photoService = new PhotoService($photo); + $doNotSave = false; + + /* IF CHANGING THIS LOGIC OR ADDING EXTRA case OPTIONS, ALSO CHECK ProcessQueueCommand::processQueueItem AND ProcessQueueCommand::processPhotoBulkActionMessage */ + switch (strtolower($action)) + { + case 'change_album': + if (Auth::user()->can('change-metadata', $photo)) + { + $newAlbumId = intval($request->get('new-album-id')); + if ($newAlbumId == $photo->album_id) + { + // Photo already belongs to this album, don't move + continue 2; + } + + $newAlbum = $this->loadAlbum($newAlbumId, 'upload-photos'); + $photoService->changeAlbum($newAlbum); + $changed = true; + } + break; + + case 'delete': + if (Auth::user()->can('delete', $photo)) + { + $photoService->delete(); + $doNotSave = true; + $changed = true; + } + break; + + case 'flip_both': + if (Auth::user()->can('manipulate', $photo)) + { + $photoService->flip(true, true); + $changed = true; + } + break; + + case 'flip_horizontal': + if (Auth::user()->can('manipulate', $photo)) + { + $photoService->flip(true, false); + $changed = true; + } + break; + + case 'flip_vertical': + if (Auth::user()->can('manipulate', $photo)) + { + $photoService->flip(false, true); + $changed = true; + } + break; + + case 'refresh_thumbnails': + if (Auth::user()->can('change-metadata', $photo)) + { + $photoService->regenerateThumbnails(); + $changed = true; + } + break; + + case 'rotate_left': + if (Auth::user()->can('manipulate', $photo)) + { + $photoService->rotate(90); + $changed = true; + } + break; + + case 'rotate_right': + if (Auth::user()->can('manipulate', $photo)) + { + $photoService->rotate(270); + $changed = true; + } + break; + } + + if (!$doNotSave) + { + $photo->save(); + } + + if (!in_array(strtolower($action), ['delete', 'refresh_thumbnails', 'change_album'])) + { + // Log an activity record for the user's feed + $this->createActivityRecord($photo, 'photo.edited'); + } + + if ($changed) + { + $numberChanged++; + } + } + } return $numberChanged; } diff --git a/app/QueueItem.php b/app/QueueItem.php index a1f5a96..1e4e8ab 100644 --- a/app/QueueItem.php +++ b/app/QueueItem.php @@ -16,6 +16,22 @@ class QueueItem extends Model 'action_type', 'album_id', 'photo_id', - 'queued_at' + 'queued_at', + 'user_id' ]; + + public function album() + { + return $this->belongsTo(Album::class); + } + + public function photo() + { + return $this->belongsTo(Photo::class); + } + + public function user() + { + return $this->belongsTo(User::class); + } } diff --git a/database/migrations/2019_07_09_203137_create_queue_items_table.php b/database/migrations/2019_07_09_203137_create_queue_items_table.php index 2f16272..adca513 100644 --- a/database/migrations/2019_07_09_203137_create_queue_items_table.php +++ b/database/migrations/2019_07_09_203137_create_queue_items_table.php @@ -15,14 +15,19 @@ class CreateQueueItemsTable extends Migration { Schema::create('queue_items', function (Blueprint $table) { $table->increments('id'); + $table->unsignedInteger('user_id'); $table->string('batch_reference')->nullable(true); - $table->string('action_type', 20); + $table->string('action_type', 50); $table->unsignedInteger('album_id'); $table->unsignedBigInteger('photo_id'); $table->dateTime('queued_at'); $table->dateTime('completed_at')->nullable(true); $table->timestamps(); + $table->foreign('user_id') + ->references('id')->on('users') + ->onDelete('cascade'); + $table->foreign('album_id') ->references('id')->on('albums') ->onDelete('cascade'); diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 276c278..220b1f8 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -66,6 +66,7 @@ return [ 'bulk_comments_approved' => ':number comment was approved successfully.|:number comments were approved successfully.', 'bulk_comments_deleted' => ':number comment was deleted successfully.|:number comments were deleted successfully.', 'bulk_photos_changed' => ':number photo was updated successfully.|:number photos were updated successfully.', + 'bulk_photos_changed_queued' => 'Your requested change has been queued. :number photo will be updated shortly.|Your requested change has been queued. :number photos will be updated shortly.', 'cannot_delete_own_user_account' => 'It is not possible to delete your own user account. Please ask another administrator to delete it for you.', 'cannot_remove_own_admin' => 'You cannot remove your own administrator permissions. Please ask another administrator to remove the administrator permissions for you.', 'change_album_message' => 'Please select the album to move the photo(s) to:',