getQueryParams()['identifier'] ?? null; $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); if ($resource === null) { return new JsonResponse(null, 404); } if (!$resource->checkActionPermission('read')) { return new JsonResponse(null, 403); } return new JsonResponse($this->getResourceResponseData($resource)); } public function requestThumbnailAction(ServerRequestInterface $request): ResponseInterface { $identifier = $request->getQueryParams()['identifier'] ?? null; $thumbnailSizeIdentifier = $request->getQueryParams()['size'] ?? 'default'; $keepAspectRatio = (bool)($request->getQueryParams()['keepAspectRatio'] ?? false); $resource = null; if ($identifier) { $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); } if ($resource === null || !($resource instanceof File && ($resource->isImage() || $resource->isMediaFile()))) { return new Response(null, 404); } if (!$resource->checkActionPermission('read')) { return new Response(null, 403); } $thumbnailSize = ThumbnailSize::tryFrom($thumbnailSizeIdentifier) ?? ThumbnailSize::DEFAULT; [$width, $height] = $keepAspectRatio ? $thumbnailSize->getDimensions() : $thumbnailSize->getCroppedDimensions(); $thumbnail = $resource ->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, ['width' => $width, 'height' => $height]); return new RedirectResponse( GeneralUtility::locationHeaderUrl($thumbnail->getPublicUrl() ?? '', $request) ); } public function renameResourceAction(ServerRequestInterface $request): ResponseInterface { $identifier = $request->getParsedBody()['identifier'] ?? null; $origin = null; if ($identifier) { $origin = $this->resourceFactory->retrieveFileOrFolderObject($identifier); } try { if (!$origin instanceof File && !$origin instanceof Folder) { throw new \InvalidArgumentException('Resource must be a file or a folder', 1676979120); } if ($origin->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1676299579); } if (!$origin->checkActionPermission('rename')) { throw new InsufficientFileAccessPermissionsException('You are not allowed to rename the resource', 1676979130); } $resourceName = $request->getParsedBody()['resourceName'] ?? null; if (!$resourceName || trim((string)$resourceName) === '') { throw new \InvalidArgumentException('The resource name cannot be empty', 1676978732); } $oldName = $origin->getName(); if ($oldName === $resourceName) { $message = sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNameNotDifferent'), $oldName); return new JsonResponse($this->getResponseData(true, $message, $origin)); } $resource = $origin->rename($resourceName); if ($resource->getName() === $oldName) { $message = sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotRenamed'), $oldName); return new JsonResponse($this->getResponseData(false, $message, $origin)); } } catch (ResultException $exception) { // Possible Exception thrown within the `->rename(...)` chain via ResourceConsistencyService return new JsonResponse($this->getResponseData(false, $this->renderResultException($exception, $this->getLanguageService()))); } catch (\Exception $exception) { $message = match ($exception->getCode()) { 1676979120 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotFileOrFolder'), 1676299579 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceOutsideOfStorages'), 1676979130 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNoPermissionRename'), 1676978732 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNameCannotBeEmpty'), default => $exception->getMessage(), }; return new JsonResponse($this->getResponseData(false, $message)); } return new JsonResponse($this->getResponseData( true, sprintf( $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.success.message.renamed'), $oldName, $resource->getName() ), $origin, $resource, )); } public function replaceResourceAction(ServerRequestInterface $request): ResponseInterface { $uploadedFiles = $request->getUploadedFiles(); if ($uploadedFiles === []) { return new JsonResponse($this->getResponseData( false, $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotAvailableToUpload'), )); } $uid = $request->getParsedBody()['uid']; $keepFilename = (bool)($request->getParsedBody()['keepFilename'] ?? false); $origin = $this->resourceFactory->retrieveFileOrFolderObject($uid); if ($origin === null) { return new JsonResponse($this->getResponseData( false, $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotFound'), )); } $this->fileProcessor->setActionPermissions(); $this->fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::REPLACE); $this->fileProcessor->start([ 'replace' => [ 1 => [ 'data' => 1, 'uid' => $uid, 'keepFilename' => $keepFilename, ], ], ], $uploadedFiles); $result = $this->fileProcessor->processData(); $flashMessageQueue = $this->flashMessageService->getMessageQueueByIdentifier(); $messages = implode("\n", array_map(static fn(FlashMessage $message) => $message->getMessage(), $flashMessageQueue->getAllMessagesAndFlush())); /** @var File|null $fileReplacement */ $fileReplacement = $result['replace'][0][0] ?? null; if ($fileReplacement === null) { return new JsonResponse($this->getResponseData( false, $messages, $origin )); } return new JsonResponse($this->getResponseData( true, $messages, $origin, $fileReplacement )); } /** * Prepare response data for a JSON response */ private function getResponseData(bool $success, string $message, ?ResourceInterface $origin = null, ?ResourceInterface $resource = null): array { $flashMessageQueue = new FlashMessageQueue('backend'); $flashMessageQueue->enqueue( new FlashMessage( $message, $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.' . ($success ? 'success' : 'error')) ) ); // Next to the flash message, also log the action to be consistent with the use in ExtendedFileUtiltiy $this->getBackendUser()->writelog(SystemLogType::FILE, SystemLogFileAction::RENAME, $success ? SystemLogErrorClassification::MESSAGE : SystemLogErrorClassification::USER_ERROR, null, $message, []); return [ 'success' => $success, 'status' => $flashMessageQueue, 'origin' => $this->getResourceResponseData($origin), 'resource' => $this->getResourceResponseData($resource), ]; } /** * Prepare resource data for a JSON response */ private function getResourceResponseData(?ResourceInterface $resource): ?array { if (!$resource) { return null; } return [ 'type' => $resource instanceof File ? 'file' : 'folder', 'identifier' => $resource instanceof File || $resource instanceof Folder ? $resource->getCombinedIdentifier() : null, 'name' => $resource->getName(), 'hasPreview' => $resource instanceof File && ($resource->isImage() || $resource->isMediaFile()), 'uid' => $resource instanceof File ? $resource->getUid() : null, 'metaUid' => $resource instanceof File ? $resource->getMetaData()->offsetGet('uid') : null, 'createdAt' => $resource instanceof File ? $resource->getCreationTime() : null, 'size' => $resource instanceof File ? $resource->getSize() : null, ]; } private function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } private function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }