middleware(['auth', 'max_post_size_exceeded']); View::share('is_admin', true); } public function analyse($photoId, $queue_token) { $this->authorizeAccessToAdminPanel(); /** @var Photo $photo */ $photo = Photo::where('id', intval($photoId))->first(); if (is_null($photo)) { App::abort(404); return null; } $result = ['is_successful' => false, 'message' => '']; try { $photoService = new PhotoService($photo); $photoService->analyse($queue_token); $result['is_successful'] = true; } catch (\Exception $ex) { $result['is_successful'] = false; $result['message'] = $ex->getMessage(); // Remove the photo if it cannot be analysed $photo->delete(); } return response()->json($result); } /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Request $request, $id) { $this->authorizeAccessToAdminPanel(); $photo = $this->loadPhoto($id, 'delete'); $photoService = new PhotoService($photo); $photoService->delete(); $request->session()->flash('success', trans('admin.delete_photo_successful_message', ['name' => $photo->name])); } public function flip($photoId, $horizontal, $vertical) { $this->authorizeAccessToAdminPanel(); settype($horizontal, 'boolean'); settype($vertical, 'boolean'); $photo = $this->loadPhoto($photoId, 'manipulate'); $photoService = new PhotoService($photo); $photoService->flip($horizontal, $vertical); } public function move(Request $request, $photoId) { $this->authorizeAccessToAdminPanel(); $photo = $this->loadPhoto($photoId, 'manipulate'); $newAlbum = Album::where('id', intval($request->get('new_album_id')))->first(); if (is_null($newAlbum)) { App::abort(404); } $messageData = ['name' => $photo->name, 'album' => $newAlbum->name]; if ($newAlbum->id == $photo->album_id) { $request->session()->flash('warning', trans('admin.move_failed_same_album', $messageData)); } else { $photoService = new PhotoService($photo); $photoService->changeAlbum($newAlbum); $request->session()->flash('success', trans('admin.move_successful_message', $messageData)); } } public function regenerateThumbnails($photoId) { $this->authorizeAccessToAdminPanel(); $photo = $this->loadPhoto($photoId, 'change-metadata'); $result = ['is_successful' => false, 'message' => '']; try { $photoService = new PhotoService($photo); $photoService->regenerateThumbnails(); $result['is_successful'] = true; } catch (\Exception $ex) { $result['is_successful'] = false; $result['message'] = $ex->getMessage(); } return response()->json($result); } public function rotate($photoId, $angle) { $this->authorizeAccessToAdminPanel(); $photo = $this->loadPhoto($photoId, 'manipulate'); if ($angle != 90 && $angle != 180 && $angle != 270) { App::aport(400); return null; } $photoService = new PhotoService($photo); $photoService->rotate($angle); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $this->authorizeAccessToAdminPanel(); $photoFiles = $request->files->get('photo'); // Load the linked album $album = $this->loadAlbum($request->get('album_id'), 'upload-photos'); $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); if ($photoFile->getError() != UPLOAD_ERR_OK) { Log::error('Image upload failed.', ['error' => $photoFile->getError(), 'reason' => $photoFile->getErrorMessage()]); } else { /** @var File $savedFile */ $savedFile = FileHelper::saveUploadedFile($photoFile, $queueFolder); $photo = new Photo(); $photo->album_id = $album->id; $photo->user_id = Auth::user()->id; $photo->name = pathinfo($photoFile->getClientOriginalName(), PATHINFO_FILENAME); $photo->file_name = $photoFile->getClientOriginalName(); $photo->storage_file_name = $savedFile->getFilename(); $photo->mime_type = $savedFile->getMimeType(); $photo->file_size = $savedFile->getSize(); $photo->is_analysed = false; $photo->save(); $isSuccessful = true; } } if ($request->isXmlHttpRequest()) { return response()->json(['is_successful' => $isSuccessful]); } else { return redirect(route('albums.analyse', [ 'id' => $album->id, 'queue_token' => $queueUid ])); } } public function storeBulk(Request $request) { $this->authorizeAccessToAdminPanel(); // Load the linked album $album = $this->loadAlbum($request->get('album_id')); $archiveFile = UploadedFile::createFromBase($request->files->get('archive')); if ($archiveFile->getError() != UPLOAD_ERR_OK) { Log::error('Bulk image upload failed.', ['error' => $archiveFile->getError(), 'reason' => $archiveFile->getErrorMessage()]); $request->session()->flash('error', $archiveFile->getErrorMessage()); return redirect(route('albums.show', ['id' => $album->id])); } // 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) { case 'application/zip': $zip = new \ZipArchive(); $zip->open($archiveFile->getPathname()); $zip->extractTo($queueFolder); $zip->close(); @unlink($archiveFile->getPathname()); break; default: $request->session()->flash('error', sprintf('The file type "%s" is not supported for bulk uploads.', $mimeType)); return redirect(route('albums.show', ['id' => $album->id])); } $di = new \RecursiveDirectoryIterator($queueFolder, \RecursiveDirectoryIterator::SKIP_DOTS); $recursive = new \RecursiveIteratorIterator($di); /** @var \SplFileInfo $fileInfo */ foreach ($recursive as $fileInfo) { if ($fileInfo->isDir()) { if ($fileInfo->getFilename() == '__MACOSX' || substr($fileInfo->getFilename(), 0, 1) == '.') { @rmdir($fileInfo->getPathname()); } continue; } if (substr($fileInfo->getFilename(), 0, 1) == '.') { // Temporary/hidden file - skip @unlink($fileInfo->getPathname()); continue; } $result = getimagesize($fileInfo->getPathname()); if ($result === false) { // Not an image file - skip @unlink($fileInfo->getPathname()); continue; } $photoFile = new File($fileInfo->getPathname()); /** @var File $savedFile */ $savedFile = FileHelper::saveExtractedFile($photoFile, $queueFolder); $photo = new Photo(); $photo->album_id = $album->id; $photo->user_id = Auth::user()->id; $photo->name = pathinfo($photoFile->getFilename(), PATHINFO_FILENAME); $photo->file_name = $photoFile->getFilename(); $photo->storage_file_name = $savedFile->getFilename(); $photo->mime_type = $savedFile->getMimeType(); $photo->file_size = $savedFile->getSize(); $photo->is_analysed = false; $photo->save(); } return redirect(route('albums.analyse', [ 'id' => $album->id, 'queue_token' => $queueUid ])); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } public function updateBulk(UpdatePhotosBulkRequest $request, $albumId) { $this->authorizeAccessToAdminPanel(); $album = $this->loadAlbum($albumId); if ($request->has('bulk-apply')) { $numberChanged = $this->applyBulkActions($request, $album); } else { $numberChanged = $this->updatePhotoDetails($request, $album); } $request->session()->flash('success', trans_choice('admin.bulk_photos_changed', $numberChanged, ['number' => $numberChanged])); return redirect(route('albums.show', array('id' => $albumId, 'page' => $request->get('page', 1)))); } private function applyBulkActions(Request $request, Album $album) { $selectAllInAlbum = boolval($request->get('select-all-album')); $photosToProcess = []; if ($selectAllInAlbum) { foreach ($album->photos as $photo) { $photosToProcess[] = $photo; } } else { $photoIds = $request->get('select-photo'); if (is_null($photoIds) || !is_array($photoIds) || count($photoIds) == 0) { $request->session()->flash('warning', trans('admin.no_photo_selected_message')); return 0; } foreach ($photoIds as $photoId) { /** @var Photo $photo */ $photo = $album->photos()->where('id', intval($photoId))->first(); if (is_null($photo)) { continue; } $photosToProcess[] = $photo; } } $action = $request->get('bulk-action'); $numberChanged = 0; foreach ($photosToProcess as $photo) { $changed = false; $photoService = new PhotoService($photo); $doNotSave = false; 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; } $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 ($changed) { $numberChanged++; } } return $numberChanged; } /** * @param $id * @return Album */ private function loadAlbum($id, $permission = 'edit') { $album = Album::where('id', intval($id))->first(); if (is_null($album)) { App::abort(404); return null; } $this->authorize($permission, $album); return $album; } /** * @param $id * @param string|null $permission * @return Photo */ private function loadPhoto($id, $permission = null) { $photo = Photo::where('id', intval($id))->first(); if (is_null($photo)) { App::abort(404); return null; } if (!is_null($permission)) { $this->authorize($permission, $photo); } return $photo; } private function updatePhotoDetails(Request $request, Album $album) { $numberChanged = 0; $photos = $request->get('photo'); foreach ($photos as $photoId => $value) { /** @var Photo $photo */ $photo = $album->photos()->where('id', intval($photoId))->first(); if (is_null($photo) || !Auth::user()->can('change-metadata', $photo)) { continue; } $photo->fill($value); // Update the photo labels $labelIDs = trim($value['labels']); $photo->labels()->detach(); if (strlen($labelIDs) > 0) { foreach (explode(',', $labelIDs) as $labelID) { if (intval($labelID) == 0) { // Create new label $newLabel = new Label(); $newLabel->name = $labelID; $newLabel->save(); $newLabel->save(); $labelID = $newLabel->id; } $photo->labels()->attach(intval($labelID)); } } // Save all changes $photo->save(); $numberChanged++; } return $numberChanged; } }