#121: Bulk updates to photos now take place on the queue if enabled (just need to handle album changes)

This commit is contained in:
Andy Heathershaw 2019-07-10 14:31:04 +01:00
parent 0cca6eec66
commit ebbc5ba097
5 changed files with 265 additions and 98 deletions

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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');

View File

@ -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:',