diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php
index ca99f2d374d8..75cc5779100a 100644
--- a/apps/dav/lib/Connector/Sabre/File.php
+++ b/apps/dav/lib/Connector/Sabre/File.php
@@ -40,6 +40,7 @@
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
use OCA\DAV\Connector\Sabre\Exception\Forbidden as DAVForbiddenException;
use OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType;
+use OCA\DAV\Files\IFileNode;
use OCP\Encryption\Exceptions\GenericEncryptionException;
use OCP\Events\EventEmitterTrait;
use OCP\Files\EntityTooLargeException;
@@ -61,7 +62,7 @@
use Sabre\DAV\IFile;
use Symfony\Component\EventDispatcher\GenericEvent;
-class File extends Node implements IFile {
+class File extends Node implements IFile, IFileNode {
use EventEmitterTrait;
protected $request;
@@ -714,4 +715,11 @@ public function getChecksum($algo = null) {
protected function header($string) {
\header($string);
}
+
+ /**
+ * @return \OCP\Files\Node
+ */
+ public function getNode() {
+ return \OC::$server->getRootFolder()->get($this->getFileInfo()->getPath());
+ }
}
diff --git a/apps/dav/lib/Files/IFileNode.php b/apps/dav/lib/Files/IFileNode.php
new file mode 100644
index 000000000000..588dfcbd6d55
--- /dev/null
+++ b/apps/dav/lib/Files/IFileNode.php
@@ -0,0 +1,35 @@
+
+ *
+ * @copyright Copyright (c) 2017, ownCloud GmbH
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+
+namespace OCA\DAV\Files;
+
+
+use OCP\Files\Node;
+
+interface IFileNode {
+
+ /**
+ * @return Node
+ */
+ public function getNode();
+
+}
diff --git a/apps/dav/lib/Files/PreviewPlugin.php b/apps/dav/lib/Files/PreviewPlugin.php
new file mode 100644
index 000000000000..ad56f800f2df
--- /dev/null
+++ b/apps/dav/lib/Files/PreviewPlugin.php
@@ -0,0 +1,117 @@
+
+ *
+ * @copyright Copyright (c) 2017, ownCloud GmbH
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCA\DAV\Files;
+
+use OCP\Files\IPreviewNode;
+use OCP\ILogger;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+
+class PreviewPlugin extends ServerPlugin {
+
+ /** @var Server */
+ protected $server;
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(ILogger $logger) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Initializes the plugin and registers event handlers
+ *
+ * @param Server $server
+ * @return void
+ */
+ function initialize(Server $server) {
+
+ $this->server = $server;
+ $this->server->on('method:GET', [$this, 'httpGet'], 90);
+ }
+
+ /**
+ * Intercepts GET requests on node urls ending with ?preview.
+ * The node has to implement IPreviewNode
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @return bool
+ * @throws NotFound
+ */
+ function httpGet(RequestInterface $request, ResponseInterface $response) {
+
+ $queryParams = $request->getQueryParameters();
+ if (!array_key_exists('preview', $queryParams)) {
+ return true;
+ }
+
+ $path = $request->getPath();
+ $node = $this->server->tree->getNodeForPath($path);
+
+ if (!$node instanceof IFileNode) {
+ return false;
+ }
+ $fileNode = $node->getNode();
+ if (!$fileNode instanceof IPreviewNode) {
+ return false;
+ }
+
+ // Checking ACL, if available.
+ if ($aclPlugin = $this->server->getPlugin('acl')) {
+ /** @var \Sabre\DAVACL\Plugin $aclPlugin */
+ $aclPlugin->checkPrivileges($path, '{DAV:}read');
+ }
+
+ if ($image = $fileNode->getThumbnail($queryParams)) {
+ if ($image === null || !$image->valid()) {
+ return false;
+ }
+ $type = $image->mimeType();
+ if (!in_array($type, ['image/png', 'image/jpeg', 'image/gif'])) {
+ $type = 'application/octet-stream';
+ }
+
+ // Enable output buffering
+ ob_start();
+ // Capture the output
+ $image->show();
+ $imageData = ob_get_contents();
+ // Clear the output buffer
+ ob_end_clean();
+
+ $response->setHeader('Content-Type', $type);
+ $response->setHeader('Content-Disposition', 'attachment');
+ $response->setStatus(200);
+
+ $response->setBody($imageData);
+
+ // Returning false to break the event chain
+ return false;
+ }
+ // TODO: add forceIcon handling .... if still needed
+ throw new NotFound();
+ }
+}
diff --git a/apps/dav/lib/Meta/MetaFile.php b/apps/dav/lib/Meta/MetaFile.php
index b3e277b6361d..00cfa5a4cd0f 100644
--- a/apps/dav/lib/Meta/MetaFile.php
+++ b/apps/dav/lib/Meta/MetaFile.php
@@ -26,6 +26,8 @@
use OC\Files\Meta\MetaFileVersionNode;
use OCA\DAV\Files\ICopySource;
use OCA\DAV\Files\IProvidesAdditionalHeaders;
+use OCA\DAV\Files\IFileNode;
+use OCP\Files\Node;
use Sabre\DAV\File;
/**
@@ -34,7 +36,7 @@
*
* @package OCA\DAV\Meta
*/
-class MetaFile extends File implements ICopySource, IProvidesAdditionalHeaders {
+class MetaFile extends File implements ICopySource, IFileNode, IProvidesAdditionalHeaders {
/** @var \OCP\Files\File */
private $file;
@@ -119,4 +121,11 @@ public function getContentDispositionFileName() {
}
return $this->getName();
}
+
+ /**
+ * @return Node
+ */
+ public function getNode() {
+ return $this->file;
+ }
}
diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php
index 24d5b564c059..0daed1f1cc20 100644
--- a/apps/dav/lib/Server.php
+++ b/apps/dav/lib/Server.php
@@ -50,6 +50,7 @@
use OCA\DAV\DAV\MiscCustomPropertiesBackend;
use OCA\DAV\DAV\PublicAuth;
use OCA\DAV\Files\BrowserErrorPagePlugin;
+use OCA\DAV\Files\PreviewPlugin;
use OCA\DAV\SystemTag\SystemTagPlugin;
use OCA\DAV\Upload\ChunkingPlugin;
use OCP\IRequest;
@@ -185,6 +186,7 @@ public function __construct(IRequest $request, $baseUri) {
$this->server->addPlugin(new BrowserErrorPagePlugin());
}
+ $this->server->addPlugin(new PreviewPlugin($logger));
// wait with registering these until auth is handled and the filesystem is setup
$this->server->on('beforeMethod', function () use ($root) {
// custom properties plugin must be the last one
diff --git a/lib/private/Files/Meta/MetaFileVersionNode.php b/lib/private/Files/Meta/MetaFileVersionNode.php
index 4ab1b29320d7..de5fe6fe47b2 100644
--- a/lib/private/Files/Meta/MetaFileVersionNode.php
+++ b/lib/private/Files/Meta/MetaFileVersionNode.php
@@ -19,17 +19,18 @@
*
*/
-
namespace OC\Files\Meta;
-
use OC\Files\Node\AbstractFile;
use OC\Files\Node\File;
use OCP\Files\ForbiddenException;
use OCP\Files\IProvidesAdditionalHeaders;
+use OC\Preview;
use OCP\Files\IRootFolder;
+use OCP\Files\IPreviewNode;
use OCP\Files\Storage\IVersionedStorage;
use OCP\Files\Storage;
+use OCP\IImage;
/**
* Class MetaFileVersionNode - this class represents a version of a file in the
@@ -37,7 +38,7 @@
*
* @package OC\Files\Meta
*/
-class MetaFileVersionNode extends AbstractFile implements IProvidesAdditionalHeaders {
+class MetaFileVersionNode extends AbstractFile implements IPreviewNode, IProvidesAdditionalHeaders {
/** @var string */
private $versionId;
@@ -143,4 +144,33 @@ public function getContentDispositionFileName() {
return basename($this->internalPath);
}
+ public function getId() {
+ return $this->parent->getId();
+ }
+
+ public function getPath() {
+ return $this->parent->getPath() . '/' . $this->getName();
+ }
+
+ /**
+ * @param array $options
+ * @return IImage
+ * @since 10.1.0
+ */
+ public function getThumbnail($options) {
+ $maxX = array_key_exists('x', $options) ? (int)$options['x'] : 32;
+ $maxY = array_key_exists('y', $options) ? (int)$options['y'] : 32;
+ $scalingUp = array_key_exists('scalingup', $options) ? (bool)$options['scalingup'] : true;
+ $keepAspect = array_key_exists('a', $options) ? true : false;
+ $mode = array_key_exists('mode', $options) ? $options['mode'] : 'fill';
+
+ $preview = new Preview();
+ $preview->setFile($this, $this->versionId);
+ $preview->setMaxX($maxX);
+ $preview->setMaxY($maxY);
+ $preview->setScalingUp($scalingUp);
+ $preview->setMode($mode);
+ $preview->setKeepAspect($keepAspect);
+ return $preview->getPreview();
+ }
}
diff --git a/lib/private/Files/Node/File.php b/lib/private/Files/Node/File.php
index 5deb6a8efac9..9af1d2364667 100644
--- a/lib/private/Files/Node/File.php
+++ b/lib/private/Files/Node/File.php
@@ -26,9 +26,11 @@
namespace OC\Files\Node;
+use OCP\Files\IPreviewNode;
use OCP\Files\NotPermittedException;
+use OCP\IImage;
-class File extends Node implements \OCP\Files\File {
+class File extends Node implements \OCP\Files\File, IPreviewNode {
/**
* Creates a Folder that represents a non-existing path
*
@@ -138,4 +140,26 @@ public function hash($type, $raw = false) {
public function getChecksum() {
return $this->getFileInfo()->getChecksum();
}
+
+ /**
+ * @param array $options
+ * @return IImage
+ * @since 10.1.0
+ */
+ public function getThumbnail($options) {
+ $maxX = array_key_exists('x', $options) ? (int)$options['x'] : 32;
+ $maxY = array_key_exists('y', $options) ? (int)$options['y'] : 32;
+ $scalingUp = array_key_exists('scalingup', $options) ? (bool)$options['scalingup'] : true;
+ $keepAspect = array_key_exists('a', $options) ? true : false;
+ $mode = array_key_exists('mode', $options) ? $options['mode'] : 'fill';
+
+ $preview = new \OC\Preview();
+ $preview->setFile($this->getInternalPath(), $this->getFileInfo());
+ $preview->setMaxX($maxX);
+ $preview->setMaxY($maxY);
+ $preview->setScalingUp($scalingUp);
+ $preview->setMode($mode);
+ $preview->setKeepAspect($keepAspect);
+ return $preview->getPreview();
+ }
}
diff --git a/lib/private/Preview.php b/lib/private/Preview.php
index 685831f226fd..1b79f28511c1 100644
--- a/lib/private/Preview.php
+++ b/lib/private/Preview.php
@@ -31,7 +31,9 @@
*/
namespace OC;
+use OC\Files\View;
use OC\Preview\Provider;
+use OCP\Files\File;
use OCP\Files\FileInfo;
use OCP\Files\NotFoundException;
@@ -54,6 +56,7 @@ class Preview {
private $userView = null;
//vars
+ /** @var File */
private $file;
private $maxX;
private $maxY;
@@ -72,7 +75,7 @@ class Preview {
/** @var int $previewHeight calculated height of the preview we're looking for */
private $previewHeight;
- //filemapper used for deleting previews
+ // filemapper used for deleting previews
// index is path, value is fileinfo
static public $deleteFileMapper = [];
static public $deleteChildrenMapper = [];
@@ -83,18 +86,15 @@ class Preview {
* @var \OCP\IImage
*/
private $preview;
-
- /**
- * @var \OCP\Files\FileInfo
- */
- protected $info;
+ /** @var string */
+ private $versionId;
/**
* check if thumbnail or bigger version of thumbnail of file is cached
*
* @param string $user userid - if no user is given, OC_User::getUser will be used
* @param string $root path of root
- * @param string $file The path to the file where you want a thumbnail from
+ * @param File $file The path to the file where you want a thumbnail from
* @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the
* shape of the image
* @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the
@@ -109,16 +109,17 @@ class Preview {
public function __construct(
$user = '',
$root = '/',
- $file = '', $maxX = 1,
+ $file = null, $maxX = 1,
$maxY = 1,
- $scalingUp = true
+ $scalingUp = true,
+ $versionId = null
) {
//init fileviews
if ($user === '') {
$user = \OC_User::getUser();
}
- $this->fileView = new \OC\Files\View('/' . $user . '/' . $root);
- $this->userView = new \OC\Files\View('/' . $user);
+ $this->fileView = new View('/' . $user . '/' . $root);
+ $this->userView = new View('/' . $user);
//set config
$sysConfig = \OC::$server->getConfig();
@@ -127,7 +128,9 @@ public function __construct(
$this->maxScaleFactor = $sysConfig->getSystemValue('preview_max_scale_factor', 2);
//save parameters
- $this->setFile($file);
+ if ($file !== null) {
+ $this->setFile($file, $versionId);
+ }
$this->setMaxX((int)$maxX);
$this->setMaxY((int)$maxY);
$this->setScalingup($scalingUp);
@@ -148,7 +151,7 @@ public function __construct(
/**
* returns the path of the file you want a thumbnail from
*
- * @return string
+ * @return File
*/
public function getFile() {
return $this->file;
@@ -223,18 +226,9 @@ public function getConfigMaxY() {
* @return false|Files\FileInfo|\OCP\Files\FileInfo
*/
protected function getFileInfo() {
- $absPath = $this->fileView->getAbsolutePath($this->file);
- $absPath = Files\Filesystem::normalizePath($absPath);
- if (array_key_exists($absPath, self::$deleteFileMapper)) {
- $this->info = self::$deleteFileMapper[$absPath];
- } else if (!$this->info) {
- $this->info = $this->fileView->getFileInfo($this->file);
- }
-
- return $this->info;
+ return $this->file;
}
-
/**
* @return array|null
*/
@@ -252,21 +246,16 @@ private function getChildren() {
/**
* Sets the path of the file you want a preview of
*
- * @param string $file
+ * @param File $file
* @param \OCP\Files\FileInfo|null $info
+ * @param string $versionId
*
- * @return \OC\Preview
+ * @return Preview
*/
- public function setFile($file, $info = null) {
+ public function setFile(File $file, $versionId = null) {
$this->file = $file;
- $this->info = $info;
-
- if ($file !== '') {
- $this->getFileInfo();
- if ($this->info instanceof \OCP\Files\FileInfo) {
- $this->mimeType = $this->info->getMimetype();
- }
- }
+ $this->versionId = $versionId;
+ $this->mimeType = $this->file->getMimetype();
return $this;
}
@@ -370,14 +359,14 @@ public function setKeepAspect($keepAspect) {
*/
public function isFileValid() {
$file = $this->getFile();
- if ($file === '') {
+ if ($file === null) {
\OCP\Util::writeLog('core', 'No filename passed', \OCP\Util::DEBUG);
return false;
}
if (!$this->getFileInfo() instanceof FileInfo) {
- \OCP\Util::writeLog('core', 'File:"' . $file . '" not found', \OCP\Util::DEBUG);
+ \OCP\Util::writeLog('core', 'File:"' . $file->getPath() . '" not found', \OCP\Util::DEBUG);
return false;
}
@@ -395,9 +384,7 @@ public function isFileValid() {
public function deletePreview() {
$fileInfo = $this->getFileInfo();
if ($fileInfo !== null && $fileInfo !== false) {
- $fileId = $fileInfo->getId();
-
- $previewPath = $this->buildCachePath($fileId);
+ $previewPath = $this->buildCachePath();
if (!strpos($previewPath, 'max')) {
return $this->userView->unlink($previewPath);
}
@@ -425,7 +412,7 @@ public function deleteAllPreviews() {
// getId() might return null, e.g. when the file is a
// .ocTransferId*.part file from chunked file upload.
if (!empty($fileId)) {
- $previewPath = $this->getPreviewPath($fileId);
+ $previewPath = $this->getPreviewPath();
$this->userView->rmdir($previewPath);
}
}
@@ -443,11 +430,10 @@ public function deleteAllPreviews() {
* thumbnail should be
* * And finally, we look for a suitable candidate in the cache
*
- * @param int $fileId fileId of the original file we need a preview of
- *
* @return string|false path to the cached preview if it exists or false
*/
- public function isCached($fileId) {
+ public function isCached() {
+ $fileId = $this->getFileInfo()->getId();
if (is_null($fileId)) {
return false;
}
@@ -455,7 +441,7 @@ public function isCached($fileId) {
/**
* Phase 1: Looking for the max preview
*/
- $previewPath = $this->getPreviewPath($fileId);
+ $previewPath = $this->getPreviewPath();
// We currently can't look for a single file due to bugs related to #16478
$allThumbnails = $this->userView->getDirectoryContent($previewPath);
list($maxPreviewWidth, $maxPreviewHeight) = $this->getMaxPreviewSize($allThumbnails);
@@ -482,7 +468,7 @@ public function isCached($fileId) {
*/
// This gives us a calculated path to a preview of asked dimensions
// thumbnailFolder/fileId/-(-max|-with-aspect).png
- $preview = $this->buildCachePath($fileId, $previewWidth, $previewHeight);
+ $preview = $this->buildCachePath($previewWidth, $previewHeight);
// This checks if we have a preview of those exact dimensions in the cache
if ($this->thumbnailSizeExists($allThumbnails, basename($preview))) {
@@ -497,11 +483,11 @@ public function isCached($fileId) {
) {
// The preview we-re looking for is the exact size or larger than the max preview,
// so return that
- return $this->buildCachePath($fileId, $maxPreviewWidth, $maxPreviewHeight);
+ return $this->buildCachePath($maxPreviewWidth, $maxPreviewHeight);
} else {
// The last resort is to look for something bigger than what we've calculated,
// but still smaller than the max preview
- return $this->isCachedBigger($fileId, $allThumbnails);
+ return $this->isCachedBigger($allThumbnails);
}
}
@@ -648,12 +634,11 @@ private function fixSize($askedWidth, $askedHeight) {
* Checks if a bigger version of a file preview is cached and if not
* return the preview of max allowed dimensions
*
- * @param int $fileId fileId of the original image
* @param FileInfo[] $allThumbnails the list of all our cached thumbnails
*
* @return string path to bigger thumbnail
*/
- private function isCachedBigger($fileId, $allThumbnails) {
+ private function isCachedBigger($allThumbnails) {
// This is used to eliminate any thumbnail narrower than what we need
$maxX = $this->getMaxX();
@@ -669,7 +654,7 @@ private function isCachedBigger($fileId, $allThumbnails) {
}
// At this stage, we didn't find a preview, so we return the max preview
- return $this->buildCachePath($fileId, $this->maxPreviewWidth, $this->maxPreviewHeight);
+ return $this->buildCachePath($this->maxPreviewWidth, $this->maxPreviewHeight);
}
/**
@@ -766,14 +751,13 @@ public function getPreview() {
return new \OC_Image();
}
- $fileId = $fileInfo->getId();
- $cached = $this->isCached($fileId);
+ $cached = $this->isCached();
if ($cached) {
- $this->getCachedPreview($fileId, $cached);
+ $this->getCachedPreview($cached);
}
if (is_null($this->preview)) {
- $this->generatePreview($fileId);
+ $this->generatePreview();
}
// We still don't have a preview, so we send back an empty object
@@ -813,10 +797,9 @@ public function showPreview($mimeTypeForHeaders = null) {
/**
* Retrieves the preview from the cache and resizes it if necessary
*
- * @param int $fileId fileId of the original image
* @param string $cached the path to the cached preview
*/
- private function getCachedPreview($fileId, $cached) {
+ private function getCachedPreview($cached) {
$stream = $this->userView->fopen($cached, 'r');
$this->preview = null;
if ($stream) {
@@ -835,7 +818,7 @@ private function getCachedPreview($fileId, $cached) {
// We don't have an exact match
if ($previewX !== $maxX || $previewY !== $maxY) {
- $this->resizeAndStore($fileId);
+ $this->resizeAndStore();
}
}
@@ -845,10 +828,8 @@ private function getCachedPreview($fileId, $cached) {
/**
* Resizes, crops, fixes orientation and stores in the cache
- *
- * @param int $fileId fileId of the original image
*/
- private function resizeAndStore($fileId) {
+ private function resizeAndStore() {
$image = $this->preview;
if (!($image instanceof \OCP\IImage)) {
\OCP\Util::writeLog(
@@ -885,7 +866,7 @@ private function resizeAndStore($fileId) {
// The preview has been resized and should now have the asked dimensions
if ($newPreviewWidth === $askedWidth && $newPreviewHeight === $askedHeight) {
- $this->storePreview($fileId, $newPreviewWidth, $newPreviewHeight);
+ $this->storePreview($newPreviewWidth, $newPreviewHeight);
return;
}
@@ -897,7 +878,7 @@ private function resizeAndStore($fileId) {
// It turns out the scaled preview is now too big, so we crop the image
if ($newPreviewWidth >= $askedWidth && $newPreviewHeight >= $askedHeight) {
$this->crop($image, $askedWidth, $askedHeight, $newPreviewWidth, $newPreviewHeight);
- $this->storePreview($fileId, $askedWidth, $askedHeight);
+ $this->storePreview($askedWidth, $askedHeight);
return;
}
@@ -908,13 +889,13 @@ private function resizeAndStore($fileId) {
$this->cropAndFill(
$image, $askedWidth, $askedHeight, $newPreviewWidth, $newPreviewHeight
);
- $this->storePreview($fileId, $askedWidth, $askedHeight);
+ $this->storePreview($askedWidth, $askedHeight);
return;
}
// The preview is smaller, but we can't touch it
- $this->storePreview($fileId, $newPreviewWidth, $newPreviewHeight);
+ $this->storePreview($newPreviewWidth, $newPreviewHeight);
}
/**
@@ -1038,11 +1019,10 @@ private function cropAndFill($image, $askedWidth, $askedHeight, $previewWidth, $
*
* Do not nullify the preview as it might send the whole process in a loop
*
- * @param int $fileId fileId of the original image
* @param int $previewWidth
* @param int $previewHeight
*/
- private function storePreview($fileId, $previewWidth, $previewHeight) {
+ private function storePreview($previewWidth, $previewHeight) {
if (empty($previewWidth) || empty($previewHeight)) {
\OCP\Util::writeLog(
'core', 'Cannot save preview of dimension ' . $previewWidth . 'x' . $previewHeight,
@@ -1050,7 +1030,7 @@ private function storePreview($fileId, $previewWidth, $previewHeight) {
);
} else {
- $cachePath = $this->buildCachePath($fileId, $previewWidth, $previewHeight);
+ $cachePath = $this->buildCachePath($previewWidth, $previewHeight);
$this->userView->file_put_contents($cachePath, $this->preview->data());
}
}
@@ -1058,13 +1038,12 @@ private function storePreview($fileId, $previewWidth, $previewHeight) {
/**
* Returns the path to a preview based on its dimensions and aspect
*
- * @param int $fileId
* @param int|null $maxX
* @param int|null $maxY
*
* @return string
*/
- private function buildCachePath($fileId, $maxX = null, $maxY = null) {
+ private function buildCachePath($maxX = null, $maxY = null) {
if (is_null($maxX)) {
$maxX = $this->getMaxX();
}
@@ -1072,7 +1051,7 @@ private function buildCachePath($fileId, $maxX = null, $maxY = null) {
$maxY = $this->getMaxY();
}
- $previewPath = $this->getPreviewPath($fileId);
+ $previewPath = $this->getPreviewPath();
$previewPath = $previewPath . strval($maxX) . '-' . strval($maxY);
$isMaxPreview =
($maxX === $this->maxPreviewWidth && $maxY === $this->maxPreviewHeight) ? true : false;
@@ -1093,11 +1072,14 @@ private function buildCachePath($fileId, $maxX = null, $maxY = null) {
/**
* Returns the path to the folder where the previews are stored, identified by the fileId
*
- * @param int $fileId
- *
* @return string
*/
- private function getPreviewPath($fileId) {
+ private function getPreviewPath() {
+ $fileId = $this->getFileInfo()->getId();
+ if ($this->versionId !== null) {
+ $fileId .= '/';
+ $fileId .= $this->versionId;
+ }
return $this->getThumbnailsFolder() . '/' . $fileId . '/';
}
@@ -1111,9 +1093,8 @@ private function getPreviewPath($fileId) {
* We never upscale the original conversion as this will be done later by the resizing
* operation
*
- * @param int $fileId fileId of the original image
*/
- private function generatePreview($fileId) {
+ private function generatePreview() {
$file = $this->getFile();
$preview = null;
@@ -1131,22 +1112,20 @@ private function generatePreview($fileId) {
}
\OCP\Util::writeLog(
- 'core', 'Generating preview for "' . $file . '" with "' . get_class($provider)
+ 'core', 'Generating preview for "' . $file->getPath() . '" with "' . get_class($provider)
. '"', \OCP\Util::DEBUG
);
/** @var $provider Provider */
$preview = $provider->getThumbnail(
- $file, $this->configMaxWidth, $this->configMaxHeight, $scalingUp = false,
- $this->fileView
- );
+ $file, $this->configMaxWidth, $this->configMaxHeight, $scalingUp = false);
if (!($preview instanceof \OCP\IImage)) {
continue;
}
$this->preview = $preview;
- $previewPath = $this->getPreviewPath($fileId);
+ $previewPath = $this->getPreviewPath();
if ($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) {
$this->userView->mkdir($this->getThumbnailsFolder() . '/');
@@ -1165,7 +1144,7 @@ private function generatePreview($fileId) {
// The providers have been kind enough to give us a preview
if ($preview) {
- $this->resizeAndStore($fileId);
+ $this->resizeAndStore();
}
}
@@ -1262,7 +1241,7 @@ public static function prepare_delete(array $args, $prefix = '') {
$path = substr($path, 1);
}
- $view = new \OC\Files\View('/' . \OC_User::getUser() . '/' . $prefix);
+ $view = new View('/' . \OC_User::getUser() . '/' . $prefix);
$absPath = Files\Filesystem::normalizePath($view->getAbsolutePath($path));
$fileInfo = $view->getFileInfo($path);
@@ -1285,7 +1264,7 @@ private static function addPathToDeleteFileMapper($absolutePath, $info) {
}
/**
- * @param \OC\Files\View $view
+ * @param View $view
* @param string $path
*
* @return array
diff --git a/lib/private/Preview/Provider.php b/lib/private/Preview/Provider.php
index ede6a4781ba6..448071c39477 100644
--- a/lib/private/Preview/Provider.php
+++ b/lib/private/Preview/Provider.php
@@ -44,24 +44,14 @@ public function __construct(array $options = []) {
abstract public function getMimeType();
/**
- * Check if a preview can be generated for $path
- *
- * @param \OCP\Files\FileInfo $file
- * @return bool
+ * @inheritdoc
*/
public function isAvailable(\OCP\Files\FileInfo $file) {
return true;
}
/**
- * Generates thumbnail which fits in $maxX and $maxY and keeps the aspect ratio, for file at path $path
- *
- * @param string $path Path of file
- * @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
- * @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
- * @param bool $scalingup Disable/Enable upscaling of previews
- * @param \OC\Files\View $fileview fileview object of user folder
- * @return bool|\OCP\IImage false if no preview was generated
+ * @inheritdoc
*/
- abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview);
+ abstract public function getThumbnail($path, $maxX, $maxY, $scalingup);
}
diff --git a/lib/private/Preview/TXT.php b/lib/private/Preview/TXT.php
index e984f8adf5c7..39acddebb0ba 100644
--- a/lib/private/Preview/TXT.php
+++ b/lib/private/Preview/TXT.php
@@ -43,8 +43,8 @@ public function isAvailable(\OCP\Files\FileInfo $file) {
/**
* {@inheritDoc}
*/
- public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
- $stream = $fileview->fopen($path, 'r');
+ public function getThumbnail($file, $maxX, $maxY, $scalingup) {
+ $stream = $file->fopen('r');
$content = stream_get_contents($stream,3000);
fclose($stream);
diff --git a/lib/public/Files/IPreviewNode.php b/lib/public/Files/IPreviewNode.php
new file mode 100644
index 000000000000..b849d1eeb6c7
--- /dev/null
+++ b/lib/public/Files/IPreviewNode.php
@@ -0,0 +1,43 @@
+
+ *
+ * @copyright Copyright (c) 2017, ownCloud GmbH
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCP\Files;
+
+use OCP\IImage;
+
+/**
+ * Interface IPreviewNode - a node which can generate a preview will implement
+ * this interface.
+ *
+ * @package OCP\Files
+ * @since 10.1.0
+ */
+interface IPreviewNode {
+
+ /**
+ * Generates a preview image of the node
+ *
+ * @param array $options
+ * @return IImage
+ * @since 10.1.0
+ */
+ public function getThumbnail($options);
+}
diff --git a/lib/public/Preview/IProvider.php b/lib/public/Preview/IProvider.php
index ae7c2d22c343..50bf5c325cd1 100644
--- a/lib/public/Preview/IProvider.php
+++ b/lib/public/Preview/IProvider.php
@@ -21,6 +21,8 @@
*/
namespace OCP\Preview;
+use OCP\Files\File;
+
/**
* Interface IProvider
*
@@ -46,13 +48,12 @@ public function isAvailable(\OCP\Files\FileInfo $file);
/**
* get thumbnail for file at path $path
*
- * @param string $path Path of file
+ * @param File $path Path of file
* @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
* @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
* @param bool $scalingup Disable/Enable upscaling of previews
- * @param \OC\Files\View $fileview fileview object of user folder
* @return bool|\OCP\IImage false if no preview was generated
* @since 8.1.0
*/
- public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview);
+ public function getThumbnail($path, $maxX, $maxY, $scalingup);
}
diff --git a/tests/lib/Files/Node/FileTest.php b/tests/lib/Files/Node/FileTest.php
index 6ac5c8f0eb78..fc1b8457f2f9 100644
--- a/tests/lib/Files/Node/FileTest.php
+++ b/tests/lib/Files/Node/FileTest.php
@@ -7,6 +7,13 @@
*/
namespace Test\Files\Node;
+use OC\Files\Mount\Manager;
+use OC\Files\Node\File;
+use OC\Files\Node\NonExistingFile;
+use OC\Files\Node\Root;
+use OC\Files\View;
+use OCP\Constants;
+use OCP\IImage;
/**
* Class FileTest
@@ -18,23 +25,21 @@
class FileTest extends NodeTest {
public $viewDeleteMethod = 'unlink';
- public $nodeClass = '\OC\Files\Node\File';
- public $nonExistingNodeClass = '\OC\Files\Node\NonExistingFile';
+ public $nodeClass = File::class;
+ public $nonExistingNodeClass = NonExistingFile::class;
protected function createTestNode($root, $view, $path) {
- return new \OC\Files\Node\File($root, $view, $path);
+ return new File($root, $view, $path);
}
public function testGetContent() {
+ /** @var Manager $manager */
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
- /**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
- */
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, $view, $this->user);
$hook = function ($file) {
throw new \Exception('Hooks are not supposed to be called');
@@ -51,9 +56,9 @@ public function testGetContent() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_READ])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$this->assertEquals('bar', $node->getContent());
}
@@ -61,11 +66,10 @@ public function testGetContent() {
* @expectedException \OCP\Files\NotPermittedException
*/
public function testGetContentNotPermitted() {
- /**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
- */
- $view = $this->createMock('\OC\Files\View');
- $root = $this->createMock('\OC\Files\Node\Root');
+ /** @var View | \PHPUnit_Framework_MockObject_MockObject $view */
+ $view = $this->createMock(View::class);
+ /** @var Root | \PHPUnit_Framework_MockObject_MockObject $root */
+ $root = $this->createMock(Root::class);
$root->expects($this->any())
->method('getUser')
@@ -76,16 +80,15 @@ public function testGetContentNotPermitted() {
->with('/bar/foo')
->will($this->returnValue($this->getFileInfo(['permissions' => 0])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->getContent();
}
public function testPutContent() {
- /**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
- */
- $view = $this->createMock('\OC\Files\View');
- $root = $this->createMock('\OC\Files\Node\Root');
+ /** @var View | \PHPUnit_Framework_MockObject_MockObject $view */
+ $view = $this->createMock(View::class);
+ /** @var Root | \PHPUnit_Framework_MockObject_MockObject $root */
+ $root = $this->createMock(Root::class);
$root->expects($this->any())
->method('getUser')
@@ -94,14 +97,14 @@ public function testPutContent() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL])));
$view->expects($this->once())
->method('file_put_contents')
->with('/bar/foo', 'bar')
->will($this->returnValue(true));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->putContent('bar');
}
@@ -109,34 +112,32 @@ public function testPutContent() {
* @expectedException \OCP\Files\NotPermittedException
*/
public function testPutContentNotPermitted() {
- /**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
- */
- $view = $this->createMock('\OC\Files\View');
- $root = $this->createMock('\OC\Files\Node\Root');
+ /** @var View | \PHPUnit_Framework_MockObject_MockObject $view */
+ $view = $this->createMock(View::class);
+ /** @var Root | \PHPUnit_Framework_MockObject_MockObject $root */
+ $root = $this->createMock(Root::class);
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_READ])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->putContent('bar');
}
public function testGetMimeType() {
- /**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
- */
- $view = $this->createMock('\OC\Files\View');
- $root = $this->createMock('\OC\Files\Node\Root');
+ /** @var View | \PHPUnit_Framework_MockObject_MockObject $view */
+ $view = $this->createMock(View::class);
+ /** @var Root | \PHPUnit_Framework_MockObject_MockObject $root */
+ $root = $this->createMock(Root::class);
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
->will($this->returnValue($this->getFileInfo(['mimetype' => 'text/plain'])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$this->assertEquals('text/plain', $node->getMimeType());
}
@@ -146,14 +147,14 @@ public function testFOpenRead() {
rewind($stream);
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var Manager $manager
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, $view, $this->user);
$hook = function ($file) {
throw new \Exception('Hooks are not supposed to be called');
@@ -170,9 +171,9 @@ public function testFOpenRead() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$fh = $node->fopen('r');
$this->assertEquals($stream, $fh);
$this->assertEquals('bar', fread($fh, 3));
@@ -182,14 +183,14 @@ public function testFOpenWrite() {
$stream = fopen('php://memory', 'w+');
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var Manager $manager
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, new $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, new $view, $this->user);
$hooksCalled = 0;
$hook = function ($file) use (&$hooksCalled) {
@@ -207,9 +208,9 @@ public function testFOpenWrite() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_ALL])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$fh = $node->fopen('w');
$this->assertEquals($stream, $fh);
fwrite($fh, 'bar');
@@ -223,14 +224,14 @@ public function testFOpenWrite() {
*/
public function testFOpenReadNotPermitted() {
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var Manager $manager
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, $view, $this->user);
$hook = function ($file) {
throw new \Exception('Hooks are not supposed to be called');
@@ -241,7 +242,7 @@ public function testFOpenReadNotPermitted() {
->with('/bar/foo')
->will($this->returnValue($this->getFileInfo(['permissions' => 0])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->fopen('r');
}
@@ -250,14 +251,14 @@ public function testFOpenReadNotPermitted() {
*/
public function testFOpenReadWriteNoReadPermissions() {
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var Manager $manager
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, $view, $this->user);
$hook = function () {
throw new \Exception('Hooks are not supposed to be called');
@@ -266,9 +267,9 @@ public function testFOpenReadWriteNoReadPermissions() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_UPDATE])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_UPDATE])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->fopen('w');
}
@@ -277,14 +278,14 @@ public function testFOpenReadWriteNoReadPermissions() {
*/
public function testFOpenReadWriteNoWritePermissions() {
/**
- * @var \OC\Files\Mount\Manager $manager
+ * @var Manager $manager
*/
- $manager = $this->createMock('\OC\Files\Mount\Manager');
+ $manager = $this->createMock(Manager::class);
/**
- * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
*/
- $view = $this->createMock('\OC\Files\View');
- $root = new \OC\Files\Node\Root($manager, new $view, $this->user);
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, new $view, $this->user);
$hook = function () {
throw new \Exception('Hooks are not supposed to be called');
@@ -293,11 +294,48 @@ public function testFOpenReadWriteNoWritePermissions() {
$view->expects($this->once())
->method('getFileInfo')
->with('/bar/foo')
- ->will($this->returnValue($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ])));
+ ->will($this->returnValue($this->getFileInfo(['permissions' => Constants::PERMISSION_READ])));
- $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+ $node = new File($root, $view, '/bar/foo');
$node->fopen('w');
}
+ public function testThumbnail() {
+ /** @var Manager $manager */
+ $manager = $this->createMock(Manager::class);
+ /**
+ * @var View | \PHPUnit_Framework_MockObject_MockObject $view
+ */
+ $view = $this->createMock(View::class);
+ $root = new Root($manager, $view, $this->user);
+
+ $hook = function ($file) {
+ throw new \Exception('Hooks are not supposed to be called');
+ };
+
+ $root->listen('\OC\Files', 'preWrite', $hook);
+ $root->listen('\OC\Files', 'postWrite', $hook);
+
+ $content = $stream = fopen('data://text/plain,hello world!','r');;
+ $view->expects($this->once())
+ ->method('fopen')
+ ->with('/bar/foo')
+ ->will($this->returnValue($content));
+
+ $view->expects($this->once())
+ ->method('getFileInfo')
+ ->with('/bar/foo')
+ ->will($this->returnValue($this->getFileInfo([
+ 'permissions' => Constants::PERMISSION_READ,
+ 'mimetype' => 'text/plain',
+ 'fileid' => 666
+ ])));
+
+ $node = new File($root, $view, '/bar/foo');
+ $image = $node->getThumbnail([]);
+ $this->assertInstanceOf(IImage::class, $image);
+ $this->assertEquals(32, $image->height());
+ $this->assertEquals(32, $image->width());
+ }
}