diff options
author | Julien Veyssier <eneiluj@posteo.net> | 2022-06-08 18:44:49 +0300 |
---|---|---|
committer | Julien Veyssier <eneiluj@posteo.net> | 2022-09-06 15:44:53 +0300 |
commit | 3fec1f052dbb8cbe33172e779ac853eeb934ee62 (patch) | |
tree | 9cbdb5e28225dce8e45b14b06829668615fb6f55 /lib/Service/ImageService.php | |
parent | 3af1eb84126c4bb9396b701c963ee229cdc26c66 (diff) |
allow media file upload, handle display in ImageView
Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
Diffstat (limited to 'lib/Service/ImageService.php')
-rw-r--r-- | lib/Service/ImageService.php | 257 |
1 files changed, 186 insertions, 71 deletions
diff --git a/lib/Service/ImageService.php b/lib/Service/ImageService.php index 901575355..f305a5e39 100644 --- a/lib/Service/ImageService.php +++ b/lib/Service/ImageService.php @@ -31,12 +31,14 @@ use OCA\Text\Controller\ImageController; use OCP\Constants; use OCP\Files\Folder; use OCP\Files\File; +use OCP\Files\IMimeTypeDetector; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\IPreview; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IShare; +use OCP\Util; use Throwable; use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ConnectException; @@ -57,10 +59,6 @@ class ImageService { */ private $rootFolder; /** - * @var IClientService - */ - private $clientService; - /** * @var LoggerInterface */ private $logger; @@ -68,21 +66,25 @@ class ImageService { * @var IPreview */ private $previewManager; + /** + * @var IMimeTypeDetector + */ + private $mimeTypeDetector; public function __construct(IRootFolder $rootFolder, LoggerInterface $logger, ShareManager $shareManager, IPreview $previewManager, - IClientService $clientService) { + IMimeTypeDetector $mimeTypeDetector) { $this->rootFolder = $rootFolder; $this->shareManager = $shareManager; - $this->clientService = $clientService; $this->logger = $logger; $this->previewManager = $previewManager; + $this->mimeTypeDetector = $mimeTypeDetector; } /** - * Get image content or preview from file id + * Get image content or preview from file name * @param int $documentId * @param string $imageFileName * @param string $userId @@ -91,9 +93,9 @@ class ImageService { * @throws \OCP\Files\InvalidPathException * @throws \OCP\Files\NotPermittedException */ - public function getImage(int $documentId, string $imageFileName, string $userId) { + public function getImageFile(int $documentId, string $imageFileName, string $userId) { $textFile = $this->getTextFile($documentId, $userId); - return $this->getImagePreview($imageFileName, $textFile); + return $this->getImageFilePreview($imageFileName, $textFile); } /** @@ -107,9 +109,9 @@ class ImageService { * @throws \OCP\Files\InvalidPathException * @throws \OC\User\NoUserException */ - public function getImagePublic(int $documentId, string $imageFileName, string $shareToken) { + public function getImageFilePublic(int $documentId, string $imageFileName, string $shareToken) { $textFile = $this->getTextFilePublic($documentId, $shareToken); - return $this->getImagePreview($imageFileName, $textFile); + return $this->getImageFilePreview($imageFileName, $textFile); } /** @@ -121,10 +123,10 @@ class ImageService { * @throws \OCP\Files\InvalidPathException * @throws \OC\User\NoUserException */ - private function getImagePreview(string $imageFileName, File $textFile) { + private function getImageFilePreview(string $imageFileName, File $textFile) { $attachmentFolder = $this->getAttachmentDirectoryForFile($textFile, true); $imageFile = $attachmentFolder->get($imageFileName); - if ($imageFile instanceof File) { + if ($imageFile instanceof File && in_array($imageFile->getMimetype(), ImageController::IMAGE_MIME_TYPES)) { if ($this->previewManager->isMimeSupported($imageFile->getMimeType())) { return $this->previewManager->getPreview($imageFile, 1024, 1024); } @@ -134,6 +136,168 @@ class ImageService { } /** + * Get media file from file name + * @param int $documentId + * @param string $mediaFileName + * @param string $userId + * @return File|\OCP\Files\Node|ISimpleFile|null + * @throws NotFoundException + * @throws \OCP\Files\InvalidPathException + * @throws \OCP\Files\NotPermittedException + */ + public function getMediaFile(int $documentId, string $mediaFileName, string $userId) { + $textFile = $this->getTextFile($documentId, $userId); + return $this->getMediaFullFile($mediaFileName, $textFile); + } + + /** + * Get image content or preview from file id in public context + * @param int $documentId + * @param string $mediaFileName + * @param string $shareToken + * @return File|\OCP\Files\Node|ISimpleFile|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + public function getMediaFilePublic(int $documentId, string $mediaFileName, string $shareToken) { + $textFile = $this->getTextFilePublic($documentId, $shareToken); + return $this->getMediaFullFile($mediaFileName, $textFile); + } + + /** + * @param string $mediaFileName + * @param File $textFile + * @return File|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + private function getMediaFullFile(string $mediaFileName, File $textFile): ?File { + $attachmentFolder = $this->getAttachmentDirectoryForFile($textFile, true); + $mediaFile = $attachmentFolder->get($mediaFileName); + if ($mediaFile instanceof File) { + return $mediaFile; + } + return null; + } + + /** + * @param int $documentId + * @param string $mediaFileName + * @param string $userId + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + public function getMediaFilePreview(int $documentId, string $mediaFileName, string $userId): ?array { + $textFile = $this->getTextFile($documentId, $userId); + return $this->getMediaFilePreviewFile($mediaFileName, $textFile); + } + /** + * @param int $documentId + * @param string $mediaFileName + * @param string $shareToken + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + public function getMediaFilePreviewPublic(int $documentId, string $mediaFileName, string $shareToken): ?array { + $textFile = $this->getTextFilePublic($documentId, $shareToken); + return $this->getMediaFilePreviewFile($mediaFileName, $textFile); + } + + /** + * Get media preview or mimetype icon address + * @param string $mediaFileName + * @param File $textFile + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + private function getMediaFilePreviewFile(string $mediaFileName, File $textFile): ?array { + $attachmentFolder = $this->getAttachmentDirectoryForFile($textFile, true); + $mediaFile = $attachmentFolder->get($mediaFileName); + if ($mediaFile instanceof File) { + if ($this->previewManager->isMimeSupported($mediaFile->getMimeType())) { + try { + return [ + 'type' => 'file', + 'file' => $this->previewManager->getPreview($mediaFile, 1024, 1024), + ]; + } catch (NotFoundException $e) { + // the preview might not be found even if the mimetype is supported + } + } + // fallback: mimetype icon URL + return [ + 'type' => 'icon', + 'iconUrl' => $this->mimeTypeDetector->mimeTypeIcon($mediaFile->getMimeType()), + ]; + } + return null; + } + + /** + * @param int $documentId + * @param string $mediaFileName + * @param string $userId + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + public function getMediaFileMetadataPrivate(int $documentId, string $mediaFileName, string $userId): ?array { + $textFile = $this->getTextFile($documentId, $userId); + return $this->getMediaFileMetadata($mediaFileName, $textFile); + } + + /** + * @param int $documentId + * @param string $mediaFileName + * @param string $shareToken + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + public function getMediaFileMetadataPublic(int $documentId, string $mediaFileName, string $shareToken): ?array { + $textFile = $this->getTextFilePublic($documentId, $shareToken); + return $this->getMediaFileMetadata($mediaFileName, $textFile); + } + + /** + * @param string $mediaFileName + * @param File $textFile + * @return array|null + * @throws NotFoundException + * @throws NotPermittedException + * @throws \OCP\Files\InvalidPathException + * @throws \OC\User\NoUserException + */ + private function getMediaFileMetadata(string $mediaFileName, File $textFile): ?array { + $attachmentFolder = $this->getAttachmentDirectoryForFile($textFile, true); + $mediaFile = $attachmentFolder->get($mediaFileName); + if ($mediaFile instanceof File) { + return [ + 'size' => Util::humanFileSize($mediaFile->getSize()), + 'mtime' => $mediaFile->getMTime(), + ]; + } + return null; + } + + /** * Save an uploaded image in the attachment folder * * @param int $documentId @@ -221,21 +385,15 @@ class ImageService { * @throws \OCP\Files\InvalidPathException */ private function copyImageFile(File $imageFile, Folder $saveDir, File $textFile): array { - $mimeType = $imageFile->getMimeType(); - if (in_array($mimeType, ImageController::IMAGE_MIME_TYPES, true)) { - $fileName = $this->getUniqueFileName($saveDir, $imageFile->getName()); - $targetPath = $saveDir->getPath() . '/' . $fileName; - $targetFile = $imageFile->copy($targetPath); - // get file type and name - return [ - 'name' => $fileName, - 'dirname' => $saveDir->getName(), - 'id' => $targetFile->getId(), - 'documentId' => $textFile->getId(), - ]; - } + $fileName = $this->getUniqueFileName($saveDir, $imageFile->getName()); + $targetPath = $saveDir->getPath() . '/' . $fileName; + $targetFile = $imageFile->copy($targetPath); return [ - 'error' => 'Unsupported file type', + 'name' => $fileName, + 'dirname' => $saveDir->getName(), + 'id' => $targetFile->getId(), + 'documentId' => $textFile->getId(), + 'mimetype' => $targetFile->getMimetype(), ]; } @@ -390,49 +548,6 @@ class ImageService { } /** - * Download a file and write it to a resource - * @param string $url - * @param $resource - * @return array - */ - private function simpleDownload(string $url, $resource): array { - $client = $this->clientService->newClient(); - try { - $options = [ - // does not work with sink if SSE is enabled - // 'sink' => $resource, - // rather use stream and write to the file ourselves - 'stream' => true, - 'timeout' => 0, - 'headers' => [ - 'User-Agent' => 'Nextcloud Text', - ], - ]; - - $response = $client->get($url, $options); - $body = $response->getBody(); - while (!feof($body)) { - // write ~5 MB chunks - $chunk = fread($body, 5000000); - fwrite($resource, $chunk); - } - - return ['Content-Type' => $response->getHeader('Content-Type')]; - } catch (ServerException | ClientException $e) { - //$response = $e->getResponse(); - //if ($response->getStatusCode() === 401) { - $this->logger->warning('Impossible to download image', ['exception' => $e]); - return ['error' => 'Impossible to download image']; - } catch (ConnectException $e) { - $this->logger->error('Connection error', ['exception' => $e]); - return ['error' => 'Connection error']; - } catch (Throwable | Exception $e) { - $this->logger->error('Unknown download error', ['exception' => $e]); - return ['error' => 'Unknown download error']; - } - } - - /** * Actually delete attachment files which are not pointed in the markdown content * * @param int $fileId @@ -498,7 +613,7 @@ class ImageService { $matches = []; // matches ![ANY_CONSIDERED_CORRECT_BY_PHP-MARKDOWN](.attachments.DOCUMENT_ID/ANY_FILE_NAME) and captures FILE_NAME preg_match_all( - '/\!\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[\])*\])*\])*\])*\])*\])*\]\(\.attachments\.'.$fileId.'\/([^)&]+)\)/', + '/\!\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[(?>[^\[\]]+|\[\])*\])*\])*\])*\])*\])*\]\(\.attachments\.' . $fileId . '\/([^)&]+)\)/', $content, $matches, PREG_SET_ORDER |